Skip to content
Open
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
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,52 @@
# Publish-PSModule

This GitHub Action is a part of the [PSModule framework](https://github.com/PSModule).

It publishes a **pre-versioned** PowerShell module artifact to the PowerShell Gallery and creates a matching GitHub
Release. The compressed module is also uploaded as a release asset so the GitHub Release page exposes the exact bytes
that were tested and pushed to the Gallery.

## Breaking change — v3.0.0

`Publish-PSModule` no longer calculates the next version or mutates the module manifest. The artifact passed in must
already contain the final `ModuleVersion` (and `Prerelease` tag, if any).

The following inputs were **removed**:

- `AutoPatching`
- `IncrementalPrerelease`
- `DatePrereleaseFormat`
- `VersionPrefix`
- `MajorLabels`, `MinorLabels`, `PatchLabels`, `IgnoreLabels`
- `ReleaseType`

To migrate, run [`PSModule/Resolve-PSModuleVersion`](https://github.com/PSModule/Resolve-PSModuleVersion) to compute
the version and pass it to [`PSModule/Build-PSModule`](https://github.com/PSModule/Build-PSModule) so the artifact is
stamped before it is tested. The publish action then ships that artifact without any post-build manipulation.

This makes the tested artifact identical to the published artifact (see
[PSModule/Process-PSModule#326](https://github.com/PSModule/Process-PSModule/issues/326)).

## What it does

1. Downloads the `module` artifact uploaded by `Build-PSModule`.
2. Reads `ModuleVersion` and `PrivateData.PSData.Prerelease` from the downloaded manifest.
3. Installs `RequiredModules` declared by the manifest.
4. Publishes the module to the PowerShell Gallery (`Publish-PSResource`).
5. Creates a GitHub Release with the same tag.
6. Zips the module folder and uploads it as a release asset (`<Name>-<Version>.zip`).
7. Optionally cleans up prerelease tags whose name matches the current PR branch.

## Inputs

| Name | Description | Required | Default |
| -------------------------- | ------------------------------------------------------------------------------------------ | -------- | ---------------- |
| `Name` | Name of the module. Defaults to the repository name. | No | Repository name |
| `ModulePath` | Path to the downloaded module folder. | No | `outputs/module` |
| `APIKey` | PowerShell Gallery API key. | Yes | |
| `AutoCleanup` | Delete prerelease tags matching the PR branch after a stable release. | No | `true` |
| `WhatIf` | Log the changes that would be made without publishing, creating, or deleting anything. | No | `false` |
| `WorkingDirectory` | The working directory where the script will run from. | No | `.` |
| `UsePRTitleAsReleaseName` | Use the PR title as the release name (otherwise the version string is used). | No | `false` |
| `UsePRBodyAsReleaseNotes` | Use the PR body as the release notes (otherwise `--generate-notes` is used). | No | `true` |
| `UsePRTitleAsNotesHeading` | Prefix the release notes with the PR title as an H1 heading linking to the PR. | No | `true` |
Comment on lines +42 to +52
68 changes: 9 additions & 59 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
name: Publish-PSModule
description: Publish a PowerShell module to the PowerShell Gallery.
description: Publish a pre-versioned PowerShell module artifact to the PowerShell Gallery and GitHub Releases.
author: PSModule

# BREAKING CHANGE (v3.0.0):
# This action no longer calculates the next version or mutates the module manifest. The artifact passed in
# must already contain the final ModuleVersion (and Prerelease tag, if any). Use PSModule/Resolve-PSModuleVersion
# to compute the version and PSModule/Build-PSModule (v5+) to stamp it before testing. The version-calculation
# inputs (AutoPatching, IncrementalPrerelease, DatePrereleaseFormat, VersionPrefix, *Labels, ReleaseType, IgnoreLabels)
# have been removed.

inputs:
Name:
description: Name of the module to publish.
Expand All @@ -17,42 +24,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'
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'
DatePrereleaseFormat:
description: If specified, uses a date based prerelease scheme. The format should be a valid .NET format string like 'yyyyMMddHHmm'.
required: false
default: ''
VersionPrefix:
description: The prefix to use for the version number.
required: false
default: v
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
IgnoreLabels:
description: A comma separated list of labels that do not trigger a release.
required: false
default: NoRelease
ReleaseType:
description: The type of release to create. Values are 'Release' (stable), 'Prerelease', or 'None'.
required: false
default: Release
WhatIf:
description: If specified, the action will only log the changes it would make, but will not actually create or delete any releases or tags.
required: false
Expand Down Expand Up @@ -85,34 +56,13 @@ runs:
run: |
Install-PSResource -Name Microsoft.PowerShell.PSResourceGet -Repository PSGallery -TrustRepository

- name: Initialize Publish Context
id: init
shell: pwsh
working-directory: ${{ inputs.WorkingDirectory }}
env:
PSMODULE_PUBLISH_PSMODULE_INPUT_Name: ${{ inputs.Name }}
PSMODULE_PUBLISH_PSMODULE_INPUT_AutoCleanup: ${{ inputs.AutoCleanup }}
PSMODULE_PUBLISH_PSMODULE_INPUT_AutoPatching: ${{ inputs.AutoPatching }}
PSMODULE_PUBLISH_PSMODULE_INPUT_DatePrereleaseFormat: ${{ inputs.DatePrereleaseFormat }}
PSMODULE_PUBLISH_PSMODULE_INPUT_IgnoreLabels: ${{ inputs.IgnoreLabels }}
PSMODULE_PUBLISH_PSMODULE_INPUT_ReleaseType: ${{ inputs.ReleaseType }}
PSMODULE_PUBLISH_PSMODULE_INPUT_IncrementalPrerelease: ${{ inputs.IncrementalPrerelease }}
PSMODULE_PUBLISH_PSMODULE_INPUT_MajorLabels: ${{ inputs.MajorLabels }}
PSMODULE_PUBLISH_PSMODULE_INPUT_MinorLabels: ${{ inputs.MinorLabels }}
PSMODULE_PUBLISH_PSMODULE_INPUT_PatchLabels: ${{ inputs.PatchLabels }}
PSMODULE_PUBLISH_PSMODULE_INPUT_VersionPrefix: ${{ inputs.VersionPrefix }}
PSMODULE_PUBLISH_PSMODULE_INPUT_WhatIf: ${{ inputs.WhatIf }}
run: ${{ github.action_path }}/src/init.ps1

- name: Download module artifact
if: env.PUBLISH_CONTEXT_ShouldPublish == 'true' || inputs.WhatIf == 'true'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: module
path: ${{ inputs.ModulePath }}

- name: Publish Module
if: env.PUBLISH_CONTEXT_ShouldPublish == 'true' || inputs.WhatIf == 'true'
shell: pwsh
working-directory: ${{ inputs.WorkingDirectory }}
env:
Expand All @@ -126,7 +76,7 @@ runs:
run: ${{ github.action_path }}/src/publish.ps1
Comment on lines 59 to 76

- name: Cleanup Prereleases
if: env.PUBLISH_CONTEXT_ShouldCleanup == 'true' || inputs.WhatIf == 'true'
if: inputs.AutoCleanup == 'true' || inputs.WhatIf == 'true'
Comment on lines 78 to +79
shell: pwsh
working-directory: ${{ inputs.WorkingDirectory }}
env:
Expand Down
46 changes: 34 additions & 12 deletions src/cleanup.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,40 @@ $PSStyle.OutputRendering = 'Ansi'

Import-Module -Name 'Helpers' -Force

$prereleaseName = $env:PUBLISH_CONTEXT_PrereleaseName
$prereleaseTagsToCleanup = $env:PUBLISH_CONTEXT_PrereleaseTagsToCleanup
$whatIf = $env:PSMODULE_PUBLISH_PSMODULE_INPUT_WhatIf -eq 'true'
#region Load inputs
LogGroup 'Load inputs' {
$whatIf = $env:PSMODULE_PUBLISH_PSMODULE_INPUT_WhatIf -eq 'true'

if ([string]::IsNullOrWhiteSpace($prereleaseName)) {
Write-Error 'PUBLISH_CONTEXT_PrereleaseName is not set. Run init.ps1 first.'
exit 1
}
$githubEventJson = Get-Content $env:GITHUB_EVENT_PATH
$githubEvent = $githubEventJson | ConvertFrom-Json
$pull_request = $githubEvent.pull_request
if (-not $pull_request) {
throw 'GitHub event does not contain pull_request data. This script must be run from a pull_request event.'
}
$prHeadRef = $pull_request.head.ref
$prereleaseName = $prHeadRef -replace '[^a-zA-Z0-9]'

LogGroup "Cleanup prereleases for [$prereleaseName]" {
if ([string]::IsNullOrWhiteSpace($prereleaseTagsToCleanup)) {
Write-Host "No prereleases found to cleanup for [$prereleaseName]."
if ([string]::IsNullOrWhiteSpace($prereleaseName)) {
Write-Host "No prerelease tag derivable from PR head ref [$prHeadRef]. Nothing to cleanup."
return
}

$tagsToDelete = $prereleaseTagsToCleanup -split ',' | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
Write-Host "PR head ref: [$prHeadRef]"
Write-Host "Prerelease name: [$prereleaseName]"
Write-Host "WhatIf: [$whatIf]"
}
#endregion Load inputs

#region Find prereleases to cleanup
LogGroup "Find prereleases to cleanup for [$prereleaseName]" {
$releases = gh release list --json 'createdAt,isDraft,isLatest,isPrerelease,name,publishedAt,tagName' | ConvertFrom-Json
if ($LASTEXITCODE -ne 0) {
Write-Error 'Failed to list releases for the repository.'
exit $LASTEXITCODE
}

$prereleasesToCleanup = $releases | Where-Object { $_.tagName -like "*$prereleaseName*" }
$tagsToDelete = @($prereleasesToCleanup | ForEach-Object { $_.tagName } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
Comment on lines +34 to +41

if ($tagsToDelete.Count -eq 0) {
Write-Host "No prereleases found to cleanup for [$prereleaseName]."
Expand All @@ -29,8 +47,11 @@ LogGroup "Cleanup prereleases for [$prereleaseName]" {

Write-Host "Found $($tagsToDelete.Count) prereleases to cleanup:"
$tagsToDelete | ForEach-Object { Write-Host " - $_" }
Write-Host ''
}
#endregion Find prereleases to cleanup

#region Delete prereleases
LogGroup "Delete prereleases for [$prereleaseName]" {
foreach ($tag in $tagsToDelete) {
Write-Host "Deleting prerelease: [$tag]"
if ($whatIf) {
Expand All @@ -47,3 +68,4 @@ LogGroup "Cleanup prereleases for [$prereleaseName]" {

Write-Host "::notice::Cleaned up $($tagsToDelete.Count) prerelease(s) for [$prereleaseName]."
}
#endregion Delete prereleases
Loading
Loading