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: 0 additions & 1 deletion .eslintignore

This file was deleted.

18 changes: 0 additions & 18 deletions .eslintrc.json

This file was deleted.

51 changes: 27 additions & 24 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,44 +18,44 @@ jobs:

steps:

- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
persist-credentials: true

- name: Use Node.js 20.x
uses: actions/setup-node@v6
- uses: actions/setup-node@v6
with:
node-version: 20.x
node-version: 24.x
registry-url: 'https://npm.pkg.github.com'
scope: '@nemerosa'

- name: Install dependencies
id: npm-ci
run: npm ci
env:
# See https://docs.github.com/en/packages/learn-github-packages/configuring-a-packages-access-control-and-visibility#ensuring-workflow-access-to-your-package
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Building and running tests
id: npm-build
run: npm run build && npm test
- run: npm run lint

# Testing the action
- run: npm run build

- run: npm test

- name: "Test: download"
if: github.repository_owner == 'nemerosa'
id: test-download
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: "Test: getting the version"
if: github.repository_owner == 'nemerosa'
id: test-version
run: |
yontrack version --cli
run: yontrack version --cli

- name: "Test: local configuration"
if: github.repository_owner == 'nemerosa' && vars.YONTRACK_URL != ''
id: test-config
uses: ./
env:
Expand All @@ -64,21 +64,24 @@ jobs:
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Commit and push built files
- name: Semantic release
id: release
if: ${{ github.ref == 'refs/heads/main' }}
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add dist/
if ! git diff --staged --quiet; then
git commit -m "chore: update built files [skip ci]"
git push
fi

- name: Publication
id: npm-publish
if: ${{ github.ref == 'refs/heads/main' }}
run: npx semantic-release
npx semantic-release
VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
echo "version=$VERSION" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Update floating major/minor tags
if: ${{ github.ref == 'refs/heads/main' && steps.release.outputs.version != '' }}
run: |
VERSION="${{ steps.release.outputs.version }}"
[[ "$VERSION" =~ ^v([0-9]+)\.([0-9]+)\.[0-9]+$ ]] || exit 0
MAJOR="v${BASH_REMATCH[1]}"
MINOR="v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
git tag -f "$MAJOR" "$VERSION"
git tag -f "$MINOR" "$VERSION"
git push origin -f "$MAJOR" "$MINOR"
35 changes: 19 additions & 16 deletions .releaserc
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
{
"branches": [
"main"
],
"branches": ["main"],
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "angular",
"releaseRules": [
{"type": "docs", "release": false},
{"type": "fix", "release": "patch"},
{"type": "feat", "release": "minor"},
{"type": "refactor", "release": "major"},
{"type": "release", "release": "patch"}
],
{ "breaking": true, "release": "major" },
{ "type": "feat", "release": "minor" },
{ "type": "refactor", "release": "major" },
{ "type": "fix", "release": "patch" },
{ "type": "perf", "release": "patch" },
{ "type": "chore", "release": "patch" },
{ "type": "docs", "release": "patch" },
{ "type": "style", "release": "patch" },
{ "type": "test", "release": "patch" },
{ "type": "build", "release": "patch" },
{ "type": "ci", "release": "patch" },
{ "type": "revert", "release": "patch" },
{ "type": "release", "release": "patch" }
]
}],
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
[
"@semantic-release/git",
{
"assets": ["dist/**/*", "CHANGELOG.md", "package.json", "package-lock.json", "action.yml"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
],
["@semantic-release/git", {
"assets": ["dist/**/*", "CHANGELOG.md", "package.json", "package-lock.json", "action.yml"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}],
"@semantic-release/github"
]
}
49 changes: 49 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```bash
npm run lint # ESLint (flat config, v10)
npm run build # esbuild bundle to dist/index.js + esbuild-plugin-license writes dist/licenses.txt
npm test # Jest unit tests (mocked @actions/core and @nemerosa/* deps)
npm run all # lint + build + test
```

`npm run build` runs `node build.js`, which invokes esbuild with `esbuild-plugin-license` to produce `dist/index.js` and license attribution. ncc is no longer used.

## Architecture

This is a thin GitHub Action that installs and configures the [Yontrack CLI](https://github.com/nemerosa/ontrack-cli). It's substantially simpler than `cli-config` — no env-var injection, no CLI invocation beyond what `module-install` does internally. Its only job: download the binary, configure auth (when url/token are provided), and add the CLI's directory to PATH.

**Execution flow** (`index.js`):
1. Reads `url`/`token` inputs (falling back to `YONTRACK_URL`/`YONTRACK_TOKEN` env vars)
2. Delegates to `@nemerosa/ontrack-github-actions-module-install` — handles binary download, PATH setup, and Yontrack auth config
3. Sets the `installed` output to the actual version installed

**Source shape:** `index.js` exports `runAction({core, client})`. A top-level IIFE loads pure-ESM `@actions/core` via dynamic import (namespace, not `.default`) and `require()`s the CJS `@nemerosa/ontrack-github-actions-module-install` at top level. Tests inject mock objects directly.

**Why dependency injection:** `@actions/core@3` is pure ESM. Top-level `require('@actions/core')` no longer works in CJS source. `@nemerosa/ontrack-github-actions-module-install` stays CJS so it's required at top level normally.

**Key files:**
- `index.js` — source. Top-level `require` for module-install + IIFE-loaded `@actions/core`.
- `dist/index.js` — bundled output (esbuild, CJS) committed alongside source changes.
- `dist/licenses.txt` — license attributions, generated by `esbuild-plugin-license`.
- `action.yml` — action metadata: inputs, single output (`installed`), `runs.using: node24`.
- `index.test.js` — Jest unit tests with hand-rolled mock objects.
- `build.js` — esbuild driver.

## Release process

Releases are automated via `semantic-release` (`.releaserc`). Commit messages follow Angular convention. Every conventional-commit type triggers at least a patch release; `feat` is minor; `refactor` and any commit with a `BREAKING CHANGE:` footer is major.

The CI workflow on `main`:
1. Runs `npm run lint && npm run build && npm test`.
2. Self-tests the action (downloads CLI, optionally configures it).
3. Runs `npx semantic-release` — produces `vX.Y.Z` GitHub release; `@semantic-release/git` commits the regenerated `dist/`, `CHANGELOG.md`, `package.json`, `package-lock.json`, and `action.yml`.
4. Force-updates floating `vX` and `vX.Y` tags to point at the new release SHA.

## NPM registry

The `@nemerosa` scoped packages come from GitHub Packages. The `.npmrc` file sets this up; you need a valid `NODE_AUTH_TOKEN` to install dependencies (`read:packages` scope is sufficient).
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ outputs:
installed:
description: Version which was actually installed
runs:
using: node20
using: node24
main: dist/index.js
28 changes: 28 additions & 0 deletions build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const esbuild = require('esbuild');
const license = require('esbuild-plugin-license').default;

esbuild.build({
entryPoints: ['index.js'],
bundle: true,
platform: 'node',
format: 'cjs',
target: 'node24',
outfile: 'dist/index.js',
sourcemap: true,
plugins: [license({
thirdParty: {
output: {
file: 'dist/licenses.txt',
template(dependencies) {
return dependencies
.map((dep) => [dep.packageJson.name, dep.packageJson.license, dep.licenseText]
.filter(Boolean).join('\n'))
.join('\n\n');
},
},
},
})],
}).catch((err) => {
console.error(err);
process.exit(1);
});
Loading