diff --git a/packages/docker/package.json b/packages/docker/package.json index 707e891..ea8ba84 100644 --- a/packages/docker/package.json +++ b/packages/docker/package.json @@ -5,7 +5,10 @@ "main": "lib/index.js", "scripts": { "test": "jest --runInBand", - "build": "npx tsc && npx ncc build" + "build": "npx tsc && npx ncc build", + "format": "prettier --write '**/*.ts'", + "format-check": "prettier --check '**/*.ts'", + "lint": "eslint src/**/*.ts" }, "author": "", "license": "MIT", diff --git a/packages/docker/src/dockerCommands/container.ts b/packages/docker/src/dockerCommands/container.ts index 91637a9..807d77a 100644 --- a/packages/docker/src/dockerCommands/container.ts +++ b/packages/docker/src/dockerCommands/container.ts @@ -43,11 +43,16 @@ export async function createContainer( if (args.environmentVariables) { for (const [key] of Object.entries(args.environmentVariables)) { - dockerArgs.push('-e') - dockerArgs.push(key) + dockerArgs.push('-e', key) } } + dockerArgs.push('-e', 'GITHUB_ACTIONS=true') + // Use same behavior as the runner https://github.com/actions/runner/blob/27d9c886ab9a45e0013cb462529ac85d581f8c41/src/Runner.Worker/Container/DockerCommandManager.cs#L150 + if (!('CI' in (args.environmentVariables ?? {}))) { + dockerArgs.push('-e', 'CI=true') + } + const mountVolumes = [ ...(args.userMountVolumes || []), ...(args.systemMountVolumes || []) @@ -403,11 +408,16 @@ export async function containerRun( } if (args.environmentVariables) { for (const [key] of Object.entries(args.environmentVariables)) { - dockerArgs.push('-e') - dockerArgs.push(key) + dockerArgs.push('-e', key) } } + dockerArgs.push('-e', 'GITHUB_ACTIONS=true') + // Use same behavior as the runner https://github.com/actions/runner/blob/27d9c886ab9a45e0013cb462529ac85d581f8c41/src/Runner.Worker/Container/DockerCommandManager.cs#L150 + if (!('CI' in (args.environmentVariables ?? {}))) { + dockerArgs.push('-e', 'CI=true') + } + const mountVolumes = [ ...(args.userMountVolumes || []), ...(args.systemMountVolumes || []) diff --git a/packages/docker/tests/run-script-step-test.ts b/packages/docker/tests/run-script-step-test.ts index 5fdd33c..edf1f02 100644 --- a/packages/docker/tests/run-script-step-test.ts +++ b/packages/docker/tests/run-script-step-test.ts @@ -75,4 +75,22 @@ describe('run script step', () => { runScriptStep(definitions.runScriptStep.args, prepareJobResponse.state) ).resolves.not.toThrow() }) + + it('Should confirm that CI and GITHUB_ACTIONS are set', async () => { + definitions.runScriptStep.args.entryPoint = '/bin/bash' + definitions.runScriptStep.args.entryPointArgs = [ + '-c', + `'if [[ ! $(env | grep "^CI=") = "CI=true" ]]; then exit 1; fi'` + ] + await expect( + runScriptStep(definitions.runScriptStep.args, prepareJobResponse.state) + ).resolves.not.toThrow() + definitions.runScriptStep.args.entryPointArgs = [ + '-c', + `'if [[ ! $(env | grep "^GITHUB_ACTIONS=") = "GITHUB_ACTIONS=true" ]]; then exit 1; fi'` + ] + await expect( + runScriptStep(definitions.runScriptStep.args, prepareJobResponse.state) + ).resolves.not.toThrow() + }) }) diff --git a/packages/k8s/src/hooks/prepare-job.ts b/packages/k8s/src/hooks/prepare-job.ts index 89202dc..1dc7ad3 100644 --- a/packages/k8s/src/hooks/prepare-job.ts +++ b/packages/k8s/src/hooks/prepare-job.ts @@ -229,6 +229,18 @@ export function createContainerSpec( } } + podContainer.env.push({ + name: 'GITHUB_ACTIONS', + value: 'true' + }) + + if (!('CI' in container['environmentVariables'])) { + podContainer.env.push({ + name: 'CI', + value: 'true' + }) + } + podContainer.volumeMounts = containerVolumes( container.userMountVolumes, jobContainer diff --git a/packages/k8s/src/hooks/run-container-step.ts b/packages/k8s/src/hooks/run-container-step.ts index dbc98b4..e526153 100644 --- a/packages/k8s/src/hooks/run-container-step.ts +++ b/packages/k8s/src/hooks/run-container-step.ts @@ -29,7 +29,14 @@ export async function runContainerStep( let secretName: string | undefined = undefined if (stepContainer.environmentVariables) { try { - secretName = await createSecretForEnvs(stepContainer.environmentVariables) + const envs = JSON.parse( + JSON.stringify(stepContainer.environmentVariables) + ) + envs['GITHUB_ACTIONS'] = 'true' + if (!('CI' in envs)) { + envs.CI = 'true' + } + secretName = await createSecretForEnvs(envs) } catch (err) { core.debug(`createSecretForEnvs failed: ${JSON.stringify(err)}`) const message = (err as any)?.response?.body?.message || err diff --git a/packages/k8s/tests/prepare-job-test.ts b/packages/k8s/tests/prepare-job-test.ts index 18e3683..ca94e6c 100644 --- a/packages/k8s/tests/prepare-job-test.ts +++ b/packages/k8s/tests/prepare-job-test.ts @@ -62,6 +62,54 @@ describe('Prepare job', () => { ).resolves.not.toThrow() }) + it('should prepare job with envs CI and GITHUB_ACTIONS', async () => { + await prepareJob(prepareJobData.args, prepareJobOutputFilePath) + + const content = JSON.parse( + fs.readFileSync(prepareJobOutputFilePath).toString() + ) + + const got = await getPodByName(content.state.jobPod) + expect(got.spec?.containers[0].env).toEqual( + expect.arrayContaining([ + { name: 'CI', value: 'true' }, + { name: 'GITHUB_ACTIONS', value: 'true' } + ]) + ) + expect(got.spec?.containers[1].env).toEqual( + expect.arrayContaining([ + { name: 'CI', value: 'true' }, + { name: 'GITHUB_ACTIONS', value: 'true' } + ]) + ) + }) + + it('should not override CI env var if already set', async () => { + prepareJobData.args.container.environmentVariables = { + CI: 'false' + } + + await prepareJob(prepareJobData.args, prepareJobOutputFilePath) + + const content = JSON.parse( + fs.readFileSync(prepareJobOutputFilePath).toString() + ) + + const got = await getPodByName(content.state.jobPod) + expect(got.spec?.containers[0].env).toEqual( + expect.arrayContaining([ + { name: 'CI', value: 'false' }, + { name: 'GITHUB_ACTIONS', value: 'true' } + ]) + ) + expect(got.spec?.containers[1].env).toEqual( + expect.arrayContaining([ + { name: 'CI', value: 'true' }, + { name: 'GITHUB_ACTIONS', value: 'true' } + ]) + ) + }) + it('should throw an exception if the user volume mount is absolute path outside of GITHUB_WORKSPACE', async () => { prepareJobData.args.container.userMountVolumes = [ { @@ -133,9 +181,13 @@ describe('Prepare job', () => { expect(got.spec?.containers[1].image).toBe('redis') expect(got.spec?.containers[1].command).toBeFalsy() expect(got.spec?.containers[1].args).toBeFalsy() - expect(got.spec?.containers[1].env).toEqual([ - { name: 'ENV2', value: 'value2' } - ]) + expect(got.spec?.containers[1].env).toEqual( + expect.arrayContaining([ + { name: 'CI', value: 'true' }, + { name: 'GITHUB_ACTIONS', value: 'true' }, + { name: 'ENV2', value: 'value2' } + ]) + ) expect(got.spec?.containers[1].resources).toEqual({ requests: { memory: '1Mi', cpu: '1' }, limits: { memory: '1Gi', cpu: '2' } diff --git a/packages/k8s/tests/run-container-step-test.ts b/packages/k8s/tests/run-container-step-test.ts index 7689c80..51a33b7 100644 --- a/packages/k8s/tests/run-container-step-test.ts +++ b/packages/k8s/tests/run-container-step-test.ts @@ -78,4 +78,15 @@ describe('Run container step', () => { runContainerStep(runContainerStepData.args) ).resolves.not.toThrow() }) + + it('should run container step with envs CI and GITHUB_ACTIONS', async () => { + runContainerStepData.args.entryPoint = 'bash' + runContainerStepData.args.entryPointArgs = [ + '-c', + "'if [[ -z $GITHUB_ACTIONS ]] || [[ -z $CI ]]; then exit 1; fi'" + ] + await expect( + runContainerStep(runContainerStepData.args) + ).resolves.not.toThrow() + }) })