Skip to content

Commit 2c424f2

Browse files
Copilotneilime
andcommitted
feat(continuous-integration)!: add configurable lint/test commands and container better support
Co-authored-by: neilime <[email protected]> Signed-off-by: Emilien Escalle <[email protected]>
1 parent d476f06 commit 2c424f2

File tree

13 files changed

+541
-236
lines changed

13 files changed

+541
-236
lines changed

.github/linters/actionlint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ paths:
88
- '"env" section must be mapping node but got scalar node'
99
- '"ports" section must be sequence node but got scalar node'
1010
- '"volumes" section must be sequence node but got scalar node'
11+
- '"runs-on" section is alias node but mapping node is expected'

.github/workflows/__test-workflow-continuous-integration.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ jobs:
1111
uses: ./.github/workflows/continuous-integration.yml
1212
permissions:
1313
contents: read
14+
packages: read
1415
pull-requests: write
1516
security-events: write
1617
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
@@ -41,6 +42,7 @@ jobs:
4142
uses: ./.github/workflows/continuous-integration.yml
4243
permissions:
4344
contents: read
45+
packages: read
4446
pull-requests: write
4547
security-events: write
4648
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
@@ -82,6 +84,7 @@ jobs:
8284
needs: arrange-with-container
8385
permissions:
8486
contents: read
87+
packages: read
8588
pull-requests: write
8689
security-events: write
8790
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
@@ -116,6 +119,7 @@ jobs:
116119
needs: arrange-with-container
117120
permissions:
118121
contents: read
122+
packages: read
119123
pull-requests: write
120124
security-events: write
121125
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659

.github/workflows/continuous-integration.md

Lines changed: 46 additions & 13 deletions
Large diffs are not rendered by default.

