Skip to content

Commit c02a28b

Browse files
committed
chore: use github-scripts for cross-platform compatibility
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent 4b87508 commit c02a28b

File tree

9 files changed

+407
-136
lines changed

9 files changed

+407
-136
lines changed

.github/workflows/__test-action-get-package-manager.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,28 @@ jobs:
1616
- working-directory: tests/npm
1717
package-manager: npm
1818
lock-file: package-lock.json
19-
cache-dependency-path: "**/package-lock.json"
19+
cache-dependency-path: "tests/npm/**/package-lock.json"
2020
install-command: npm ci
2121
run-script-command: npm run
2222

2323
- working-directory: tests/pnpm
2424
package-manager: pnpm
2525
lock-file: pnpm-lock.yaml
26-
cache-dependency-path: "**/pnpm-lock.yaml"
26+
cache-dependency-path: "tests/pnpm/**/pnpm-lock.yaml"
2727
install-command: pnpm install --frozen-lockfile
2828
run-script-command: pnpm
2929

3030
- working-directory: tests/pnpm-package-manager
3131
package-manager: pnpm
3232
lock-file: pnpm-lock.yaml
33-
cache-dependency-path: "**/pnpm-lock.yaml"
33+
cache-dependency-path: "tests/pnpm-package-manager/**/pnpm-lock.yaml"
3434
install-command: pnpm install --frozen-lockfile
3535
run-script-command: pnpm
3636

3737
- working-directory: tests/yarn
3838
package-manager: yarn
3939
lock-file: yarn.lock
40-
cache-dependency-path: "**/yarn.lock"
40+
cache-dependency-path: "tests/yarn/**/yarn.lock"
4141
install-command: yarn install --frozen-lockfile
4242
run-script-command: yarn
4343
steps:

.github/workflows/continuous-integration.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!-- header:start -->
22

3-
# GitHub Reusable Workflow: NodeJS Continuous Integration
3+
# GitHub Reusable Workflow: Node.js Continuous Integration
44

55
<div align="center">
66
<img src="https://opengraph.githubassets.com/d404625773c747748dc7d301c22e3486f68a45a9b6ecf6dcbbc8827f4cf9ccf8/hoverkraft-tech/ci-github-nodejs" width="60px" align="center" alt="NodeJS Continuous Integration" />
@@ -23,7 +23,7 @@
2323

2424
## Overview
2525

26-
Workflow to performs continuous integration steps agains a NodeJs project:
26+
Workflow to performs continuous integration steps agains a Node.js project:
2727

2828
- CodeQL analysis
2929
- Linting
@@ -99,13 +99,13 @@ jobs:
9999
100100
| **Input** | **Description** | **Required** | **Type** | **Default** |
101101
| ----------------------- | ----------------------------------------------------------------------------------------- | ------------ | ----------- | ------------ |
102-
| **`build`** | Build parameters. Must be a string or a json object. | **false** | **string** | `build` |
102+
| **`build`** | Build parameters. Must be a string or a JSON object. | **false** | **string** | `build` |
103103
| **`checks`** | Optional flag to enable check steps. | **false** | **boolean** | `true` |
104104
| **`lint`** | Optional flag to enable linting. | **false** | **boolean** | `true` |
105105
| **`code-ql`** | Code QL analysis language. See <https://github.com/github/codeql-action>. | **false** | **string** | `typescript` |
106106
| **`dependency-review`** | Enable dependency review scan. See <https://github.com/actions/dependency-review-action>. | **false** | **boolean** | `true` |
107107
| **`test`** | Optional flag to enable test. | **false** | **boolean** | `true` |
108-
| **`coverage`** | Specifify code coverage reporter. Supported values: 'codecov'. | **false** | **string** | `codecov` |
108+
| **`coverage`** | Specifify code coverage reporter. Supported values: 'Codecov'. | **false** | **string** | `codecov` |
109109
| **`working-directory`** | Working directory where the dependencies are installed. | **false** | **string** | `.` |
110110

111111
<!-- inputs:end -->

