Skip to content

Commit f855ae3

Browse files
amis92Copilot
andcommitted
ci: extract publish workflow with trusted publishing
- Create publish.yml: reusable (workflow_call) + direct (workflow_dispatch) with NuGet trusted publishing (OIDC via NuGet/login@v1, user: warhub) - Push job uses environment: package-release for protection rules - Optional comment-id input for status updates and reactions - Simplify deploy-command.yml to chatops-only, calling publish.yml - Fix deprecated ::set-output in tag-command.yml - Document release process in README.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 32cc5d5 commit f855ae3

File tree

4 files changed

+207
-96
lines changed

4 files changed

+207
-96
lines changed

.github/workflows/deploy-command.yml

Lines changed: 14 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -6,99 +6,18 @@ name: Deploy
66
on:
77
repository_dispatch:
88
types: [deploy-command]
9-
workflow_dispatch:
10-
inputs:
11-
ref:
12-
description: 'Git ref to deploy (branch, tag, or SHA)'
13-
required: false
14-
default: 'main'
15-
env:
16-
description: 'Target environment (github, nuget, all)'
17-
required: false
18-
default: 'github'
19-
type: choice
20-
options:
21-
- github
22-
- nuget
23-
- all
24-
tag:
25-
description: 'Tag the ref with version from nbgv'
26-
required: false
27-
default: false
28-
type: boolean
29-
jobs:
30-
pack:
31-
runs-on: ubuntu-latest
32-
env:
33-
DOTNET_NOLOGO: 1
34-
PUSH_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.event.client_payload.slash_command.args.unnamed.arg1 == 'tag' }}
35-
steps:
36-
- name: Add deployment run link to command comment
37-
if: github.event_name == 'repository_dispatch'
38-
uses: peter-evans/create-or-update-comment@v5
39-
with:
40-
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
41-
body: "[Deployment run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})"
42-
- uses: actions/checkout@v6
43-
with:
44-
fetch-depth: 0 # all history
45-
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.event.client_payload.slash_command.args.named.ref }}
46-
- uses: actions/setup-dotnet@v5
47-
with:
48-
dotnet-version: '10.0.x'
49-
- run: dotnet --info
50-
- run: dotnet tool restore
51-
- run: dotnet nbgv get-version
52-
- run: dotnet restore -v m
53-
- run: dotnet build --no-restore
54-
- run: dotnet test --no-build
55-
- run: dotnet pack
56-
- name: Add and push version tag
57-
if: env.PUSH_TAG == 'true'
58-
id: tagpush
59-
continue-on-error: true
60-
shell: pwsh
61-
run: |
62-
$env:PublicRelease = $true
63-
$v = "v$(dotnet nbgv get-version -v SemVer2)"
64-
git tag $v
65-
git push origin $v
66-
Write-Host "::set-output name=tag::$v"
67-
- name: Add tag info to command comment
68-
if: env.PUSH_TAG == 'true' && github.event_name == 'repository_dispatch'
69-
uses: peter-evans/create-or-update-comment@v5
70-
with:
71-
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
72-
body: "Pushed tag `${{ steps.tagpush.outputs.tag }}`"
73-
- name: Upload nugets to workflow artifacts
74-
uses: actions/upload-artifact@v7
75-
with:
76-
name: nugets
77-
path: artifacts/package/release
78-
push:
79-
runs-on: ubuntu-latest
80-
needs: pack
81-
env:
82-
DOTNET_NOLOGO: 1
83-
PUSH_TO: ${{ github.event_name == 'workflow_dispatch' && inputs.env || github.event.client_payload.slash_command.args.named.env }}
84-
steps:
85-
- uses: actions/download-artifact@v8
86-
with:
87-
name: nugets
88-
89-
- name: Push to nuget.org
90-
if: env.PUSH_TO == 'all' || env.PUSH_TO == 'nuget'
91-
shell: pwsh
92-
run: dotnet nuget push '*.nupkg' -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_APIKEY }} --skip-duplicate
939

