mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
[release/v7.6] Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26501)
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com>
This commit is contained in:
co-authored by
Copilot
TravisEz13
parent
0e83f60c0e
commit
ce725ce207
@@ -27,13 +27,15 @@
|
||||
|
||||
### For Release/Packaging
|
||||
|
||||
**Use: Release with version tag**
|
||||
**Use: Release with version tag and public NuGet feeds**
|
||||
|
||||
```yaml
|
||||
- name: Build for Release
|
||||
shell: pwsh
|
||||
run: |
|
||||
Import-Module ./build.psm1
|
||||
Import-Module ./tools/ci.psm1
|
||||
Switch-PSNugetConfig -Source Public
|
||||
$releaseTag = Get-ReleaseTag
|
||||
Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag
|
||||
```
|
||||
@@ -43,6 +45,11 @@
|
||||
- No debug symbols (smaller size)
|
||||
- Production-ready
|
||||
|
||||
**Why Switch-PSNugetConfig -Source Public:**
|
||||
- Switches NuGet package sources to public feeds (nuget.org and public Azure DevOps feeds)
|
||||
- Required for CI/CD environments that don't have access to private feeds
|
||||
- Uses publicly available packages instead of Microsoft internal feeds
|
||||
|
||||
### For Code Coverage
|
||||
|
||||
**Use: CodeCoverage configuration**
|
||||
@@ -93,3 +100,42 @@ src/powershell-win-core/bin/Debug/<netversion>/<runtime>/publish/
|
||||
3. Match configuration to purpose
|
||||
4. Use `-CI` only when needed
|
||||
5. Always specify `-ReleaseTag` for release or packaging builds
|
||||
6. Use `Switch-PSNugetConfig -Source Public` in CI/CD for release builds
|
||||
|
||||
## NuGet Feed Configuration
|
||||
|
||||
### Switch-PSNugetConfig
|
||||
|
||||
The `Switch-PSNugetConfig` function in `build.psm1` manages NuGet package source configuration.
|
||||
|
||||
**Available Sources:**
|
||||
|
||||
- **Public**: Uses public feeds (nuget.org and public Azure DevOps feeds)
|
||||
- Required for: CI/CD environments, public builds, packaging
|
||||
- Does not require authentication
|
||||
|
||||
- **Private**: Uses internal PowerShell team feeds
|
||||
- Required for: Internal development with preview packages
|
||||
- Requires authentication credentials
|
||||
|
||||
- **NuGetOnly**: Uses only nuget.org
|
||||
- Required for: Minimal dependency scenarios
|
||||
|
||||
**Usage:**
|
||||
|
||||
```powershell
|
||||
# Switch to public feeds (most common for CI/CD)
|
||||
Switch-PSNugetConfig -Source Public
|
||||
|
||||
# Switch to private feeds with authentication
|
||||
Switch-PSNugetConfig -Source Private -UserName $userName -ClearTextPAT $pat
|
||||
|
||||
# Switch to nuget.org only
|
||||
Switch-PSNugetConfig -Source NuGetOnly
|
||||
```
|
||||
|
||||
**When to Use:**
|
||||
|
||||
- **Always use `-Source Public`** before building in CI/CD workflows
|
||||
- Use before any build that will create packages for distribution
|
||||
- Use in forks or environments without access to Microsoft internal feeds
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
applyTo:
|
||||
- "**/*.ps1"
|
||||
- "**/*.psm1"
|
||||
---
|
||||
|
||||
# Using Start-NativeExecution for Native Command Execution
|
||||
|
||||
## Purpose
|
||||
|
||||
`Start-NativeExecution` is the standard function for executing native commands (external executables) in PowerShell scripts within this repository. It provides consistent error handling and better diagnostics when native commands fail.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use `Start-NativeExecution` whenever you need to:
|
||||
- Execute external commands (e.g., `git`, `dotnet`, `pkgbuild`, `productbuild`, `fpm`, `rpmbuild`)
|
||||
- Ensure proper exit code checking
|
||||
- Get better error messages with caller information
|
||||
- Handle verbose output on error
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```powershell
|
||||
Start-NativeExecution {
|
||||
git clone https://github.com/PowerShell/PowerShell.git
|
||||
}
|
||||
```
|
||||
|
||||
## With Parameters
|
||||
|
||||
Use backticks for line continuation within the script block:
|
||||
|
||||
```powershell
|
||||
Start-NativeExecution {
|
||||
pkgbuild --root $pkgRoot `
|
||||
--identifier $pkgIdentifier `
|
||||
--version $Version `
|
||||
--scripts $scriptsDir `
|
||||
$outputPath
|
||||
}
|
||||
```
|
||||
|
||||
## Common Parameters
|
||||
|
||||
### -VerboseOutputOnError
|
||||
|
||||
Captures command output and displays it only if the command fails:
|
||||
|
||||
```powershell
|
||||
Start-NativeExecution -VerboseOutputOnError {
|
||||
dotnet build --configuration Release
|
||||
}
|
||||
```
|
||||
|
||||
### -IgnoreExitcode
|
||||
|
||||
Allows the command to fail without throwing an exception:
|
||||
|
||||
```powershell
|
||||
Start-NativeExecution -IgnoreExitcode {
|
||||
git diff --exit-code # Returns 1 if differences exist
|
||||
}
|
||||
```
|
||||
|
||||
## Availability
|
||||
|
||||
The function is defined in `tools/buildCommon/startNativeExecution.ps1` and is available in:
|
||||
- `build.psm1` (dot-sourced automatically)
|
||||
- `tools/packaging/packaging.psm1` (dot-sourced automatically)
|
||||
- Test modules that include `HelpersCommon.psm1`
|
||||
|
||||
To use in other scripts, dot-source the function:
|
||||
|
||||
```powershell
|
||||
. "$PSScriptRoot/../buildCommon/startNativeExecution.ps1"
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
When a native command fails (non-zero exit code), `Start-NativeExecution`:
|
||||
1. Captures the exit code
|
||||
2. Identifies the calling location (file and line number)
|
||||
3. Throws a descriptive error with full context
|
||||
|
||||
Example error message:
|
||||
```
|
||||
Execution of {git clone ...} by /path/to/script.ps1: line 42 failed with exit code 1
|
||||
```
|
||||
|
||||
## Examples from the Codebase
|
||||
|
||||
### Git Operations
|
||||
```powershell
|
||||
Start-NativeExecution {
|
||||
git fetch --tags --quiet upstream
|
||||
}
|
||||
```
|
||||
|
||||
### Build Operations
|
||||
```powershell
|
||||
Start-NativeExecution -VerboseOutputOnError {
|
||||
dotnet publish --configuration Release
|
||||
}
|
||||
```
|
||||
|
||||
### Packaging Operations
|
||||
```powershell
|
||||
Start-NativeExecution -VerboseOutputOnError {
|
||||
pkgbuild --root $pkgRoot --identifier $pkgId --version $version $outputPath
|
||||
}
|
||||
```
|
||||
|
||||
### Permission Changes
|
||||
```powershell
|
||||
Start-NativeExecution {
|
||||
find $staging -type d | xargs chmod 755
|
||||
find $staging -type f | xargs chmod 644
|
||||
}
|
||||
```
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
**Don't do this:**
|
||||
```powershell
|
||||
& somecommand $args
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Command failed"
|
||||
}
|
||||
```
|
||||
|
||||
**Do this instead:**
|
||||
```powershell
|
||||
Start-NativeExecution {
|
||||
somecommand $args
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always use Start-NativeExecution** for native commands to ensure consistent error handling
|
||||
2. **Use -VerboseOutputOnError** for commands with useful diagnostic output
|
||||
3. **Use backticks for readability** when commands have multiple arguments
|
||||
4. **Don't capture output unnecessarily** - let the function handle it
|
||||
5. **Use -IgnoreExitcode sparingly** - only when non-zero exit codes are expected and acceptable
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- Source: `tools/buildCommon/startNativeExecution.ps1`
|
||||
- Blog post: https://mnaoumov.wordpress.com/2015/01/11/execution-of-external-commands-in-powershell-done-right/
|
||||
@@ -157,7 +157,7 @@ jobs:
|
||||
runner_os: macos-15-large
|
||||
test_results_artifact_name: testResults-xunit
|
||||
PackageMac-macos_packaging:
|
||||
name: macOS packaging (bootstrap only)
|
||||
name: macOS packaging and testing
|
||||
needs:
|
||||
- changes
|
||||
if: ${{ needs.changes.outputs.source == 'true' }}
|
||||
@@ -166,12 +166,63 @@ jobs:
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 1000
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
global-json-file: ./global.json
|
||||
- name: Bootstrap packaging
|
||||
if: success() || failure()
|
||||
if: success()
|
||||
run: |-
|
||||
import-module ./build.psm1
|
||||
start-psbootstrap -Scenario package
|
||||
shell: pwsh
|
||||
- name: Build PowerShell and Create macOS package
|
||||
if: success()
|
||||
run: |-
|
||||
import-module ./build.psm1
|
||||
import-module ./tools/ci.psm1
|
||||
import-module ./tools/packaging/packaging.psm1
|
||||
Switch-PSNugetConfig -Source Public
|
||||
Sync-PSTags -AddRemoteIfMissing
|
||||
$releaseTag = Get-ReleaseTag
|
||||
Start-PSBuild -Configuration Release -PSModuleRestore -ReleaseTag $releaseTag
|
||||
$macOSRuntime = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'osx-arm64' } else { 'osx-x64' }
|
||||
Start-PSPackage -Type osxpkg -ReleaseTag $releaseTag -MacOSRuntime $macOSRuntime -SkipReleaseChecks
|
||||
shell: pwsh
|
||||
- name: Test package contents
|
||||
if: success()
|
||||
run: |-
|
||||
$env:PACKAGE_FOLDER = Get-Location
|
||||
$testResultsPath = Join-Path $env:RUNNER_WORKSPACE "testResults"
|
||||
if (-not (Test-Path $testResultsPath)) {
|
||||
New-Item -ItemType Directory -Path $testResultsPath -Force | Out-Null
|
||||
}
|
||||
Import-Module Pester
|
||||
$pesterConfig = New-PesterConfiguration
|
||||
$pesterConfig.Run.Path = './tools/packaging/releaseTests/macOSPackage.tests.ps1'
|
||||
$pesterConfig.Run.PassThru = $true
|
||||
$pesterConfig.Output.Verbosity = 'Detailed'
|
||||
$pesterConfig.TestResult.Enabled = $true
|
||||
$pesterConfig.TestResult.OutputFormat = 'NUnitXml'
|
||||
$pesterConfig.TestResult.OutputPath = Join-Path $testResultsPath "macOSPackage.xml"
|
||||
$result = Invoke-Pester -Configuration $pesterConfig
|
||||
if ($result.FailedCount -gt 0) {
|
||||
throw "Package validation failed with $($result.FailedCount) failed test(s)"
|
||||
}
|
||||
shell: pwsh
|
||||
- name: Publish and Upload Pester Test Results
|
||||
if: always()
|
||||
uses: "./.github/actions/test/process-pester-results"
|
||||
with:
|
||||
name: "macOSPackage"
|
||||
testResultsFolder: "${{ runner.workspace }}/testResults"
|
||||
- name: Upload package artifact
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macos-package
|
||||
path: "*.pkg"
|
||||
ready_to_merge:
|
||||
name: macos ready to merge
|
||||
needs:
|
||||
|
||||
Reference in New Issue
Block a user