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
1 change: 1 addition & 0 deletions .github/linters/actionlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ paths:
- '"env" section must be mapping node but got scalar node'
- '"ports" section must be sequence node but got scalar node'
- '"volumes" section must be sequence node but got scalar node'
- '"runs-on" section is alias node but mapping node is expected'
4 changes: 4 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
packages: read
pull-requests: write
security-events: write
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
Expand Down Expand Up @@ -41,6 +42,7 @@ jobs:
uses: ./.github/workflows/continuous-integration.yml
permissions:
contents: read
packages: read
pull-requests: write
security-events: write
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
Expand Down Expand Up @@ -82,6 +84,7 @@ jobs:
needs: arrange-with-container
permissions:
contents: read
packages: read
pull-requests: write
security-events: write
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
Expand Down Expand Up @@ -116,6 +119,7 @@ jobs:
needs: arrange-with-container
permissions:
contents: read
packages: read
pull-requests: write
security-events: write
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
Expand Down
59 changes: 46 additions & 13 deletions .github/workflows/continuous-integration.md

Large diffs are not rendered by default.

115 changes: 73 additions & 42 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,17 @@ on:
required: false
default: "true"
code-ql:
description: "Code QL analysis language. See <https://github.com/github/codeql-action>."
description: |
Code QL analysis language.
See https://github.com/github/codeql-action.
type: string
required: false
default: "typescript"
dependency-review:
description: "Enable dependency review scan. See <https://github.com/actions/dependency-review-action>."
description: |
Enable dependency review scan.
Works with public repositories and private repositories with a GitHub Advanced Security license.
See https://github.com/actions/dependency-review-action.
type: boolean
required: false
default: true
Expand All @@ -88,11 +93,13 @@ on:
Accepts either a string (container image name) or a JSON object with container options.

String format (simple):

```yml
container: "node:18"
```

JSON object format (advanced):

```json
{
"image": "node:18",
Expand All @@ -108,9 +115,16 @@ on:
}
```

Supported properties: image (required), env (object), options (string), ports (array), volumes (array), credentials (object with username).
Supported properties:

See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container
- `image` (required)
- `env` (object)
- `options` (string)
- `ports` (array)
- `volumes` (array)
- `credentials` (object with `username`).

See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container.

When specified, steps will execute inside this container instead of checking out code.
The container should have the project code and dependencies pre-installed.
Expand All @@ -133,6 +147,11 @@ on:
Used when the container image is hosted in a private registry.
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.
required: false
github-token:
description: |
GitHub token to use for authentication.
Defaults to `GITHUB_TOKEN` if not provided.
required: false
outputs:
build-artifact-id:
description: "ID of the build artifact) uploaded during the build step."
Expand All @@ -143,7 +162,7 @@ permissions: {}
jobs:
prepare:
name: 📦 Prepare configuration
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
runs-on: &ci-runner ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
permissions: {}
outputs:
container-image: ${{ steps.parse.outputs.container-image }}
Expand Down Expand Up @@ -177,8 +196,8 @@ jobs:
try {
const parsedContainer = JSON.parse(containerInput);
core.debug(`Parsed container input as JSON: ${JSON.stringify(parsedContainer)}`);
container = {
...container,
container = {
...container,
...parsedContainer,
options: `${container.options} ${parsedContainer.options || ''}`.trim()
};
Expand Down Expand Up @@ -228,7 +247,7 @@ jobs:
if: inputs.checks == true && inputs.code-ql != ''
permissions:
security-events: write
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
runs-on: *ci-runner
steps:
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
- uses: github/codeql-action/init@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
Expand All @@ -241,32 +260,35 @@ jobs:
if: github.event_name == 'pull_request' && inputs.checks == true && inputs.dependency-review
permissions:
contents: read
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
runs-on: *ci-runner
steps:
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
- uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2

setup:
name: ⚙️ Setup
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
needs: prepare
container: &container-setup
runs-on: *ci-runner
needs:
- prepare
permissions:
contents: read
packages: read
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
container: &ci-container
image: ${{ needs.prepare.outputs.container-image || '' }}
env: ${{ fromJSON(needs.prepare.outputs.container-env || '{}') }}
options: ${{ needs.prepare.outputs.container-options || ' ' }}
ports: ${{ fromJSON(needs.prepare.outputs.container-ports || '[]') }}
volumes: ${{ fromJSON(needs.prepare.outputs.container-volumes || '[]') }}
credentials: ${{ fromJSON(needs.prepare.outputs.container-username && format('{{"username":{0},"password":{1}}}',toJSON(needs.prepare.outputs.container-username),toJSON(secrets.container-password)) || '{}') }}
permissions:
contents: read
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
outputs:
build-env: ${{ steps.build-variables.outputs.env }}
build-commands: ${{ steps.build-variables.outputs.commands }}
build-artifact: ${{ steps.build-variables.outputs.artifact }}
steps:
- if: needs.prepare.outputs.container-image == null
- name: Checkout repository
if: inputs.container == ''
uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0

- id: build-variables
Expand Down Expand Up @@ -369,21 +391,21 @@ jobs:
core.setOutput('env', JSON.stringify(env));

lint:
name: 👕 Lint
if: inputs.checks == true && inputs.lint
name: 👕 Lint
runs-on: *ci-runner
container: *ci-container
needs:
- prepare
- setup
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
container: *container-setup
# jscpd:ignore-start
permissions:
contents: read
packages: read
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
steps:
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
if: needs.prepare.outputs.container-image == null
if: inputs.container == ''

- id: oidc
uses: ChristopherHX/oidc@73eee1ff03fdfce10eda179f617131532209edbd # v3
Expand All @@ -397,7 +419,7 @@ 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
# jscpd:ignore-end

- id: preparel-lint-options
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
Expand All @@ -417,29 +439,35 @@ jobs:
}
}

