Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 21, 2025

Update macOS packaging to use Xcode command line tools instead of fpm

Summary

This PR replaces the Ruby gem fpm (Effing Package Management) with native macOS packaging tools (pkgbuild and productbuild) from Xcode Command Line Tools for creating macOS PowerShell packages.

Plan

  • Explore the current implementation to understand how fpm is used
  • Understand macOS packaging tools (pkgbuild, productbuild)
  • Create new functions to build macOS packages using native tools
  • Replace fpm-based implementation for macOS (osxpkg type)
  • Update Test-Dependencies to check for pkgbuild/productbuild on macOS
  • Remove fpm workarounds and hacks
  • Fix symlink handling to match fpm behavior
  • Update documentation to reflect the changes
  • Review and validate changes
  • Run security checks (CodeQL - no issues found)
  • Add package creation and validation to macOS CI workflow
  • Combine build and package steps in same task to preserve build state
  • Convert package validation to Pester test
  • Add -SkipReleaseChecks to avoid repo path validation in CI
  • Use process-pester-results action for proper test result publishing
  • Fix symlink creation to recreate instead of copy temp files
  • Use Pester TestDrive for temporary test directories
  • Improve verbose logging and path construction in test
  • Refactor to reuse New-MacOsDistributionPackage function
  • Use Start-NativeExecution for native command execution
  • Add Copilot instructions for Start-NativeExecution usage
  • Configure public NuGet feeds for CI environment
  • Apply Start-NativeExecution consistently for all native commands

Changes Made

New Function: New-MacOSPackage (tools/packaging/packaging.psm1)

Created a comprehensive function that uses native macOS packaging tools:

  • Uses pkgbuild via Start-NativeExecution to create a component package from the staged files
  • Calls New-MacOsDistributionPackage to create the final distribution package with proper metadata
  • Handles complete file layout including binaries, modules, man pages, symlinks, launcher app, and post-install scripts
  • Recreates symlinks in package root by reading target from temp symlinks
  • Uses Start-NativeExecution for all native commands (chmod, pkgbuild)

Refactored New-MacOsDistributionPackage Function

Modernized and generalized this function to work with component packages from the native tools:

  • Updated parameters to accept a component package instead of FPM package
  • Added explicit parameters for package name, version, output directory, and package identifier
  • Uses productbuild via Start-NativeExecution with proper distribution XML
  • Handles background image and resources
  • Supports both x86_64 and arm64 architectures
  • Now reused by New-MacOSPackage to avoid code duplication

Updated Packaging Module Initialization

  • Dot-sourced startNativeExecution.ps1 to make Start-NativeExecution available
  • Updated all native command invocations to use Start-NativeExecution with proper error handling
  • Consistently applied Start-NativeExecution for chmod, pkgbuild, productbuild, and pkgutil commands
  • Improved error handling and diagnostics for packaging operations

Updated New-UnixPackage Function

  • Added conditional logic to call New-MacOSPackage for osxpkg type packages
  • Removed fpm symlink workaround hack - no longer needed with native tools
  • Removed call to New-MacOsDistributionPackage since the new implementation creates distribution packages directly
  • Simplified cleanup logic in finally block

Updated Test-Dependencies Function

  • Added checks for pkgbuild and productbuild on macOS
  • Kept fpm dependency check only for Debian-based systems
  • Updated comments to reflect tool usage by platform

Updated Documentation

  • docs/maintainers/releasing.md: Clarified that different packaging tools are used for different platforms
  • .github/instructions/start-native-execution.instructions.md: Comprehensive guide on using Start-NativeExecution for native command execution in packaging scripts
  • .github/instructions/build-configuration-guide.instructions.md: Added comprehensive documentation about Switch-PSNugetConfig usage, including when and why to use public feeds in CI/CD environments

