Skip to content

Commit f2aaf6d

Browse files
Copilotneilime
andcommitted
feat(continuous-integration)!: add better reporting for lint and tests
Co-authored-by: neilime <314088+neilime@users.noreply.github.com> Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent 7c60326 commit f2aaf6d

File tree

22 files changed

+1060
-181
lines changed

22 files changed

+1060
-181
lines changed

.github/linters/.jscpd.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"threshold": 5,
3+
"ignore": ["**/tests/npm/coverage/*", "**/node_modules/*"]
4+
}

.github/workflows/__main-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
actions: read
2525
contents: read
2626
packages: write
27-
pull-requests: read
27+
pull-requests: write
2828
id-token: write
2929
issues: read
3030
security-events: write

.github/workflows/__pull-request-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
actions: read
1919
contents: read
2020
packages: write
21-
pull-requests: read
21+
pull-requests: write
2222
id-token: write
2323
issues: read
2424
security-events: write

.github/workflows/__shared-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
permissions:
5050
contents: read
5151
packages: write
52-
pull-requests: read
52+
pull-requests: write
5353
id-token: write
5454
issues: read
5555
security-events: write

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

Lines changed: 22 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+
pull-requests: write
1415
security-events: write
1516
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
1617
id-token: write
@@ -35,6 +36,24 @@ jobs:
3536
- name: Check the build artifacts
3637
run: test -f tests/npm/dist/test.txt
3738

39+
act-without-container-and-github-reports:
40+
name: Act - Run the continuous integration workflow (without container and GitHub reports)
41+
uses: ./.github/workflows/continuous-integration.yml
42+
permissions:
43+
contents: read
44+
pull-requests: write
45+
security-events: write
46+
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
47+
id-token: write
48+
with:
49+
working-directory: tests/npm
50+
build: |
51+
{
52+
"artifact": "dist"
53+
}
54+
test: |
55+
{"coverage": "github"}
56+
3857
arrange-with-container:
3958
permissions:
4059
id-token: write
@@ -63,6 +82,7 @@ jobs:
6382
needs: arrange-with-container
6483
permissions:
6584
contents: read
85+
pull-requests: write
6686
security-events: write
6787
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
6888
id-token: write
@@ -73,6 +93,8 @@ jobs:
7393
{
7494
"artifact": "dist"
7595
}
96+
test: |
97+
{"coverage": "codecov"}
7698
7799
assert-with-container:
78100
name: Assert - Ensure build artifact has been uploaded (with container)

.github/workflows/continuous-integration.yml

