Skip to content

Commit 6dfddf4

Browse files
🩹 [Patch]: Actions are internalized and automatically follow the workflow version (#385)
When you reference Process-PSModule at a release tag, run it from a branch during development, or test it from a fork, the actions it calls now automatically match that same version. There's no more keeping a workflow and its actions in sync by hand — pin the workflow, and the actions follow. - Fixes #384 ## New: Actions automatically follow the workflow version in use Every stage workflow now checks out its own source at the exact commit it is running from, then calls its actions from that local copy instead of a separately pinned action reference. In practice this means: - Reference a release tag → you get that tag's actions. - Run a development branch → the branch's actions run together with it, with no separate action release or pin update needed to test a change. - Fork the repository → your fork's actions are used, not upstream's. This is possible using `job.workflow_repository` and `job.workflow_sha`, a set of GitHub Actions context properties that let a reusable workflow discover its own source repository and commit. This capability did not exist before — it was introduced by GitHub in April 2026 (shipped in [Actions Runner v2.334.0](https://github.com/actions/runner/releases/tag/v2.334.0), see [actions/runner#4335](actions/runner#4335)) and is documented in the [`job` context reference](https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#job-context). No official GitHub changelog announcement could be found for this change — the runner release and context documentation are the primary references. `GitHub-Script`, `Invoke-Pester`, and `Invoke-ScriptAnalyzer` continue to be consumed from their own repositories at pinned commits, as before. No changes are required to consumer workflows. Inputs, outputs, and secrets are unchanged. ## Changed: Internalized actions have moved out of their standalone repositories `Build-PSModule`, `Document-PSModule`, `Get-PSModuleSettings`, `Get-PesterCodeCoverage`, `Get-PesterTestResults`, `Initialize-PSModule`, `Install-PSModuleHelpers`, `Publish-PSModule`, `Resolve-PSModuleVersion`, and `Test-PSModule` now ship directly inside Process-PSModule instead of living in their own PSModule repositories. Those standalone repositories are now archived and will be deleted soon. If you reference any of them directly, switch to Process-PSModule instead. The old actions will also be the ones older versions of Process-PSModule will use, so be sure to update to be able to use the framework. ## Technical Details - Ten composite actions are now bundled under `.github/actions/`: `Build-PSModule`, `Document-PSModule`, `Get-PSModuleSettings`, `Get-PesterCodeCoverage`, `Get-PesterTestResults`, `Initialize-PSModule`, `Install-PSModuleHelpers`, `Publish-PSModule`, `Resolve-PSModuleVersion`, `Test-PSModule`. - All stage workflows add a self-checkout step before any action call: `repository: ${{ job.workflow_repository }}`, `ref: ${{ job.workflow_sha }}`, `path: _wf`. - Action call sites change from `PSModule/<Name>@<sha>` to `./_wf/.github/actions/<Name>`. - Nested dependencies on `Install-PSModuleHelpers` resolve from the same bundled revision. - `.github/actionlint.yaml` is updated to recognize the self-checkout pattern and the `job.workflow_*` properties. - Action READMEs and test-suite consolidation are out of scope for this change. **Validation** - [MariusTestModule SHA-pinned consumer run](https://github.com/MariusStorhaug/MariusTestModule/actions/runs/29379826692) passed. - [MariusTestModule ref-based consumer run](https://github.com/MariusStorhaug/MariusTestModule/actions/runs/29380061013) passed and resolved `feat/internalize-process-actions` to the invoked workflow commit.
1 parent 3211236 commit 6dfddf4

294 files changed

Lines changed: 17212 additions & 396 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Build-PSModule
2+
description: Build a PowerShell module to the PowerShell Gallery.
3+
author: PSModule
4+
5+
inputs:
6+
Name:
7+
description: Name of the module to build. Defaults to the repository name.
8+
required: false
9+
OutputFolder:
10+
description: Path to the folder where the built module is outputted.
11+
required: false
12+
default: 'outputs/module'
13+
Version:
14+
description: Module version to stamp into the manifest.
15+
required: true
16+
Prerelease:
17+
description: Prerelease tag to stamp into the manifest's `PrivateData.PSData.Prerelease`. When empty, no prerelease tag is written.
18+
required: false
19+
ArtifactName:
20+
description: Name of the artifact to upload.
21+
required: false
22+
default: module
23+
WorkingDirectory:
24+
description: The working directory where the script will run from.
25+
required: false
26+
default: '.'
27+
28+
runs:
29+
using: composite
30+
steps:
31+
- name: Install-PSModuleHelpers
32+
uses: ./_wf/.github/actions/Install-PSModuleHelpers
33+
34+
- name: Run Build-PSModule
35+
shell: pwsh
36+
id: build
37+
working-directory: ${{ inputs.WorkingDirectory }}
38+
env:
39+
PSMODULE_BUILD_PSMODULE_INPUT_Name: ${{ inputs.Name }}
40+
PSMODULE_BUILD_PSMODULE_INPUT_OutputFolder: ${{ inputs.OutputFolder }}
41+
PSMODULE_BUILD_PSMODULE_INPUT_Version: ${{ inputs.Version }}
42+
PSMODULE_BUILD_PSMODULE_INPUT_Prerelease: ${{ inputs.Prerelease }}
43+
run: |
44+
# Build-PSModule
45+
${{ github.action_path }}/src/main.ps1
46+
47+
- name: Upload module artifact
48+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
49+
with:
50+
name: ${{ inputs.ArtifactName }}
51+
path: ${{ steps.build.outputs.ModuleOutputFolderPath }}
52+
if-no-files-found: error
53+
retention-days: 1
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
function Build-PSModule {
2+
<#
3+
.SYNOPSIS
4+
Builds a module.
5+
6+
.DESCRIPTION
7+
Builds a module.
8+
#>
9+
[OutputType([void])]
10+
[CmdletBinding()]
11+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
12+
'PSReviewUnusedParameter', '', Scope = 'Function',
13+
Justification = 'LogGroup - Scoping affects the variables line of sight.'
14+
)]
15+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
16+
'PSAvoidUsingWriteHost', '', Scope = 'Function',
17+
Justification = 'Want to just write to the console, not the pipeline.'
18+
)]
19+
param(
20+
# Name of the module.
21+
[Parameter(Mandatory)]
22+
[string] $ModuleName,
23+
24+
# Path to the folder where the modules are located.
25+
[Parameter(Mandatory)]
26+
[string] $ModuleSourceFolderPath,
27+
28+
# Path to the folder where the built modules are outputted.
29+
[Parameter(Mandatory)]
30+
[string] $ModuleOutputFolderPath,
31+
32+
# Module version to stamp into the manifest.
33+
[Parameter(Mandatory)]
34+
[string] $ModuleVersion,
35+
36+
# Prerelease tag to stamp into the manifest. When empty, no prerelease tag is written.
37+
[Parameter()]
38+
[string] $ModulePrerelease
39+
)
40+
41+
Set-GitHubLogGroup "Building module [$ModuleName]" {
42+
$moduleSourceFolder = Get-Item -Path $ModuleSourceFolderPath
43+
$moduleOutputFolder = New-Item -Path $ModuleOutputFolderPath -Name $ModuleName -ItemType Directory -Force
44+
[pscustomobject]@{
45+
ModuleSourceFolderPath = $moduleSourceFolder
46+
ModuleOutputFolderPath = $moduleOutputFolder
47+
} | Format-List | Out-String
48+
}
49+
50+
Build-PSModuleBase -ModuleName $ModuleName -ModuleSourceFolder $moduleSourceFolder -ModuleOutputFolder $moduleOutputFolder
51+
Build-PSModuleManifest -ModuleName $ModuleName -ModuleOutputFolder $moduleOutputFolder `
52+
-ModuleVersion $ModuleVersion -ModulePrerelease $ModulePrerelease
53+
Build-PSModuleRootModule -ModuleName $ModuleName -ModuleOutputFolder $moduleOutputFolder
54+
Update-PSModuleManifestAliasesToExport -ModuleName $ModuleName -ModuleSourceFolder $moduleSourceFolder -ModuleOutputFolder $moduleOutputFolder
55+
56+
Set-GitHubLogGroup 'Build manifest file - Final Result' {
57+
$outputManifestPath = Join-Path -Path $ModuleOutputFolder -ChildPath "$ModuleName.psd1"
58+
Show-FileContent -Path $outputManifestPath
59+
}
60+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
function Add-ContentFromItem {
2+
<#
3+
.SYNOPSIS
4+
Add the content of a folder or file to the root module file.
5+
6+
.DESCRIPTION
7+
This function will add the content of a folder or file to the root module file.
8+
9+
.EXAMPLE
10+
Add-ContentFromItem -Path 'C:\MyModule\src\MyModule' -RootModuleFilePath 'C:\MyModule\src\MyModule.psm1' -RootPath 'C:\MyModule\src'
11+
#>
12+
param(
13+
# The path to the folder or file to process.
14+
[Parameter(Mandatory)]
15+
[string] $Path,
16+
17+
# The path to the root module file.
18+
[Parameter(Mandatory)]
19+
[string] $RootModuleFilePath,
20+
21+
# The root path of the module.
22+
[Parameter(Mandatory)]
23+
[string] $RootPath
24+
)
25+
# Get the path separator for the current OS
26+
$pathSeparator = [System.IO.Path]::DirectorySeparatorChar
27+
28+
$relativeFolderPath = $Path -replace $RootPath, ''
29+
$relativeFolderPath = $relativeFolderPath -replace $file.Extension, ''
30+
$relativeFolderPath = $relativeFolderPath.TrimStart($pathSeparator)
31+
$relativeFolderPath = $relativeFolderPath -split $pathSeparator | ForEach-Object { "[$_]" }
32+
$relativeFolderPath = $relativeFolderPath -join ' - '
33+
34+
Add-Content -Path $RootModuleFilePath -Force -Value @"
35+
#region $relativeFolderPath
36+
Write-Debug "[`$scriptName] - $relativeFolderPath - Processing folder"
37+
"@
38+
39+
$files = $Path | Get-ChildItem -File -Force -Filter '*.ps1' | Sort-Object -Property FullName
40+
foreach ($file in $files) {
41+
$relativeFilePath = $file.FullName -replace $RootPath, ''
42+
$relativeFilePath = $relativeFilePath -replace $file.Extension, ''
43+
$relativeFilePath = $relativeFilePath.TrimStart($pathSeparator)
44+
$relativeFilePath = $relativeFilePath -split $pathSeparator | ForEach-Object { "[$_]" }
45+
$relativeFilePath = $relativeFilePath -join ' - '
46+
47+
Add-Content -Path $RootModuleFilePath -Force -Value @"
48+
#region $relativeFilePath
49+
Write-Debug "[`$scriptName] - $relativeFilePath - Importing"
50+
"@
51+
Get-Content -Path $file.FullName | Add-Content -Path $RootModuleFilePath -Force
52+
Add-Content -Path $RootModuleFilePath -Value @"
53+
Write-Debug "[`$scriptName] - $relativeFilePath - Done"
54+
#endregion $relativeFilePath
55+
"@
56+
}
57+
58+
$subFolders = $Path | Get-ChildItem -Directory -Force | Sort-Object -Property Name
59+
foreach ($subFolder in $subFolders) {
60+
Add-ContentFromItem -Path $subFolder.FullName -RootModuleFilePath $RootModuleFilePath -RootPath $RootPath
61+
}
62+
Add-Content -Path $RootModuleFilePath -Force -Value @"
63+
Write-Debug "[`$scriptName] - $relativeFolderPath - Done"
64+
#endregion $relativeFolderPath
65+
"@
66+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
function Build-PSModuleBase {
2+
<#
3+
.SYNOPSIS
4+
Compiles the base module files.
5+
6+
.DESCRIPTION
7+
This function will compile the base module files.
8+
It will copy the source files to the output folder and remove the files that are not needed.
9+
10+
.EXAMPLE
11+
Build-PSModuleBase -SourceFolderPath 'C:\MyModule\src\MyModule' -OutputFolderPath 'C:\MyModule\build\MyModule'
12+
#>
13+
[CmdletBinding()]
14+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
15+
'PSReviewUnusedParameter', '', Scope = 'Function',
16+
Justification = 'LogGroup - Scoping affects the variables line of sight.'
17+
)]
18+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
19+
'PSAvoidUsingWriteHost', '', Scope = 'Function',
20+
Justification = 'Want to just write to the console, not the pipeline.'
21+
)]
22+
param(
23+
# Name of the module.
24+
[Parameter(Mandatory)]
25+
[string] $ModuleName,
26+
27+
# Path to the folder where the module source code is located.
28+
[Parameter(Mandatory)]
29+
[System.IO.DirectoryInfo] $ModuleSourceFolder,
30+
31+
# Path to the folder where the built modules are outputted.
32+
[Parameter(Mandatory)]
33+
[System.IO.DirectoryInfo] $ModuleOutputFolder
34+
)
35+
36+
Set-GitHubLogGroup 'Build base' {
37+
$relModuleSourceFolder = $ModuleSourceFolder | Resolve-Path -Relative
38+
$relModuleOutputFolder = $ModuleOutputFolder | Resolve-Path -Relative
39+
Write-Host "Copying files from [$relModuleSourceFolder] to [$relModuleOutputFolder]"
40+
Copy-Item -Path "$ModuleSourceFolder\*" -Destination $ModuleOutputFolder -Recurse -Force -Exclude "$ModuleName.psm1"
41+
$null = New-Item -Path $ModuleOutputFolder -Name "$ModuleName.psm1" -ItemType File -Force
42+
}
43+
44+
Set-GitHubLogGroup 'Build base - Result' {
45+
Get-ChildItem -Path $ModuleOutputFolder -Recurse -Force | Resolve-Path -Relative | Sort-Object
46+
}
47+
}

0 commit comments

Comments
 (0)