Compare commits

...

3 Commits

Author SHA1 Message Date
Nikola Jokic
7da5474a5d Release 0.7.0 (#218) 2025-04-17 12:34:48 +02:00
Nikola Jokic
375992cd31 Expose CI=true and GITHUB_ACTIONS env variables (#215)
* Expose CI=true and GITHUB_ACTIONS env variables

* fmt

* revert the prettier and finish this

* revert package-lock.json
2025-04-17 12:08:32 +02:00
Nikola Jokic
aae800a69b bump node in tests to node 22 since node14 is quite old (#216)
* bump node in tests to node 22 since node14 is quite old

* change test contsants
2025-04-16 15:57:59 +02:00
13 changed files with 148 additions and 21 deletions

View File

@@ -4,7 +4,7 @@
"state": {}, "state": {},
"args": { "args": {
"container": { "container": {
"image": "node:14.16", "image": "node:22",
"workingDirectory": "/__w/repo/repo", "workingDirectory": "/__w/repo/repo",
"createOptions": "--cpus 1", "createOptions": "--cpus 1",
"environmentVariables": { "environmentVariables": {

View File

@@ -9,7 +9,7 @@
} }
}, },
"args": { "args": {
"image": "node:14.16", "image": "node:22",
"dockerfile": null, "dockerfile": null,
"entryPointArgs": [ "entryPointArgs": [
"-e", "-e",

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "hooks", "name": "hooks",
"version": "0.6.2", "version": "0.7.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "hooks", "name": "hooks",
"version": "0.6.2", "version": "0.7.0",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/jest": "^27.5.1", "@types/jest": "^27.5.1",

View File

@@ -1,6 +1,6 @@
{ {
"name": "hooks", "name": "hooks",
"version": "0.6.2", "version": "0.7.0",
"description": "Three projects are included - k8s: a kubernetes hook implementation that spins up pods dynamically to run a job - docker: A hook implementation of the runner's docker implementation - A hook lib, which contains shared typescript definitions and utilities that the other packages consume", "description": "Three projects are included - k8s: a kubernetes hook implementation that spins up pods dynamically to run a job - docker: A hook implementation of the runner's docker implementation - A hook lib, which contains shared typescript definitions and utilities that the other packages consume",
"main": "", "main": "",
"directories": { "directories": {

View File

@@ -5,7 +5,10 @@
"main": "lib/index.js", "main": "lib/index.js",
"scripts": { "scripts": {
"test": "jest --runInBand", "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": "", "author": "",
"license": "MIT", "license": "MIT",

View File

@@ -43,11 +43,16 @@ export async function createContainer(
if (args.environmentVariables) { if (args.environmentVariables) {
for (const [key] of Object.entries(args.environmentVariables)) { for (const [key] of Object.entries(args.environmentVariables)) {
dockerArgs.push('-e') dockerArgs.push('-e', key)
dockerArgs.push(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 = [ const mountVolumes = [
...(args.userMountVolumes || []), ...(args.userMountVolumes || []),
...(args.systemMountVolumes || []) ...(args.systemMountVolumes || [])
@@ -403,11 +408,16 @@ export async function containerRun(
} }
if (args.environmentVariables) { if (args.environmentVariables) {
for (const [key] of Object.entries(args.environmentVariables)) { for (const [key] of Object.entries(args.environmentVariables)) {
dockerArgs.push('-e') dockerArgs.push('-e', key)
dockerArgs.push(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 = [ const mountVolumes = [
...(args.userMountVolumes || []), ...(args.userMountVolumes || []),
...(args.systemMountVolumes || []) ...(args.systemMountVolumes || [])

View File

@@ -75,4 +75,22 @@ describe('run script step', () => {
runScriptStep(definitions.runScriptStep.args, prepareJobResponse.state) runScriptStep(definitions.runScriptStep.args, prepareJobResponse.state)
).resolves.not.toThrow() ).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()
})
}) })

View File

@@ -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( podContainer.volumeMounts = containerVolumes(
container.userMountVolumes, container.userMountVolumes,
jobContainer jobContainer

View File

@@ -29,7 +29,14 @@ export async function runContainerStep(
let secretName: string | undefined = undefined let secretName: string | undefined = undefined
if (stepContainer.environmentVariables) { if (stepContainer.environmentVariables) {
try { 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) { } catch (err) {
core.debug(`createSecretForEnvs failed: ${JSON.stringify(err)}`) core.debug(`createSecretForEnvs failed: ${JSON.stringify(err)}`)
const message = (err as any)?.response?.body?.message || err const message = (err as any)?.response?.body?.message || err

View File

@@ -394,7 +394,7 @@ metadata:
spec: spec:
containers: containers:
- name: test - name: test
image: node:14.16 image: node:22
- name: job - name: job
image: ubuntu:latest` image: ubuntu:latest`
) )
@@ -407,7 +407,7 @@ spec:
it('should merge container spec', () => { it('should merge container spec', () => {
const base = { const base = {
image: 'node:14.16', image: 'node:22',
name: 'test', name: 'test',
env: [ env: [
{ {
@@ -462,7 +462,7 @@ spec:
const base = { const base = {
containers: [ containers: [
{ {
image: 'node:14.16', image: 'node:22',
name: 'test', name: 'test',
env: [ env: [
{ {

View File

@@ -62,6 +62,54 @@ describe('Prepare job', () => {
).resolves.not.toThrow() ).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 () => { it('should throw an exception if the user volume mount is absolute path outside of GITHUB_WORKSPACE', async () => {
prepareJobData.args.container.userMountVolumes = [ prepareJobData.args.container.userMountVolumes = [
{ {
@@ -125,7 +173,7 @@ describe('Prepare job', () => {
// job container // job container
expect(got.spec?.containers[0].name).toBe(JOB_CONTAINER_NAME) expect(got.spec?.containers[0].name).toBe(JOB_CONTAINER_NAME)
expect(got.spec?.containers[0].image).toBe('node:14.16') expect(got.spec?.containers[0].image).toBe('node:22')
expect(got.spec?.containers[0].command).toEqual(['sh']) expect(got.spec?.containers[0].command).toEqual(['sh'])
expect(got.spec?.containers[0].args).toEqual(['-c', 'sleep 50']) expect(got.spec?.containers[0].args).toEqual(['-c', 'sleep 50'])
@@ -133,9 +181,13 @@ describe('Prepare job', () => {
expect(got.spec?.containers[1].image).toBe('redis') expect(got.spec?.containers[1].image).toBe('redis')
expect(got.spec?.containers[1].command).toBeFalsy() expect(got.spec?.containers[1].command).toBeFalsy()
expect(got.spec?.containers[1].args).toBeFalsy() expect(got.spec?.containers[1].args).toBeFalsy()
expect(got.spec?.containers[1].env).toEqual([ expect(got.spec?.containers[1].env).toEqual(
{ name: 'ENV2', value: 'value2' } expect.arrayContaining([
]) { name: 'CI', value: 'true' },
{ name: 'GITHUB_ACTIONS', value: 'true' },
{ name: 'ENV2', value: 'value2' }
])
)
expect(got.spec?.containers[1].resources).toEqual({ expect(got.spec?.containers[1].resources).toEqual({
requests: { memory: '1Mi', cpu: '1' }, requests: { memory: '1Mi', cpu: '1' },
limits: { memory: '1Gi', cpu: '2' } limits: { memory: '1Gi', cpu: '2' }

View File

@@ -78,4 +78,15 @@ describe('Run container step', () => {
runContainerStep(runContainerStepData.args) runContainerStep(runContainerStepData.args)
).resolves.not.toThrow() ).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()
})
}) })

View File

@@ -1,10 +1,24 @@
<!-- ## Features --> ## Features
<!-- ## Bugs --> - k8s: Use pod affinity when KubeScheduler is enabled [#212]
- docker: support alternative network modes [#209]
## Bugs
- Expose CI=true and GITHUB_ACTIONS env variables [#215]
- k8s: add /github/home to containerAction mounts and surface createSecretForEnvs errors [#198]
- k8s: start logging from the beginning [#184]
## Misc ## Misc
- Bump `@kubernetes/client-node` from 0.18.1 to 0.22.0 in /packages/k8s [#182] - Bump node in tests to node 22 since node14 is quite old [#216]
- Bump jsonpath-plus from 10.1.0 to 10.3.0 in /packages/k8s [#213]
- Bump braces from 3.0.2 to 3.0.3 in /packages/hooklib [#194]
- Bump cross-spawn from 7.0.3 to 7.0.6 in /packages/k8s [#196]
- Bump ws from 7.5.8 to 7.5.10 in /packages/k8s [#192]
- Remove dependency on deprecated release actions [#193]
- Update to the latest available actions [#191]
## SHA-256 Checksums ## SHA-256 Checksums