Enhanced macOS CI Workflow (.github/workflows/macos-ci.yml)

  • Added Switch-PSNugetConfig -Source Public to use public NuGet feeds (required for CI environments)
  • Combined build and package steps in single task to preserve PowerShell build state (PSOptions)
  • Added -SkipReleaseChecks flag to Start-PSPackage to bypass repo path validation in CI
  • Replaced inline validation script with comprehensive Pester test for package validation
  • Configured Pester to output NUnitXml format test results
  • Integrated with .github/actions/test/process-pester-results action for proper test result publishing and aggregation
  • Added artifact upload for created packages

New Pester Test (tools/packaging/releaseTests/macOSPackage.tests.ps1)

Created comprehensive Pester-based validation test:

  • Tests package existence and structure
  • Validates required files (pwsh executable, symlinks, man pages, launcher app)
  • Verifies PowerShell binary has executable permissions
  • Validates launcher application bundle structure
  • Uses Start-NativeExecution for pkgutil command to ensure proper error handling
  • Provides detailed test output with clear assertions
  • Follows existing test patterns in the repository (similar to sbom.tests.ps1)
  • Outputs results in NUnitXml format for CI processing
  • Uses Pester TestDrive for temporary directories, allowing pkgutil to create directories as it expects
  • Improved verbose logging to show full path of component package being processed
  • Uses Join-Path for proper path construction

Key Benefits

  1. No Ruby Dependency: Eliminates the need for Ruby and the fpm gem on macOS
  2. Native Tools: Uses Apple's official packaging tools that come with Xcode Command Line Tools
  3. Better Integration: Native tools are better maintained and aligned with macOS standards
  4. Cleaner Code: Removed workarounds and hacks needed for fpm quirks, and refactored to reuse existing functions
  5. Better Maintainability: Uses Apple-supported tools that are kept up-to-date with macOS releases
  6. CI Validation: Package creation and contents are now validated in CI with proper Pester tests
  7. Better Testing: Package validation now uses standard Pester test framework for consistency and maintainability
  8. Proper Test Reporting: Uses the standard process-pester-results action for consistent test result publishing across the repository
  9. Code Reusability: Refactored New-MacOsDistributionPackage to be reusable by both legacy and new packaging approaches
  10. Consistent Error Handling: Uses Start-NativeExecution for all native command execution with proper error handling and diagnostics
  11. CI-Ready Configuration: Properly configured to use public NuGet feeds for CI/CD environments

Testing

The macOS CI workflow now includes comprehensive testing that:

  • Switches to public NuGet feeds before building (via Switch-PSNugetConfig -Source Public)
  • Builds PowerShell from source
  • Creates the macOS package using the new implementation in the same task (preserving build state)
  • Uses -SkipReleaseChecks to bypass repo path validation (CI repos are not at /PowerShell)
  • Properly handles symlink creation by reading the target from temp symlinks and recreating them in the package
  • Runs Pester tests (tools/packaging/releaseTests/macOSPackage.tests.ps1) using TestDrive for temporary directories
  • Lets pkgutil create the expand directory itself (as expected by the tool)
  • Saves test results in NUnitXml format to ${{ runner.workspace }}/testResults
  • Uses .github/actions/test/process-pester-results action to aggregate, summarize, and upload test results
  • Uploads the package as an artifact for inspection
Original prompt

In tools/packaging/packaging.psm1 we use fpm to create the macos packages. Update to use the xcode command line tools from apple and do not use any ruby gems, such an fpm.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@TravisEz13
Copy link
Member

@copilot Add a test to actually package and test the contents of the package in the packaging job in .github/workflows/macos-ci.yml

Copilot AI changed the title [WIP] Update macOS packaging to use Xcode command line tools Replace fpm with native macOS packaging tools (pkgbuild/productbuild) Oct 21, 2025
Copilot AI requested a review from TravisEz13 October 21, 2025 21:06
Copy link
Contributor Author

Copilot AI commented Oct 21, 2025

@copilot Add a test to actually package and test the contents of the package in the packaging job in .github/workflows/macos-ci.yml

