Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions .github/workflows/Action-Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,45 @@ run-name: "Action-Test - [${{ github.event.pull_request.title }} #${{ github.eve
on:
workflow_dispatch:
pull_request:
types:
- opened
- reopened
- synchronize
- labeled
- unlabeled
schedule:
- cron: '0 0 * * *'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: read
permissions: {}

jobs:
UnitTest:
name: Pester 6.1
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repo
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Test release decisions
uses: PSModule/Invoke-Pester@4ff33199141fdf22568990b6107fe3148ae93a1c # v5.1.0
with:
Path: tests
Version: 6.1.0

ActionTestDefault:
name: Action-Test - [Default]
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
Comment thread
MariusStorhaug marked this conversation as resolved.
steps:
- name: Checkout repo
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/Release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Release
run-name: "Release - [${{ github.event.pull_request.title }} #${{ github.event.pull_request.number }}] by @${{ github.actor }}"

on:
pull_request:
pull_request_target: # zizmor: ignore[dangerous-triggers] trusted base checkout; writes labels and releases
branches:
- main
types:
Expand All @@ -12,16 +12,15 @@ on:
- reopened
- synchronize
- labeled
paths:
- 'action.yml'
- 'src/**'
- unlabeled

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

permissions:
contents: write # Required to create releases
issues: write # Required to provision release labels
pull-requests: write # Required to create comments on the PRs
Comment thread
MariusStorhaug marked this conversation as resolved.

jobs:
Expand Down
158 changes: 82 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,83 +1,41 @@
# Release-GHRepository

Automatically creates releases based on pull requests and labels.
Create GitHub releases from explicit, owned pull-request labels.

## Release decision

## Specifications and practices
Release-GHRepository owns and provisions five labels:

Release-GHRepository follows:
| Label | Instruction | Valid combination |
| --- | --- | --- |
| `release:patch` | Increment the patch version. | Exactly one bump label. |
| `release:minor` | Increment the minor version. | Exactly one bump label. |
| `release:major` | Increment the major version. | Exactly one bump label. |
| `release:pre-release` | Publish from an open pull request as a prerelease. | With exactly one bump label. |
| `release:skip` | Validate without publishing a release. | Without another owned release label. |

