diff --git a/.github/workflows/Breakage.yml b/.github/workflows/Breakage.yml index 73a75c057..39dd232a8 100644 --- a/.github/workflows/Breakage.yml +++ b/.github/workflows/Breakage.yml @@ -1,87 +1,64 @@ -# Ref: https://securitylab.github.com/research/github-actions-preventing-pwn-requests name: Breakage -# read-only repo token -# no access to secrets +# The packages that depend on OptimalControl (derived from the Project.toml files) and the +# tutorials, then the applications, tested against it; one report per group. On push to +# main and by hand, the run is the baseline the next release PR compares with (REL1); see +# CTActions docs/workflows/breakage-suite.md. + on: pull_request: types: [labeled, synchronize, reopened] + push: + branches: [main] + workflow_dispatch: jobs: - break-pkg: + packages: # A 'labeled' event fires once per label added, and re-evaluates against the PR's # *current* full label set — so adding several labels in a row would otherwise # re-run this job on every subsequent label add. Only react to 'labeled' when it's - # this specific label; for other trigger types (opened/synchronize/reopened), fall - # back to checking the current label set as before. + # this specific label; for other trigger types (synchronize/reopened), fall back to + # checking the current label set as before. On push to main and by hand, always. if: > + github.event_name != 'pull_request' || (github.event.action == 'labeled' && github.event.label.name == 'run breakage') || (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'run breakage')) - strategy: - fail-fast: false - matrix: - pkgname: - - OptimalControlProblems - - Tutorials - pkgversion: - - latest - - stable - include: - - pkgbreak: test - - pkgbreak: doc - pkgname: Tutorials - - pkgpath: control-toolbox - uses: control-toolbox/CTActions/.github/workflows/breakage.yml@main + uses: control-toolbox/CTActions/.github/workflows/breakage-suite.yml@main with: - pkgname: ${{ matrix.pkgname }} - pkgpath: ${{ matrix.pkgpath }} - pkgversion: ${{ matrix.pkgversion }} - pkgbreak: ${{ matrix.pkgbreak }} + group: packages + # the packages that load OptimalControl are derived; the tutorials build their docs + targets: >- + [{"name": "Tutorials", "break": "doc"}] use_ct_registry: true secrets: SSH_KEY: ${{ secrets.SSH_KEY }} - break-pkg-app: - # See the comment on break-pkg above. + + applications: + # The applications and tutorials, some of them owned outside control-toolbox. + # A 'labeled' event fires once per label added, and re-evaluates against the PR's + # *current* full label set — so adding several labels in a row would otherwise + # re-run this job on every subsequent label add. Only react to 'labeled' when it's + # this specific label; for other trigger types (synchronize/reopened), fall back to + # checking the current label set as before. On push to main and by hand, always. if: > + github.event_name != 'pull_request' || (github.event.action == 'labeled' && github.event.label.name == 'run breakage applications') || (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'run breakage applications')) - strategy: - fail-fast: false - matrix: - pkgname: - - OptimalControlProblems - - Tutorials - - CalculusOfVariations - - LossControl - - GeometricPreconditioner - - MedicalResonanceImaging - - Kepler - - PWLdynamics - - SIRcontrol - - DiauxicGrowth - - CTMembraneFiltration - pkgversion: - - latest - - stable - include: - - pkgbreak: doc - - pkgbreak: test - pkgname: OptimalControlProblems - - pkgpath: control-toolbox - - pkgpath: agustinyabo - pkgname: PWLdynamics - - pkgpath: AnasXbouali - pkgname: SIRcontrol - - pkgpath: agustinyabo - pkgname: DiauxicGrowth - - pkgpath: remydutto - pkgname: CTMembraneFiltration - uses: control-toolbox/CTActions/.github/workflows/breakage.yml@main + uses: control-toolbox/CTActions/.github/workflows/breakage-suite.yml@main with: - pkgname: ${{ matrix.pkgname }} - pkgpath: ${{ matrix.pkgpath }} - pkgversion: ${{ matrix.pkgversion }} - pkgbreak: ${{ matrix.pkgbreak }} + group: applications + consumers: false + targets: >- + [{"name": "OptimalControlProblems"}, {"name": "Tutorials", "break": "doc"}, + {"name": "CalculusOfVariations", "break": "doc"}, + {"name": "LossControl", "break": "doc"}, + {"name": "GeometricPreconditioner", "break": "doc"}, + {"name": "MedicalResonanceImaging", "break": "doc"}, + {"name": "Kepler", "break": "doc"}, + {"name": "PWLdynamics", "owner": "agustinyabo", "break": "doc"}, + {"name": "SIRcontrol", "owner": "AnasXbouali", "break": "doc"}, + {"name": "DiauxicGrowth", "owner": "agustinyabo", "break": "doc"}, + {"name": "CTMembraneFiltration", "owner": "remydutto", "break": "doc"}] use_ct_registry: true secrets: SSH_KEY: ${{ secrets.SSH_KEY }} diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml index 84bde499b..11d674d9a 100644 --- a/.github/workflows/Documentation.yml +++ b/.github/workflows/Documentation.yml @@ -8,6 +8,8 @@ on: - 'v[0-9]+\.[0-9]+\.[0-9]+' pull_request: types: [labeled, synchronize, reopened] + # run on a tag by ReleaseTag.yml: a tag it creates triggers no push event + workflow_dispatch: # A GPU-attempt job now runs behind every push/tag build (see `gpu_runner` below) and # can take up to `gpu_timeout_minutes`. Without this, two pushes to `main` in quick diff --git a/.github/workflows/ReleaseGate.yml b/.github/workflows/ReleaseGate.yml new file mode 100644 index 000000000..38d4eb3a9 --- /dev/null +++ b/.github/workflows/ReleaseGate.yml @@ -0,0 +1,12 @@ +name: Release gate + +# REL1-REL7 of ct-conventions on every PR (a PR that does not change the version passes at +# once); see CTActions docs/workflows/release-gate.md. + +on: + pull_request: + types: [opened, synchronize, reopened, labeled, unlabeled, edited] + +jobs: + call: + uses: control-toolbox/CTActions/.github/workflows/release-gate.yml@main diff --git a/.github/workflows/ReleaseTag.yml b/.github/workflows/ReleaseTag.yml new file mode 100644 index 000000000..d5b784d55 --- /dev/null +++ b/.github/workflows/ReleaseTag.yml @@ -0,0 +1,18 @@ +name: Release tag + +# Tags the merge commit of a release PR, creates its GitHub release and runs the +# documentation on the tag; see CTActions docs/workflows/release-tag.md. + +on: + push: + branches: [main] + paths: [Project.toml] + workflow_dispatch: + +permissions: + contents: write + actions: write + +jobs: + call: + uses: control-toolbox/CTActions/.github/workflows/release-tag.yml@main diff --git a/AGENTS.md b/AGENTS.md index 053e5b022..6f053f29f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -35,10 +35,10 @@ is not the pinned tag, (re)create it: ```bash rm -rf .conventions -git -c advice.detachedHead=false clone --quiet --depth 1 --branch v0.5.2 https://github.com/control-toolbox/ct-conventions.git .conventions +git -c advice.detachedHead=false clone --quiet --depth 1 --branch v0.7.0 https://github.com/control-toolbox/ct-conventions.git .conventions ``` -**Pinned version: ct-conventions v0.5.2.** Cite rules by identifier (`MOD3`, `TST1`), and +**Pinned version: ct-conventions v0.7.0.** Cite rules by identifier (`MOD3`, `TST1`), and state the version you applied in plans and reports. Read in this order: @@ -46,7 +46,7 @@ Read in this order: | File | Content | | --- | --- | | [`rules/general.md`](.conventions/rules/general.md) | Rules that hold everywhere — **always read** | -| [`README.md`](.conventions/README.md) | Index of the rule files, one per area (`MOD`, `TYP`, `DIM`, `EXC`, `PERF`, `DOC`, `TST`, `SITE`, `CHG`) | +| [`README.md`](.conventions/README.md) | Index of the rule files, one per area (`MOD`, `TYP`, `DIM`, `EXC`, `PERF`, `DOC`, `TST`, `SITE`, `CHG`, `REL`) | | [`method.md`](.conventions/method.md) | How to work: tests, coverage, docs build, output capture | | [`plan-template.md`](.conventions/plan-template.md) | Template for a substantial piece of work | @@ -72,4 +72,14 @@ trigger labels are described in - **1-D is a scalar** — a one-dimensional state/control/variable is a `Number` (`DIM1`). - **Plan before code** — a local agent proposes a plan ([`plan-template.md`](.conventions/plan-template.md)) and waits for confirmation before working on code. The process for remote agents is still to be defined. - **Docstrings last** — written once the implementation is stable (`DOC1`–`DOC8`). -- **The human merges** — an agent never merges a pull request. +- **The human merges** — an agent never merges a pull request, except a release PR in `autonomous` mode, and then only with `release.jl merge` (see below). + +--- + +## Recurring tasks + +- **Release.** When asked, in any language, to prepare a release, follow + [`recipes/release.md`](https://github.com/control-toolbox/ct-agents/blob/main/recipes/release.md) + of ct-agents (rules `REL1`–`REL7`). Read it with + `gh api repos/control-toolbox/ct-agents/contents/recipes/release.md -H "Accept: application/vnd.github.raw"`. + Stable or beta is the human's choice: if the request does not say, ask; never infer it. diff --git a/CHANGELOG.md b/CHANGELOG.md index b87360c0e..ed15adda3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). `.conventions/`); `AGENTS.md` cites rules by identifier, `CLAUDE.md` redirects to it, and the references to the former Handbook become rule identifiers. One `.markdownlint.json` (`GEN2`) replaces the `markdownlint-disable MD024` comment of this changelog (`CHG2`). +- ct-conventions pinned at `v0.7.0` in `AGENTS.md`: the release rules `REL1`–`REL7` in the + index, and a *Recurring tasks* section pointing to the release recipe of ct-agents. ### 📚 Documentation @@ -24,6 +26,13 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - **`init` and `initial_guess` together raise "Conflicting aliases" in descriptive mode too** ([#964](https://github.com/control-toolbox/OptimalControl.jl/issues/964)). Explicit mode already reported the conflict; descriptive mode, the common case, routed the leftover `init` to the strategies and rejected it as an unknown option, with unrelated suggestions. Both modes now run the same check before any routing. +### 🧪 Testing + +- Release workflows: `ReleaseGate.yml` (the gate of a release PR, `REL1`–`REL7`) and + `ReleaseTag.yml` (tag and GitHub release of a merged release PR) call CTActions; + `Breakage.yml` moves to `breakage-suite.yml` (one report, the `REL1` check of a release + PR) and also runs on push to `main`; `Documentation.yml` accepts `workflow_dispatch`. + ## [2.2.1-beta] — 2026-09-02 Documentation-infrastructure follow-up to the 2.2.0-beta site rewrite. No change to OptimalControl's API or runtime behaviour; nothing to migrate — see [BREAKING.md](BREAKING.md).