94-
- name: Push to GitHub Packages
95-
if: env.PUSH_TO == 'all' || env.PUSH_TO == 'github' || env.PUSH_TO == ''
96-
shell: pwsh
97-
run: dotnet nuget push '*.nupkg' -s https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json -k ${{ github.token }} --skip-duplicate
98-
99-
- name: Add reaction to command comment
100-
if: github.event_name == 'repository_dispatch'
101-
uses: peter-evans/create-or-update-comment@v5
102-
with:
103-
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
104-
reactions: hooray
10+
jobs:
11+
publish:
12+
uses: ./.github/workflows/publish.yml
13+
permissions:
14+
contents: write
15+
packages: write
16+
id-token: write
17+
issues: write
18+
pull-requests: write
19+
with:
20+
ref: ${{ github.event.client_payload.slash_command.args.named.ref || '' }}
21+
push-to: ${{ github.event.client_payload.slash_command.args.named.env || 'github' }}
22+
tag: ${{ github.event.client_payload.slash_command.args.unnamed.arg1 == 'tag' }}
23+
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}

.github/workflows/publish.yml

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
name: Publish
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
ref:
7+
description: 'Git ref to build and publish (branch, tag, or SHA)'
8+
type: string
9+
default: ''
10+
push-to:
11+
description: 'Package registries to push to: github, nuget, or all'
12+
type: string
13+
default: 'github'
14+
tag:
15+
description: 'Tag the ref with nbgv version before publishing'
16+
type: boolean
17+
default: false
18+
comment-id:
19+
description: 'GitHub comment ID for status updates (optional)'
20+
type: string
21+
default: ''
22+
workflow_dispatch:
23+
inputs:
24+
ref:
25+
description: 'Git ref to build and publish (branch, tag, or SHA)'
26+
required: false
27+
default: ''
28+
push-to:
29+
description: 'Package registries to push to'
30+
required: false
31+
default: 'github'
32+
type: choice
33+
options:
34+
- github
35+
- nuget
36+
- all
37+
tag:
38+
description: 'Tag the ref with nbgv version before publishing'
39+
required: false
40+
default: false
41+
type: boolean
42+
43+
permissions:
44+
contents: write
45+
packages: write
46+
id-token: write
47+
issues: write
48+
pull-requests: write
49+
50+
jobs:
51+
pack:
52+
runs-on: ubuntu-latest
53+
env:
54+
DOTNET_NOLOGO: 1
55+
steps:
56+
- name: Link run to comment
57+
if: inputs.comment-id != ''
58+
uses: peter-evans/create-or-update-comment@v5
59+
with:
60+
comment-id: ${{ inputs.comment-id }}
61+
body: "[Publish run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})"
62+
- uses: actions/checkout@v6
63+
with:
64+
fetch-depth: 0 # all history
65+
ref: ${{ inputs.ref || '' }}
66+
- uses: actions/setup-dotnet@v5
67+
with:
68+
dotnet-version: '10.0.x'
69+
- run: dotnet --info
70+
- run: dotnet tool restore
71+
- run: dotnet nbgv get-version
72+
- run: dotnet restore -v m
73+
- run: dotnet build --no-restore
74+
- run: dotnet test --no-build
75+
- run: dotnet pack
76+
- name: Add and push version tag
77+
if: inputs.tag
78+
id: tagpush
79+
shell: pwsh
80+
run: |
81+
$env:PublicRelease = $true
82+
$v = "v$(dotnet nbgv get-version -v SemVer2)"
83+
git tag $v
84+
git push origin $v
85+
"tag=$v" >> $env:GITHUB_OUTPUT
86+
- name: Update comment with tag
87+
if: inputs.tag && inputs.comment-id != ''
88+
uses: peter-evans/create-or-update-comment@v5
89+
with:
90+
comment-id: ${{ inputs.comment-id }}
91+
body: "Pushed tag `${{ steps.tagpush.outputs.tag }}`"
92+
- name: Upload nugets
93+
uses: actions/upload-artifact@v7
94+
with:
95+
name: nugets
96+
path: artifacts/package/release
97+
98+
push:
99+
runs-on: ubuntu-latest
100+
needs: pack
101+
environment: package-release
102+
env:
103+
DOTNET_NOLOGO: 1
104+
PUSH_TO: ${{ inputs.push-to }}
105+
steps:
106+
- uses: actions/download-artifact@v8
107+
with:
108+
name: nugets
109+
110+
- name: NuGet login (trusted publishing)
111+
if: env.PUSH_TO == 'all' || env.PUSH_TO == 'nuget'
112+
uses: NuGet/login@v1
113+
id: nuget-login
114+
with:
115+
user: warhub
116+
117+
- name: Push to nuget.org
118+
if: env.PUSH_TO == 'all' || env.PUSH_TO == 'nuget'
119+
shell: pwsh
120+
run: dotnet nuget push '*.nupkg' -s https://api.nuget.org/v3/index.json -k ${{ steps.nuget-login.outputs.NUGET_API_KEY }} --skip-duplicate
121+
122+
- name: Push to GitHub Packages
123+
if: env.PUSH_TO == 'all' || env.PUSH_TO == 'github' || env.PUSH_TO == ''
124+
shell: pwsh
125+
run: dotnet nuget push '*.nupkg' -s https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json -k ${{ github.token }} --skip-duplicate
126+
127+
- name: React to comment
128+
if: inputs.comment-id != ''
129+
uses: peter-evans/create-or-update-comment@v5
130+
with:
131+
comment-id: ${{ inputs.comment-id }}
132+
reactions: hooray

