Implement basic ci detection
All checks were successful
/ deploy (push) Successful in 13s

This commit is contained in:
Jonatan Nilsson 2024-11-18 23:57:35 +00:00
parent be00a19e87
commit cae63830da
7 changed files with 204 additions and 1 deletions

View file

@ -0,0 +1,24 @@
on:
push:
branches:
- master
jobs:
deploy:
runs-on: arch
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Install dependencies
run: time pnpm install
- name: Run Tests
run: pnpm run test --ignore-only
- name: Sanity check it detects this CI
run: |
if node index.js; then
echo "Success"
else
echo "Failed for forgejo"
exit 1
fi

View file

@ -1,3 +1,22 @@
# inside-ci # inside-ci
Quick tool to check if we are inside a CI environment Quick tool to check if we are inside a CI environment
# API
`insideCi()`
Returns true if inside CI. Otherwise returns false.
# CLI
`inside-ci`
Returns code 0 if inside CI. Otherwise returns an error code of 1.
`inside-ci || echo 'We are not inside CI, install some stuff'`
`inside-ci && echo 'We are inside CI, install some stuff'`
Example:
`is-ci || husky install`

2
index.d.ts vendored Normal file
View file

@ -0,0 +1,2 @@
/** Returns true if current environment is running inside CI. Otherwise returns false. */
export function insideCi()

22
index.js Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env node
/** Returns true if current environment is running inside CI. Otherwise returns false. */
function insideCi() {
// Bail out if this is specifically overwritten to false.
// Some users seem to wanna be able to do that
if (process.env.CI === 'false') return false
// Most CI use env.CI (travis, Gitlab, etc.)
// There are some exceptions though:
// CI_APP_ID is used by Appflow: https://ionic.io/docs/appflow/package/environments#predefined-environments
// CI_NAME is used by Codeship:https://docs.cloudbees.com/docs/cloudbees-codeship/latest/pro-builds-and-configuration/environment-variables
// BUILD_NUMBER is used by TeamCity: https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters
// RUN_ID is used by Taskcluster: https://docs.taskcluster.net/docs/reference/workers/docker-worker/environment
return Boolean(['CI','CI_APP_ID','BUILD_NUMBER','CI_NAME','RUN_ID'].some(x => process.env[x]))
}
module.exports.insideCi = insideCi
if (require.main === module) {
process.exit(insideCi() ? 0 : 1)
}

26
package-lock.json generated Normal file
View file

@ -0,0 +1,26 @@
{
"name": "inside-ci",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "inside-ci",
"version": "1.0.0",
"license": "WTFPL",
"devDependencies": {
"eltro": "^1.6.1"
}
},
"node_modules/eltro": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/eltro/-/eltro-1.6.1.tgz",
"integrity": "sha512-g291jOxdUPnXBexOedGFNhswQ4127EuPOmYG6UMkPnowCUw91JRyogoEQKxtIrnhrfGR60b98C54GUzi3pJ44Q==",
"dev": true,
"license": "WTFPL",
"bin": {
"eltro": "cli.mjs"
}
}
}
}

39
package.json Normal file
View file

@ -0,0 +1,39 @@
{
"name": "inside-ci",
"version": "1.0.0",
"description": "Quick tool to check if we are inside CI",
"main": "index.js",
"scripts": {
"test": "eltro -r dot test.mjs",
"test:watch": "eltro -r dot -w test test.mjs"
},
"bin": {
"inside-ci": "./index.js"
},
"watch": {
"test": {
"patterns": ["index.js", "test.mjs"]
}
},
"repository": {
"type": "git",
"url": "https://git.nfp.is/TheThing/inside-ci.git"
},
"keywords": [
"ci",
"is-ci",
"inside-ci",
"environment"
],
"author": "Jonatan Nilsson",
"license": "WTFPL",
"devDependencies": {
"eltro": "^1.6.1"
},
"files": [
"index.js",
"index.d.ts",
"README.md",
"LICENSE"
]
}

71
test.mjs Normal file
View file

@ -0,0 +1,71 @@
import { exec } from 'child_process'
import { Eltro as t, assert } from 'eltro'
import { insideCi } from './index.js'
t.describe('#insideCi()', function () {
const testVariables = [
'CI',
'CI_APP_ID',
'BUILD_NUMBER',
'CI_NAME',
'RUN_ID',
]
t.beforeEach(function () {
for (let name of testVariables) {
delete process.env[name]
}
})
testVariables.forEach(name => {
t.test(`env.${name} should return true if set`, function () {
process.env[name] = 'asdf'
assert.ok(insideCi())
})
})
t.test('should return false by default', function() {
assert.notOk(insideCi())
})
t.test('should return false if all are empty strings', function () {
for (let name of testVariables) {
process.env[name] = ''
}
assert.notOk(insideCi())
})
t.test('should return false if env.CI is specifically "false"', function () {
process.env.CI = 'false'
assert.notOk(insideCi())
})
})
function runCommand(command, options) {
return new Promise(function (res) {
exec(command, options, function (err, stdout, stderr) {
res({
err, stdout, stderr
})
})
})
}
t.describe('CLI', function() {
t.test('should return success/code 0 if CI is filled', async function () {
let result = await runCommand('node index.js', {
env: { CI: 'true' }
})
assert.notOk(result.err)
})
t.test('should return error code 1 if CI is false', async function () {
let result = await runCommand('node index.js', {
env: { CI: 'false' }
})
assert.ok(result.err)
assert.strictEqual(result.err.code, 1)
})
})