.github/workflows/continuous-integration.yml

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,17 @@ on:
6060
required: false
6161
default: "true"
6262
code-ql:
63-
description: "Code QL analysis language. See <https://github.com/github/codeql-action>."
63+
description: |
64+
Code QL analysis language.
65+
See https://github.com/github/codeql-action.
6466
type: string
6567
required: false
6668
default: "typescript"
6769
dependency-review:
68-
description: "Enable dependency review scan. See <https://github.com/actions/dependency-review-action>."
70+
description: |
71+
Enable dependency review scan.
72+
Works with public repositories and private repositories with a GitHub Advanced Security license.
73+
See https://github.com/actions/dependency-review-action.
6974
type: boolean
7075
required: false
7176
default: true
@@ -88,11 +93,13 @@ on:
8893
Accepts either a string (container image name) or a JSON object with container options.
8994
9095
String format (simple):
96+
9197
```yml
9298
container: "node:18"
9399
```
94100
95101
JSON object format (advanced):
102+
96103
```json
97104
{
98105
"image": "node:18",
@@ -108,9 +115,16 @@ on:
108115
}
109116
```
110117
111-
Supported properties: image (required), env (object), options (string), ports (array), volumes (array), credentials (object with username).
118+
Supported properties:
119+
120+
- `image` (required)
121+
- `env` (object)
122+
- `options` (string)
123+
- `ports` (array)
124+
- `volumes` (array)
125+
- `credentials` (object with `username`).
112126
113-
See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container
127+
See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container.
114128
115129
When specified, steps will execute inside this container instead of checking out code.
116130
The container should have the project code and dependencies pre-installed.
@@ -133,6 +147,11 @@ on:
133147
Used when the container image is hosted in a private registry.
134148
See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container#defining-credentials-for-a-container-registry.
135149
required: false
150+
github-token:
151+
description: |
152+
GitHub token to use for authentication.
153+
Defaults to `GITHUB_TOKEN` if not provided.
154+
required: false
136155
outputs:
137156
build-artifact-id:
138157
description: "ID of the build artifact) uploaded during the build step."
@@ -143,7 +162,7 @@ permissions: {}
143162
jobs:
144163
prepare:
145164
name: 📦 Prepare configuration
146-
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
165+
runs-on: &ci-runner ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
147166
permissions: {}
148167
outputs:
149168
container-image: ${{ steps.parse.outputs.container-image }}
@@ -177,8 +196,8 @@ jobs:
177196
try {
178197
const parsedContainer = JSON.parse(containerInput);
179198
core.debug(`Parsed container input as JSON: ${JSON.stringify(parsedContainer)}`);
180-
container = {
181-
...container,
199+
container = {
200+
...container,
182201
...parsedContainer,
183202
options: `${container.options} ${parsedContainer.options || ''}`.trim()
184203
};
@@ -228,7 +247,7 @@ jobs:
228247
if: inputs.checks == true && inputs.code-ql != ''
229248
permissions:
230249
security-events: write
231-
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
250+
runs-on: *ci-runner
232251
steps:
233252
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
234253
- uses: github/codeql-action/init@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
@@ -241,32 +260,35 @@ jobs:
241260
if: github.event_name == 'pull_request' && inputs.checks == true && inputs.dependency-review
242261
permissions:
243262
contents: read
244-
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
263+
runs-on: *ci-runner
245264
steps:
246265
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
247266
- uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2
248267

249268
setup:
250269
name: ⚙️ Setup
251-
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
252-
needs: prepare
253-
container: &container-setup
270+
runs-on: *ci-runner
271+
needs:
272+
- prepare
273+
permissions:
274+
contents: read
275+
packages: read
276+
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
277+
id-token: write
278+
container: &ci-container
254279
image: ${{ needs.prepare.outputs.container-image || '' }}
255280
env: ${{ fromJSON(needs.prepare.outputs.container-env || '{}') }}
256281
options: ${{ needs.prepare.outputs.container-options || ' ' }}
257282
ports: ${{ fromJSON(needs.prepare.outputs.container-ports || '[]') }}
258283
volumes: ${{ fromJSON(needs.prepare.outputs.container-volumes || '[]') }}
259284
credentials: ${{ fromJSON(needs.prepare.outputs.container-username && format('{{"username":{0},"password":{1}}}',toJSON(needs.prepare.outputs.container-username),toJSON(secrets.container-password)) || '{}') }}
260-
permissions:
261-
contents: read
262-
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
263-
id-token: write
264285
outputs:
265286
build-env: ${{ steps.build-variables.outputs.env }}
266287
build-commands: ${{ steps.build-variables.outputs.commands }}
267288
build-artifact: ${{ steps.build-variables.outputs.artifact }}
268289
steps:
269-
- if: needs.prepare.outputs.container-image == null
290+
- name: Checkout repository
291+
if: inputs.container == ''
270292
uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
271293

272294
- id: build-variables
@@ -369,21 +391,21 @@ jobs:
369391
core.setOutput('env', JSON.stringify(env));
370392
371393
lint:
372-
name: 👕 Lint
373394
if: inputs.checks == true && inputs.lint
395+
name: 👕 Lint
396+
runs-on: *ci-runner
397+
container: *ci-container
374398
needs:
375399
- prepare
376400
- setup
377-
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
378-
container: *container-setup
379-
# jscpd:ignore-start
380401
permissions:
381402
contents: read
403+
packages: read
382404
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
383405
id-token: write
384406
steps:
385407
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
386-
if: needs.prepare.outputs.container-image == null
408+
if: inputs.container == ''
387409

388410
- id: oidc
389411
uses: ChristopherHX/oidc@73eee1ff03fdfce10eda179f617131532209edbd # v3
@@ -397,7 +419,7 @@ jobs:
397419
- run: |
398420
if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi
399421
if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi
400-
# jscpd:ignore-end
422+
401423
- id: preparel-lint-options
402424
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
403425
env:
@@ -417,29 +439,35 @@ jobs:
417439
}
418440
}
419441
420-
- uses: ./self-workflow/actions/lint
442+
core.setOutput('command', lintOptions.command || 'lint:ci');
443+
core.setOutput('report-file', lintOptions['report-file'] || '');
444+
445+
- name: Run lint
446+
uses: ./self-workflow/actions/lint
421447
with:
422448
working-directory: ${{ inputs.working-directory }}
423-
container: ${{ needs.prepare.outputs.container-image && 'true' || 'false' }}
449+
container: ${{ inputs.container != '' && 'true' || 'false' }}
450+
command: ${{ steps.preparel-lint-options.outputs.command }}
451+
report-file: ${{ steps.preparel-lint-options.outputs.report-file }}
424452

425453
build:
426-
name: 🏗️ Build
427454
if: inputs.checks == true
428-
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
429-
container: *container-setup
430-
# jscpd:ignore-start
455+
name: 🏗️ Build
456+
runs-on: *ci-runner
457+
container: *ci-container
431458
needs:
432459
- prepare
433460
- setup
434461
permissions:
435462
contents: read
463+
packages: read
436464
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
437465
id-token: write
438466
outputs:
439467
artifact-id: ${{ steps.build.outputs.artifact-id }}
440468
steps:
441469
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
442-
if: needs.setup.outputs.build-commands && needs.prepare.outputs.container-image == null
470+
if: needs.setup.outputs.build-commands && inputs.container == ''
443471

444472
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
445473
- id: oidc
@@ -457,37 +485,38 @@ jobs:
457485
run: |
458486
if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi
459487
if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi
460-
# jscpd:ignore-end
488+
461489
- id: build
462490
if: needs.setup.outputs.build-commands
463491
uses: ./self-workflow/actions/build
464492
with:
493+
container: ${{ inputs.container != '' && 'true' || 'false' }}
465494
working-directory: ${{ inputs.working-directory }}
495+
build-secrets: ${{ secrets.build-secrets }}
466496
build-commands: ${{ needs.setup.outputs.build-commands }}
467497
build-env: ${{ needs.setup.outputs.build-env }}
468-
build-secrets: ${{ secrets.build-secrets }}
469498
build-artifact: ${{ needs.setup.outputs.build-artifact }}
470-
container: ${{ needs.prepare.outputs.container-image && 'true' || 'false' }}
471499