.github/workflows/tag-command.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
$v = "v$(dotnet nbgv get-version -v SemVer2)"
4141
git tag $v
4242
git push origin $v
43-
Write-Host "::set-output name=tag::$v"
43+
"tag=$v" >> $env:GITHUB_OUTPUT
4444
- name: Add tag info and reaction to command comment
4545
if: github.event_name == 'repository_dispatch'
4646
uses: peter-evans/create-or-update-comment@v5

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,66 @@ This project uses `Nerdbank.GitVersioning` package that automatically generates
6969
for assemblies and packages from git tree. It won't work if the git clone is *shallow* or otherwise
7070
incomplete.
7171

72+
## Release Process
73+
74+
### Preparing a release
75+
76+
1. Create a PR that sets `version.json` to the stable version (e.g. `"0.14"`) and updates
77+
`CHANGELOG.md` with the release date. Merge the PR.
78+
2. Tag the merged commit: `git tag vX.Y.Z && git push origin vX.Y.Z`
79+
3. After tagging, create a PR to bump `version.json` to the next alpha version
80+
(e.g. `"0.15.0-alpha.{height}"`) and add an `[Unreleased]` section to `CHANGELOG.md`.
81+
82+
### Publishing packages
83+
84+
Packages are published via the **Publish** workflow (`.github/workflows/publish.yml`).
85+
86+
**Via GitHub CLI or Actions UI** (recommended):
87+
88+
```bash
89+
# Publish to GitHub Packages only
90+
gh workflow run publish.yml -f ref=vX.Y.Z -f push-to=github
91+
92+
# Publish to nuget.org only
93+
gh workflow run publish.yml -f ref=vX.Y.Z -f push-to=nuget
94+
95+
# Publish to both registries
96+
gh workflow run publish.yml -f ref=vX.Y.Z -f push-to=all
97+
```
98+
99+
**Via ChatOps** (requires `SLASH_COMMAND_DISPATCH_TOKEN` secret):
100+
101+
Comment on any issue or PR:
102+
```
103+
/deploy ref=vX.Y.Z env=all
104+
```
105+
106+
### NuGet trusted publishing
107+
108+
NuGet.org publishing uses [Trusted Publishing](https://learn.microsoft.com/en-us/nuget/nuget-org/trusted-publishing)
109+
(OIDC) instead of long-lived API keys. The trusted publishing policy is configured on nuget.org for:
110+
111+
| Field | Value |
112+
|--------------------|--------------------|
113+
| Package Owner | `warhub` |
114+
| Repository Owner | `WarHub` |
115+
| Repository | `wham` |
116+
| Workflow | `publish.yml` |
117+
| Environment | `package-release` |
118+
119+
The `push` job in `publish.yml` uses `environment: package-release` which provides
120+
environment protection rules (e.g. required reviewers) as a gate before publishing.
121+
122+
### Tagging
123+
124+
Tags can also be created via the **Tag** workflow:
125+
126+
```bash
127+
gh workflow run tag-command.yml -f ref=main
128+
```
129+
130+
Or via ChatOps: `/tag ref=main`
131+
72132
## Credits
73133

74134
The library is MIT licensed (license in repo root).

0 commit comments

Comments
 (0)