Repository navigation
client: a read-only window's face-room overview still draws the Room lead's Change, and a hint that is false there #4602
Workflow file for this run
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
| name: Test | |
| on: | |
| push: | |
| branches: [main] | |
| # Docs-only pushes do not need the shipgate. | |
| # pull_request must NOT ignore docs: Test is a required check there, and a | |
| # skipped required check would block docs-only pull requests. | |
| paths-ignore: ['docs/**', '**/*.md'] | |
| pull_request: | |
| # A merge queue (not enabled; see docs/autonomous-dev.md) runs the required checks on each queue entry, | |
| # a gh-readonly-queue/* branch. Without this trigger they would never report there and the queue would | |
| # wait for them until it times out. merge_group takes no path filters, so a docs-only entry runs in full | |
| # (as a docs-only pull request does), and `push` above is limited to main, so an entry does not run twice. | |
| merge_group: | |
| workflow_dispatch: | |
| # On main a run finishes: a release waits for a green run on its commit, and one cancelled | |
| # by every next push would leave none to wait for. A PR's run is cancelled by its next push. | |
| concurrency: | |
| group: test-${{ github.ref }} | |
| cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} | |
| permissions: | |
| contents: read | |
| jobs: | |
| # #2124: the gate-change signature is a job of its own. Required contexts in this repository are | |
| # job names (.github/agent/merge-gate-ruleset.json), so while it lived as a step of `test` a pull | |
| # request that deleted the step left `test` green and nothing was missing. Deleting this job | |
| # instead removes a context the merge path needs, and `test` cannot start because it needs it. | |
| policy-sign: | |
| name: policy-sign | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ github.event.merge_group.base_sha || github.event.pull_request.base.sha }} | |
| path: base | |
| persist-credentials: false | |
| # policy/gates.json (#2054): a pull request that edits an acceptance gate carries | |
| # `Policy-sign: <comment id or url>` in its body, written by someone other than its author. | |
| # It runs before the suite: a gate change nobody else signed is not worth 20 minutes of tests. | |
| # #2099: the checker comes from the base commit, not from the pull request's own tree, so a | |
| # pull request that weakens or deletes `policy-sign.mjs` is still judged by the copy it started | |
| # from. The `merge_group` half of `ref` is required, not decoration: a queue run carries no | |
| # `pull_request`, and an expression with only that half falls back to the sha that triggered | |
| # the run, which is the pull request again. `merge-gate.yml` checks base out the same way. | |
| - name: Gate change signature | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: node base/.github/scripts/policy-sign.mjs | |
| # The PR gate: one job (see #31). Its name is the required check on main: keep it exactly. | |
| # Windows, Node 22 and the next DSH run in the Compatibility workflow (nightly.yml). | |
| test: | |
| name: ubuntu-latest · Node 24 · DSH 0.2.0-rc.2 | |
| needs: policy-sign | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/flybot-tests | |
| with: | |
| node: '24' | |
| dsh: 0.2.1-rc.2 | |
| coverage: 'true' | |
| plugins: 'false' | |
| # Each peer plugin (plugins/<name>) on its own: lint and its suite against core/ and the DSH | |
| # harness. DSH_HARNESS points the frontend (web entry) tests at real Cordis; a skipped test | |
| # fails the job, so they cannot silently stop running. | |
| plugins: | |
| name: plugins (${{ matrix.plugin }}) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| plugin: [tree, social, timeline, workflow] | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 | |
| with: | |
| node-version: 24 | |
| cache: npm | |
| cache-dependency-path: core/package-lock.json | |
| - name: npm ci (core) | |
| working-directory: core | |
| run: npm ci --no-fund --no-audit | |
| - name: Install DSH | |
| working-directory: core | |
| env: | |
| DSH: 0.2.1-rc.2 | |
| run: npm run harness -- --no-save "@deepseek-ai/dsh@$DSH" | |
| - name: Lint | |
| run: node scripts/lint-plugins.mjs "$PLUGIN" | |
| env: | |
| PLUGIN: ${{ matrix.plugin }} | |
| - name: Tests (none skipped) | |
| working-directory: plugins/${{ matrix.plugin }} | |
| env: | |
| DSH_HARNESS: ${{ github.workspace }}/core/dev/harness | |
| run: | | |
| set -o pipefail | |
| npm test | tee test-output.txt | |
| skipped=$(sed -n 's/^ℹ skipped \([0-9]*\)$/\1/p' test-output.txt) | |
| echo "skipped: ${skipped:-?}" | |
| [ "${skipped:-1}" = 0 ] || { echo "::error::plugins/${{ matrix.plugin }}: $skipped test(s) skipped (or no summary)"; exit 1; } | |
| # The core pin (ds-bot.pin.json + patches/ds-bot/ -> core/), then what a DSH profile installs: each package packs with everything its main/exports/files | |
| # name, and no tests or dev tools. The release job ships these same tarballs. | |
| package: | |
| name: package | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 | |
| with: | |
| node-version: 24 | |
| - name: ds-bot/ matches the pin, patches apply, core/ is ds-bot/ + patches (#34) | |
| run: node scripts/ds-bot-patches.mjs check | |
| - name: generate is a no-op on the committed patch split (#1890) | |
| run: node scripts/ds-bot-patches.mjs canonical | |
| - name: Pack and check core (ds-bot), plugins/social, plugins/tree, plugins/timeline, plugins/workflow | |
| run: node .github/scripts/check-pack.mjs | |
| - name: Typecheck the plugin API (types/*.d.ts, strict) | |
| working-directory: core | |
| run: npx --yes -p typescript@5.9.3 tsc --noEmit --strict --skipLibCheck types/*.d.ts | |
| - name: Every test file and every workflow belongs to a layer (#749) | |
| run: node .github/scripts/testing-layers.mjs --check | |
| - name: No text file carries a replacement character U+FFFD (#1188) | |
| run: node .github/scripts/check-mojibake.mjs --check | |
| - name: The self-test catalog page matches docs/self-test.json (#782) | |
| run: node scripts/self-test-catalog.mjs --check | |
| - name: Tests of the repo scripts (risk tier, labels) | |
| run: node --test ".github/scripts/*.test.mjs" "policy/*.test.mjs" | |
| - name: Offline cross-runtime harness (no network or model) | |
| run: npm run test:interop | |
| - name: Changelog has an Unreleased section and well-formed fragments (changelog.d/) | |
| run: node .github/scripts/changelog.mjs check | |
| - name: Lint the workflows (actionlint) | |
| env: | |
| VERSION: 1.7.7 | |
| run: | | |
| curl -fsSL "https://github.com/rhysd/actionlint/releases/download/v${VERSION}/actionlint_${VERSION}_linux_amd64.tar.gz" | tar -xz actionlint | |
| ./actionlint -color | |
| # One check that is green only when the test, plugins (every leg) and package jobs are. | |
| tests-ok: | |
| name: tests-ok | |
| if: always() | |
| needs: [policy-sign, test, plugins, package] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Every job passed | |
| env: | |
| SIGN: ${{ needs.policy-sign.result }} | |
| TEST: ${{ needs.test.result }} | |
| PLUGINS: ${{ needs.plugins.result }} | |
| PACKAGE: ${{ needs.package.result }} | |
| run: | | |
| echo "policy-sign: $SIGN, test: $TEST, plugins: $PLUGINS, package: $PACKAGE" | |
| [ "$SIGN" = success ] && [ "$TEST" = success ] && [ "$PLUGINS" = success ] && [ "$PACKAGE" = success ] |