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.

81 changes: 0 additions & 81 deletions .github/workflows/build.yml

This file was deleted.

87 changes: 87 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: ci

on:
pull_request:
push:
branches: [main]

concurrency: "ci-${{ github.ref }}"

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
packages: read

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

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

- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- run: npm run lint

- run: npm run build

- id: npm-test
run: npm test

- name: Yontrack configuration
if: github.repository_owner == 'nemerosa' && vars.ONTRACK_URL != ''
id: yontrack-config
uses: nemerosa/ontrack-github-actions-cli-config@v1.3.0
env:
YONTRACK_URL: ${{ vars.ONTRACK_URL }}
YONTRACK_TOKEN: ${{ secrets.ONTRACK_TOKEN }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Build validation (self-test)
if: github.repository_owner == 'nemerosa' && vars.ONTRACK_URL != '' && !cancelled()
uses: ./
with:
logging: true
validation: BUILD
status: ${{ steps.npm-test.outcome == 'success' && 'PASSED' || 'FAILED' }}

- name: Semantic release
id: release
if: ${{ github.ref == 'refs/heads/main' }}
run: |
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"

- name: Released validation (self-test)
if: github.repository_owner == 'nemerosa' && vars.ONTRACK_URL != '' && !cancelled() && github.ref == 'refs/heads/main' && steps.release.outputs.version != ''
uses: ./
with:
logging: true
validation: RELEASE
status: PASSED
30 changes: 30 additions & 0 deletions .releaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"branches": ["main"],
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "angular",
"releaseRules": [
{ "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/github"
]
}
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Changelog

(This file is populated by semantic-release.)
51 changes: 51 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# 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/* 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 JavaScript GitHub Action that creates a validation run in [Yontrack](https://github.com/nemerosa/ontrack-cli) for an existing build. It takes a `validation` stamp name and an optional explicit `status` (PASSED, FAILED, etc.), with optional `type`+`flags` for typed validation data, and invokes the Yontrack CLI's `validate` subcommand.

**Project / branch / build resolution:**
- Each can be passed explicitly as an action input
- Otherwise falls back to the corresponding `YONTRACK_PROJECT_NAME` / `YONTRACK_BRANCH_NAME` / `YONTRACK_BUILD_NAME` env var (set by a prior `cli-config` step)
- For project/branch only: further fallback to `github.context.repo.repo` and parsing `github.context.ref` if env vars are unset
- `build` has no further fallback — must be provided either explicitly or via the env var

**Key files:**
- `index.js` — source. A top-level IIFE loads pure-ESM `@actions/*` packages via dynamic import and calls `runAction({core, exec, github})`.
- `dist/index.js` — bundled output (esbuild, CJS). The runner executes this.
- `dist/licenses.txt` — license attributions, generated by `esbuild-plugin-license`.
- `action.yml` — action metadata: inputs (project, branch, build, validation, status, type, flags, executable, logging), `runs.using: node24`, `runs.main: dist/index.js`.
- `index.test.js` — Jest unit tests with hand-rolled mock objects.
- `build.js` — esbuild driver with `esbuild-plugin-license`.
- `.yontrack/ci.yaml` — cli-config target config, used by the previous step in CI workflows.

**Why dependency injection:** All `@actions/*` packages at the latest majors are pure ESM. Top-level CJS imports no longer work. The IIFE loads ESM deps once at startup and passes them into `runAction`.

**History note:** Prior to this overhaul, the action implemented an "API polling" mode that took a `step-name` input and queried GitHub Actions for that step's completion status. The maintainer's commit `9e9af49 feat: explicit status` (Nov 2025) updated `action.yml` to advertise an explicit-status interface but never updated `index.js`. This upgrade completes that migration — `step-name` and the polling logic are removed; `status` is now read from inputs as `action.yml` describes.

## 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. Configures Yontrack via `cli-config` (which sets `YONTRACK_*` env vars).
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

This repo's runtime deps come from npmjs.com (the public registry). No GH Packages auth needed.
117 changes: 117 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Ontrack GitHub actions: CLI validation

GitHub action to create a [validation run](https://nemerosa.github.io/ontrack/) in [Yontrack](https://github.com/nemerosa/ontrack-cli) for an existing build, using the Yontrack CLI.

## Prerequisites

The Yontrack CLI must be installed and configured on the runner. The recommended setup is to run [`ontrack-github-actions-cli-config`](https://github.com/nemerosa/ontrack-github-actions-cli-config) earlier in the same job — it installs and configures the CLI and exports `YONTRACK_PROJECT_NAME`, `YONTRACK_BRANCH_NAME`, and `YONTRACK_BUILD_NAME` env vars that this action reads as fallbacks.

## Inputs

| Input | Required | Description |
|---|---|---|
| `validation` | yes | Name of the validation stamp to use for the validation run. |
| `status` | no | Status of the validation run (e.g. `PASSED`, `FAILED`). If omitted but `type`/`flags` are provided, Yontrack computes the status from the data. |
| `type` | no | Type of validation data, as supported by the Yontrack CLI (e.g. `tests`). |
| `flags` | no | Additional CLI flags for the data type (e.g. `--passed 10 --failed 1`). Required if `type` is set. |
| `project` | no | Project name in Yontrack. Defaults to `YONTRACK_PROJECT_NAME` env var, then to the GitHub repo name. |
| `branch` | no | Branch name in Yontrack. Defaults to `YONTRACK_BRANCH_NAME` env var, then to the parsed Git ref. |
| `build` | no | Build name in Yontrack. Defaults to `YONTRACK_BUILD_NAME` env var. Required (either input or env var). |
| `executable` | no | Name of the Yontrack CLI executable. Defaults to `ontrack-cli`. |
| `logging` | no | Set to `true` for verbose logging. Defaults to `false`. |

## Outputs

None.

## Example usage

### Pass a status from the previous step's outcome

```yaml
- name: Run tests
id: tests
run: npm test

- name: Validate the build
uses: nemerosa/ontrack-github-actions-cli-validation@v3
with:
validation: TESTS
status: ${{ steps.tests.outcome == 'success' && 'PASSED' || 'FAILED' }}
```

### Validate even when an earlier step failed (use `!cancelled()`)

By default, GitHub Actions skips a step if any earlier step failed. To run a validation regardless of prior failures (so you can mark a stamp as `FAILED` when something broke), use `if: ${{ !cancelled() }}`:

```yaml
- name: Run tests
id: tests
run: npm test

- name: Validate the build
if: ${{ !cancelled() }}
uses: nemerosa/ontrack-github-actions-cli-validation@v3
with:
validation: TESTS
status: ${{ steps.tests.outcome == 'success' && 'PASSED' || 'FAILED' }}
```

`!cancelled()` runs the step on success or failure, but skips it if the workflow run was cancelled by a user.

### Pass typed validation data

```yaml
- name: Validate test results
if: ${{ !cancelled() }}
uses: nemerosa/ontrack-github-actions-cli-validation@v3
with:
validation: TESTS
type: tests
flags: --passed 42 --failed 1 --skipped 3
```

When `type` is provided, Yontrack derives the status from the data (e.g. any failures → `FAILED`). You can also pass an explicit `status` to override.

### Use after `cli-config` (env-var fallback)

If a previous step ran [`cli-config`](https://github.com/nemerosa/ontrack-github-actions-cli-config), it sets `YONTRACK_*` env vars and you can omit `project`/`branch`/`build`:

```yaml
- name: Configure Yontrack
uses: nemerosa/ontrack-github-actions-cli-config@v2
env:
YONTRACK_URL: ${{ vars.YONTRACK_URL }}
YONTRACK_TOKEN: ${{ secrets.YONTRACK_TOKEN }}

- name: Run tests
id: tests
run: npm test

- name: Validate
if: ${{ !cancelled() }}
uses: nemerosa/ontrack-github-actions-cli-validation@v3
with:
validation: TESTS
status: ${{ steps.tests.outcome == 'success' && 'PASSED' || 'FAILED' }}
```

## Building

Download the dependencies by running:

```bash
npm install
```

To build the distribution:

```bash
npm run build
```

This runs `node build.js`, which invokes esbuild with `esbuild-plugin-license` to produce `dist/index.js` (the bundle the action runner executes) and `dist/licenses.txt` (license attributions). To run lint, build, and tests in one go:

```bash
npm run all
```
Loading