472500
test:
473-
name: 🧪 Test
474501
if: inputs.checks == true && inputs.test
475-
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
476-
container: *container-setup
502+
name: 🧪 Test
503+
runs-on: *ci-runner
504+
container: *ci-container
477505
needs:
478506
- prepare
479507
- setup
480508
- build
481509
permissions:
482510
contents: read
483511
pull-requests: write
512+
packages: read
484513
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
485514
id-token: write
486515
steps:
487516
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
488-
if: needs.prepare.outputs.container-image == null
517+
if: inputs.container == ''
489518

490-
- if: needs.build.outputs.artifact-id && needs.prepare.outputs.container-image == null
519+
- if: needs.build.outputs.artifact-id && inputs.container == ''
491520
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
492521
with:
493522
artifact-ids: ${{ needs.build.outputs.artifact-id }}
@@ -530,13 +559,15 @@ jobs:
530559
testOptions.coverage = 'github';
531560
}
532561
core.setOutput('coverage', testOptions.coverage );
533-
534562
core.setOutput('coverage-files', testOptions['coverage-files'] || '');
563+
core.setOutput('command', testOptions.command || 'test:ci');
535564
536-
- uses: ./self-workflow/actions/test
565+
- name: Run tests
566+
uses: ./self-workflow/actions/test
537567
with:
538568
working-directory: ${{ inputs.working-directory }}
539-
container: ${{ needs.prepare.outputs.container-image && 'true' || 'false' }}
569+
container: ${{ inputs.container != '' && 'true' || 'false' }}
570+
command: ${{ steps.prepare-test-options.outputs.command }}
540571
coverage: ${{ steps.prepare-test-options.outputs.coverage }}
541572
coverage-files: ${{ steps.prepare-test-options.outputs.coverage-files }}
542-
github-token: ${{ github.token }}
573+
github-token: ${{ secrets.github-token || github.token }}

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ _Actions for continuous integration steps: build, lint, and test._
2828

2929
#### - [Test](actions/test/README.md)
3030

31+
#### - [Rewrite Report Paths](actions/rewrite-report-paths/README.md)
32+
3133
### Dependencies
3234

3335
_Actions dedicated to caching and validating Node.js dependencies._

actions/get-package-manager/action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ runs:
4444
if (!path.isAbsolute(workingDirectory)) {
4545
workingDirectory = path.join(process.env.GITHUB_WORKSPACE, workingDirectory);
4646
}
47+
core.debug(`Resolved working directory: ${workingDirectory}`);
4748
4849
if (!fs.existsSync(workingDirectory)) {
4950
core.setFailed(`The specified working directory does not exist: ${workingDirectory}`);
@@ -91,6 +92,8 @@ runs:
9192
}
9293
9394
let relativeWorkingDirectory = path.relative(process.env.GITHUB_WORKSPACE, workingDirectory) || '.';
95+
core.debug(`Relative working directory to GITHUB_WORKSPACE (${process.env.GITHUB_WORKSPACE}): ${relativeWorkingDirectory}`);
96+
9497
let cacheDependencyPathPrefix = relativeWorkingDirectory;
9598
9699
if (relativeWorkingDirectory.startsWith('../')) {
@@ -115,6 +118,8 @@ runs:
115118
}
116119
}
117120
121+
core.debug(`Cache dependency path prefix: ${cacheDependencyPathPrefix}`);
122+
118123
const packageManagerConfig = {
119124
yarn: {
120125
cacheDependencyPath: cacheDependencyPathPrefix ? `${cacheDependencyPathPrefix}/**/yarn.lock` : '',

actions/lint/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ Action to lint Node.js projects with support for pull request reporting and anno
4242
# Default: `false`
4343
container: "false"
4444

45+
# NPM/package manager script command to run for linting.
46+
# This should be a script defined in your package.json.
47+
# The command should generate lint report files in a standard format (ESLint JSON or Checkstyle XML).
48+
#
49+
# Default: `lint:ci`
50+
command: "lint:ci"
51+
4552
# Path to lint report file to process as GitHub annotations.
4653
# Supports ESLint JSON and Checkstyle XML formats.
4754
# If not specified, auto-detection will be attempted for common paths:
@@ -60,6 +67,9 @@ Action to lint Node.js projects with support for pull request reporting and anno
6067
| **`working-directory`** | Working directory where lint commands are executed. | **false** | `.` |
6168
| | Can be absolute or relative to the repository root. | | |
6269
| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` |
70+
| **`command`** | NPM/package manager script command to run for linting. | **false** | `lint:ci` |
71+
| | This should be a script defined in your package.json. | | |
72+
| | The command should generate lint report files in a standard format. | | |
6373
| **`report-file`** | Path to lint report file to process as GitHub annotations. | **false** | - |
6474
| | Supports ESLint JSON and Checkstyle XML formats. | | |
6575
| | If not specified, auto-detection will be attempted for common paths: | | |

0 commit comments

Comments
 (0)