Skip to content

Commit 65d9c93

Browse files
committed
Prepare preview.3 package releases
1 parent 1db1f01 commit 65d9c93

13 files changed

Lines changed: 90 additions & 59 deletions

File tree

.github/workflows/release-all.yml

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -157,48 +157,59 @@ jobs:
157157
]];
158158
159159
for (const packageDefinition of packages) {
160-
const registryStates = [];
160+
try {
161+
const registryStates = [];
161162
162-
for (const [registry, check] of packageDefinition.checks) {
163-
const exists = await check(packageDefinition.version);
164-
registryStates.push(`${registry}: ${exists ? "published" : "missing"}`);
165-
}
163+
for (const [registry, check] of packageDefinition.checks) {
164+
const exists = await check(packageDefinition.version);
165+
registryStates.push(`${registry}: ${exists ? "published" : "missing"}`);
166+
}
167+
168+
const missing = registryStates.some(state => state.endsWith(": missing"));
169+
let action = "Skipped: version is fully published";
166170
167-
const missing = registryStates.some(state => state.endsWith(": missing"));
168-
let action = "Skipped: version is fully published";
169-
170-
if (missing) {
171-
const activeRuns = await github.rest.actions.listWorkflowRuns({
172-
owner,
173-
repo,
174-
workflow_id: packageDefinition.workflow,
175-
branch: ref,
176-
per_page: 20
177-
});
178-
179-
const alreadyRunning = activeRuns.data.workflow_runs.some(run =>
180-
run.head_sha === context.sha && run.status !== "completed"
181-
);
182-
183-
if (alreadyRunning) {
184-
action = "Skipped: workflow already running for this revision";
185-
} else {
186-
await github.rest.actions.createWorkflowDispatch({
171+
if (missing) {
172+
const activeRuns = await github.rest.actions.listWorkflowRuns({
187173
owner,
188174
repo,
189175
workflow_id: packageDefinition.workflow,
190-
ref
176+
branch: ref,
177+
per_page: 20
191178
});
192-
action = `Dispatched ${packageDefinition.workflow}`;
179+
180+
const alreadyRunning = activeRuns.data.workflow_runs.some(run =>
181+
run.head_sha === context.sha && run.status !== "completed"
182+
);
183+
184+
if (alreadyRunning) {
185+
action = "Skipped: workflow already running for this revision";
186+
} else {
187+
await github.rest.actions.createWorkflowDispatch({
188+
owner,
189+
repo,
190+
workflow_id: packageDefinition.workflow,
191+
ref
192+
});
193+
action = `Dispatched ${packageDefinition.workflow}`;
194+
}
193195
}
194-
}
195196
196-
rows.push([
197-
packageDefinition.name,
198-
packageDefinition.version,
199-
registryStates.join("; "),
200-
action
201-
]);
197+
rows.push([
198+
packageDefinition.name,
199+
packageDefinition.version,
200+
registryStates.join("; "),
201+
action
202+
]);
203+
} catch (error) {
204+
core.error(`${packageDefinition.name}: ${error.message}`);
205+
core.setFailed("One or more package checks or dispatches failed; remaining packages were still processed.");
206+
rows.push([
207+
packageDefinition.name,
208+
packageDefinition.version,
209+
"Check incomplete",
210+
`Failed: ${error.message}`
211+
]);
212+
}
202213
}
203214
204215
await core.summary

AGENTS.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ When adding tests:
211211
`## <version> - YYYY-MM-DD`; the service may append ` - <release title>`.
212212
Run `./build.cmd ValidateReleaseMetadata` after changing either side. Main
213213
builds, staging checks, and every package target enforce the same gate.
214+
- During a prerelease line, keep one rolling top release-notes entry and bump
215+
its preview version in place. Preserve published non-preview entries as
216+
immutable history.
214217
- `ci.yml` owns path-focused main solution tests for core libraries and clients. Downstream package compatibility belongs to the downstream repository's normal CI and release process; AVPR workflows must not clone and rebuild `arc-validate`.
215218
- `portable-ci.yml` owns cross-target Model and Codecs tests. It runs both portable targets when either portable implementation, consumer test, or shared build tool changes.
216219
- `staging-ci.yml` owns `StagingArea/**`, staging-checker, staging-model/codec, and relevant build-tool changes. It runs `TestStagingArea` on Windows with `uv` installed.
@@ -222,12 +225,13 @@ When adding tests:
222225
- Model and Codecs NuGet trusted-publisher policies must name their direct workflow (`release-model.yml` or `release-codecs.yml`). Client and Interop policies must name the called reusable workflow `release-package.yml`, which NuGet observes through `job_workflow_ref`.
223226
- npm trusted-publisher policies for the scoped Model and Codecs packages must name the corresponding direct package workflow and allow `npm publish`. These workflows use Node 24, npm with trusted-publishing support, and no npm token.
224227
- PyPI trusted-publisher policies for Model and Codecs must name the corresponding direct, top-level package workflow. Do not move PyPI publishing into a reusable workflow.
225-
- The `nfdi4plants` NuGet organization must own every actively released NuGet
226-
package and every NuGet trusted-publishing policy. `NUGET_USER` is the
227-
personal nuget.org username that creates those organization policies, not
228-
the organization name. npm publishers are configured per scoped package and
229-
PyPI publishers per project, using the exact field matrix in
230-
`docs/operations/releases.md`.
228+
- NuGet trusted-publishing policies are owner-wide and cannot be scoped to an
229+
individual package. The current policy owner and package owner is the
230+
`Mutagene` nuget.org account, and `NUGET_USER` must contain that same profile
231+
name. Separate policies restrict the repository/workflow identity, but each
232+
successful policy can publish any NuGet package owned by that account. npm
233+
publishers are configured per scoped package and PyPI publishers per project,
234+
using the exact field matrix in `docs/operations/releases.md`.
231235
- All package publish jobs need `id-token: write` and the `release` environment. `NuGet/login` exchanges OIDC for a temporary key; never restore a long-lived `NUGET_KEY`. `NUGET_USER` is only the nuget.org profile name associated with the policy. Reusable publishers must read it directly from their job environment because GitHub cannot pass environment secrets through `workflow_call`.
232236
- A staged package marked for publication can be pushed to the production registry after checks pass.
233237
- Workflow actions should remain pinned to deliberate versions/commits. Preserve least-privilege permissions and never print secrets.

docs/operations/releases.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ Release workflows rerun their required tests before publishing. No
105105
`RELEASE_NOTES.md` change or branch push publishes a library package
106106
automatically.
107107

108+
Prerelease notes use one rolling top entry: bump that entry in place and keep
109+
accumulating the unreleased preview changes beneath it. Once a non-preview
110+
version is published, its release-notes entry is immutable.
111+
108112
To release every new package version in this repository, manually dispatch
109113
`release-all.yml` against the intended ref. It validates the version gate,
110114
checks the exact committed versions on each package's target registries, and
@@ -149,17 +153,19 @@ Create a protected GitHub environment named `release` in both repositories.
149153
Add required reviewers and allow deployments from both `dev` and `release` so
150154
the manually dispatched package workflows can publish reviewed preview versions
151155
from `dev` as well as production versions from `release`. Store one environment
152-
secret, `NUGET_USER`, whose value is the personal nuget.org
153-
username that creates the trusted-publishing policies (currently `Mutagene`),
156+
secret, `NUGET_USER`, whose value is the nuget.org profile that owns the
157+
trusted-publishing policies (currently `Mutagene`),
154158
not an email address, GitHub username, organization name, or API key.
155159

156-
On nuget.org, select the `nfdi4plants` organization as the policy owner. Every
157-
NuGet package below must be owned by that organization. If it currently shows a
158-
personal owner, add `nfdi4plants` as co-owner first and remove the personal
159-
owner only after organization ownership and publishing have been verified.
160-
Create these policies; workflow values are filenames only:
160+
On nuget.org, select the personal account `Mutagene` as the policy owner and
161+
keep the NuGet packages owned by that account. NuGet policies are owner-wide:
162+
they cannot be restricted to an individual package. Consequently, each policy
163+
below can technically publish any package owned by `Mutagene`; the package
164+
column documents the intended use of the authorized workflow, not a NuGet
165+
enforcement boundary. Create these policies; workflow values are filenames
166+
only:
161167

162-
| Packages covered | Repository owner | Repository | Workflow file | Environment |
168+
| Intended packages | Repository owner | Repository | Workflow file | Environment |
163169
| --- | --- | --- | --- | --- |
164170
| `ValidationPackage.Model` | `nfdi4plants` | `arc-validate-package-registry` | `release-model.yml` | `release` |
165171
| `ValidationPackage.Codecs` | `nfdi4plants` | `arc-validate-package-registry` | `release-codecs.yml` | `release` |
@@ -169,7 +175,9 @@ Create these policies; workflow values are filenames only:
169175
The Client and Interop policy names the called reusable workflow because that
170176
is the workflow NuGet observes in the `job_workflow_ref` claim. The reusable
171177
workflow reads `NUGET_USER` directly from its `release` environment; environment
172-
secrets cannot be passed through `workflow_call` by the caller.
178+
secrets cannot be passed through `workflow_call` by the caller. The four policy
179+
rows distinguish trusted workflow identities, but they do not create four
180+
package-level scopes.
173181

174182
On npmjs.com, open each package's **Settings → Trusted Publisher**, select
175183
**GitHub Actions**, and enter:

src/AVPRClient.Interop/AVPRClient.Interop.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<RepositoryType>git</RepositoryType>
2323
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/RELEASE_NOTES.md"))</PackageReleaseNotes>
2424
<PackageReadmeFile>README.md</PackageReadmeFile>
25-
<PackageVersion>0.1.0-preview.2</PackageVersion>
25+
<PackageVersion>0.1.0-preview.3</PackageVersion>
2626
</PropertyGroup>
2727

2828
<ItemGroup>
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
## 0.1.0-preview.2 - 2026-07-31
1+
## 0.1.0-preview.3 - 2026-08-07
22

33
- Add bidirectional mappings between generated AVPR DTOs and `ValidationPackage.Model`.
44
- Cover nested authors, ontology annotations, CWL inputs, collection defaults, and full semantic-version suffixes.
5+
- Add an independently versioned, manually approved NuGet trusted-publishing
6+
workflow with retry-safe duplicate handling.

src/AVPRClient/AVPRClient.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<RepositoryType>git</RepositoryType>
2323
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/RELEASE_NOTES.md"))</PackageReleaseNotes>
2424
<PackageReadmeFile>README.md</PackageReadmeFile>
25-
<PackageVersion>0.3.0-preview.2</PackageVersion>
25+
<PackageVersion>0.3.0-preview.3</PackageVersion>
2626
</PropertyGroup>
2727

2828
<ItemGroup>

src/AVPRClient/RELEASE_NOTES.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
## 0.3.0-preview.2 - 2026-07-31
1+
## 0.3.0-preview.3 - 2026-08-07
22
- Regenerate the client for the supported CWL v1.2 scalar `Inputs` contract.
33
- Move all handwritten model and staging mappings to `AVPRClient.Interop` and `AVPRCI`, leaving this package generated-only.
4+
- Replace token-based publication with a manually approved, retry-safe NuGet
5+
trusted-publishing workflow.
46

57
## v0.2.1
68
- fix : Correct `ProgrammingLanguage` field mapping in `ValidationPackage` type extension.
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
## 0.1.0-preview.2 - 2026-07-31
1+
## 0.1.0-preview.3 - 2026-08-07
22

33
- Add portable frontmatter extraction and YAML/JSON codecs for validation-package metadata.
44
- Preserve the AVPR CWL scalar and wire-name contract across .NET, JavaScript, and Python.
55
- Use YAMLicious for YAML writing with the Fable 5.11 Python compiler fix.
66
- Organize JSON and YAML encoders and decoders into separate source trees.
77
- Build installable npm and Python packages with an explicit native Model dependency.
8+
- Publish one versioned artifact set through independently retriable NuGet,
9+
npm, and PyPI trusted-publishing jobs.

src/ValidationPackage.Codecs/ValidationPackage.Codecs.fsproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<RepositoryType>git</RepositoryType>
1818
<PackageReadmeFile>README.md</PackageReadmeFile>
1919
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/RELEASE_NOTES.md"))</PackageReleaseNotes>
20-
<PackageVersion>0.1.0-preview.2</PackageVersion>
20+
<PackageVersion>0.1.0-preview.3</PackageVersion>
2121
</PropertyGroup>
2222

2323
<ItemGroup>
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
## 0.1.0-preview.2 - 2026-07-31
1+
## 0.1.0-preview.3 - 2026-08-07
22

33
- Add the portable validation-package metadata domain.
44
- Add CWL scalar command-input types and behavior.
55
- Add semantic-version and package-identity behavior.
66
- Include Fable sources for .NET, JavaScript, and Python consumers.
77
- Build installable npm and Python packages alongside the NuGet package.
8+
- Publish one versioned artifact set through independently retriable NuGet,
9+
npm, and PyPI trusted-publishing jobs.

0 commit comments

Comments
 (0)