From 3d8a9679beb9a633082a59a8fe5794d830b21e41 Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Thu, 6 Aug 2026 18:18:51 +0200 Subject: [PATCH] ci: replace Drone with GitHub Actions Ports the .drone.yml pipeline: eslint, build and karma tests in the cypress/browsers image (Chrome comes from the image), semantic-release on master, and the tag-triggered gh-pages publish of examples/. The release job uses a GitHub App token for the tag push, because tags pushed with the built-in GITHUB_TOKEN do not trigger workflows and the docs publish is tag-triggered. Releases are serialized repo-wide since npm rejects concurrent publishes of one package. Adds CODEOWNERS requiring review for changes under .github/. .drone.yml is left in place so both pipelines run side by side. --- .github/CODEOWNERS | 3 ++ .github/workflows/ci.yml | 109 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/workflows/ci.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..61a46821 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +# Changes under .github/ require code-owner review: workflow files decide what +# runs in CI and with which credentials. +/.github/ @livingdocsIO/devops @livingdocsIO/admins diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..a85b301e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,109 @@ +# Replaces .drone.yml. +# +# GitHub-hosted runners on purpose: this repo is public, and self-hosted +# runners must never be reachable from public repositories (a fork PR can run +# arbitrary code). GitHub-hosted minutes are free for public repos. +name: CI + +on: + push: + branches: ['**'] + tags: ['**'] + pull_request: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +permissions: + contents: read + +jobs: + test: + name: Lint, build and test + runs-on: ubuntu-latest + timeout-minutes: 20 + # Chrome for the karma suite comes from the image, not the runner host. + container: + image: cypress/browsers:node-22.21.0-chrome-141.0.7390.107-1-ff-144.0-edge-141.0.3537.92-1 + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: npm ci + + - name: Lint + run: npm run lint + + - name: Build + run: npm run build -s + + # karma.conf.js already runs ChromeHeadlessNoSandbox, single-run + - name: Test + run: npm run test:ci -s + + release: + name: Semantic release + # Only publishes once the whole suite is green on the default branch. + if: github.ref == 'refs/heads/master' && github.event_name == 'push' + needs: test + runs-on: ubuntu-latest + timeout-minutes: 15 + # npm rejects concurrent publishes of the same package, so a repo-wide lock + concurrency: + group: release + cancel-in-progress: false + permissions: + contents: read # the App token below does the writing + steps: + # Tags pushed with the built-in GITHUB_TOKEN never trigger workflows, so + # semantic-release pushes with a livingdocs-release App token instead — + # that is what makes the tag fire the gh-pages job below. + - uses: actions/create-github-app-token@v2 + id: app-token + with: + app-id: ${{ vars.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + permission-contents: write + permission-issues: write + permission-pull-requests: write + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # semantic-release needs full history and tags + token: ${{ steps.app-token.outputs.token }} + # CRITICAL: without this the persisted default GITHUB_TOKEN wins the + # push, the tag is attributed to github-actions[bot], and the + # tag-triggered gh-pages job never fires. + persist-credentials: false + + - name: Release + uses: docker://livingdocs/semantic-release:v3.0.3 + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN_PUBLISH }} + + publish-docs: + name: Publish examples to gh-pages + if: startsWith(github.ref, 'refs/tags/') + needs: test + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: cypress/browsers:node-22.21.0-chrome-141.0.7390.107-1-ff-144.0-edge-141.0.3537.92-1 + permissions: + contents: write # pushes the built docs to the gh-pages branch + steps: + - uses: actions/checkout@v4 + + - run: npm ci + + - name: Build docs + run: npm run build -s + + - name: Publish to gh-pages + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./examples + keep_files: false