diff --git a/.changeset/runtime-rule-execution.md b/.changeset/runtime-rule-execution.md new file mode 100644 index 00000000..961f8065 --- /dev/null +++ b/.changeset/runtime-rule-execution.md @@ -0,0 +1,7 @@ +--- +"@taskless/cli": minor +--- + +Add server-owned rule reconciliation and runtime rules to `taskless check`. Authenticated runs reconcile the repo's rules against the Taskless service and execute only the server-blessed set. A new class of **runtime rules** (`.taskless/runtime-rules/` — one or more ast-grep capture rules plus a `check.ts` assertion) runs through a local harness: the capture rules narrow with ast-grep, and only on a match is `check.ts` invoked via a bundled `tsx`. Because `check.ts` is arbitrary code, it runs only when its signature is validated by the server; otherwise it is skipped and reported. Adds the `--dangerously-run-scripts` (run runtime rules unverified) and `--timeout` flags. + +(Backfills the changeset that was missed when this work landed across #47, #49, and #50.) diff --git a/.github/workflows/require-changeset.yml b/.github/workflows/require-changeset.yml new file mode 100644 index 00000000..03695006 --- /dev/null +++ b/.github/workflows/require-changeset.yml @@ -0,0 +1,56 @@ +name: Require Changeset + +# Every PR to `main` must add a changeset (a new `.changeset/.md`) so the +# version bump is intentional and the changelog stays complete. A PR that +# legitimately needs no release note (docs, CI, chores) can carry the +# `skip-changeset` label to bypass the requirement. +# +# The job ALWAYS runs and reports a status (the label is checked inside the +# step, not via a job-level `if`), so it stays safe to mark as a required check — +# a conditionally-skipped required check would otherwise block merges. + +on: + pull_request: + branches: [main] + types: [opened, reopened, synchronize, labeled, unlabeled] + +permissions: + contents: read + +jobs: + changeset: + name: Require a changeset + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check for a changeset + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }} + run: | + set -euo pipefail + + # Escape hatch for PRs that intentionally ship no release note. + case ",${LABELS}," in + *,skip-changeset,*) + echo "The 'skip-changeset' label is present — bypassing the changeset requirement." + exit 0 + ;; + esac + + # A changeset is any new `.changeset/*.md` added by this PR, other than + # the template README. + ADDED=$(git diff --name-only --diff-filter=A "$BASE_SHA...$HEAD_SHA" -- '.changeset/*.md' \ + | grep -viE '/README\.md$' || true) + + if [ -z "$ADDED" ]; then + echo "::error::This PR adds no changeset. Run \`pnpm changeset\` to record the release impact, or apply the \`skip-changeset\` label if no release note is needed (docs / CI / chore)." + exit 1 + fi + + echo "Changeset(s) added by this PR:" + echo "$ADDED" | sed 's/^/ - /'