Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/linters/.jscpd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"threshold": 5,
"ignore": ["**/tests/npm/coverage/*", "**/node_modules/*"]
}
2 changes: 1 addition & 1 deletion .github/workflows/__main-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
actions: read
contents: read
packages: write
pull-requests: read
pull-requests: write
id-token: write
issues: read
security-events: write
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/__pull-request-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
actions: read
contents: read
packages: write
pull-requests: read
pull-requests: write
id-token: write
issues: read
security-events: write
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/__shared-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
permissions:
contents: read
packages: write
pull-requests: read
pull-requests: write
id-token: write
issues: read
security-events: write
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/__test-workflow-continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:
uses: ./.github/workflows/continuous-integration.yml
permissions:
contents: read
pull-requests: write
security-events: write
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
Expand All @@ -35,6 +36,24 @@ jobs:
- name: Check the build artifacts
run: test -f tests/npm/dist/test.txt

act-without-container-and-github-reports:
name: Act - Run the continuous integration workflow (without container and GitHub reports)
uses: ./.github/workflows/continuous-integration.yml
permissions:
contents: read
pull-requests: write
security-events: write
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
with:
working-directory: tests/npm
build: |
{
"artifact": "dist"
}
test: |
{"coverage": "github"}
arrange-with-container:
permissions:
id-token: write
Expand Down Expand Up @@ -63,6 +82,7 @@ jobs:
needs: arrange-with-container
permissions:
contents: read
pull-requests: write
security-events: write
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
Expand All @@ -73,6 +93,8 @@ jobs:
{
"artifact": "dist"
}
test: |
{"coverage": "codecov"}
assert-with-container:
name: Assert - Ensure build artifact has been uploaded (with container)
Expand Down
205 changes: 71 additions & 134 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,13 @@ on:
required: false
default: true
lint:
description: "Optional flag to enable linting."
type: boolean
description: |
Whether to enable linting.
Set to `null` or empty to disable.
Accepts a JSON object for lint options. See [lint action](../actions/lint/README.md).
type: string
required: false
default: true
default: "true"
code-ql:
description: "Code QL analysis language. See <https://github.com/github/codeql-action>."
type: string
Expand All @@ -67,15 +70,13 @@ on:
required: false
default: true
test:
description: "Optional flag to enable test."
type: boolean
required: false
default: true
coverage:
description: "Specify code coverage reporter. Supported values: `codecov`."
description: |
Whether to enable testing.
Set to `null` or empty to disable.
Accepts a JSON object for test options. See [test action](../actions/test/README.md).
type: string
required: false
default: "codecov"
default: "true"
working-directory:
description: "Working directory where the dependencies are installed."
type: string
Expand Down Expand Up @@ -247,7 +248,7 @@ jobs:

lint:
name: 👕 Lint
if: inputs.checks == true && inputs.lint != false
if: inputs.checks == true && inputs.lint
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
container:
image: ${{ inputs.container != '' && inputs.container || null }}
Expand Down Expand Up @@ -276,25 +277,30 @@ jobs:
- run: |
if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi
if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi

- id: setup-node
if: inputs.container == ''
uses: ./self-workflow/actions/setup-node
# jscpd:ignore-end
- id: preparel-lint-options
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
LINT_INPUT: ${{ inputs.lint }}
with:
working-directory: ${{ inputs.working-directory }}
dependencies-cache: |
nx
prettier
script: |
const lintInput = process.env.LINT_INPUT.trim();

- id: get-package-manager
if: inputs.container
uses: ./self-workflow/actions/get-package-manager
let lintOptions = {};
if (lintInput && lintInput !== 'true') {
try {
const parsed = JSON.parse(lintInput);
lintOptions = { ...lintOptions, ...parsed };
} catch (error) {
core.setFailed(`Failed to parse lint input as JSON: ${error.message}`);
return;
}
}

- uses: ./self-workflow/actions/lint
with:
working-directory: ${{ inputs.working-directory }}
# jscpd:ignore-end

