Skip to content

Conversation

@MariusStorhaug
Copy link
Member

@MariusStorhaug MariusStorhaug commented Jan 18, 2026

The action now supports explicit control over the release type through the new ReleaseType input parameter. The AutoCleanup input has been renamed to CleanupPrereleases and cleanup is now handled independently from the release type.

New ReleaseType input parameter

The ReleaseType input accepts the following values:

Value Description
Release Create a stable release (default)
Prerelease Create a prerelease
None Do not create any release

Note: The Cleanup value has been removed. Cleanup is now controlled separately via CleanupPrereleases.

Renamed AutoCleanup to CleanupPrereleases

The AutoCleanup input has been renamed to CleanupPrereleases for clarity. This parameter now directly controls whether old prerelease tags should be cleaned up, independent of the release type.

When CleanupPrereleases is true, old prereleases will be deleted:

  • During a stable release (ReleaseType = Release)
  • When a PR is abandoned (ReleaseType = None but cleanup is needed)

Usage

The inputs work together with Get-PSModuleSettings which pre-calculates both values:

- uses: PSModule/Publish-PSModule@v2
  with:
    APIKey: ${{ secrets.PSGALLERY_API_KEY }}
    ReleaseType: ${{ fromJson(inputs.Settings).Publish.Module.ReleaseType }}
    CleanupPrereleases: ${{ fromJson(inputs.Settings).Publish.Module.CleanupPrereleases }}

Backward compatibility

The ReleaseType parameter defaults to Release, maintaining current behavior for merged PRs targeting the default branch. The CleanupPrereleases parameter defaults to false (the caller is expected to provide the pre-calculated value).

@MariusStorhaug MariusStorhaug changed the title 🚀 [Feature]: Add ReleaseType input to Publish-PSModule for explicit release control 🌟 [Feature]: Make ReleaseType required input for explicit release control Jan 18, 2026
@MariusStorhaug MariusStorhaug changed the title 🌟 [Feature]: Make ReleaseType required input for explicit release control 🌟 [Major]: Make ReleaseType required input for explicit release control Jan 18, 2026
@MariusStorhaug MariusStorhaug changed the title 🌟 [Major]: Make ReleaseType required input for explicit release control 🌟 [Major]: Added ReleaseType input for explicit release control Jan 18, 2026
@MariusStorhaug MariusStorhaug changed the title 🌟 [Major]: Added ReleaseType input for explicit release control 🚀 [Feature]: Add ReleaseType input for explicit release control Jan 18, 2026
@MariusStorhaug MariusStorhaug marked this pull request as ready for review January 18, 2026 00:57
@MariusStorhaug MariusStorhaug requested a review from a team as a code owner January 18, 2026 00:57
Copilot AI review requested due to automatic review settings January 18, 2026 00:57
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new ReleaseType input parameter that provides explicit control over release creation, replacing the previous automatic detection based on pull request state and branch information. The feature enables callers (typically Get-PSModuleSettings) to specify whether to create a Release, Prerelease, Cleanup, or None.

Changes:

  • Added ReleaseType input parameter to action.yml with default value 'Release'
  • Removed automatic detection logic for release types based on PR state, merge status, and target branch
  • Added validation for the ReleaseType parameter with support for four values: Release, Prerelease, Cleanup, None
  • Updated logging to display ReleaseType instead of PR state details

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
action.yml Adds ReleaseType input parameter definition and environment variable mapping
scripts/helpers/Publish-PSModule.ps1 Replaces automatic release type detection with explicit ReleaseType input handling and validation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

MariusStorhaug and others added 2 commits January 18, 2026 02:12
Copilot AI review requested due to automatic review settings January 18, 2026 01:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings January 18, 2026 03:03
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

