scheduled-smoke #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Scheduled maintenance gate. | |
| # | |
| # Purpose: detect when a *generated project* stops building/testing because of | |
| # EXTERNAL drift — a Cardano hardfork, a breaking upstream tool release, or an | |
| # unmaintained dependency — even though nothing in this repo changed. The | |
| # templates pin floating version ranges (e.g. meshjs "^1.7.0", aiken stdlib | |
| # "v2"), so this can happen with zero commits here and would otherwise go | |
| # unnoticed until a user hits it. | |
| # | |
| # This is DISTINCT from the PR/commit gates (which catch regressions we | |
| # introduce). It runs the per-tool build smoke tests the docs already require | |
| # (ARCHITECTURE §11, PRD SM-1), but on a schedule, and opens a tracking issue | |
| # on failure. | |
| name: scheduled-smoke | |
| on: | |
| schedule: | |
| - cron: "0 6 * * 1" # every Monday 06:00 UTC | |
| workflow_dispatch: {} # allow manual runs | |
| permissions: | |
| contents: read | |
| jobs: | |
| smoke: | |
| name: ${{ matrix.tool }} build+test | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false # one tool breaking must not mask the others | |
| matrix: | |
| # Only the tools that are meant to build green are listed. Placeholders | |
| # (scalus, blaster, yaci) are intentionally excluded — their `just` | |
| # targets only echo, so they have no external dependency to drift. Add a | |
| # tool here the moment its template becomes genuinely build-green. | |
| include: | |
| - tool: aiken | |
| flags: --on-chain aiken | |
| - tool: meshjs | |
| flags: --off-chain meshjs | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install just | |
| uses: extractions/setup-just@v4 | |
| # --- per-tool toolchain (extend as the matrix grows) --- | |
| - name: Install Aiken | |
| if: matrix.tool == 'aiken' | |
| uses: aiken-lang/setup-aiken@v1 | |
| with: | |
| #Keep this in lockstep with templates/aiken/on-chain/aiken.toml.jinja. | |
| version: v1.1.21 | |
| - name: Install Node | |
| if: matrix.tool == 'meshjs' | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 20 | |
| - name: Scaffold project in isolation | |
| run: cargo run --quiet -- --name smoke-${{ matrix.tool }} ${{ matrix.flags }} | |
| - name: Build & test the generated project | |
| working-directory: smoke-${{ matrix.tool }} | |
| # Each component's Justfile installs its own deps (e.g. meshjs `_install` | |
| # runs `npm install` in off-chain/ on first build), so `just build` is | |
| # self-sufficient from the project root — no per-tool dep step here. | |
| run: | | |
| just build | |
| just test | |
| notify-on-failure: | |
| needs: smoke | |
| # Only file an issue for the unattended scheduled run, not manual debugging. | |
| if: failure() && github.event_name == 'schedule' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| steps: | |
| - uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const { owner, repo } = context.repo; | |
| const label = "scheduled-smoke"; | |
| const title = "Scheduled smoke test failed: a generated project no longer builds"; | |
| const today = new Date().toISOString().slice(0, 10); | |
| const runUrl = `${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`; | |
| const body = [ | |
| `The weekly per-tool smoke run failed on ${today}.`, | |
| ``, | |
| `A generated project stopped building/testing with no change to this repo —`, | |
| `likely a Cardano hardfork, a breaking upstream tool release, or an`, | |
| `unmaintained dependency. Investigate which template drifted.`, | |
| ``, | |
| `Run: ${runUrl}`, | |
| ].join("\n"); | |
| // De-dupe: comment on the existing open issue instead of spamming a | |
| // new one every Monday. (Creating an issue auto-creates the label.) | |
| const existing = await github.rest.issues.listForRepo({ | |
| owner, repo, state: "open", labels: label, | |
| }); | |
| if (existing.data.length === 0) { | |
| await github.rest.issues.create({ owner, repo, title, body, labels: [label] }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner, repo, issue_number: existing.data[0].number, body, | |
| }); | |
| } |