Skip to content

Commit 5f316b8

Browse files
Document push-authoritative releases
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 56195c6 commit 5f316b8

12 files changed

Lines changed: 118 additions & 75 deletions

File tree

docs/content/get-started/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Start new modules from the PSModule template repository:
1515
3. Replace placeholder metadata and remove scaffold sample files.
1616
4. Add your first public command and tests.
1717
5. Validate `.github/PSModule.yml` defaults for your module.
18-
6. [Open a draft pull request](your-first-release.md) and run the full pipeline.
18+
6. [Open a draft pull request](your-first-release.md), then release from its resulting important default-branch push.
1919

2020
If the module needs several interdependent commands before it is usable at all, see
2121
[Module bootstrap](module-bootstrap.md) instead of shipping them as one command per step.
@@ -31,7 +31,7 @@ If the module needs several interdependent commands before it is usable at all,
3131
| Page | Description |
3232
| --- | --- |
3333
| [Repository setup](repository-setup.md) | GitHub Pages, `PSGALLERY_API_KEY`, permissions, and the caller workflow. |
34-
| [Your first release](your-first-release.md) | The pull request flow, version labels, and what happens on merge. |
34+
| [Your first release](your-first-release.md) | The pull request flow, version labels, and the resulting default-branch release. |
3535
| [Module bootstrap](module-bootstrap.md) | Getting a brand-new module to its first release with an integration branch. |
3636

