Skip to content
Merged
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
48 changes: 47 additions & 1 deletion .github/instructions/build-configuration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand All @@ -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**
Expand Down Expand Up @@ -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
149 changes: 149 additions & 0 deletions .github/instructions/start-native-execution.instructions.md
Original file line number Diff line number Diff line change
@@ -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/
55 changes: 53 additions & 2 deletions .github/workflows/macos-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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' }}
Expand All @@ -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:
Expand Down
17 changes: 12 additions & 5 deletions docs/maintainers/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,18 @@ The output of `Start-PSBuild` includes a `powershell.exe` executable which can s
#### Linux / macOS

The `Start-PSPackage` function delegates to `New-UnixPackage`.
It relies on the [Effing Package Management][fpm] project,
which makes building packages for any (non-Windows) platform a breeze.
Similarly, the PowerShell man-page is generated from the Markdown-like file

For **Linux** (Debian-based distributions), it relies on the [Effing Package Management][fpm] project,
which makes building packages a breeze.

For **macOS**, it uses native packaging tools (`pkgbuild` and `productbuild`) from Xcode Command Line Tools,
eliminating the need for Ruby or fpm.

For **Linux** (Red Hat-based distributions), it uses `rpmbuild` directly.

The PowerShell man-page is generated from the Markdown-like file
[`assets/pwsh.1.ronn`][man] using [Ronn][].
The function `Start-PSBootstrap -Package` will install both these tools.
The function `Start-PSBootstrap -Package` will install these tools.

To modify any property of the packages, edit the `New-UnixPackage` function.
Please also refer to the function for details on the package properties
Expand Down Expand Up @@ -131,7 +138,7 @@ Without `-Name` specified, the primary `powershell`
package will instead be created.

[fpm]: https://github.com/jordansissel/fpm
[man]: ../../assets/pwsh.1.ronn
[man]: ../../assets/manpage/pwsh.1.ronn
[ronn]: https://github.com/rtomayko/ronn

### Build and Packaging Examples
Expand Down
Loading
Loading