if ((($closedPullRequest -or $createRelease) -and $autoCleanup) -or $whatIf) {
if ((($isCleanupMode -or $createRelease) -and $autoCleanup) -or $whatIf) {
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition for cleanup includes 'or $whatIf' which means cleanup will always execute in WhatIf mode regardless of ReleaseType or autoCleanup settings. This seems inconsistent - if ReleaseType is 'None' and WhatIf is true, should cleanup still be shown? Consider whether the WhatIf check should be inside the condition rather than ORed with it, or document this behavior explicitly.

Suggested change
if ((($isCleanupMode -or $createRelease) -and $autoCleanup) -or $whatIf) {
if (($isCleanupMode -or $createRelease) -and $autoCleanup) {

Copilot uses AI. Check for mistakes.
@MariusStorhaug MariusStorhaug changed the title 🚀 [Feature]: Add ReleaseType input for explicit release control 🚀 [Feature]: Add ReleaseType input and rename AutoCleanup to CleanupPrereleases Jan 18, 2026
- Remove main.ps1 and split functionality into init.ps1, publish.ps1, and cleanup.ps1 for better organization.
- Implement init.ps1 to handle dependency installation, input loading, and configuration setup.
- Create publish.ps1 to manage module publishing to PSGallery and GitHub releases, including versioning and release notes handling.
- Add cleanup.ps1 to remove old prereleases based on specified tags.
Copilot AI review requested due to automatic review settings January 18, 2026 11:50
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 }}/scripts/init.ps1

Check warning

Code scanning / CodeQL

Code injection Medium

Potential code injection in
${ github.action_path }
, which may be controlled by an external user.

Copilot Autofix

AI 1 minute ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsReleaseName: ${{ inputs.UsePRTitleAsReleaseName }}
PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsNotesHeading: ${{ inputs.UsePRTitleAsNotesHeading }}
run: ${{ github.action_path }}/scripts/main.ps1
run: ${{ github.action_path }}/scripts/publish.ps1

Check warning

Code scanning / CodeQL

Code injection Medium

Potential code injection in
${ github.action_path }
, which may be controlled by an external user.

Copilot Autofix

AI less than a minute ago

In general, to fix code injection issues in GitHub Actions run: steps, avoid embedding expressions like ${{ ... }} directly into the command string. Instead, assign any expression values (even those that are expected to be safe) to environment variables using the workflow syntax, and then reference those variables via the shell’s native variable expansion ($VAR in pwsh/Bash). This separates the expression evaluation phase from the command parsing phase and prevents user-controlled data from being interpreted as code.

For this specific case, the best fix is to add an environment variable (for example, ACTION_PATH) whose value is ${{ github.action_path }}, and then change the run: line to use $env:ACTION_PATH (PowerShell syntax) to build the script path. We will apply this change consistently to all three PowerShell steps that currently use run: ${{ github.action_path }}/scripts/...ps1:

  • “Initialize Publish Context” (line 105)
  • “Publish Module” (line 126)
  • “Cleanup Prereleases” (line 134)

For each step:

  • Add ACTION_PATH: ${{ github.action_path }} under env:.
  • Replace run: ${{ github.action_path }}/scripts/<script>.ps1 with run: $env:ACTION_PATH/scripts/<script>.ps1.

This requires no new imports or external libraries and does not alter the logic of the scripts; it only changes how the script path is passed to PowerShell.

Suggested changeset 1
action.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/action.yml b/action.yml
--- a/action.yml
+++ b/action.yml
@@ -90,6 +90,7 @@
       shell: pwsh
       working-directory: ${{ inputs.WorkingDirectory }}
       env:
+        ACTION_PATH: ${{ github.action_path }}
         PSMODULE_PUBLISH_PSMODULE_INPUT_Name: ${{ inputs.Name }}
         PSMODULE_PUBLISH_PSMODULE_INPUT_CleanupPrereleases: ${{ inputs.CleanupPrereleases }}
         PSMODULE_PUBLISH_PSMODULE_INPUT_AutoPatching: ${{ inputs.AutoPatching }}
@@ -102,7 +103,7 @@
         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 }}/scripts/init.ps1
+      run: $env:ACTION_PATH/scripts/init.ps1
 
     - name: Download module artifact
       if: env.PUBLISH_CONTEXT_ShouldPublish == 'true' || inputs.WhatIf == 'true'
