From 4068afa2f0763491214b56d83686409cb4549b8c Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Sat, 18 Apr 2026 15:22:23 -0300 Subject: [PATCH] build: drop docker-bake in favor of plain npm (#551) * build: drop docker-bake in favor of plain npm Every TypeScript action maintained by actions/* (checkout, setup-node, setup-go, cache, upload-artifact) uses plain npm scripts. The bake setup is a docker/* org convention and adds friction for TS work: contributors need Docker, the dev loop is ~10x slower than npm, and Alpine-vs-host byte drift in dist/index.js makes PRs bounce. Replace with the standard pattern: - .node-version pins Node 24 so contributors and CI agree - npm scripts (build, lint, format, test, pre-checkin) replace bake targets one-for-one - validate.yml runs lint + a check-dist diff (mirrors actions/setup-node) and a vendor check that npm install --package-lock-only is a no-op - test.yml uses setup-node + sigstore/cosign-installer, drops bake-action - dependabot-build.yml regenerates dist via npm instead of bake CONTRIBUTING.md and README development section updated to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * build: align scripts and workflows with actions/* convention Match the standard layout used by actions/checkout, actions/setup-node, etc.: - package.json scripts: split format/format-check (Prettier) from lint/lint:fix (ESLint), and have pre-checkin run all four (format, lint:fix, build, test) in that order. - validate.yml lint job runs format-check + lint as separate steps. - test.yml drops the redundant --coverage flag (now in the test script). - Drop dependabot-build.yml: actions/* don't auto-rebuild dist on dependabot PRs; the check-dist style validate / build job catches drift and a maintainer rebuilds locally if needed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/dependabot-build.yml | 46 ------------- .github/workflows/test.yml | 17 +++-- .github/workflows/validate.yml | 85 +++++++++++++++++++----- .node-version | 1 + CONTRIBUTING.md | 89 +++++++++++--------------- README.md | 11 ++-- dev.Dockerfile | 72 --------------------- docker-bake.hcl | 61 ------------------ package.json | 14 ++-- 9 files changed, 129 insertions(+), 267 deletions(-) delete mode 100644 .github/workflows/dependabot-build.yml create mode 100644 .node-version delete mode 100644 dev.Dockerfile delete mode 100644 docker-bake.hcl diff --git a/.github/workflows/dependabot-build.yml b/.github/workflows/dependabot-build.yml deleted file mode 100644 index 3569c07..0000000 --- a/.github/workflows/dependabot-build.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: dependabot-build - -on: - pull_request: - paths: - - 'package.json' - -# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions -permissions: - contents: write - -jobs: - build: - runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' - steps: - - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: ${{ github.head_ref }} - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - - name: Vendor - uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 - with: - targets: vendor - - - name: Pre-checkin - uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 - with: - targets: pre-checkin - - - name: Commit and push changes - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - if git diff --cached --quiet; then - echo "No changes to commit" - else - git commit -m "chore: update dist and vendor" - git push - fi diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aa5e35c..25d9d61 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,11 +25,20 @@ jobs: with: fetch-depth: 0 - - name: Test - uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 + name: Setup Node.js + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v6.0.0 with: - source: . - targets: test + node-version-file: '.node-version' + cache: npm + - + name: Install cosign + uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2 + - + name: Install dependencies + run: npm ci + - + name: Test + run: npm test - name: Upload coverage uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index ebc509b..92692c3 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -16,32 +16,83 @@ on: pull_request: jobs: - prepare: + lint: runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.generate.outputs.matrix }} steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Generate matrix - id: generate - uses: docker/bake-action/subaction/matrix@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 + name: Setup Node.js + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v6.0.0 with: - target: validate + node-version-file: '.node-version' + cache: npm + - + name: Install dependencies + run: npm ci + - + name: Format check + run: npm run format-check + - + name: Lint + run: npm run lint - validate: + build: runs-on: ubuntu-latest - needs: - - prepare - strategy: - fail-fast: false - matrix: - include: ${{ fromJson(needs.prepare.outputs.matrix) }} steps: - - name: Validate - uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 + name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - + name: Setup Node.js + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v6.0.0 with: - targets: ${{ matrix.target }} + node-version-file: '.node-version' + cache: npm + - + name: Install dependencies + run: npm ci --ignore-scripts + - + name: Rebuild dist + run: npm run build + - + name: Compare dist + id: diff + run: | + if [ "$(git diff --ignore-space-at-eol dist | wc -l)" -gt "0" ]; then + echo "Detected uncommitted changes after build. Run 'npm run build' and commit dist/." >&2 + git diff dist + exit 1 + fi + - + name: Upload built dist on failure + if: ${{ failure() && steps.diff.conclusion == 'failure' }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: dist + path: dist + + vendor: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - + name: Setup Node.js + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v6.0.0 + with: + node-version-file: '.node-version' + cache: npm + - + name: Refresh package-lock.json + run: npm install --package-lock-only + - + name: Compare package-lock.json + run: | + if [ -n "$(git status --porcelain -- package-lock.json)" ]; then + echo "package-lock.json is out of sync with package.json. Run 'npm install' and commit." >&2 + git diff package-lock.json + exit 1 + fi diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..a45fd52 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e333119..eaa00d6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,78 +1,63 @@ # Contributing -Thanks for your interest in contributing! This document covers the development -workflow needed to get a change ready to commit and push. +Thanks for your interest in contributing! ## Prerequisites -- [Docker](https://docs.docker.com/get-docker/) with [Buildx](https://docs.docker.com/buildx/working-with-buildx/) -- Git +- [Node.js](https://nodejs.org/) — version pinned in [`.node-version`](./.node-version). + Tools like [`nvm`](https://github.com/nvm-sh/nvm), [`fnm`](https://github.com/Schniz/fnm), + [`asdf`](https://asdf-vm.com/), or [`mise`](https://mise.jdx.dev/) read this file + automatically. +- [`cosign`](https://docs.sigstore.dev/cosign/installation/) — only required if you + want to run the signature-verification integration tests locally. -That's it. Everything else (Node, npm, linters, the test environment) runs -inside containers driven by `docker buildx bake`. +## Setup + +```sh +npm ci +``` ## Pre-commit checklist -Run these commands, in order, before committing any change to `src/`, -`__tests__/`, `package.json`, `package-lock.json`, or `action.yml`: +Before committing changes to `src/`, `__tests__/`, `package.json`, +`package-lock.json`, or `action.yml`: ```sh -# 1. Format source, refresh node_modules, regenerate dist/index.js -docker buildx bake pre-checkin - -# 2. Run the test suite (unit + integration; needs network for release downloads) -docker buildx bake test - -# 3. Validate that everything is committed and reproducible -docker buildx bake validate +npm run pre-checkin ``` -`validate` is what CI runs. If it passes locally, your PR will pass the -`validate` job too. +That runs `format` + `build` + `test` — the same checks CI runs. -### Why `pre-checkin` matters +Then commit `dist/` along with your source changes; the action runtime loads +`dist/index.js` directly, so it must stay in sync. -The repository ships the compiled action as `dist/index.js`. CI's -`build-validate` target rebuilds it inside an Alpine container and fails if the -checked-in bytes don't match. **You must commit the `dist/` output produced by -`docker buildx bake pre-checkin`** — running `npm run build` on macOS or a -non-Alpine host produces slightly different bytes and `validate` will reject -the PR. +If CI's `validate / build` job fails because `dist/` differs from a fresh +build, just download the `dist` artifact from the failed run and commit it — +or rerun `npm run build` locally with the Node version in `.node-version`. -If you forget and CI complains about a `dist/` diff, just run: +## npm scripts -```sh -docker buildx bake build -git add dist/ -git commit --amend --no-edit -git push --force-with-lease -``` - -## Available bake targets - -| Target | Purpose | -| --------------- | --------------------------------------------------- | -| `build` | Regenerate `dist/index.js` only | -| `format` | Run Prettier on `src/` and `__tests__/` | -| `vendor` | Refresh `node_modules` / `package-lock.json` | -| `pre-checkin` | `vendor` + `format` + `build` (run before commits) | -| `lint` | Prettier check + ESLint | -| `build-validate`| Verify `dist/index.js` matches a fresh build | -| `vendor-validate`| Verify `package-lock.json` is in sync | -| `validate` | `lint` + `build-validate` + `vendor-validate` | -| `test` | Run Jest with coverage in an Alpine container | +| Script | Purpose | +| ------------------- | ------------------------------------------------ | +| `npm run build` | Bundle `src/` to `dist/index.js` via `ncc` | +| `npm run format` | Run Prettier (write) | +| `npm run format-check` | Run Prettier (check only, used in CI) | +| `npm run lint` | Run ESLint (check only, used in CI) | +| `npm run lint:fix` | Run ESLint with `--fix` | +| `npm test` | Run Jest with coverage | +| `npm run pre-checkin` | `format` + `lint:fix` + `build` + `test` | ## Tests -`docker buildx bake test` runs the full Jest suite, including integration -tests that: +`npm test` runs the full Jest suite, including integration tests that: - Download real GoReleaser releases from GitHub - Verify `checksums.txt` against the downloaded archive -- Verify the cosign sigstore bundle (`cosign` is installed in the test image) +- Verify the cosign sigstore bundle (skipped if `cosign` isn't on `PATH`, + but the CI image always has it installed) -These need outbound network access. If you're behind a restrictive proxy or -offline, those tests will fail — that's expected. +These need outbound network access. Offline / restrictive-proxy runs will +have those tests fail — that's expected. ## Commit messages @@ -82,7 +67,7 @@ Use [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, ## Pull requests - Target `master`. -- Make sure `docker buildx bake validate` and `docker buildx bake test` pass. +- Make sure `npm run pre-checkin` passes. - One logical change per PR is easier to review. - The `signing` CI job and `goreleaser-pro` matrix entries are skipped on PRs from forks because they need repository secrets — that's expected and not diff --git a/README.md b/README.md index 199093a..399569b 100644 --- a/README.md +++ b/README.md @@ -238,14 +238,11 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full development workflow. Quick reference: ``` -# format code and build javascript artifacts -docker buildx bake pre-checkin +# install dependencies +npm ci -# validate all code has correctly formatted and built -docker buildx bake validate - -# run tests -docker buildx bake test +# format, build dist/, and run tests +npm run pre-checkin ``` ## License diff --git a/dev.Dockerfile b/dev.Dockerfile deleted file mode 100644 index 69bc6ce..0000000 --- a/dev.Dockerfile +++ /dev/null @@ -1,72 +0,0 @@ -# syntax=docker/dockerfile:1 - -ARG NODE_VERSION=24 - -FROM node:${NODE_VERSION}-alpine AS base -RUN apk add --no-cache cpio findutils git -WORKDIR /src - -FROM base AS deps -RUN --mount=type=bind,target=.,rw \ - --mount=type=cache,target=/src/node_modules \ - npm install && mkdir /vendor && cp package-lock.json /vendor - -FROM scratch AS vendor-update -COPY --from=deps /vendor / - -FROM deps AS vendor-validate -RUN --mount=type=bind,target=.,rw <&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor"' - git status --porcelain -- package-lock.json - exit 1 - fi -EOT - -FROM deps AS build -RUN --mount=type=bind,target=.,rw \ - --mount=type=cache,target=/src/node_modules \ - npm run build && mkdir /out && cp -Rf dist /out/ - -FROM scratch AS build-update -COPY --from=build /out / - -FROM build AS build-validate -RUN --mount=type=bind,target=.,rw <&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"' - git status --porcelain -- dist - exit 1 - fi -EOT - -FROM deps AS format -RUN --mount=type=bind,target=.,rw \ - --mount=type=cache,target=/src/node_modules \ - npm run format \ - && mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out - -FROM scratch AS format-update -COPY --from=format /out / - -FROM deps AS lint -RUN --mount=type=bind,target=.,rw \ - --mount=type=cache,target=/src/node_modules \ - npm run lint - -FROM deps AS test -RUN apk add --no-cache cosign -ENV RUNNER_TEMP=/tmp/github_runner -ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache -RUN --mount=type=bind,target=.,rw \ - --mount=type=cache,target=/src/node_modules \ - npm run test -- --coverage --coverageDirectory=/tmp/coverage - -FROM scratch AS test-coverage -COPY --from=test /tmp/coverage / diff --git a/docker-bake.hcl b/docker-bake.hcl deleted file mode 100644 index 81b5f76..0000000 --- a/docker-bake.hcl +++ /dev/null @@ -1,61 +0,0 @@ -target "_common" { - args = { - BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1 - } -} - -group "default" { - targets = ["build"] -} - -group "pre-checkin" { - targets = ["vendor", "format", "build"] -} - -group "validate" { - targets = ["lint", "build-validate", "vendor-validate"] -} - -target "build" { - dockerfile = "dev.Dockerfile" - target = "build-update" - output = ["."] -} - -target "build-validate" { - inherits = ["_common"] - dockerfile = "dev.Dockerfile" - target = "build-validate" - output = ["type=cacheonly"] -} - -target "format" { - dockerfile = "dev.Dockerfile" - target = "format-update" - output = ["."] -} - -target "lint" { - dockerfile = "dev.Dockerfile" - target = "lint" - output = ["type=cacheonly"] -} - -target "vendor" { - dockerfile = "dev.Dockerfile" - target = "vendor-update" - output = ["."] -} - -target "vendor-validate" { - inherits = ["_common"] - dockerfile = "dev.Dockerfile" - target = "vendor-validate" - output = ["type=cacheonly"] -} - -target "test" { - dockerfile = "dev.Dockerfile" - target = "test-coverage" - output = ["./coverage"] -} diff --git a/package.json b/package.json index edd065e..64cc579 100644 --- a/package.json +++ b/package.json @@ -5,14 +5,12 @@ "type": "module", "scripts": { "build": "ncc build src/main.ts --minify --license licenses.txt", - "lint": "npm run prettier && npm run eslint", - "format": "npm run prettier:fix && npm run eslint:fix", - "eslint": "eslint --max-warnings=0 .", - "eslint:fix": "eslint --fix .", - "prettier": "prettier --check \"./**/*.ts\"", - "prettier:fix": "prettier --write \"./**/*.ts\"", - "test": "NODE_OPTIONS='--experimental-vm-modules' jest", - "all": "npm run build && npm run format && npm test" + "format": "prettier --write \"**/*.ts\"", + "format-check": "prettier --check \"**/*.ts\"", + "lint": "eslint --max-warnings=0 \"**/*.ts\"", + "lint:fix": "eslint --fix \"**/*.ts\"", + "test": "NODE_OPTIONS='--experimental-vm-modules' jest --coverage", + "pre-checkin": "npm run format && npm run lint:fix && npm run build && npm test" }, "repository": { "type": "git",