3737
For framework-level practices, refer to [MSX Ways of Working](https://msx.no/docs/Ways-of-Working/).

docs/content/get-started/module-bootstrap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Scope the integration branch to exactly that core, not to everything planned for
2020

2121
1. Cut one long-lived branch from the default branch for the initial release, named for the outcome, e.g. `build-thing-module`.
2222
2. Open one pull request per function (or small group of related functions) targeting that branch instead of `main`. These PRs can land in parallel — there is no strict order between them, unlike a [stacked pull request](https://msx.no/docs/Ways-of-Working/Branching-and-Merging/#stacked-pull-requests).
23-
3. Once the load-bearing core is coherent and complete, open the pull request that merges the integration branch into `main`. This becomes the module's first real release (`v1.0.0`).
23+
3. Once the load-bearing core is coherent and complete, open the pull request that merges the integration branch into `main`. Its resulting important push becomes the module's first real release (`v1.0.0`).
2424
4. Smaller follow-up features (one more function, a formatter, an alias) can keep targeting the integration branch before it lands, the same way they targeted it during bootstrap.
2525

2626
## After the core lands

docs/content/get-started/repository-setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ on:
5353
- unlabeled
5454

5555
concurrency:
56-
group: ${{ github.workflow }}-${{ github.ref }}
56+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
5757
cancel-in-progress: false
5858

5959
permissions:

docs/content/get-started/your-first-release.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
11
---
22
title: Your first release
3-
description: The pull request flow, version labels, and what happens when a Process-PSModule pull request is merged.
3+
description: The pull request flow, version labels, and the default-branch push that creates a stable Process-PSModule release.
44
---
55

66
# Your first release
77

8-
Process-PSModule is driven entirely by pull requests. There is no manual publish step, no version file to edit, and no
9-
tag to push by hand.
8+
Process-PSModule uses pull requests for review and release metadata, and an important push to the default branch as
9+
the authority for stable publication. There is no manual publish step, no version file to edit, and no tag to push by
10+
hand.
1011

1112
## The flow
1213

1314
1. Clone the repository, create a branch, and make your changes.
1415
2. Push the branch and open a pull request against `main`.
1516
3. The workflow builds the module, runs tests on Windows, Linux, and macOS, lints the repository, and reports back on
1617
the pull request.
17-
4. Apply a version label to declare release intent (see below). Without a label, the change releases as a **patch**.
18-
5. Merge the pull request. The workflow publishes the module to the PowerShell Gallery, creates a GitHub Release and
19-
tag, and deploys the documentation site to GitHub Pages.
18+
4. Apply a version label to declare release intent (see below). An unlabeled pull request defaults to a **patch** when
19+
`Publish.Module.AutoPatching` is enabled, which is the default.
20+
5. Merge the pull request. Its resulting important push to `main` runs the stable release: after the pipeline passes,
21+
it publishes the module to the PowerShell Gallery, creates a GitHub Release and tag for the tested commit, and
22+
deploys the documentation site unless site publication is configured to skip. The closed-pull-request event only
23+
cleans up prereleases.
24+
25+
An important direct push to the default branch, or a manual dispatch on that branch, also creates a stable **patch**
26+
release with commit-based notes. It has no pull-request labels or body to use as metadata.
2027

2128
## Version labels
2229

2330
| Label | Effect |
2431
| --- | --- |
2532
| `major` / `breaking` | Bump `MAJOR`. |
2633
| `minor` / `feature` | Bump `MINOR`. |
27-
| `patch` / `fix` | Bump `PATCH`. This is the default when no label is applied. |
34+
| `patch` / `fix` | Bump `PATCH`. This is the default for an unlabeled PR when `AutoPatching` is enabled. |
2835
| `Prerelease` | Publish a prerelease version from the pull request, before it is merged. |
2936
| `NoRelease` | Run the pipeline but skip publication. |
3037

@@ -43,9 +50,9 @@ cleaned up automatically.
4350

4451
## When nothing is released
4552

46-
If a pull request only touches files outside the configured important-file patterns — documentation, CI tweaks, comment
47-
typos — the build, test, and publish stages are skipped and no release is created. A comment on the pull request
48-
explains why. See
53+
If a pull request or default-branch push only touches files outside the configured important-file patterns —
54+
documentation, CI tweaks, comment typos — the build, test, and publish stages are skipped and no release is created.
55+
A pull-request comment explains why for pull-request runs. See
4956
[important-file change detection](../guides/calling-the-workflow.md#important-file-change-detection) to change which
5057
paths trigger a release.
5158

docs/content/guides/calling-the-workflow.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ on:
3636
- unlabeled
3737

3838
concurrency:
39-
group: ${{ github.workflow }}-${{ github.ref }}
39+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
4040
cancel-in-progress: false
4141

4242
permissions:
@@ -61,6 +61,10 @@ Stable releases are evaluated from a push to the default branch. A merged pull r
6161
release notes; a direct default-branch push or a manual dispatch uses the default `Patch` bump and commit-based notes.
6262
Keep the `pull_request` trigger for CI, prereleases, and prerelease cleanup.
6363

64+
The concurrency key keeps a pull request distinct from a default-branch push, so the close-event cleanup and the
65+
resulting stable release do not serialize as one run. Keep `cancel-in-progress: false`: a release-capable run mutates
66+
the PowerShell Gallery, GitHub Releases, and tags, so later runs must queue rather than interrupt it.
67+
6468
## Passing test data
6569

6670
The reusable workflow at `.github/workflows/workflow.yml` declares four workflow-call secrets,

docs/content/index.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ An end-to-end PowerShell module pipeline that automates the entire lifecycle of
99

1010
## How it works
1111

12-
The workflow is triggered on pull requests to the repository's default branch. When a pull request is opened, closed, reopened, synchronized (push), or labeled, the workflow runs. Depending on the labels on the pull request, the [workflow results in different outcomes](reference/scenario-matrix.md).
12+
The caller workflow runs for pull-request lifecycle events and pushes to the repository's default branch. Open pull
13+
requests run CI and can publish prereleases; closed pull requests clean up their prereleases. An important
14+
default-branch push is the sole authority for a stable release. When that push is the exact merge commit of a pull
15+
request, its labels and release notes supply the release metadata. See the
16+
[scenario matrix](reference/scenario-matrix.md) for the resulting job execution.
1317

1418
Everything is packaged into a single reusable workflow so that a module repository only needs a small caller workflow and one settings file. A user configures the behaviour by editing `.github/PSModule.yml`.
1519

@@ -23,7 +27,7 @@ New to Process-PSModule? Work through these in order.
2327
| --- | --- |
2428
| [Get started](get-started/index.md) | Create a module repository from the template and get the pipeline running. |
2529
| [Repository setup](get-started/repository-setup.md) | Configure GitHub Pages, `PSGALLERY_API_KEY`, permissions, and the caller workflow. |
26-
| [Your first release](get-started/your-first-release.md) | The pull request flow, version labels, and what happens on merge. |
30+
| [Your first release](get-started/your-first-release.md) | The pull request flow, version labels, and the resulting default-branch release. |
2731

2832
## Guides
2933

@@ -32,6 +36,7 @@ Task-oriented deep dives into the pipeline's functionality.
3236
| Page | Description |
3337
| --- | --- |
3438
| [Calling the workflow](guides/calling-the-workflow.md) | The caller workflow, passing test secrets and variables with `TestData`, and important-file change detection. |
39+
| [GitHub App authentication](guides/github-app-authentication.md) | Configure Shelly credentials and the scoped tokens used for repository API operations. |
3540
| [Configuring the pipeline](guides/configuring-the-pipeline.md) | Worked examples for coverage targets, rapid testing, linting, and PR-based release notes. |
3641
| [Structuring your module](guides/structuring-your-module.md) | The repository and module source layout the workflow expects, and how to declare dependencies. |
3742
| [Writing module tests](guides/writing-module-tests.md) | Test discovery, setup and teardown phases, and shared test infrastructure. |

docs/content/reference/pipeline-stages.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,11 @@ How to write these tests, including the Pester version requirement and shared-in
132132

133133
[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Publish-Module.yml)
134134

135+
- An important default-branch push is the only stable-publication authority. A closed pull request performs
136+
prerelease cleanup only.
135137
- Publishes the artifact to the PowerShell Gallery exactly as built — no version mutation.
136-
- Creates a GitHub Release using the version already stamped in the manifest.
138+
- Creates a GitHub Release only after the Gallery publication succeeds, targeting the exact tested push SHA and using
139+
the version already stamped in the manifest.
137140
- Attaches the built module as a `.zip` asset on the GitHub Release so consumers can download the exact bytes that were tested and pushed to the PowerShell Gallery.
138141
- **Abandoned PR cleanup**: When a PR is closed without merging (abandoned), the workflow automatically cleans up any
139142
prerelease versions and tags that were created for that PR. This ensures that abandoned work doesn't leave orphaned

docs/content/reference/powershell-module-standard.md

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,20 @@ Keep related things together so the connection between code and its context is v
111111

112112
### Linear versioning
113113

114-
The release process treats each merged PR as a release on a single linear ancestry. There is no patching of older versions — security fixes go on the current tip of `main` only.
114+
The release process treats each important default-branch push as a release on a single linear ancestry. A merged pull
115+
request supplies release metadata when its merge commit exactly matches that push. There is no patching of older
116+
versions — security fixes go on the current tip of `main` only.
115117

116118
### Release and feature branches
117119

118-
For large work, open a release branch and target it from feature branches. Apply the `Prerelease` label on the release branch PR to publish preview versions before the final merge to `main`.
120+
For large work, open a release branch and target it from feature branches. Apply the `Prerelease` label on the release
121+
branch PR to publish preview versions before its final merge creates the stable default-branch push.
119122

120123
## CI/CD pipeline
121124

122-
The [Process-PSModule](https://github.com/PSModule/Process-PSModule) workflow orchestrates the full lifecycle. Every PR triggers a **Plan** job that resolves configuration and version, then conditionally runs build, test, lint, and publish stages.
125+
The [Process-PSModule](https://github.com/PSModule/Process-PSModule) workflow orchestrates the full lifecycle. Pull
126+
requests and default-branch pushes trigger a **Plan** job that resolves configuration and version, then conditionally
127+
runs build, test, lint, and publish stages.
123128

124129
### Pipeline stages
125130

@@ -147,20 +152,20 @@ graph LR
147152

148153
| Stage | Runs on | Purpose |
149154
| ----- | ------- | ------- |
150-
| **Plan** | All events | Loads `.github/PSModule.yml`, resolves version from PR labels, produces the Settings JSON |
155+
| **Plan** | All events | Loads `.github/PSModule.yml`, resolves the release context, produces the Settings JSON |
151156
| **Lint-Repository** | Open/Updated PR | Runs super-linter on the full repo (Markdown, YAML, etc.) |
152-
| **Lint-SourceCode** | Open/Updated PR, Merged PR, Manual | Runs PSScriptAnalyzer against `src/` |
153-
| **Build-Module** | Open/Updated PR, Merged PR, Manual | Compiles source into a versioned module artifact |
154-
| **Test-SourceCode** | Open/Updated PR, Merged PR, Manual | Framework tests on raw source files |
155-
| **Test-Module** | Open/Updated PR, Merged PR, Manual | Pester tests against the built module artifact |
156-
| **BeforeAll-ModuleLocal** | Open/Updated PR, Merged PR, Manual | Runs `tests/BeforeAll.ps1` once before the local test matrix |
157-
| **Test-ModuleLocal** | Open/Updated PR, Merged PR, Manual | Pester tests with the module installed locally (cross-OS matrix) |
157+
| **Lint-SourceCode** | Open/Updated PR, default-branch push/manual run | Runs PSScriptAnalyzer against `src/` |
158+
| **Build-Module** | Open/Updated PR, default-branch push/manual run | Compiles source into a versioned module artifact |
159+
| **Test-SourceCode** | Open/Updated PR, default-branch push/manual run | Framework tests on raw source files |
160+
| **Test-Module** | Open/Updated PR, default-branch push/manual run | Pester tests against the built module artifact |
161+
| **BeforeAll-ModuleLocal** | Open/Updated PR, default-branch push/manual run | Runs `tests/BeforeAll.ps1` once before the local test matrix |
162+
| **Test-ModuleLocal** | Open/Updated PR, default-branch push/manual run | Pester tests with the module installed locally (cross-OS matrix) |
158163
| **AfterAll-ModuleLocal** | Always (if tests started) | Runs `tests/AfterAll.ps1` for cleanup |
159164
| **Get-TestResults** | Always (if Plan succeeded) | Aggregates and reports test results |
160165
| **Get-CodeCoverage** | Always (if Plan succeeded) | Calculates and reports code coverage |
161-
| **Publish-Module** | Merged PR (or Prerelease label) | Publishes to PowerShell Gallery and creates a GitHub Release |
162-
| **Build-Docs / Build-Site** | Open/Updated PR, Merged PR, Manual | Generates documentation site from source |
163-
| **Publish-Site** | Merged PR | Deploys documentation site to GitHub Pages |
166+
| **Publish-Module** | Prerelease PR, stable default-branch push/manual run, or closed PR | Publishes a prerelease or stable release, or cleans up closed-PR prereleases |
167+
| **Build-Docs / Build-Site** | Open/Updated PR, default-branch push/manual run | Generates documentation site from source |
168+
| **Publish-Site** | Stable default-branch push/manual run | Deploys documentation site to GitHub Pages unless `Publish.Site.Skip` is set |
164169

165170
### Important file patterns
166171

@@ -186,7 +191,7 @@ The **Plan** job resolves the next version before any build occurs. This means t
186191
187192
**Flow:**
188193
189-
1. `Get-PSModuleSettings` loads `.github/PSModule.yml` and determines `ReleaseType` from PR labels
194+
1. `Get-PSModuleSettings` loads `.github/PSModule.yml` and determines `ReleaseType` from the normalized event context
190195
2. `Resolve-PSModuleVersion` calculates the next semantic version from the latest Git tag
191196
3. `Build-PSModule` stamps the resolved version into the compiled manifest
192197
4. `Publish-PSModule` reads the version from the manifest (read-only) and publishes
@@ -203,6 +208,9 @@ The **Plan** job resolves the next version before any build occurs. This means t
203208

204209
**Prerelease versions:** Adding a `Prerelease` label to the PR produces a prerelease tag (e.g., `1.2.3-preview0001`). The format is controlled by `IncrementalPrerelease` (sequential numbering) or `DatePrereleaseFormat` (.NET DateTime format string).
205210

211+
An important direct default-branch push and a default-branch manual dispatch always resolve to `Patch`, regardless of
212+
`AutoPatching`. A push that exactly matches a merged pull request uses that PR's version label instead.
213+
206214
**Tag format:** Releases are tagged with a configurable prefix (default `v`) — e.g., `v1.2.3`.
207215

208216
### Configuration (`.github/PSModule.yml`)
@@ -246,9 +254,11 @@ Test:
246254
PercentTarget: 0
247255
248256
Publish:
257+
Site:
258+
Skip: false
249259
Module:
250260
Skip: false
251-
AutoCleanup: true # Delete prerelease tags after stable release
261+
AutoCleanup: true # Delete prerelease tags after stable release or PR closure
252262
AutoPatching: true # Unlabeled PRs default to patch bump
253263
IncrementalPrerelease: true # Sequential prerelease numbering
254264
DatePrereleaseFormat: '' # Alternative: .NET DateTime format for prerelease
@@ -274,16 +284,17 @@ The `Publish-Module` stage:
274284
2. Reads the version from the compiled manifest (no recalculation)
275285
3. Publishes to the PowerShell Gallery
276286
4. Creates a GitHub Release with the module attached as a ZIP artifact
277-
5. Comments on the PR with links to the Gallery package and GitHub Release
287+
5. Comments on the associated PR with links to the Gallery package and GitHub Release
278288
6. Cleans up old prerelease tags when publishing a stable release (if `AutoCleanup: true`)
279289

280290
The publish step only runs when:
281291

282292
- All tests and code coverage pass (or are skipped)
283-
- The PR is merged to the default branch (stable release), or
293+
- An important push reaches the default branch (stable release), or
284294
- The PR carries the `Prerelease` label (prerelease from the feature/release branch)
285295

286-
On abandoned (closed without merge) PRs, the pipeline cleans up any prerelease tags created for that branch.
296+
On any closed PR, the pipeline cleans up any prerelease tags created for that branch. A closed pull request cannot
297+
create a stable release.
287298

288299
## Tests
289300

0 commit comments

Comments
 (0)