@@ -116,6 +117,7 @@
       shell: pwsh
       working-directory: ${{ inputs.WorkingDirectory }}
       env:
+        ACTION_PATH: ${{ github.action_path }}
         PSMODULE_PUBLISH_PSMODULE_INPUT_Name: ${{ inputs.Name }}
         PSMODULE_PUBLISH_PSMODULE_INPUT_ModulePath: ${{ inputs.ModulePath }}
         PSMODULE_PUBLISH_PSMODULE_INPUT_APIKey: ${{ inputs.APIKey }}
@@ -123,12 +125,13 @@
         PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRBodyAsReleaseNotes: ${{ inputs.UsePRBodyAsReleaseNotes }}
         PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsReleaseName: ${{ inputs.UsePRTitleAsReleaseName }}
         PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsNotesHeading: ${{ inputs.UsePRTitleAsNotesHeading }}
-      run: ${{ github.action_path }}/scripts/publish.ps1
+      run: $env:ACTION_PATH/scripts/publish.ps1
 
     - name: Cleanup Prereleases
       if: env.PUBLISH_CONTEXT_ShouldCleanup == 'true' || inputs.WhatIf == 'true'
       shell: pwsh
       working-directory: ${{ inputs.WorkingDirectory }}
       env:
+        ACTION_PATH: ${{ github.action_path }}
         PSMODULE_PUBLISH_PSMODULE_INPUT_WhatIf: ${{ inputs.WhatIf }}
-      run: ${{ github.action_path }}/scripts/cleanup.ps1
+      run: $env:ACTION_PATH/scripts/cleanup.ps1
EOF
@@ -90,6 +90,7 @@
shell: pwsh
working-directory: ${{ inputs.WorkingDirectory }}
env:
ACTION_PATH: ${{ github.action_path }}
PSMODULE_PUBLISH_PSMODULE_INPUT_Name: ${{ inputs.Name }}
PSMODULE_PUBLISH_PSMODULE_INPUT_CleanupPrereleases: ${{ inputs.CleanupPrereleases }}
PSMODULE_PUBLISH_PSMODULE_INPUT_AutoPatching: ${{ inputs.AutoPatching }}
@@ -102,7 +103,7 @@
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 }}/scripts/init.ps1
run: $env:ACTION_PATH/scripts/init.ps1

- name: Download module artifact
if: env.PUBLISH_CONTEXT_ShouldPublish == 'true' || inputs.WhatIf == 'true'
@@ -116,6 +117,7 @@
shell: pwsh
working-directory: ${{ inputs.WorkingDirectory }}
env:
ACTION_PATH: ${{ github.action_path }}
PSMODULE_PUBLISH_PSMODULE_INPUT_Name: ${{ inputs.Name }}
PSMODULE_PUBLISH_PSMODULE_INPUT_ModulePath: ${{ inputs.ModulePath }}
PSMODULE_PUBLISH_PSMODULE_INPUT_APIKey: ${{ inputs.APIKey }}
@@ -123,12 +125,13 @@
PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRBodyAsReleaseNotes: ${{ inputs.UsePRBodyAsReleaseNotes }}
PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsReleaseName: ${{ inputs.UsePRTitleAsReleaseName }}
PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsNotesHeading: ${{ inputs.UsePRTitleAsNotesHeading }}
run: ${{ github.action_path }}/scripts/publish.ps1
run: $env:ACTION_PATH/scripts/publish.ps1

- name: Cleanup Prereleases
if: env.PUBLISH_CONTEXT_ShouldCleanup == 'true' || inputs.WhatIf == 'true'
shell: pwsh
working-directory: ${{ inputs.WorkingDirectory }}
env:
ACTION_PATH: ${{ github.action_path }}
PSMODULE_PUBLISH_PSMODULE_INPUT_WhatIf: ${{ inputs.WhatIf }}
run: ${{ github.action_path }}/scripts/cleanup.ps1
run: $env:ACTION_PATH/scripts/cleanup.ps1
Copilot is powered by AI and may make mistakes. Always verify output.
working-directory: ${{ inputs.WorkingDirectory }}
env:
PSMODULE_PUBLISH_PSMODULE_INPUT_WhatIf: ${{ inputs.WhatIf }}
run: ${{ github.action_path }}/scripts/cleanup.ps1