.github/workflows/continuous-integration.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# Workflow to performs continuous integration steps agains a NodeJs project:
1+
# Workflow to performs continuous integration steps agains a Node.js project:
22
#
33
# - CodeQL analysis
44
# - Linting
55
# - Build
66
# - Test
77

8-
name: NodeJS Continuous Integration
8+
name: Node.js Continuous Integration
99

1010
on:
1111
workflow_call:
@@ -41,7 +41,7 @@ on:
4141
required: false
4242
default: true
4343
coverage:
44-
description: "Specifify code coverage reporter. Supported values: 'codecov'."
44+
description: "Specifify code coverage reporter. Supported values: `codecov`."
4545
type: string
4646
required: false
4747
default: "codecov"

AGENTS.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# AGENTS.md — agent instructions and operational contract
2+
3+
This file is written for automated coding agents (for example: Copilot coding agents). It exists to provide a concise operational contract and guardrails for agents working in this repository. It is not the canonical source for design or style rules. Those live in the developer documentation linked below.
4+
5+
## Organization-wide guidelines (required)
6+
7+
- Follow the prioritized shared instructions in [hoverkraft-tech/.github/AGENTS.md](https://github.com/hoverkraft-tech/.github/blob/main/AGENTS.md) before working in this repository.
8+
9+
## Quick Start
10+
11+
This project is a collection of **opinionated GitHub Actions** and **reusable workflows** tailored for Node.js continuous integration pipelines. For comprehensive documentation, see the main [README.md](README.md).
12+
13+
### Key Sections to Reference
14+
15+
- **[Overview](README.md#overview)** – Project purpose and scope
16+
- **[Actions](README.md#actions)** – Catalog of available actions by category
17+
- **[Reusable Workflows](README.md#reusable-workflows)** – Orchestration workflows for Node.js CI
18+
- **[Development Workflow](README.md#development-workflow)** – Commands and conventions for local development
19+
- **[Contributing](README.md#contributing)** – Guidelines for contributing to the project
20+
21+
## Agent-Specific Development Patterns
22+
23+
### Critical Workflow Knowledge
24+
25+
```bash
26+
# Essential commands for development
27+
make lint # Run Super Linter (dockerized)
28+
make lint-fix # Auto-fix linting issues
29+
gh act -W .github/workflows/__test-workflow-continuous-integration.yml # Optional: exercise reusable workflows locally
30+
```
31+
32+
For detailed documentation on each action and workflow, refer to the individual readme files linked in the main [README.md](README.md).

README.md

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,88 @@
55
[![License](https://img.shields.io/badge/License-MIT-blue)](#license)
66
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
77

8-
Opinionated GitHub Actions and workflows for continuous integration in Node.js context
8+
Opinionated GitHub Actions and reusable workflows for Node.js continuous integration pipelines.
99

1010
---
1111

12+
## Overview
13+
14+
This repository centralizes the Hoverkraft toolkit for building, testing, and shipping Node.js projects on GitHub. It bundles:
15+
16+
- Composite actions that detect project tooling, manage dependencies, and bootstrap runtimes.
17+
- Reusable workflows that apply those actions to deliver consistent CI pipelines across repositories.
18+
1219
## Actions
1320

14-
### - [Get package manager](actions/get-package-manager/README.md)
21+
### Dependencies
22+
23+
_Actions dedicated to caching and validating Node.js dependencies._
24+
25+
#### - [Dependencies cache](actions/dependencies-cache/README.md)
26+
27+
#### - [Has installed dependencies](actions/has-installed-dependencies/README.md)
28+
29+
### Environment setup
1530

16-
### - [Has installed dependencies](actions/has-installed-dependencies/README.md)
31+
_Actions focused on discovering and preparing the Node.js environment._
1732

18-
### - [Setup node](actions/setup-node/README.md)
33+
#### - [Get package manager](actions/get-package-manager/README.md)
1934

20-
## Workflows
35+
#### - [Setup node](actions/setup-node/README.md)
2136

22-
### - [Continuous Integration](.github/workflows/continuous-integration.md)
37+
## Reusable Workflows
38+
39+
### Continuous Integration
40+
41+
- [Continuous Integration](.github/workflows/continuous-integration.md) — documentation for the reusable Node.js CI workflow.
2342

2443
## Contributing
2544

26-
👍 If you wish to contribute to this project, please read the [CONTRIBUTING.md](CONTRIBUTING.md) file, PRs are Welcome !
45+
Contributions are welcome! Please review the [contributing guidelines](CONTRIBUTING.md) before opening a PR.
46+
47+
### Action Structure Pattern
48+
49+
All actions follow a consistent layout:
50+
51+
```text
52+
actions/{category}/{action-name}/
53+
├── action.yml # Action definition with inputs/outputs
54+
├── README.md # Usage documentation and examples
55+
└── index.js / scripts # Optional Node.js helpers (when required)
56+
```
57+
58+
### Development Standards
59+
60+
#### Action Definition Standards
61+
62+
1. **Consistent branding**: Use `author: hoverkraft` with `color: blue` and a meaningful `icon`.
63+
2. **Pinned dependencies**: Reference third-party actions via exact SHAs to guarantee reproducibility.
64+
3. **Input validation**: Validate critical inputs early within composite steps or supporting scripts.
65+
4. **Idempotent steps**: Ensure actions can run multiple times without leaving residual state in the workspace.
66+
5. **Multi-platform support**: Test actions in both `ubuntu-latest` and `windows-latest` runners when applicable.
67+
6. **Cross-platform compatibility**: Uses `actions/github-script` steps for cross-platform compatibility. Avoid `run` steps.
68+
7. **Logging**: Use structured logs with clear prefixes (`[build-image]`, `[helm-test-chart]`, …) to simplify debugging.
69+
8. **Security**: Avoid shell interpolation with untrusted inputs; prefer parameterized commands or `set -euo pipefail` wrappers.
70+
71+
#### File Conventions
72+
73+
- **Tests**: Located in `tests/` with fixtures for container builds and chart-testing scenarios.
74+
- **Workflows**: Reusable definitions live in `.github/workflows/`; internal/private workflows are prefixed with `__`.
75+
76+
#### JavaScript Development Patterns
77+
78+
- Encapsulate reusable logic in modules under the action directory (for example, `actions/my-action/index.js`).
79+
- Prefer async/await with explicit error handling when interacting with the GitHub API or filesystem.
80+
- Centralize environment variable parsing and validation to keep composite YAML lean.
81+
82+
### Development Workflow
83+
84+
#### Linting & Testing
85+
86+
```bash
87+
make lint # Run the dockerized Super Linter
88+
make lint-fix # Attempt auto-fixes for lint findings
89+
```
2790

2891
## Author
2992

@@ -34,5 +97,10 @@ Opinionated GitHub Actions and workflows for continuous integration in Node.js c
3497

3598
## License
3699

37-
📝 Copyright © 2023 [Hoverkraft <contact@hoverkraft.cloud>](https://hoverkraft.cloud).<br />
38-
This project is [MIT](LICENSE) licensed.
100+
This project is licensed under the MIT License.
101+
102+
SPDX-License-Identifier: MIT
103+
104+
Copyright © 2023 [Hoverkraft](https://hoverkraft.cloud).
105+
106+
For more details, see the [license](http://choosealicense.com/licenses/mit/).

actions/dependencies-cache/action.yml

Lines changed: 77 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ inputs:
1010
description: "List of dependencies for which the cache should be managed."
1111
required: true
1212
working-directory:
13-
description: "Working directory where the dependencies are installed."
13+
description: |
14+
Working directory where the dependencies are installed.
15+
Can be absolute or relative to the repository root.
1416
required: false
1517
default: "."
1618

@@ -75,35 +77,80 @@ runs:
7577
- name: ♻️ Get Jest cache dir
7678
id: jest-cache-dir-path
7779
if: fromJson(steps.has-installed-dependencies.outputs.installed-dependencies).jest == true
78-
shell: bash
79-
working-directory: ${{ inputs.working-directory }}
80-
run: |
81-
case "${{ steps.get-package-manager.outputs.package-manager }}" in
82-
npm)
83-
JEST_CONFIG=$(${{ steps.get-package-manager.outputs.package-manager }} exec jest -- --showConfig)
84-
;;
85-
*)
86-
JEST_CONFIG=$(${{ steps.get-package-manager.outputs.package-manager }} jest --showConfig)
87-
;;
88-
esac
89-
90-
if [ -z "$JEST_CONFIG" ]; then
91-
echo "::error::Unable to get Jest config"
92-
exit 1
93-
fi
94-
95-
echo "::debug::Jest config: $JEST_CONFIG"
96-
97-
JEST_CACHE_DIR=$(echo "$JEST_CONFIG" | grep -oP '(?<="cacheDirectory": ")[^"]+(?=")')
98-
99-
if [ -z "$JEST_CACHE_DIR" ]; then
100-
echo "::error ::Unable to get Jest cache directory from config: $JEST_CONFIG"
101-
exit 1
102-
fi
103-
104-
echo "::debug::Jest cache directory: $JEST_CACHE_DIR"
105-
106-
echo "dir=$JEST_CACHE_DIR" >> "$GITHUB_OUTPUT"
80+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
81+
env:
82+
WORKING_DIRECTORY: ${{ inputs.working-directory }}
83+
PACKAGE_MANAGER: ${{ steps.get-package-manager.outputs.package-manager }}
84+
with:
85+
# jscpd:ignore-start
86+
script: |
87+
const fs = require('node:fs');
88+
const path = require('node:path');
89+
90+
let workingDirectory = process.env.WORKING_DIRECTORY || '.';
91+
if (!path.isAbsolute(workingDirectory)) {
92+
workingDirectory = path.join(process.env.GITHUB_WORKSPACE, workingDirectory);
93+
}
94+
95+
if (!fs.existsSync(workingDirectory)) {
96+
core.setFailed(`The specified working directory does not exist: ${workingDirectory}`);
97+
return;
98+
}
99+
100+
workingDirectory = path.resolve(workingDirectory);
101+
core.debug(`Running in working directory: ${workingDirectory}`);
102+
process.chdir(workingDirectory);
103+
104+
const packageManager = process.env.PACKAGE_MANAGER;
105+
if (!packageManager) {
106+
core.setFailed('Unable to determine package manager');
107+
return;
108+
}
109+
core.debug(`Using package manager: ${packageManager}`);
110+
111+
const commandArgs = packageManager === 'npm'
112+
? ['exec', 'jest', '--', '--showConfig']
113+
: ['jest', '--showConfig'];
114+
115+
let execResult;
116+
try {
117+
execResult = await exec.getExecOutput(packageManager, commandArgs, { cwd: workingDirectory });
118+
} catch (error) {
119+
core.setFailed(`Unable to get Jest config: ${error.message}`);
120+
return;
121+
}
122+
123+
if (execResult.exitCode !== 0) {
124+
const errorMessage = execResult.stderr?.trim() || execResult.stdout?.trim();
125+
core.setFailed(`Unable to get Jest config (exit code ${execResult.exitCode}): ${errorMessage}`);
126+
return;
127+
}
128+
129+
const jestConfigRaw = execResult.stdout.trim();
130+
131+
if (!jestConfigRaw) {
132+
core.setFailed('Unable to get Jest config');
133+
return;
134+
}
135+
136+
core.debug(`Jest config: ${jestConfigRaw}`);
137+
138+
// Find cacheDirectory in the config with regex
139+
const cacheDirMatch = jestConfigRaw.match(/"cacheDirectory"\s*:\s*"([^"]+)"/);
140+
if (!cacheDirMatch || cacheDirMatch.length < 2) {
141+
core.setFailed('Unable to find cacheDirectory in Jest config');
142+
return;
143+
}
144+
145+
let jestCacheDir = cacheDirMatch[1];
146+
if (!path.isAbsolute(jestCacheDir)) {
147+
jestCacheDir = path.join(workingDirectory, jestCacheDir);
148+
}
149+
jestCacheDir = path.resolve(jestCacheDir);
150+
151+
core.debug(`Jest cache directory: ${jestCacheDir}`);
152+
core.setOutput('dir', jestCacheDir);
153+
# jscpd:ignore-end
107154

108155
- name: ♻️ Test cache
109156
if: steps.jest-cache-dir-path.outputs.dir

0 commit comments

Comments
 (0)