Skip to content

Commit 940ad6e

Browse files
authored
feat: create generic nuget pkg publish action (#24)
* feat: add publish nuget pkg action * fix: remove concurrency check * feat: add docs of nuget publish to readme, rename workflow file name * chore: change to single <a> tag, add quotes to versions, add secret information * feat: add release workflow for publish nuget
1 parent f57b889 commit 940ad6e

3 files changed

Lines changed: 188 additions & 31 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Publish NuGet Package
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
dotnet_version:
7+
description: "Version of .NET SDK to use (e.g., '10.x')"
8+
type: string
9+
required: true
10+
project_path:
11+
description: "Path to the .NET project file (e.g., 'project/project.csproj')"
12+
type: string
13+
required: true
14+
package_output:
15+
description: "Output directory for the NuGet package (e.g., 'project/bin/Release')"
16+
type: string
17+
required: true
18+
package_version:
19+
description: "Version of the NuGet package to publish (e.g., '1.0.0')"
20+
type: string
21+
required: true
22+
assembly_version:
23+
description: "(Optional) Set specific assembly version (e.g., '1.0.0'). If not set, it will default to package version."
24+
type: string
25+
secrets:
26+
github_pat:
27+
description: "GitHub Personal Access Token with 'write:packages' scope"
28+
required: true
29+
30+
jobs:
31+
publish:
32+
runs-on: ubuntu-latest
33+
permissions:
34+
contents: read
35+
packages: write
36+
steps:
37+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
38+
39+
- name: Setup .NET
40+
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
41+
with:
42+
dotnet-version: ${{ inputs.dotnet_version }}
43+
44+
- name: Install dependencies
45+
run: dotnet restore ${{ inputs.project_path }}
46+
47+
- name: Build
48+
run: dotnet build ${{ inputs.project_path }} --configuration Release --no-restore
49+
50+
- name: Create NuGet Package
51+
run: dotnet pack ${{ inputs.project_path }} --configuration Release --no-build --output ${{ inputs.package_output }} /p:PackageVersion=${{ inputs.package_version }} /p:Version=${{ inputs.assembly_version || inputs.package_version }} --verbosity minimal
52+
53+
- name: Add GitHub NuGet source
54+
run: dotnet nuget add source --username ${{ github.actor }} --password ${{ secrets.github_pat }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json"
55+
56+
- name: Publish NuGet Package
57+
shell: pwsh
58+
run: |
59+
Get-ChildItem ${{ inputs.package_output }} -Filter *.nupkg | ForEach-Object {
60+
dotnet nuget push $_.FullName `
61+
--source "github" `
62+
--api-key ${{ secrets.github_pat }} `
63+
--skip-duplicate
64+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Release Publish Nuget Package
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- ".github/workflows/publish-nuget-package-github.yml"
9+
workflow_dispatch:
10+
inputs:
11+
create_tag:
12+
description: "Create a Git tag and release"
13+
default: false
14+
type: boolean
15+
is_prerelease:
16+
description: "Create a prerelease version"
17+
default: false
18+
type: boolean
19+
20+
permissions:
21+
packages: write
22+
contents: write # needed for the semver action
23+
actions: read
24+
25+
concurrency:
26+
group: ${{ github.ref }}-${{ github.workflow }}
27+
cancel-in-progress: true
28+
29+
jobs:
30+
version:
31+
uses: ./.github/workflows/semver-version.yml
32+
with:
33+
prefix: "publish-nuget-package"
34+
suppress_tag: ${{ ((github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && inputs.create_tag)) != true }}
35+
is_prerelease: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && inputs.is_prerelease) }}

README.md

Lines changed: 89 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,67 @@
22

33
Reusable GitHub workflows for repositories in the c4a8 org.
44

5-
## Semantic versioning workflow
5+
# Table of contents
6+
7+
- [Publish NuGet package workflow](#publish_nuget)
8+
- [Calling the workflow](#nuget_calling)
9+
- [Inputs](#nuget_inputs)
10+
- [Semantic versioning workflow](#semantic_versioning)
11+
- [Calling the workflow](#semantic_calling)
12+
- [Inputs](#semantic_inputs)
13+
- [Outputs](#semantic_outputs)
14+
- [Bump rules](#semantic_bump)
15+
- [Commit message hook](#semantic_hook)
16+
- [Installation](#semantic_install)
17+
- [Windows](#semantic_windows)
18+
- [Mac / Linux](#semantic_linux)
19+
- [What it validates](#semantic_validate)
20+
- [Valid types](#semantic_types)
21+
- [Examples](#semantic_examples)
22+
- [Warnings](#semantic_warnings)
23+
24+
## Publish NuGet package workflow <a name="publish_nuget" id="publish_nuget"></a>
25+
26+
This workflow simplifies the process of publishing NuGet packages. Use this reusable workflow at `.github/workflows/publish-nuget-package-github.yml`. It is designed to be used for publishing packages in the package space of a GitHub organization.
27+
28+
### Calling the workflow <a name="nuget_calling"> <a id="nuget_calling"></a>
29+
30+
```yaml
31+
# .github/workflows/publish-nuget-package-github.yml in a consumer repository
32+
name: Publish NuGet package
33+
34+
on:
35+
push:
36+
branches:
37+
- main
38+
39+
jobs:
40+
publish:
41+
uses: c4a8/c4a8-code-reusable-actions/.github/workflows/publish-nuget-package-github.yml@main
42+
with:
43+
dotnet_version: "10.x" # required: version of .NET SDK to use
44+
project_path: "project/project.csproj" # required: path to the .NET project file
45+
package_output: "project/bin/Release" # required: output directory for the NuGet package
46+
package_version: "0.0.1" # required: version of the NuGet package to publish
47+
assembly_version: "0.0.1" # optional: set specific assembly version
48+
secrets:
49+
github_pat: your-pat-token # required: GitHub Personal Access Token with 'write:packages' scope - use GitHub's secret vars for this
50+
```
51+
52+
### Inputs <a name="nuget_inputs"> <a id="nuget_inputs"></a>
53+
54+
- `dotnet_version` _(string, default: empty)_ – Version of .NET SDK to use (e.g., '10.x').
55+
- `project_path` _(string, default: empty)_ – Path to the .NET project file (e.g., 'project/project.csproj').
56+
- `package_output` _(string, default: empty)_ – Output directory for the NuGet package (e.g., 'project/bin/Release').
57+
- `package_version` _(string, default: empty)_ – Version of the NuGet package to publish (e.g., '1.0.0').
58+
- `assembly_version` _(string, default: package version)_ – (Optional) Set specific assembly version (e.g., '1.0.0'). If not set, it will default to package version. This version usually has the same value as the package_version.
59+
- `github_pat` _(string, default: empty)_ – GitHub Personal Access Token with 'write:packages' scope. Use it as secret variable -> `${{ secrets.GITHUB_TOKEN }}`.
60+
61+
## Semantic versioning workflow <a name="semantic_versioning"> <a id="semantic_versioning"></a>
662

763
Use the reusable workflow at `.github/workflows/semver-version.yml` to compute the next semantic version, expose it as an output, and tag the current commit.
864

9-
### Calling the workflow
65+
### Calling the workflow <a name="semantic_calling"> <a id="semantic_calling"></a>
1066

1167
```yaml
1268
# .github/workflows/release.yml in a consumer repository
@@ -21,7 +77,7 @@ jobs:
2177
version:
2278
uses: c4a8/c4a8-code-reusable-actions/.github/workflows/semver-version.yml@main
2379
with:
24-
prefix: license-module # optional prefix for tags like license-module-vX.Y.Z
80+
prefix: license-module # optional: prefix for tags like license-module-vX.Y.Z
2581
suppress_release: false # optional: set true to skip creating a GitHub release
2682
suppress_tag: false # optional: set true to skip both tag and release creation
2783
check_last_commit_only: false # optional: set true to only inspect the latest commit
@@ -41,7 +97,7 @@ jobs:
4197
echo "Commit: ${{ needs.version.outputs.commit_subject }}"
4298
```
4399

44-
### Inputs
100+
### Inputs <a name="semantic_inputs" id="semantic_inputs"></a>
45101

46102
- `prefix` _(string, default: empty)_ – Optional prefix prepended to generated tags (for example `license-module-vX.Y.Z`).
47103
- `suppress_release` _(boolean, default: false)_ – When `true`, skips creating a GitHub release while still creating tags (unless suppressed below).
@@ -50,15 +106,15 @@ jobs:
50106
- `is_prerelease` _(boolean, default: false)_ – When `true`, generates a prerelease version (for example `1.2.3-rc.1`).
51107
- `prerelease_name` _(string, default: "prerelease")_ – Name for the prerelease identifier (for example `rc`, `alpha`, `beta`).
52108

53-
### Outputs
109+
### Outputs <a name="semantic_outputs" id="semantic_outputs"></a>
54110

55111
- `version` – The calculated semantic version (for example `1.2.3`).
56112
- `tag` – The tag name that would be created (for example `v1.2.3` or `module-v1.2.3`).
57113
- `bump_type` – The bump classification applied (`major`, `minor`, or `patch`).
58114
- `previous_tag` – The most recent matching tag prior to this run, if any.
59115
- `commit_subject` – The commit message subject that determined the bump decision.
60116

61-
### Bump rules
117+
### Bump rules <a name="semantic_bump" id="semantic_bump"></a>
62118

63119
The workflow inspects the latest commit message and applies the following precedence:
64120

@@ -70,25 +126,27 @@ If no existing tags matching `v*` are found, versioning starts from `0.0.0`.
70126

71127
Each run also publishes (or updates) a Git tag matching the new version. By default tags look like `vX.Y.Z`, but you can provide a `prefix` input (for example `license-module`) to emit tags such as `license-module-vX.Y.Z`. The workflow creates a GitHub release with auto-generated release notes for the generated tag. Existing tags or releases are detected and left untouched.
72128

73-
## Commit message hook
129+
### Commit message hook <a name="semantic_hook" id="semantic_hook"></a>
74130

75131
A PowerShell-based Git commit-msg hook is available at `git/hooks/enforceConventionalCommits/commit-msg.ps1` to enforce the [Conventional Commits](https://www.conventionalcommits.org/) standard locally before commits are created.
76132

77-
### Installation
133+
### Installation <a name="semantic_install" id="semantic_install"></a>
78134

79-
#### Windows
80-
1. Copy **both** the `commit-msg.ps1` and `commit-msg` to your repository's `.git/hooks` directory
135+
#### Windows <a name="semantic_windows" id="semantic_windows"></a>
81136

82-
#### Mac / Linux
137+
1. Copy **both** the `commit-msg.ps1` and `commit-msg` to your repository's `.git/hooks` directory
138+
139+
#### Mac / Linux <a name="semantic_linux" id="semantic_linux"></a>
83140

84141
1. Copy just the `commit-msg.ps1` to your repository's `.git/hooks` directory
85142
1. Remove the .ps1 ending (so the final filename inside the `.git/hooks` directory is `commit-msg`)
86143
1. Add execution permissions:
144+
87145
```bash
88146
chmod +x .git/hooks/commit-msg
89147
```
90148

91-
### What it validates
149+
### What it validates <a name="semantic_validate" id="semantic_validate"></a>
92150

93151
The hook validates that commit messages follow the Conventional Commits format:
94152

@@ -100,24 +158,24 @@ The hook validates that commit messages follow the Conventional Commits format:
100158
[optional footer(s)]
101159
```
102160

103-
#### Valid types
104-
105-
| Type | Description |
106-
|------|-------------|
107-
| `feat` | A new feature |
108-
| `fix` | A bug fix |
109-
| `docs` | Documentation only changes |
110-
| `style` | Code style changes (formatting, missing semicolons, etc.) |
111-
| `refactor` | Code change that neither fixes a bug nor adds a feature |
112-
| `perf` | Performance improvements |
113-
| `test` | Adding or correcting tests |
114-
| `build` | Changes to build system or dependencies |
115-
| `ci` | Changes to CI configuration files and scripts |
116-
| `chore` | Other changes that don't modify src or test files |
117-
| `revert` | Reverts a previous commit |
118-
| `deps` | Dependency updates |
119-
120-
#### Examples
161+
#### Valid types <a name="semantic_types" id="semantic_types"></a>
162+
163+
| Type | Description |
164+
| ---------- | --------------------------------------------------------- |
165+
| `feat` | A new feature |
166+
| `fix` | A bug fix |
167+
| `docs` | Documentation only changes |
168+
| `style` | Code style changes (formatting, missing semicolons, etc.) |
169+
| `refactor` | Code change that neither fixes a bug nor adds a feature |
170+
| `perf` | Performance improvements |
171+
| `test` | Adding or correcting tests |
172+
| `build` | Changes to build system or dependencies |
173+
| `ci` | Changes to CI configuration files and scripts |
174+
| `chore` | Other changes that don't modify src or test files |
175+
| `revert` | Reverts a previous commit |
176+
| `deps` | Dependency updates |
177+
178+
#### Examples <a name="semantic_examples" id="semantic_examples"></a>
121179

122180
```
123181
feat: add user authentication
@@ -126,7 +184,7 @@ feat(auth)!: change login flow (breaking change)
126184
docs: update README with setup instructions
127185
```
128186
129-
### Warnings
187+
### Warnings <a name="semantic_warnings" id="semantic_warnings"></a>
130188
131189
The hook will display warnings (but not reject the commit) for:
132190

0 commit comments

Comments
 (0)