- uses: ./self-workflow/actions/lint
core.setOutput('command', lintOptions.command || 'lint:ci');
core.setOutput('report-file', lintOptions['report-file'] || '');

- name: Run lint
uses: ./self-workflow/actions/lint
with:
working-directory: ${{ inputs.working-directory }}
container: ${{ needs.prepare.outputs.container-image && 'true' || 'false' }}
container: ${{ inputs.container != '' && 'true' || 'false' }}
command: ${{ steps.preparel-lint-options.outputs.command }}
report-file: ${{ steps.preparel-lint-options.outputs.report-file }}

build:
name: 🏗️ Build
if: inputs.checks == true
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
container: *container-setup
# jscpd:ignore-start
name: 🏗️ Build
runs-on: *ci-runner
container: *ci-container
needs:
- prepare
- setup
permissions:
contents: read
packages: read
# 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.outputs.artifact-id }}
steps:
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
if: needs.setup.outputs.build-commands && needs.prepare.outputs.container-image == null
if: needs.setup.outputs.build-commands && inputs.container == ''

# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
- id: oidc
Expand All @@ -457,37 +485,38 @@ 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
# jscpd:ignore-end

- id: build
if: needs.setup.outputs.build-commands
uses: ./self-workflow/actions/build
with:
container: ${{ inputs.container != '' && 'true' || 'false' }}
working-directory: ${{ inputs.working-directory }}
build-secrets: ${{ secrets.build-secrets }}
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: ${{ needs.prepare.outputs.container-image && 'true' || 'false' }}

test:
name: 🧪 Test
if: inputs.checks == true && inputs.test
runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
container: *container-setup
name: 🧪 Test
runs-on: *ci-runner
container: *ci-container
needs:
- prepare
- setup
- build
permissions:
contents: read
pull-requests: write
packages: read
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
steps:
- uses: hoverkraft-tech/ci-github-common/actions/checkout@1127e708e4072515056a4b0d26bcb0653646cedc # 0.30.0
if: needs.prepare.outputs.container-image == null
if: inputs.container == ''

- if: needs.build.outputs.artifact-id && needs.prepare.outputs.container-image == null
- if: needs.build.outputs.artifact-id && inputs.container == ''
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
artifact-ids: ${{ needs.build.outputs.artifact-id }}
Expand Down Expand Up @@ -530,13 +559,15 @@ jobs:
testOptions.coverage = 'github';
}
core.setOutput('coverage', testOptions.coverage );