- run: ${{ inputs.container && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} lint
working-directory: ${{ inputs.working-directory }}
container: ${{ inputs.container != '' }}

build:
name: 🏗️ Build
Expand All @@ -311,7 +317,7 @@ jobs:
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
outputs:
artifact-id: ${{ steps.build-artifact-id.outputs.artifact-id }}
artifact-id: ${{ steps.build.outputs.artifact-id }}
steps:
- uses: hoverkraft-tech/ci-github-common/actions/checkout@753288393de1f3d92f687a6761d236ca800f5306 # 0.28.1
if: needs.setup.outputs.build-commands && inputs.container == ''
Expand All @@ -333,83 +339,20 @@ jobs:
if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi
if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi
# jscpd:ignore-end
- if: needs.setup.outputs.build-commands
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
BUILD_ENV: ${{ needs.setup.outputs.build-env }}
BUILD_SECRETS: ${{ secrets.build-secrets }}
with:
script: |
const envInput = process.env.BUILD_ENV || '{}';

let buildEnv = {};

try {
buildEnv = JSON.parse(envInput);
} catch (e) {
core.setFailed(`Invalid build env JSON: ${e.message}`);
}

for (const [key, value] of Object.entries(buildEnv)) {
core.exportVariable(key, value);
}

const secretsInput = process.env.BUILD_SECRETS || '';
for (const line of secretsInput.split('\n').map(line => line.trim()).filter(Boolean)) {
const [key, ...rest] = line.split('=');
if (!key || !rest.length) {
return core.setFailed(`Invalid build secrets format: ${line}`);
}
const value = rest.join('=');
core.exportVariable(key.trim(), value.trim());
}

- id: setup-node
if: needs.setup.outputs.build-commands && inputs.container == ''
uses: ./self-workflow/actions/setup-node
with:
working-directory: ${{ inputs.working-directory }}
dependencies-cache: |
nx
gatsby
storybook

- id: get-package-manager
if: needs.setup.outputs.build-commands && inputs.container
uses: ./self-workflow/actions/get-package-manager
- id: build
if: needs.setup.outputs.build-commands
uses: ./self-workflow/actions/build
with:
working-directory: ${{ inputs.working-directory }}

- if: needs.setup.outputs.build-commands
working-directory: ${{ inputs.working-directory }}
env:
BUILD_COMMANDS: ${{ needs.setup.outputs.build-commands }}
RUN_SCRIPT_COMMAND: ${{ inputs.container && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }}
run: |
echo "$BUILD_COMMANDS" | while IFS= read -r COMMAND ; do
# Trim whitespace
COMMAND=$(echo "$COMMAND" | xargs)

# Skip empty lines
if [ -z "$COMMAND" ]; then
continue
fi

echo -e "\n - Running $COMMAND"
$RUN_SCRIPT_COMMAND "$COMMAND"
done

- id: build-artifact-id
if: needs.setup.outputs.build-commands && needs.setup.outputs.build-artifact
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: ${{ fromJSON(needs.setup.outputs.build-artifact).name }}
path: ${{ fromJSON(needs.setup.outputs.build-artifact).paths }}
if-no-files-found: error
build-commands: ${{ needs.setup.outputs.build-commands }}
build-env: ${{ needs.setup.outputs.build-env }}
build-secrets: ${{ secrets.build-secrets }}
build-artifact: ${{ needs.setup.outputs.build-artifact }}
container: ${{ inputs.container != '' }}

test:
name: 🧪 Test
if: inputs.checks == true && inputs.test == true
if: inputs.checks == true && inputs.test
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
container:
image: ${{ inputs.container != '' && inputs.container || null }}
Expand All @@ -420,6 +363,7 @@ jobs:
- build
permissions:
contents: read
pull-requests: write
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
steps:
Expand All @@ -446,43 +390,36 @@ jobs:
if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi
if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi

- id: setup-node
if: inputs.container == ''
uses: ./self-workflow/actions/setup-node
- id: prepare-test-options
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
TEST_INPUT: ${{ inputs.test }}
with:
working-directory: ${{ inputs.working-directory }}
dependencies-cache: |
nx
jest
script: |
const testInput = process.env.TEST_INPUT.trim();

- id: get-package-manager
if: needs.setup.outputs.build-commands && inputs.container
uses: ./self-workflow/actions/get-package-manager
with:
working-directory: ${{ inputs.working-directory }}
let testOptions = {};
if (testInput && testInput !== 'true') {
try {
const parsed = JSON.parse(testInput);
testOptions = { ...testOptions, ...parsed };
} catch (error) {
core.setFailed(`Failed to parse test input as JSON: ${error.message}`);
return;
}
}

- run: ${{ inputs.container && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} test:ci
working-directory: ${{ inputs.working-directory }}
env:
CI: "true"
if (testOptions.coverage === undefined) {
testOptions.coverage = 'github';
}
core.setOutput('coverage', testOptions.coverage );

- if: inputs.coverage == 'codecov' && inputs.container
env:
REQUIRED_DEPS: |
git
curl
gpg
run: |
apt-get update
for dep in $REQUIRED_DEPS; do
if ! dpkg -s "$dep" >/dev/null 2>&1; then
apt-get install -y "$dep"
fi
done

- name: 📊 Code coverage
if: inputs.coverage == 'codecov'
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
core.setOutput('coverage-files', testOptions['coverage-files'] || '');

- uses: ./self-workflow/actions/test
with:
use_oidc: true
disable_telem: true
working-directory: ${{ inputs.working-directory }}
container: ${{ inputs.container != '' }}
coverage: ${{ steps.prepare-test-options.outputs.coverage }}
coverage-files: ${{ steps.prepare-test-options.outputs['coverage-files'] }}
github-token: ${{ github.token }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/node_modules
/tests/*/node_modules
/tests/*/coverage
/dist
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ This repository centralizes the Hoverkraft toolkit for building, testing, and sh

## Actions

### CI Actions

_Actions for continuous integration steps: build, lint, and test._

#### - [Build](actions/build/README.md)

#### - [Lint](actions/lint/README.md)

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

### Dependencies

_Actions dedicated to caching and validating Node.js dependencies._
Expand Down
Loading
Loading