diff --git a/.github/linters/.jscpd.json b/.github/linters/.jscpd.json index 23970e8..754ec0c 100644 --- a/.github/linters/.jscpd.json +++ b/.github/linters/.jscpd.json @@ -4,7 +4,8 @@ "consoleFull" ], "ignore": [ - "**/tests/**" + "**/tests/**", + "**/scripts/**" ], "absolute": true } diff --git a/.github/workflows/Action-Test.yml b/.github/workflows/Action-Test.yml index c40d2e0..c739f89 100644 --- a/.github/workflows/Action-Test.yml +++ b/.github/workflows/Action-Test.yml @@ -22,11 +22,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Action-Test uses: ./ - env: - GITHUB_TOKEN: ${{ github.token }} with: WhatIf: true diff --git a/.github/workflows/Auto-Release.yml b/.github/workflows/Auto-Release.yml index 9cd0c64..81e3a3d 100644 --- a/.github/workflows/Auto-Release.yml +++ b/.github/workflows/Auto-Release.yml @@ -26,11 +26,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Auto-Release uses: ./ - env: - GITHUB_TOKEN: ${{ github.token }} # Used for GitHub CLI authentication with: IncrementalPrerelease: false diff --git a/.github/workflows/Linter.yml b/.github/workflows/Linter.yml index 1f677cb..94f34b0 100644 --- a/.github/workflows/Linter.yml +++ b/.github/workflows/Linter.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 diff --git a/README.md b/README.md index 58e3159..a892a3e 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Automatically creates releases based on pull requests and labels. + ## Specifications and practices Auto-Release follows: @@ -31,6 +32,7 @@ When a pull request is closed, the action will create a release based on the lab > 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: @@ -48,6 +50,9 @@ The action can be configured using the following settings: | `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 wether to simulate the action. If enabled, the action will not create any releases. Used for testing. | `false` | false | | `Debug` | Enable debug output. | `'false'` | false | @@ -100,8 +105,6 @@ jobs: - name: Auto-Release uses: PSModule/Auto-Release@v1 - env: - GITHUB_TOKEN: ${{ github.token }} # Used for GitHub CLI authentication ``` ## Permissions diff --git a/action.yml b/action.yml index 2453f28..1d719ea 100644 --- a/action.yml +++ b/action.yml @@ -50,6 +50,18 @@ inputs: 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 + default: 'false' + UsePRBodyAsReleaseNotes: + description: When enabled, uses the pull request body as the release notes for the GitHub release. + required: false + default: 'true' + UsePRTitleAsNotesHeading: + description: 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 reference the pull request number. + required: false + default: 'true' VersionPrefix: description: The prefix to use for the version number. required: false @@ -95,6 +107,9 @@ runs: 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 }} PSMODULE_AUTO_RELEASE_INPUT_VersionPrefix: ${{ inputs.VersionPrefix }} PSMODULE_AUTO_RELEASE_INPUT_WhatIf: ${{ inputs.WhatIf }} with: @@ -102,6 +117,7 @@ runs: Prerelease: ${{ inputs.Prerelease }} Verbose: ${{ inputs.Verbose }} Version: ${{ inputs.Version }} + Name: Auto-Release WorkingDirectory: ${{ inputs.WorkingDirectory }} Script: | # Auto-Release diff --git a/scripts/main.ps1 b/scripts/main.ps1 index d9d5f63..089a75f 100644 --- a/scripts/main.ps1 +++ b/scripts/main.ps1 @@ -9,29 +9,28 @@ param() LogGroup 'Loading libraries' { - 'Utilities', 'powershell-yaml', 'PSSemVer' | ForEach-Object { + 'powershell-yaml', 'PSSemVer' | ForEach-Object { $name = $_ + Write-Output "Installing module: $name" $count = 5 $delay = 10 for ($i = 1; $i -le $count; $i++) { try { - Install-PSResource -Name $name -TrustRepository -ErrorAction Stop + Install-PSResource -Name $name -WarningAction SilentlyContinue -TrustRepository -Repository PSGallery break } catch { - Write-Warning $_.Exception.Message + Write-Warning "Installation of $name failed with error: $_" if ($i -eq $count) { throw $_ } + Write-Warning "Retrying in $delay seconds..." Start-Sleep -Seconds $delay } } + Import-Module -Name $name } } -LogGroup 'Environment variables' { - Get-ChildItem -Path Env: | Select-Object Name, Value | Sort-Object Name | Format-Table -AutoSize | Out-String -} - LogGroup 'Set configuration' { if (-not (Test-Path -Path $env:PSMODULE_AUTO_RELEASE_INPUT_ConfigurationFile -PathType Leaf)) { Write-Output "Configuration file not found at [$env:PSMODULE_AUTO_RELEASE_INPUT_ConfigurationFile]" @@ -40,19 +39,22 @@ LogGroup 'Set configuration' { $configuration = ConvertFrom-Yaml -Yaml (Get-Content $env:PSMODULE_AUTO_RELEASE_INPUT_ConfigurationFile -Raw) } - $autoCleanup = ($configuration.AutoCleanup | IsNotNullOrEmpty) ? $configuration.AutoCleanup -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_AutoCleanup -eq 'true' - $autoPatching = ($configuration.AutoPatching | IsNotNullOrEmpty) ? $configuration.AutoPatching -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_AutoPatching -eq 'true' - $createMajorTag = ($configuration.CreateMajorTag | IsNotNullOrEmpty) ? $configuration.CreateMajorTag -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_CreateMajorTag -eq 'true' - $createMinorTag = ($configuration.CreateMinorTag | IsNotNullOrEmpty) ? $configuration.CreateMinorTag -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_CreateMinorTag -eq 'true' - $datePrereleaseFormat = ($configuration.DatePrereleaseFormat | IsNotNullOrEmpty) ? $configuration.DatePrereleaseFormat : $env:PSMODULE_AUTO_RELEASE_INPUT_DatePrereleaseFormat - $incrementalPrerelease = ($configuration.IncrementalPrerelease | IsNotNullOrEmpty) ? $configuration.IncrementalPrerelease -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_IncrementalPrerelease -eq 'true' - $versionPrefix = ($configuration.VersionPrefix | IsNotNullOrEmpty) ? $configuration.VersionPrefix : $env:PSMODULE_AUTO_RELEASE_INPUT_VersionPrefix - $whatIf = ($configuration.WhatIf | IsNotNullOrEmpty) ? $configuration.WhatIf -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_WhatIf -eq 'true' - - $ignoreLabels = (($configuration.IgnoreLabels | IsNotNullOrEmpty) ? $configuration.IgnoreLabels : $env:PSMODULE_AUTO_RELEASE_INPUT_IgnoreLabels) -split ',' | ForEach-Object { $_.Trim() } - $majorLabels = (($configuration.MajorLabels | IsNotNullOrEmpty) ? $configuration.MajorLabels : $env:PSMODULE_AUTO_RELEASE_INPUT_MajorLabels) -split ',' | ForEach-Object { $_.Trim() } - $minorLabels = (($configuration.MinorLabels | IsNotNullOrEmpty) ? $configuration.MinorLabels : $env:PSMODULE_AUTO_RELEASE_INPUT_MinorLabels) -split ',' | ForEach-Object { $_.Trim() } - $patchLabels = (($configuration.PatchLabels | IsNotNullOrEmpty) ? $configuration.PatchLabels : $env:PSMODULE_AUTO_RELEASE_INPUT_PatchLabels) -split ',' | ForEach-Object { $_.Trim() } + $autoCleanup = ![string]::IsNullOrEmpty($configuration.AutoCleanup) ? $configuration.AutoCleanup -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_AutoCleanup -eq 'true' + $autoPatching = ![string]::IsNullOrEmpty($configuration.AutoPatching) ? $configuration.AutoPatching -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_AutoPatching -eq 'true' + $createMajorTag = ![string]::IsNullOrEmpty($configuration.CreateMajorTag) ? $configuration.CreateMajorTag -EQ 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_CreateMajorTag -EQ 'true' + $createMinorTag = ![string]::IsNullOrEmpty($configuration.CreateMinorTag) ? $configuration.CreateMinorTag -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_CreateMinorTag -eq 'true' + $datePrereleaseFormat = ![string]::IsNullOrEmpty($configuration.DatePrereleaseFormat) ? $configuration.DatePrereleaseFormat : $env:PSMODULE_AUTO_RELEASE_INPUT_DatePrereleaseFormat + $incrementalPrerelease = ![string]::IsNullOrEmpty($configuration.IncrementalPrerelease) ? $configuration.IncrementalPrerelease -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_IncrementalPrerelease -eq 'true' + $usePRBodyAsReleaseNotes = ![string]::IsNullOrEmpty($configuration.UsePRBodyAsReleaseNotes) ? $configuration.UsePRBodyAsReleaseNotes -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_UsePRBodyAsReleaseNotes -eq 'true' + $usePRTitleAsReleaseName = ![string]::IsNullOrEmpty($configuration.UsePRTitleAsReleaseName) ? $configuration.UsePRTitleAsReleaseName -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_UsePRTitleAsReleaseName -eq 'true' + $usePRTitleAsNotesHeading = ![string]::IsNullOrEmpty($configuration.UsePRTitleAsNotesHeading) ? $configuration.UsePRTitleAsNotesHeading -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_UsePRTitleAsNotesHeading -eq 'true' + $versionPrefix = ![string]::IsNullOrEmpty($configuration.VersionPrefix) ? $configuration.VersionPrefix : $env:PSMODULE_AUTO_RELEASE_INPUT_VersionPrefix + $whatIf = ![string]::IsNullOrEmpty($configuration.WhatIf) ? $configuration.WhatIf -eq 'true' : $env:PSMODULE_AUTO_RELEASE_INPUT_WhatIf -eq 'true' + + $ignoreLabels = (![string]::IsNullOrEmpty($configuration.IgnoreLabels) ? $configuration.IgnoreLabels : $env:PSMODULE_AUTO_RELEASE_INPUT_IgnoreLabels) -split ',' | ForEach-Object { $_.Trim() } + $majorLabels = (![string]::IsNullOrEmpty($configuration.MajorLabels) ? $configuration.MajorLabels : $env:PSMODULE_AUTO_RELEASE_INPUT_MajorLabels) -split ',' | ForEach-Object { $_.Trim() } + $minorLabels = (![string]::IsNullOrEmpty($configuration.MinorLabels) ? $configuration.MinorLabels : $env:PSMODULE_AUTO_RELEASE_INPUT_MinorLabels) -split ',' | ForEach-Object { $_.Trim() } + $patchLabels = (![string]::IsNullOrEmpty($configuration.PatchLabels) ? $configuration.PatchLabels : $env:PSMODULE_AUTO_RELEASE_INPUT_PatchLabels) -split ',' | ForEach-Object { $_.Trim() } Write-Output '-------------------------------------------------' Write-Output "Auto cleanup enabled: [$autoCleanup]" @@ -61,6 +63,9 @@ LogGroup 'Set configuration' { Write-Output "Create minor tag enabled: [$createMinorTag]" Write-Output "Date-based prerelease format: [$datePrereleaseFormat]" Write-Output "Incremental prerelease enabled: [$incrementalPrerelease]" + Write-Output "Use PR body as release notes: [$usePRBodyAsReleaseNotes]" + Write-Output "Use PR title as release name: [$usePRTitleAsReleaseName]" + Write-Output "Use PR title as notes heading: [$usePRTitleAsNotesHeading]" Write-Output "Version prefix: [$versionPrefix]" Write-Output "What if mode: [$whatIf]" Write-Output '' @@ -157,7 +162,7 @@ LogGroup 'Get latest version' { $latestRelease = $releases | Where-Object { $_.isLatest -eq $true } $latestRelease | Format-List | Out-String $latestVersionString = $latestRelease.tagName - if ($latestVersionString | IsNotNullOrEmpty) { + if (![string]::IsNullOrEmpty($latestVersionString)) { $latestVersion = $latestVersionString | ConvertTo-PSSemVer Write-Output '-------------------------------------------------' Write-Output 'Latest version:' @@ -196,7 +201,7 @@ if ($createPrerelease -or $createRelease -or $whatIf) { $newVersion.Prerelease = $prereleaseName Write-Output "Partial new version: [$newVersion]" - if ($datePrereleaseFormat | IsNotNullOrEmpty) { + if (![string]::IsNullOrEmpty($datePrereleaseFormat)) { Write-Output "Using date-based prerelease: [$datePrereleaseFormat]." $newVersion.Prerelease += ".$(Get-Date -Format $datePrereleaseFormat)" Write-Output "Partial new version: [$newVersion]" @@ -227,10 +232,42 @@ if ($createPrerelease -or $createRelease -or $whatIf) { } } - if ($whatIf) { - Write-Output "WhatIf: gh release create $newVersion --title $newVersion --target $prHeadRef --generate-notes --prerelease" + # Build release creation command with options + $releaseCreateCommand = @('release', 'create', "$newVersion") + + # Add title parameter + if ($usePRTitleAsReleaseName) { + $prTitle = $pull_request.title + $releaseCreateCommand += @('--title', "$prTitle") + Write-Output "Using PR title as release name: [$prTitle]" } else { - $releaseURL = gh release create $newVersion --title $newVersion --target $prHeadRef --generate-notes --prerelease + $releaseCreateCommand += @('--title', "$newVersion") + } + + # Add notes parameter + $notes = '' + if ($usePRTitleAsNotesHeading) { + $prTitle = $pull_request.title + $prNumber = $pull_request.number + $notes += "# $prTitle (#$prNumber)`n`n" + } + if ($usePRBodyAsReleaseNotes) { + $prBody = $pull_request.body + $notes += $prBody + } + if (-not [string]::IsNullOrWhiteSpace($notes)) { + $releaseCreateCommand += @('--notes', $notes) + } else { + $releaseCreateCommand += '--generate-notes' + } + + # Add remaining parameters + $releaseCreateCommand += @('--target', $prHeadRef, '--prerelease') + + Write-Output "gh $($releaseCreateCommand -join ' ')" + if (-not $whatIf) { + # Execute the command and capture the output + $releaseURL = gh @releaseCreateCommand if ($LASTEXITCODE -ne 0) { Write-Error "Failed to create the release [$newVersion]." exit $LASTEXITCODE @@ -247,10 +284,38 @@ if ($createPrerelease -or $createRelease -or $whatIf) { } } } else { - if ($whatIf) { - Write-Output "WhatIf: gh release create $newVersion --title $newVersion --generate-notes" + # Build release creation command with options + $releaseCreateCommand = @('release', 'create', "$newVersion") + + # Add title parameter + if ($usePRTitleAsReleaseName) { + $prTitle = $pull_request.title + $releaseCreateCommand += @('--title', "$prTitle") + Write-Output "Using PR title as release name: [$prTitle]" + } else { + $releaseCreateCommand += @('--title', "$newVersion") + } + + # Add notes parameter + $notes = '' + if ($usePRTitleAsNotesHeading) { + $prTitle = $pull_request.title + $prNumber = $pull_request.number + $notes += "# $prTitle (#$prNumber)`n`n" + } + if ($usePRBodyAsReleaseNotes) { + $prBody = $pull_request.body + $notes += $prBody + } + if (-not [string]::IsNullOrWhiteSpace($notes)) { + $releaseCreateCommand += @('--notes', $notes) } else { - gh release create $newVersion --title $newVersion --generate-notes + $releaseCreateCommand += '--generate-notes' + } + + Write-Output "gh $($releaseCreateCommand -join ' ')" + if (-not $whatIf) { + gh @releaseCreateCommand if ($LASTEXITCODE -ne 0) { Write-Error "Failed to create the release [$newVersion]." exit $LASTEXITCODE