-
Notifications
You must be signed in to change notification settings - Fork 8
chore: local dev orchestration, CI for every subproject, manual release dispatch #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
964293e
60f80ef
984fbd6
7a8a0d3
c7ed651
941e40a
09cb6e8
ffd7d8b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,291 @@ | ||
| name: ci | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: | ||
| - main | ||
|
|
||
| permissions: | ||
| contents: read | ||
| # paths-filter falls back to the pull request API when it cannot diff locally | ||
| pull-requests: read | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| env: | ||
| NODE_VERSION: "24" | ||
|
|
||
| jobs: | ||
| changes: | ||
| name: Detect changes | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| console: ${{ steps.filter.outputs.console }} | ||
| worker-docker: ${{ steps.filter.outputs.worker-docker }} | ||
| worker-sys: ${{ steps.filter.outputs.worker-sys }} | ||
| worker-boxlite: ${{ steps.filter.outputs.worker-boxlite }} | ||
| web: ${{ steps.filter.outputs.web }} | ||
| website: ${{ steps.filter.outputs.website }} | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| # api/ holds the shared proto and its generated Go module: the three Go | ||
| # modules pull it in via a replace directive and worker-boxlite compiles | ||
| # api/proto in build.rs, so a change there has to rebuild every backend. | ||
| - name: Filter changed paths | ||
| uses: dorny/paths-filter@v3 | ||
| id: filter | ||
| with: | ||
| filters: | | ||
| shared: &shared | ||
| - 'api/**' | ||
| - '.github/workflows/ci.yml' | ||
| console: | ||
| - *shared | ||
| - 'console/**' | ||
|
Comment on lines
+47
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The Useful? React with 👍 / 👎. |
||
| worker-docker: | ||
| - *shared | ||
| - 'worker/worker-docker/**' | ||
| worker-sys: | ||
| - *shared | ||
| - 'worker/worker-sys/**' | ||
| worker-boxlite: | ||
| - *shared | ||
| - 'worker/worker-boxlite/**' | ||
| web: | ||
| - '.github/workflows/ci.yml' | ||
| - 'web/**' | ||
| website: | ||
| - '.github/workflows/ci.yml' | ||
| - 'website/**' | ||
|
|
||
| console: | ||
| name: Check console | ||
| needs: changes | ||
| if: needs.changes.outputs.console == 'true' | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: ./console | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Go | ||
| uses: actions/setup-go@v6 | ||
| with: | ||
| go-version-file: console/go.mod | ||
| cache-dependency-path: console/go.sum | ||
|
|
||
| - name: Vet | ||
| run: go vet ./... | ||
|
|
||
| - name: Unit tests | ||
| run: go test ./... | ||
|
|
||
| worker-docker: | ||
| name: Check worker-docker | ||
| needs: changes | ||
| if: needs.changes.outputs.worker-docker == 'true' | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: ./worker/worker-docker | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Go | ||
| uses: actions/setup-go@v6 | ||
| with: | ||
| go-version-file: worker/worker-docker/go.mod | ||
| cache-dependency-path: worker/worker-docker/go.sum | ||
|
|
||
| - name: Vet | ||
| run: go vet ./... | ||
|
|
||
| - name: Unit tests | ||
| run: go test ./... | ||
|
|
||
| worker-sys: | ||
| name: Check worker-sys | ||
| needs: changes | ||
| if: needs.changes.outputs.worker-sys == 'true' | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: ./worker/worker-sys | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Go | ||
| uses: actions/setup-go@v6 | ||
| with: | ||
| go-version-file: worker/worker-sys/go.mod | ||
| cache-dependency-path: worker/worker-sys/go.sum | ||
|
|
||
| - name: Vet | ||
| run: go vet ./... | ||
|
|
||
| - name: Unit tests | ||
| run: go test ./... | ||
|
|
||
| worker-boxlite: | ||
| name: Check worker-boxlite | ||
| needs: changes | ||
| if: needs.changes.outputs.worker-boxlite == 'true' | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: ./worker/worker-boxlite | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| # our build.rs uses protoc-bin-vendored, but the boxlite-shared build | ||
| # script needs protoc on the system | ||
| - name: Install protoc | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y protobuf-compiler | ||
| protoc --version | ||
|
|
||
| - name: Setup Rust | ||
| uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| components: rustfmt, clippy | ||
|
|
||
| - name: Cache cargo registry and target | ||
| uses: Swatinem/rust-cache@v2 | ||
| with: | ||
| workspaces: worker/worker-boxlite | ||
|
|
||
| - name: Format check | ||
| run: cargo fmt --check | ||
|
|
||
| - name: Clippy | ||
| run: cargo clippy --all-targets | ||
|
|
||
| - name: Unit tests | ||
| run: cargo test | ||
|
|
||
| web: | ||
| name: Check web | ||
| needs: changes | ||
| if: needs.changes.outputs.web == 'true' | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: ./web | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: ${{ env.NODE_VERSION }} | ||
|
|
||
| - name: Enable Corepack | ||
| run: corepack enable | ||
|
|
||
| - name: Resolve yarn cache folder | ||
| id: yarn-cache | ||
| run: echo "dir=$(yarn config get cacheFolder)" >> "${GITHUB_OUTPUT}" | ||
|
|
||
| - name: Cache yarn packages | ||
| uses: actions/cache@v6 | ||
| with: | ||
| path: ${{ steps.yarn-cache.outputs.dir }} | ||
| key: ${{ runner.os }}-yarn-web-${{ hashFiles('web/yarn.lock') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-yarn-web- | ||
|
|
||
| - name: Install dependencies | ||
| run: yarn install --immutable | ||
|
|
||
| - name: Format check | ||
| run: yarn format:check | ||
|
|
||
| - name: Type check | ||
| run: yarn type-check | ||
|
|
||
| - name: Unit tests | ||
| run: yarn test:unit --run | ||
|
|
||
| - name: Build | ||
| run: yarn build-only | ||
|
|
||
| website: | ||
| name: Check website | ||
| needs: changes | ||
| if: needs.changes.outputs.website == 'true' | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: ./website | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: ${{ env.NODE_VERSION }} | ||
|
|
||
| - name: Enable Corepack | ||
| run: corepack enable | ||
|
|
||
| - name: Resolve yarn cache folder | ||
| id: yarn-cache | ||
| run: echo "dir=$(yarn config get cacheFolder)" >> "${GITHUB_OUTPUT}" | ||
|
|
||
| - name: Cache yarn packages | ||
| uses: actions/cache@v6 | ||
| with: | ||
| path: ${{ steps.yarn-cache.outputs.dir }} | ||
| key: ${{ runner.os }}-yarn-website-${{ hashFiles('website/yarn.lock') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-yarn-website- | ||
|
|
||
| - name: Install dependencies | ||
| run: yarn install --immutable | ||
|
|
||
| - name: Unit tests | ||
| run: yarn test | ||
|
|
||
| # build runs tsc -b, the SSR build and the prerender step | ||
| - name: Build | ||
| run: yarn build | ||
|
|
||
| # Single job to mark as required in branch protection: skipped checks count as | ||
| # success, so unrelated subprojects never block a PR. | ||
| ci-ok: | ||
| name: CI | ||
| if: always() | ||
| needs: | ||
| - changes | ||
| - console | ||
| - worker-docker | ||
| - worker-sys | ||
| - worker-boxlite | ||
| - web | ||
| - website | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Verify job results | ||
| env: | ||
| NEEDS: ${{ toJSON(needs) }} | ||
| run: | | ||
| set -euo pipefail | ||
| echo "${NEEDS}" | jq -r 'to_entries[] | "\(.key): \(.value.result)"' | ||
| failed="$(echo "${NEEDS}" | jq -r '[to_entries[] | select(.value.result == "failure" or .value.result == "cancelled") | .key] | join(", ")')" | ||
| if [[ -n "${failed}" ]]; then | ||
| echo "::error::Failed or cancelled jobs: ${failed}" >&2 | ||
| exit 1 | ||
| fi | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| name: deploy-website | ||
| run-name: Deploy website (${{ inputs.mode }}) from ${{ github.ref_name }} | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| mode: | ||
| description: 'production = deploy at 100% traffic; preview = upload a version without shifting traffic' | ||
| required: true | ||
| default: production | ||
| type: choice | ||
| options: | ||
| - production | ||
| - preview | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| # shared with the deploy-cloudflare job in package-release.yml so a release | ||
| # deploy and a website-only deploy never race for production traffic | ||
| concurrency: | ||
| group: deploy-onlyboxes-website | ||
| cancel-in-progress: false | ||
|
Comment on lines
+21
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a website-only production dispatch overlaps a package release, this concurrency group serializes only runs of Useful? React with 👍 / 👎. |
||
|
|
||
| jobs: | ||
| deploy-website: | ||
| name: Build and deploy website | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: ./website | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: "24" | ||
|
|
||
| - name: Enable Corepack | ||
| run: corepack enable | ||
|
|
||
| - name: Install dependencies | ||
| run: yarn install --immutable | ||
|
|
||
| - name: Unit tests | ||
| run: yarn test | ||
|
|
||
| # build runs tsc -b, the SSR build and the prerender step | ||
| - name: Build website | ||
| run: yarn build | ||
|
|
||
| - name: Deploy to production (100% traffic) | ||
| if: inputs.mode == 'production' | ||
| uses: cloudflare/wrangler-action@v4 | ||
| with: | ||
| apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} | ||
| accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | ||
| wranglerVersion: "4" | ||
| workingDirectory: website | ||
| command: deploy | ||
|
|
||
| - name: Upload preview version (no traffic shift) | ||
| if: inputs.mode == 'preview' | ||
| uses: cloudflare/wrangler-action@v4 | ||
| with: | ||
| apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} | ||
| accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | ||
| wranglerVersion: "4" | ||
| workingDirectory: website | ||
| # version tag must stay short and free of '/', so the branch name goes in the message only | ||
| command: versions upload --tag preview-${{ github.run_number }} --message "Preview from ${{ github.ref_name }} (run ${{ github.run_number }})" | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On
pull_requestruns,dorny/paths-filterobtains the changed-file list through the pull-request REST API, for which its permissions documentation requirespull-requests: read. Declaring onlycontents: readmakes every unspecifiedGITHUB_TOKENpermission unavailable, so thechangesjob receives an API authorization failure on PRs even after the filter syntax is corrected; add the required read permission at workflow or job scope.Useful? React with 👍 / 👎.