Check warning

Code scanning / CodeQL

Code injection Medium

Potential code injection in
${ github.action_path }
, which may be controlled by an external user.

Copilot Autofix

AI 1 minute ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +223 to +238
Set-GitHubLogGroup 'Calculate new version' {
# - Increment based on label on PR
$newVersion = New-PSSemVer -Version $latestVersion
$newVersion.Prefix = $versionPrefix
if ($majorRelease) {
Write-Output 'Incrementing major version.'
$newVersion.BumpMajor()
} elseif ($minorRelease) {
Write-Output 'Incrementing minor version.'
$newVersion.BumpMinor()
} elseif ($patchRelease) {
Write-Output 'Incrementing patch version.'
$newVersion.BumpPatch()
} else {
Write-Output 'No version bump required.'
}
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When ReleaseType is 'None' and no version bump is found, the code still attempts to calculate a new version (lines 225-238) even though shouldPublish is false. This could lead to an incomplete or invalid version being stored in environment variables. The version calculation logic should be skipped entirely when shouldPublish is false, or the code should handle this case explicitly to avoid storing invalid version information.

Copilot uses AI. Check for mistakes.
Comment on lines +242 to +295
if ($createPrerelease -and $hasVersionBump) {
Write-Output "Adding a prerelease tag to the version using the branch name [$prereleaseName]."
Write-Output ($releases | Where-Object { $_.tagName -like "*$prereleaseName*" } |
Select-Object -Property name, isPrerelease, isLatest, publishedAt | Format-Table -AutoSize | Out-String)

$newVersion.Prerelease = $prereleaseName
Write-Output "Partial new version: [$newVersion]"

if (-not [string]::IsNullOrEmpty($datePrereleaseFormat)) {
Write-Output "Using date-based prerelease: [$datePrereleaseFormat]."
$newVersion.Prerelease += "$(Get-Date -Format $datePrereleaseFormat)"
Write-Output "Partial new version: [$newVersion]"
}

if ($incrementalPrerelease) {
# Find the latest prerelease version
$newVersionString = "$($newVersion.Major).$($newVersion.Minor).$($newVersion.Patch)"

# PowerShell Gallery
$params = @{
Name = $name
Version = '*'
Prerelease = $true
Repository = 'PSGallery'
Verbose = $false
ErrorAction = 'SilentlyContinue'
}
Write-Output 'Finding the latest prerelease version in the PowerShell Gallery.'
Write-Output ($params | Format-Table | Out-String)
$psGalleryPrereleases = Find-PSResource @params
$psGalleryPrereleases = $psGalleryPrereleases | Where-Object { $_.Version -like "$newVersionString" }
$psGalleryPrereleases = $psGalleryPrereleases | Where-Object { $_.Prerelease -like "$prereleaseName*" }
$latestPSGalleryPrerelease = $psGalleryPrereleases.Prerelease | ForEach-Object {
[int]($_ -replace $prereleaseName)
} | Sort-Object | Select-Object -Last 1
Write-Output "PSGallery prerelease: [$latestPSGalleryPrerelease]"

# GitHub
$ghPrereleases = $releases | Where-Object { $_.tagName -like "*$newVersionString*" }
$ghPrereleases = $ghPrereleases | Where-Object { $_.tagName -like "*$prereleaseName*" }
$latestGHPrereleases = $ghPrereleases.tagName | ForEach-Object {
$number = $_
$number = $number -replace '\.'
$number = ($number -split $prereleaseName, 2)[-1]
[int]$number
} | Sort-Object | Select-Object -Last 1
Write-Output "GitHub prerelease: [$latestGHPrereleases]"

$latestPrereleaseNumber = [Math]::Max($latestPSGalleryPrerelease, $latestGHPrereleases)
$latestPrereleaseNumber++
$latestPrereleaseNumber = ([string]$latestPrereleaseNumber).PadLeft(3, '0')
$newVersion.Prerelease += $latestPrereleaseNumber
}
}
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition $createPrerelease -and $hasVersionBump on line 242 means prerelease information is only added when there's a version bump. However, when ReleaseType is 'None', createPrerelease is false and hasVersionBump might also be false. The entire prerelease calculation block (lines 242-295) could be executed unnecessarily or with incomplete data. This should be guarded by checking shouldPublish first to avoid unnecessary computation.

Copilot uses AI. Check for mistakes.
$whatIf = $env:PSMODULE_PUBLISH_PSMODULE_INPUT_WhatIf -eq 'true'

if ([string]::IsNullOrWhiteSpace($prereleaseName)) {
Write-Error 'PUBLISH_CONTEXT_PrereleaseName is not set. Run main.ps1 first.'
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message incorrectly refers to 'main.ps1' when it should refer to 'init.ps1'. The cleanup.ps1 script requires context from init.ps1, not main.ps1 (which has been removed in this PR).

Suggested change
Write-Error 'PUBLISH_CONTEXT_PrereleaseName is not set. Run main.ps1 first.'
Write-Error 'PUBLISH_CONTEXT_PrereleaseName is not set. Run init.ps1 first.'

Copilot uses AI. Check for mistakes.
$usePRTitleAsNotesHeading = $env:PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsNotesHeading -eq 'true'

if ([string]::IsNullOrWhiteSpace($newVersionString)) {
Write-Error 'PUBLISH_CONTEXT_NewVersion is not set. Run main.ps1 first.'
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message incorrectly refers to 'main.ps1' when it should refer to 'init.ps1'. The publish.ps1 script requires context from init.ps1, not main.ps1 (which has been removed in this PR).

Suggested change
Write-Error 'PUBLISH_CONTEXT_NewVersion is not set. Run main.ps1 first.'
Write-Error 'PUBLISH_CONTEXT_NewVersion is not set. Run init.ps1 first.'

Copilot uses AI. Check for mistakes.
AutoCleanup:
description: Control wether to automatically delete the prerelease tags after the stable release is created.
CleanupPrereleases:
description: When enabled, only performs cleanup of old prerelease tags without creating a new release or publishing to PSGallery.
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description for CleanupPrereleases is misleading. According to the PR description and the code logic, CleanupPrereleases controls whether to delete old prerelease tags, not whether to "only perform cleanup without creating a new release". The cleanup can happen alongside publishing (when ReleaseType is Release) or independently (when ReleaseType is None). The description should be updated to clarify that it controls whether old prerelease tags are cleaned up.

Suggested change
description: When enabled, only performs cleanup of old prerelease tags without creating a new release or publishing to PSGallery.
description: When enabled, cleans up old prerelease tags after processing. This cleanup can run together with publishing a release (when ReleaseType is 'Release') or on its own when ReleaseType is 'None'.

Copilot uses AI. Check for mistakes.
default: 'true'
default: 'false'
AutoPatching:
description: Control wether to automatically handle patches. If disabled, the action will only create a patch release if the pull request has a 'patch' label.
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: "wether" should be "whether" in the description.

Copilot uses AI. Check for mistakes.

# Check if any version bump applies
$hasVersionBump = $majorRelease -or $minorRelease -or $patchRelease
if (-not $hasVersionBump) {
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a potential bug when ReleaseType is 'None'. The code sets shouldPublish to false when there's no version bump (line 139), but it doesn't check whether ReleaseType is 'None' before checking for version bumps. However, when ReleaseType is 'None', no version bump is needed since no release is being created. The logic should skip the version bump check entirely when ReleaseType is 'None', or handle it differently to avoid misleading output.

Suggested change
if (-not $hasVersionBump) {
if ($shouldPublish -and -not $hasVersionBump) {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Add ReleaseType input to Publish-PSModule for explicit release control

2 participants