- [SemVer 2.0.0 specifications](https://semver.org)
- [GitHub Flow specifications](https://docs.github.com/en/get-started/using-github/github-flow)
- [Continuous Delivery practices](https://en.wikipedia.org/wiki/Continuous_delivery)
Exactly one bump label or `release:skip` is required. There is no default release decision.

## How it works

The workflow will trigger on pull requests to the main branch.

The following labels will inform the action what kind of release to create:
- For a major release, and increasing the first number in the version use:
- `major`
- `breaking`
- For a minor release, and increasing the second number in the version.
- `minor`
- `feature`
- For a patch release, and increases the third number in the version.
- `patch`
- `fix`
The action rejects:

When a pull request is closed, the action will create a release based on the labels and clean up any previous prereleases that were created.
- a missing decision;
- multiple bump labels;
- `release:skip` with another owned release label;
- `release:pre-release` without exactly one bump label.

> [!NOTE]
> The labels can be configured using the `MajorLabels`, `MinorLabels` and `PatchLabels` parameters/settings in the configuration file to trigger
> on other labels.

This action is built on [GitHub-Script](https://github.com/PSModule/GitHub-Script) which by default uses the `GITHUB_TOKEN`.
## Usage

The action can be configured using the following settings:

| Name | Description | Default | Required |
| --- | --- | --- | --- |
| `AutoCleanup` | Control whether to automatically cleanup prereleases. If disabled, the action will not remove any prereleases. | `true` | false |
| `AutoPatching` | Control whether to automatically handle patches. If disabled, the action will only create a patch release if the pull request has a 'patch' label. | `true` | false |
| `ConfigurationFile` | The path to the configuration file. Settings in the configuration file take precedence over the action inputs. | `.github\auto-release.yml` | false |
| `CreateMajorTag` | Control whether to create a tag for major releases. | `true` | false |
| `CreateMinorTag` | Control whether to create a tag for minor releases. | `true` | false |
| `DatePrereleaseFormat` | The format to use for the prerelease number using [.NET DateTime format strings](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings). | `''` | false |
| `IgnoreLabels` | A comma separated list of labels that do not trigger a release. | `NoRelease` | false |
| `IncrementalPrerelease` | Control whether to automatically increment the prerelease number. If disabled, the action will ensure only one prerelease exists for a given branch. | `true` | false |
| `MajorLabels` | A comma separated list of labels that trigger a major release. | `major, breaking` | false |
| `MinorLabels` | A comma separated list of labels that trigger a minor release. | `minor, feature` | false |
| `PatchLabels` | A comma separated list of labels that trigger a patch release. | `patch, fix` | false |
| `UsePRTitleAsReleaseName` | When enabled, uses the pull request title as the name for the GitHub release. | `false` | false |
| `UsePRBodyAsReleaseNotes` | When enabled, uses the pull request body as the release notes for the GitHub release. | `true` | false |
| `UsePRTitleAsNotesHeading` | When enabled, the release notes will begin with the pull request title as a H1 heading followed by the pull request body. The title will include a reference to the PR number. | `true` | false |
| `VersionPrefix` | The prefix to use for the version number. | `v` | false |
| `WhatIf` | Control whether to simulate the action. If enabled, the action will not create any releases. Used for testing. | `false` | false |
| `Debug` | Enable debug output. | `'false'` | false |
| `Verbose` | Enable verbose output. | `'false'` | false |
| `Version` | Specifies the version of the GitHub module to install. Accepts an exact version or a NuGet version range (for example `[1.2.0, 2.0.0)`). | | false |
| `Prerelease` | Allow prerelease versions if available. | `'false'` | false |
| `WorkingDirectory` | The working directory where the script runs. | `${{ github.workspace }}` | false |
Labels outside this set do not affect releases. Bare and legacy labels such as `Major`, `Minor`, `Patch`, `Prerelease`, `NoRelease`, `major`, `minor`, and `patch` are not release decisions.

### Configuration file
## How it works

The configuration file is a YAML file that can be used to configure the action.
By default, the configuration file is expected at `.github\auto-release.yml`, which can be changed using the `ConfigurationFile` setting.
The action's configuration can be changed by altering the settings in the configuration file.
On every non-WhatIf run, the action creates missing canonical labels and reconciles their colors and descriptions. It leaves all other repository labels unchanged.

```yaml
DatePrereleaseFormat: 'yyyyMMddHHmm'
IncrementalPrerelease: false
VersionPrefix: ''
```
An open pull request with `release:pre-release` and one bump label publishes a prerelease. A pull request merged into the default branch with one bump label publishes the stable release. A closed pull request cleans up its prereleases when `AutoCleanup` is enabled. `release:skip` never publishes a version, but a closed skipped pull request still receives prerelease cleanup.

This example uses the date format for the prerelease, disables the incremental prerelease and removes the version prefix.
The workflow must run for `labeled` and `unlabeled` events so both valid and invalid label transitions are evaluated. Do not use a workflow path filter to bypass the release decision on non-artifact changes; use `release:skip`.

## Example
This action is built on [GitHub-Script](https://github.com/PSModule/GitHub-Script), which uses the workflow token by default.

Add a workflow in your repository using the following example:
## Usage

```yaml
name: Release-GHRepository
Expand All @@ -92,27 +50,75 @@ on:
- reopened
- synchronize
- labeled
- unlabeled

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}

permissions:
contents: write # Required to create releases and tags
issues: write # Required to provision repository labels
pull-requests: write # Required to comment on pull requests

jobs:
Release-GHRepository:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Release-GHRepository
uses: PSModule/Release-GHRepository@v1
- name: Release repository
uses: PSModule/Release-GHRepository@v3
```

## Permissions
The `pull_request_target` workflow checks out the trusted base branch. Do not check out or execute an untrusted pull-request head with this writable token.

## Inputs

| Name | Description | Default | Required |
| --- | --- | --- | --- |
| `AutoCleanup` | Delete prereleases after the pull request closes. | `true` | false |
| `ConfigurationFile` | Read settings from this file. File settings take precedence over action inputs. | `.github\auto-release.yml` | false |
| `CreateMajorTag` | Create or update the floating major tag after a stable release. | `true` | false |
| `CreateMinorTag` | Create or update the floating minor tag after a stable release. | `true` | false |
| `DatePrereleaseFormat` | Append a [.NET date and time format](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings) to prerelease versions. | `''` | false |
| `IncrementalPrerelease` | Increment the prerelease number; when false, keep only one prerelease for the branch. | `true` | false |
| `UsePRTitleAsReleaseName` | Use the pull-request title as the GitHub Release name. | `false` | false |
| `UsePRBodyAsReleaseNotes` | Use the pull-request body as release notes. | `true` | false |
| `UsePRTitleAsNotesHeading` | Add the pull-request title and number as the release-notes heading. | `true` | false |
| `VersionPrefix` | Prefix the version number. | `v` | false |
| `WhatIf` | Log release and label changes without mutating repository state. | `false` | false |
| `Debug` | Enable debug output. | `false` | false |
| `Verbose` | Enable verbose output. | `false` | false |
| `Version` | Select the GitHub module dependency by exact version or NuGet version range. | | false |
| `Prerelease` | Allow a prerelease version of the GitHub module dependency. This does not select a repository prerelease. | `false` | false |
| `WorkingDirectory` | Set the directory where the script runs. | `${{ github.workspace }}` | false |

Use the `release:pre-release` label to select repository prerelease behavior. The similarly named `Prerelease` action input only controls dependency resolution for the GitHub module used internally.

### Configuration file

If running the action in a restrictive mode, the following permissions needs to be granted to the action:
The default configuration file is `.github\auto-release.yml`. Change its path with `ConfigurationFile`.

```yaml
permissions:
contents: write # Required to create releases
pull-requests: write # Required to create comments on the PRs
DatePrereleaseFormat: 'yyyyMMddHHmm'
IncrementalPrerelease: false
VersionPrefix: ''
```

## Migrate from v2

`v3` is a breaking release. Existing `v2` references and behavior remain unchanged.

1. Add `issues: write` to the release job and subscribe the workflow to `unlabeled`.
2. Remove workflow path filters so `release:skip` decisions are validated.
3. Remove `AutoPatching`, `IgnoreLabels`, `MajorLabels`, `MinorLabels`, and `PatchLabels` from action inputs and configuration files.
4. Provision the five canonical labels before opening the migration pull request. The action reconciles them on every subsequent run.
5. Apply both the existing v2 decision and the equivalent canonical decision to the migration pull request so either workflow version can process it.
6. Update the action reference to `PSModule/Release-GHRepository@v3` after `v3.0.0` is published.
7. Apply one canonical decision to every other open pull request.
8. Remove legacy release labels after no open pull request uses them. Removing bare `major`, `minor`, and `patch` labels also prevents Dependabot from applying them as dependency-version metadata.

The first v3 run provisions the canonical labels before validating the pull request. A pull request without a canonical decision fails until a maintainer applies one.
27 changes: 1 addition & 26 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ inputs:
description: Control whether to automatically delete the prerelease tags after the stable release is created.
required: false
default: 'true'
AutoPatching:
description: Control whether to automatically handle patches. If disabled, the action will only create a patch release if the pull request has a 'patch' label.
required: false
default: 'true'
ConfigurationFile:
description: The path to the configuration file. Settings in the configuration file take precedence over the action inputs.
required: false
Expand All @@ -30,26 +26,10 @@ inputs:
description: If specified, uses a date based prerelease scheme. The format should be a valid .NET format string like 'yyyyMMddHHmm'.
required: false
default: ''
IgnoreLabels:
description: A comma separated list of labels that do not trigger a release.
required: false
default: NoRelease
IncrementalPrerelease:
description: Control whether to automatically increment the prerelease number. If disabled, the action will ensure only one prerelease exists for a given branch.
required: false
default: 'true'
MajorLabels:
description: A comma separated list of labels that trigger a major release.
required: false
default: major, breaking
MinorLabels:
description: A comma separated list of labels that trigger a minor release.
required: false
default: minor, feature
PatchLabels:
description: A comma separated list of labels that trigger a patch release.
required: false
default: patch, fix
UsePRTitleAsReleaseName:
description: When enabled, uses the pull request title as the name for the GitHub release.
required: false
Expand Down Expand Up @@ -82,7 +62,7 @@ inputs:
description: Specifies the version of the GitHub module to be installed. Accepts an exact version or a NuGet version range (for example '[1.2.0, 2.0.0)').
required: false
Prerelease:
description: Allow prerelease versions if available.
description: Allow prerelease versions of the GitHub module dependency. This does not control repository releases; use the release:pre-release label.
required: false
default: 'false'
WorkingDirectory:
Expand All @@ -97,16 +77,11 @@ runs:
uses: PSModule/GitHub-Script@8083ec1f733f00357ee4d0db0c6056686e483bc0 # v1.9.0
env:
PSMODULE_AUTO_RELEASE_INPUT_AutoCleanup: ${{ inputs.AutoCleanup }}
PSMODULE_AUTO_RELEASE_INPUT_AutoPatching: ${{ inputs.AutoPatching }}
PSMODULE_AUTO_RELEASE_INPUT_ConfigurationFile: ${{ inputs.ConfigurationFile }}
PSMODULE_AUTO_RELEASE_INPUT_CreateMajorTag: ${{ inputs.CreateMajorTag }}
PSMODULE_AUTO_RELEASE_INPUT_CreateMinorTag: ${{ inputs.CreateMinorTag }}
PSMODULE_AUTO_RELEASE_INPUT_DatePrereleaseFormat: ${{ inputs.DatePrereleaseFormat }}
PSMODULE_AUTO_RELEASE_INPUT_IgnoreLabels: ${{ inputs.IgnoreLabels }}
PSMODULE_AUTO_RELEASE_INPUT_IncrementalPrerelease: ${{ inputs.IncrementalPrerelease }}
PSMODULE_AUTO_RELEASE_INPUT_MajorLabels: ${{ inputs.MajorLabels }}
PSMODULE_AUTO_RELEASE_INPUT_MinorLabels: ${{ inputs.MinorLabels }}
PSMODULE_AUTO_RELEASE_INPUT_PatchLabels: ${{ inputs.PatchLabels }}
PSMODULE_AUTO_RELEASE_INPUT_UsePRBodyAsReleaseNotes: ${{ inputs.UsePRBodyAsReleaseNotes }}
PSMODULE_AUTO_RELEASE_INPUT_UsePRTitleAsReleaseName: ${{ inputs.UsePRTitleAsReleaseName }}
PSMODULE_AUTO_RELEASE_INPUT_UsePRTitleAsNotesHeading: ${{ inputs.UsePRTitleAsNotesHeading }}
Expand Down
Loading
Loading