Added comprehensive package creation and validation to the PackageMac-macos_packaging job in commit cbd9889. The job now:

  1. Builds PowerShell for the detected architecture (x86_64 or arm64)
  2. Creates the macOS package using Start-PSPackage -Type osxpkg
  3. Validates package contents by:
    • Expanding the package with pkgutil --expand
    • Extracting and verifying key files exist (pwsh binary, symlinks, man pages, launcher app)
    • Failing if expected files are missing
  4. Uploads the package as an artifact

The validation ensures the new native macOS packaging implementation creates packages with the correct structure and contents.

@TravisEz13 TravisEz13 requested review from a team and jshigetomi as code owners October 27, 2025 22:38
Copilot AI review requested due to automatic review settings October 27, 2025 22:38
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 replaces the Ruby gem fpm (Effing Package Management) with native macOS packaging tools (pkgbuild and productbuild) from Xcode Command Line Tools for creating macOS PowerShell packages. This eliminates the Ruby dependency on macOS and uses Apple-supported tools for better integration with macOS standards.

Key Changes:

  • Created New-MacOSPackage function using native pkgbuild and productbuild tools
  • Refactored New-MacOsDistributionPackage to be reusable by both legacy and new packaging approaches
  • Updated all native command invocations to use Start-NativeExecution with proper error handling
  • Enhanced macOS CI workflow to build, package, and validate packages using Pester tests
  • Added comprehensive Copilot instructions for Start-NativeExecution usage and NuGet feed configuration

Reviewed Changes

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

Show a summary per file
File Description
tools/packaging/packaging.psm1 Added New-MacOSPackage function, refactored New-MacOsDistributionPackage, updated native command execution to use Start-NativeExecution, removed fpm workarounds
tools/packaging/releaseTests/macOSPackage.tests.ps1 New comprehensive Pester test for validating macOS package structure and contents
.github/workflows/macos-ci.yml Enhanced to build PowerShell, create packages, and validate with Pester tests; added public NuGet feed configuration
docs/maintainers/releasing.md Updated documentation to reflect different packaging tools for different platforms
.github/instructions/start-native-execution.instructions.md New comprehensive guide on using Start-NativeExecution for native command execution
.github/instructions/build-configuration-guide.instructions.md Added documentation about Switch-PSNugetConfig usage for CI/CD environments

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

@TravisEz13 TravisEz13 enabled auto-merge (squash) October 28, 2025 22:04
@TravisEz13 TravisEz13 merged commit 47e8e90 into master Oct 28, 2025
38 checks passed
@adityapatwardhan adityapatwardhan deleted the copilot/update-macos-packaging-tool branch October 28, 2025 22:09
@microsoft-github-policy-service
Copy link
Contributor

microsoft-github-policy-service bot commented Oct 28, 2025

📣 Hey @@Copilot, how did we do? We would love to hear your feedback with the link below! 🗣️

🔗 https://aka.ms/PSRepoFeedback

pwshBot pushed a commit to pwshBot/PowerShell that referenced this pull request Oct 29, 2025
TravisEz13 added a commit to TravisEz13/PowerShell that referenced this pull request Nov 20, 2025
…PowerShell#26268)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: TravisEz13 <[email protected]>
Co-authored-by: Travis Plunk <[email protected]>
TravisEz13 added a commit to TravisEz13/PowerShell that referenced this pull request Nov 20, 2025
…PowerShell#26268)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: TravisEz13 <[email protected]>
Co-authored-by: Travis Plunk <[email protected]>
SIRMARGIN pushed a commit to SIRMARGIN/PowerShell that referenced this pull request Dec 12, 2025
…PowerShell#26268)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: TravisEz13 <[email protected]>
Co-authored-by: Travis Plunk <[email protected]>
kilasuit pushed a commit to kilasuit/PowerShell that referenced this pull request Jan 2, 2026
…PowerShell#26268)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: TravisEz13 <[email protected]>
Co-authored-by: Travis Plunk <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backport-7.4.x-Migrated BackPort-7.5.x-Consider Backport-7.6.x-Migrated CL-BuildPackaging Indicates that a PR should be marked as a build or packaging change in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants