Skip to content
Merged
144 changes: 17 additions & 127 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -276,25 +276,11 @@ 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
- uses: ./self-workflow/actions/lint
with:
working-directory: ${{ inputs.working-directory }}
dependencies-cache: |
nx
prettier

- id: get-package-manager
if: inputs.container
uses: ./self-workflow/actions/get-package-manager
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 +297,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,79 +319,16 @@ 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
Expand All @@ -422,6 +345,7 @@ jobs:
contents: read
# FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
id-token: write
pull-requests: write
steps:
- uses: hoverkraft-tech/ci-github-common/actions/checkout@753288393de1f3d92f687a6761d236ca800f5306 # 0.28.1
if: inputs.container == ''
Expand All @@ -446,43 +370,9 @@ 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
- uses: ./self-workflow/actions/test
with:
working-directory: ${{ inputs.working-directory }}
dependencies-cache: |
nx
jest

- 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 }}

- 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: 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
with:
use_oidc: true
disable_telem: true
container: ${{ inputs.container != '' }}
coverage: ${{ inputs.coverage }}
github-token: ${{ github.token }}
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
134 changes: 134 additions & 0 deletions actions/build/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<!-- header:start -->

# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItcGFja2FnZSIgY29sb3I9ImdyYXktZGFyayI+PGxpbmUgeDE9IjE2LjUiIHkxPSI5LjQiIHgyPSI3LjUiIHkyPSI0LjIxIj48L2xpbmU+PHBhdGggZD0iTTIxIDE2VjhhMiAyIDAgMCAwLTEtMS43M2wtNy00YTIgMiAwIDAgMC0yIDBsLTcgNEEyIDIgMCAwIDAgMyA4djhhMiAyIDAgMCAwIDEgMS43M2w3IDRhMiAyIDAgMCAwIDIgMGw3LTRBMiAyIDAgMCAwIDIxIDE2eiI+PC9wYXRoPjxwb2x5bGluZSBwb2ludHM9IjMuMjcgNi45NiAxMiAxMi4wMSAyMC43MyA2Ljk2Ij48L3BvbHlsaW5lPjxsaW5lIHgxPSIxMiIgeTE9IjIyLjA4IiB4Mj0iMTIiIHkyPSIxMiI+PC9saW5lPjwvc3ZnPg==) GitHub Action: Build

<div align="center">
<img src="https://opengraph.githubassets.com/b83a39d0a270998cbae0974683a11eba4481aa44bbb4abbc39522474251c5b0a/hoverkraft-tech/ci-github-nodejs" width="60px" align="center" alt="Build" />
</div>

---

<!-- header:end -->
<!-- badges:start -->

[![Marketplace](https://img.shields.io/badge/Marketplace-build-blue?logo=github-actions)](https://github.com/marketplace/actions/build)
[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases)
[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/)
[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)

<!-- badges:end -->
<!-- overview:start -->

## Overview

Action to build Node.js projects with support for custom commands, environment variables, and artifact handling

<!-- overview:end -->
<!-- usage:start -->

## Usage

````yaml
- uses: hoverkraft-tech/ci-github-nodejs/actions/build@db1c1d36ff3e87c4513eded15d85acb78dcbd9b9 # copilot/refactor-ci-actions-lint-test
with:
# Working directory where the build commands are executed.
# Can be absolute or relative to the repository root.
#
# Default: `.`
working-directory: .

# List of build commands to execute, one per line.
# These are npm/pnpm/yarn script names (e.g., "build", "compile").
#
# This input is required.
build-commands: ""

# JSON object of environment variables to set during the build.
# Example: {"NODE_ENV": "production", "API_URL": "https://api.example.com"}
#
# Default: `{}`
build-env: "{}"

# Multi-line string of secrets in env format (KEY=VALUE).
# Example:
# ```
# SECRET_KEY=${{ secrets.SECRET_KEY }}
# API_TOKEN=${{ secrets.API_TOKEN }}
# ```
build-secrets: ""

# JSON object specifying artifact upload configuration.
# Format: {"name": "artifact-name", "paths": "path1\npath2"}
build-artifact: ""

# Whether running in container mode (skips checkout and node setup)
# Default: `false`
container: "false"
````

<!-- usage:end -->
<!-- inputs:start -->

## Inputs

| **Input** | **Description** | **Required** | **Default** |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ----------- |
| **`working-directory`** | Working directory where the build commands are executed. | **false** | `.` |
| | Can be absolute or relative to the repository root. | | |
| **`build-commands`** | List of build commands to execute, one per line. | **true** | - |
| | These are npm/pnpm/Yarn script names (e.g., "build", "compile"). | | |
| **`build-env`** | JSON object of environment variables to set during the build. | **false** | `\{}` |
| | Example: {"NODE_ENV": "production", "API_URL": "<https://api.example.com"}> | | |
| **`build-secrets`** | Multi-line string of secrets in env format (KEY=VALUE). | **false** | - |
| | Example: | | |
| | <!-- textlint-disable --><pre>SECRET_KEY=${{ secrets.SECRET_KEY }}&#13;API_TOKEN=${{ secrets.API_TOKEN }}</pre><!-- textlint-enable --> | | |
| **`build-artifact`** | JSON object specifying artifact upload configuration. | **false** | - |
| | Format: {"name": "artifact-name", "paths": "path1\npath2"} | | |
| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` |

<!-- jscpd:ignore-start -->
<!-- inputs:end -->
<!-- secrets:start -->
<!-- secrets:end -->
<!-- outputs:start -->

## Outputs

| **Output** | **Description** |
| ----------------- | ------------------------------------------------------- |
| **`artifact-id`** | ID of the uploaded artifact (if artifact was specified) |

<!-- outputs:end -->
<!-- examples:start -->
<!-- examples:end -->
<!-- contributing:start -->

## Contributing

Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.

<!-- contributing:end -->
<!-- security:start -->
<!-- security:end -->
<!-- license:start -->

## License

This project is licensed under the MIT License.

SPDX-License-Identifier: MIT

Copyright © 2025 Hoverkraft

For more details, see the [license](http://choosealicense.com/licenses/mit/).

<!-- license:end -->
<!-- generated:start -->

---

This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).

<!-- generated:end -->
<!-- jscpd:ignore-end -->
Loading