core.setOutput('coverage-files', testOptions['coverage-files'] || '');
core.setOutput('command', testOptions.command || 'test:ci');

- uses: ./self-workflow/actions/test
- name: Run tests
uses: ./self-workflow/actions/test
with:
working-directory: ${{ inputs.working-directory }}
container: ${{ needs.prepare.outputs.container-image && 'true' || 'false' }}
container: ${{ inputs.container != '' && 'true' || 'false' }}
command: ${{ steps.prepare-test-options.outputs.command }}
coverage: ${{ steps.prepare-test-options.outputs.coverage }}
coverage-files: ${{ steps.prepare-test-options.outputs.coverage-files }}
github-token: ${{ github.token }}
github-token: ${{ secrets.github-token || github.token }}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ _Actions for continuous integration steps: build, lint, and test._

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

#### - [Rewrite Report Paths](actions/rewrite-report-paths/README.md)

### Dependencies

_Actions dedicated to caching and validating Node.js dependencies._
Expand Down
4 changes: 2 additions & 2 deletions actions/build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,12 @@ runs:

for (const command of commands) {
core.info(`Running build command: ${command}`);

try {
const result = await exec.getExecOutput(runScriptCommand, [command], {
cwd: require('path').resolve(process.env.GITHUB_WORKSPACE, workingDirectory)
});

if (result.stdout) {
core.info(result.stdout);
}
Expand Down
5 changes: 5 additions & 0 deletions actions/get-package-manager/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ runs:
if (!path.isAbsolute(workingDirectory)) {
workingDirectory = path.join(process.env.GITHUB_WORKSPACE, workingDirectory);
}
core.debug(`Resolved working directory: ${workingDirectory}`);

if (!fs.existsSync(workingDirectory)) {
core.setFailed(`The specified working directory does not exist: ${workingDirectory}`);
Expand Down Expand Up @@ -91,6 +92,8 @@ runs:
}

let relativeWorkingDirectory = path.relative(process.env.GITHUB_WORKSPACE, workingDirectory) || '.';
core.debug(`Relative working directory to GITHUB_WORKSPACE (${process.env.GITHUB_WORKSPACE}): ${relativeWorkingDirectory}`);

let cacheDependencyPathPrefix = relativeWorkingDirectory;

if (relativeWorkingDirectory.startsWith('../')) {
Expand All @@ -115,6 +118,8 @@ runs:
}
}

core.debug(`Cache dependency path prefix: ${cacheDependencyPathPrefix}`);

const packageManagerConfig = {
yarn: {
cacheDependencyPath: cacheDependencyPathPrefix ? `${cacheDependencyPathPrefix}/**/yarn.lock` : '',
Expand Down
10 changes: 10 additions & 0 deletions actions/lint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ Action to lint Node.js projects with support for pull request reporting and anno
# Default: `false`
container: "false"

# NPM/package manager script command to run for linting.
# This should be a script defined in your package.json.
# The command should generate lint report files in a standard format (ESLint JSON or Checkstyle XML).
#
# Default: `lint:ci`
command: "lint:ci"

# Path to lint report file to process as GitHub annotations.
# Supports ESLint JSON and Checkstyle XML formats.
# If not specified, auto-detection will be attempted for common paths:
Expand All @@ -60,6 +67,9 @@ Action to lint Node.js projects with support for pull request reporting and anno
| **`working-directory`** | Working directory where lint commands are executed. | **false** | `.` |
| | Can be absolute or relative to the repository root. | | |
| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` |
| **`command`** | NPM/package manager script command to run for linting. | **false** | `lint:ci` |
| | This should be a script defined in your package.json. | | |
| | The command should generate lint report files in a standard format. | | |
| **`report-file`** | Path to lint report file to process as GitHub annotations. | **false** | - |
| | Supports ESLint JSON and Checkstyle XML formats. | | |
| | If not specified, auto-detection will be attempted for common paths: | | |
Expand Down
Loading
Loading