Lines changed: 71 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,13 @@ on:
5252
required: false
5353
default: true
5454
lint:
55-
description: "Optional flag to enable linting."
56-
type: boolean
55+
description: |
56+
Whether to enable linting.
57+
Set to `null` or empty to disable.
58+
Accepts a JSON object for lint options. See [lint action](../actions/lint/README.md).
59+
type: string
5760
required: false
58-
default: true
61+
default: "true"
5962
code-ql:
6063
description: "Code QL analysis language. See <https://github.com/github/codeql-action>."
6164
type: string
@@ -67,15 +70,13 @@ on:
6770
required: false
6871
default: true
6972
test:
70-
description: "Optional flag to enable test."
71-
type: boolean
72-
required: false
73-
default: true
74-
coverage:
75-
description: "Specify code coverage reporter. Supported values: `codecov`."
73+
description: |
74+
Whether to enable testing.
75+
Set to `null` or empty to disable.
76+
Accepts a JSON object for test options. See [test action](../actions/test/README.md).
7677
type: string
7778
required: false
78-
default: "codecov"
79+
default: "true"
7980
working-directory:
8081
description: "Working directory where the dependencies are installed."
8182
type: string
@@ -247,7 +248,7 @@ jobs:
247248
248249
lint:
249250
name: 👕 Lint
250-
if: inputs.checks == true && inputs.lint != false
251+
if: inputs.checks == true && inputs.lint
251252
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
252253
container:
253254
image: ${{ inputs.container != '' && inputs.container || null }}
@@ -276,25 +277,30 @@ jobs:
276277
- run: |
277278
if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi
278279
if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi
279-
280-
- id: setup-node
281-
if: inputs.container == ''
282-
uses: ./self-workflow/actions/setup-node
280+
# jscpd:ignore-end
281+
- id: preparel-lint-options
282+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
283+
env:
284+
LINT_INPUT: ${{ inputs.lint }}
283285
with:
284-
working-directory: ${{ inputs.working-directory }}
285-
dependencies-cache: |
286-
nx
287-
prettier
286+
script: |
287+
const lintInput = process.env.LINT_INPUT.trim();
288288
289-
- id: get-package-manager
290-
if: inputs.container
291-
uses: ./self-workflow/actions/get-package-manager
289+
let lintOptions = {};
290+
if (lintInput && lintInput !== 'true') {
291+
try {
292+
const parsed = JSON.parse(lintInput);
293+
lintOptions = { ...lintOptions, ...parsed };
294+
} catch (error) {
295+
core.setFailed(`Failed to parse lint input as JSON: ${error.message}`);
296+
return;
297+
}
298+
}
299+
300+
- uses: ./self-workflow/actions/lint
292301
with:
293302
working-directory: ${{ inputs.working-directory }}
294-
# jscpd:ignore-end
295-
296-
- run: ${{ inputs.container && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} lint
297-
working-directory: ${{ inputs.working-directory }}
303+
container: ${{ inputs.container != '' }}
298304

299305
build:
300306
name: 🏗️ Build
@@ -311,7 +317,7 @@ jobs:
311317
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
312318
id-token: write
313319
outputs:
314-
artifact-id: ${{ steps.build-artifact-id.outputs.artifact-id }}
320+
artifact-id: ${{ steps.build.outputs.artifact-id }}
315321
steps:
316322
- uses: hoverkraft-tech/ci-github-common/actions/checkout@753288393de1f3d92f687a6761d236ca800f5306 # 0.28.1
317323
if: needs.setup.outputs.build-commands && inputs.container == ''
@@ -333,83 +339,20 @@ jobs:
333339
if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi
334340
if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi
335341
# jscpd:ignore-end
336-
- if: needs.setup.outputs.build-commands
337-
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
338-
env:
339-
BUILD_ENV: ${{ needs.setup.outputs.build-env }}
340-
BUILD_SECRETS: ${{ secrets.build-secrets }}
341-
with:
342-
script: |
343-
const envInput = process.env.BUILD_ENV || '{}';
344-
345-
let buildEnv = {};
346-
347-
try {
348-
buildEnv = JSON.parse(envInput);
349-
} catch (e) {
350-
core.setFailed(`Invalid build env JSON: ${e.message}`);
351-
}
352-
353-
for (const [key, value] of Object.entries(buildEnv)) {
354-
core.exportVariable(key, value);
355-
}
356-
357-
const secretsInput = process.env.BUILD_SECRETS || '';
358-
for (const line of secretsInput.split('\n').map(line => line.trim()).filter(Boolean)) {
359-
const [key, ...rest] = line.split('=');
360-
if (!key || !rest.length) {
361-
return core.setFailed(`Invalid build secrets format: ${line}`);
362-
}
363-
const value = rest.join('=');
364-
core.exportVariable(key.trim(), value.trim());
365-
}
366-
367-
- id: setup-node
368-
if: needs.setup.outputs.build-commands && inputs.container == ''
369-
uses: ./self-workflow/actions/setup-node
370-
with:
371-
working-directory: ${{ inputs.working-directory }}
372-
dependencies-cache: |
373-
nx
374-
gatsby
375-
storybook
376-
377-
- id: get-package-manager
378-
if: needs.setup.outputs.build-commands && inputs.container
379-
uses: ./self-workflow/actions/get-package-manager
342+
- id: build
343+
if: needs.setup.outputs.build-commands
344+
uses: ./self-workflow/actions/build
380345
with:
381346
working-directory: ${{ inputs.working-directory }}
382-
383-
- if: needs.setup.outputs.build-commands
384-
working-directory: ${{ inputs.working-directory }}
385-
env:
386-
BUILD_COMMANDS: ${{ needs.setup.outputs.build-commands }}
387-
RUN_SCRIPT_COMMAND: ${{ inputs.container && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }}
388-
run: |
389-
echo "$BUILD_COMMANDS" | while IFS= read -r COMMAND ; do
390-
# Trim whitespace
391-
COMMAND=$(echo "$COMMAND" | xargs)
392-
393-
# Skip empty lines
394-
if [ -z "$COMMAND" ]; then
395-
continue
396-
fi
397-
398-
echo -e "\n - Running $COMMAND"
399-
$RUN_SCRIPT_COMMAND "$COMMAND"
400-
done
401-
402-
- id: build-artifact-id
403-
if: needs.setup.outputs.build-commands && needs.setup.outputs.build-artifact
404-
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
405-
with:
406-
name: ${{ fromJSON(needs.setup.outputs.build-artifact).name }}
407-
path: ${{ fromJSON(needs.setup.outputs.build-artifact).paths }}
408-
if-no-files-found: error
347+
build-commands: ${{ needs.setup.outputs.build-commands }}
348+
build-env: ${{ needs.setup.outputs.build-env }}
349+
build-secrets: ${{ secrets.build-secrets }}
350+
build-artifact: ${{ needs.setup.outputs.build-artifact }}
351+
container: ${{ inputs.container != '' }}
409352

410353
test:
411354
name: 🧪 Test
412-
if: inputs.checks == true && inputs.test == true
355+
if: inputs.checks == true && inputs.test
413356
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
414357
container:
415358
image: ${{ inputs.container != '' && inputs.container || null }}
@@ -420,6 +363,7 @@ jobs:
420363
- build
421364
permissions:
422365
contents: read
366+
pull-requests: write
423367
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
424368
id-token: write
425369
steps:
@@ -446,43 +390,36 @@ jobs:
446390
if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi
447391
if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi
448392
449-
- id: setup-node
450-
if: inputs.container == ''
451-
uses: ./self-workflow/actions/setup-node
393+
- id: prepare-test-options
394+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
395+
env:
396+
TEST_INPUT: ${{ inputs.test }}
452397
with:
453-
working-directory: ${{ inputs.working-directory }}
454-
dependencies-cache: |
455-
nx
456-
jest
398+
script: |
399+
const testInput = process.env.TEST_INPUT.trim();
457400
458-
- id: get-package-manager
459-
if: needs.setup.outputs.build-commands && inputs.container
460-
uses: ./self-workflow/actions/get-package-manager
461-
with:
462-
working-directory: ${{ inputs.working-directory }}
401+
let testOptions = {};
402+
if (testInput && testInput !== 'true') {
403+
try {
404+
const parsed = JSON.parse(testInput);
405+
testOptions = { ...testOptions, ...parsed };
406+
} catch (error) {
407+
core.setFailed(`Failed to parse test input as JSON: ${error.message}`);
408+
return;
409+
}
410+
}
463411
464-
- run: ${{ inputs.container && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} test:ci
465-
working-directory: ${{ inputs.working-directory }}
466-
env:
467-
CI: "true"
412+
if (testOptions.coverage === undefined) {
413+
testOptions.coverage = 'github';
414+
}
415+
core.setOutput('coverage', testOptions.coverage );
468416
469-
- if: inputs.coverage == 'codecov' && inputs.container
470-
env:
471-
REQUIRED_DEPS: |
472-
git
473-
curl
474-
gpg
475-
run: |
476-
apt-get update
477-
for dep in $REQUIRED_DEPS; do
478-
if ! dpkg -s "$dep" >/dev/null 2>&1; then
479-
apt-get install -y "$dep"
480-
fi
481-
done
482-
483-
- name: 📊 Code coverage
484-
if: inputs.coverage == 'codecov'
485-
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
417+
core.setOutput('coverage-files', testOptions['coverage-files'] || '');
418+
419+
- uses: ./self-workflow/actions/test
486420
with:
487-
use_oidc: true
488-
disable_telem: true
421+
working-directory: ${{ inputs.working-directory }}
422+
container: ${{ inputs.container != '' }}
423+
coverage: ${{ steps.prepare-test-options.outputs.coverage }}
424+
coverage-files: ${{ steps.prepare-test-options.outputs['coverage-files'] }}
425+
github-token: ${{ github.token }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/node_modules
22
/tests/*/node_modules
3+
/tests/*/coverage
34
/dist

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ This repository centralizes the Hoverkraft toolkit for building, testing, and sh
1818

1919
## Actions
2020

21+
### CI Actions
22+
23+
_Actions for continuous integration steps: build, lint, and test._
24+
25+
#### - [Build](actions/build/README.md)
26+
27+
#### - [Lint](actions/lint/README.md)
28+
29+
#### - [Test](actions/test/README.md)
30+
2131
### Dependencies
2232

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

0 commit comments

Comments
 (0)