Skip to content

[release/v7.5] Replace fpm with native rpmbuild for RPM package generation#26793

Merged
daxian-dbw merged 1 commit intoPowerShell:release/v7.5from
daxian-dbw:backport/release/v7.5/26233-5661a5152
Feb 12, 2026
Merged

[release/v7.5] Replace fpm with native rpmbuild for RPM package generation#26793
daxian-dbw merged 1 commit intoPowerShell:release/v7.5from
daxian-dbw:backport/release/v7.5/26233-5661a5152

Conversation

@daxian-dbw
Copy link
Member

Backport of #26233 to release/v7.5

Triggered by @daxian-dbw on behalf of @app/copilot-swe-agent

Original CL Label: CL-BuildPackaging

/cc @PowerShell/powershell-maintainers

Impact

REQUIRED: Choose either Tooling Impact or Customer Impact (or both). At least one checkbox must be selected.

Tooling Impact

  • Required tooling change
  • Optional tooling change (include reasoning)

Eliminates Ruby dependency for RPM package generation and uses native rpmbuild tooling instead. Reduces build complexity on RHEL/CentOS/Fedora/SUSE systems.

Customer Impact

  • Customer reported
  • Found internally

Regression

REQUIRED: Check exactly one box.

  • Yes
  • No

This is not a regression.

Testing

Comprehensive testing was performed including spec file generation, building actual RPM packages, package validation, module loading checks, cross-architecture builds, and Pester tests for package name validation.

Risk

REQUIRED: Check exactly one box.

  • High
  • Medium
  • Low

This is a significant tooling change that replaces Ruby gem fpm with native rpmbuild. However, it has been tested extensively with comprehensive tests and has already been backported to 7.4 and 7.6 successfully.

…ll#26233)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: TravisEz13 <[email protected]>
Co-authored-by: Travis Plunk <[email protected]>
Co-authored-by: Copilot <[email protected]>
@daxian-dbw daxian-dbw requested a review from a team as a code owner February 12, 2026 19:15
Copilot AI review requested due to automatic review settings February 12, 2026 19:15
@daxian-dbw daxian-dbw added the CL-BuildPackaging Indicates that a PR should be marked as a build or packaging change in the Change Log label Feb 12, 2026
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 backports #26233 to the release/v7.5 branch, replacing the Ruby gem fpm with native rpmbuild for generating RPM packages. This eliminates the Ruby dependency for RPM-based systems (RHEL, CentOS, Fedora, SUSE), reducing build complexity and installation requirements.

Changes:

  • Implements native rpmbuild support with a new New-RpmSpec function that generates complete RPM spec files
  • Updates bootstrap logic to install fpm only on Debian-based systems and macOS, while ensuring rpmbuild is available on RPM-based systems
  • Adds package name validation tests to catch naming issues early in the CI pipeline

Reviewed changes

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

Show a summary per file
File Description
tools/packaging/packaging.psm1 Adds New-RpmSpec function and updates New-UnixPackage to use rpmbuild directly for RPM packages while keeping fpm for DEB/macOS packages; includes cross-architecture build support
tools/ci.psm1 Updates New-LinuxPackage to detect GitHub Actions vs Azure DevOps environment and use appropriate artifacts directory paths
test/packaging/linux/package-validation.tests.ps1 Adds Pester tests to validate RPM and tar.gz package naming conventions before artifact upload
build.psm1 Updates Start-PSBootstrap to conditionally install fpm only on Debian/macOS systems and ensure rpmbuild is available on RPM-based systems
.github/workflows/linux-ci.yml Adds packagingChanged output to trigger linux_packaging job when packaging-related files are modified
.github/actions/test/linux-packaging/action.yml Explicitly imports build.psm1 and packaging.psm1 before ci.psm1 and runs package validation tests

Comment on lines +1303 to +1304
$Output = bash -c $buildCmd 2>&1
$exitCode = $LASTEXITCODE
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rpmbuild command should use Start-NativeExecution instead of manual bash invocation with LASTEXITCODE checking. Start-NativeExecution provides consistent error handling, better diagnostics with caller information, and is the standard pattern used throughout this codebase for executing native commands. Replace the bash -c approach with Start-NativeExecution for better error messages and consistent behavior.

Copilot generated this review using guidance from repository custom instructions.
[Parameter(Mandatory,HelpMessage='Script to run after the package removal.')]
[String]$AfterRemoveScript,

[String]$Distribution = 'rhel.7',
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default distribution value 'rhel.7' doesn't match the valid RedHat distribution values defined at the top of the module (lines 10-14: "rh" and "cm"). This will cause generated RPM packages to have filenames like "powershell-7.6.0-1.rhel.7.x86_64.rpm" which will fail the package name validation test that expects only "rh" or "cm". The default should be 'rh' instead of 'rhel.7' to match $RedhatFullDistributions.

Suggested change
[String]$Distribution = 'rhel.7',
[String]$Distribution = 'rh',

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +40
# -1\. : Literal '-1.'
# (preview\.\d+\.)? : Optional 'preview.' and digits, followed by a dot
# (rh|cm)\. : Either 'rh.' or 'cm.'
# (x86_64|aarch64)\.rpm$ : Architecture and file extension
$rpmPackageNamePattern = 'powershell\-(preview-|lts-)?\d+\.\d+\.\d+(_[a-z]*\.\d+)?-1\.(preview\.\d+\.)?(rh|cm)\.(x86_64|aarch64)\.rpm'
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern includes (preview\.\d+\.)? which suggests an optional "preview.N." component between "-1." and the distribution suffix. However, based on the RPM filename format ({Name}-{Version}-{Release}.{Arch}.rpm) and the spec file generation in New-RpmSpec (Release: $Iteration.$Distribution), this component wouldn't appear in the filename. For a preview version, "preview" appears in the Name (powershell-preview) and the version field (7.6.0_preview.6), not in a separate component of the release field. This pattern component should likely be removed unless there's a specific case where it's needed.

Suggested change
# -1\. : Literal '-1.'
# (preview\.\d+\.)? : Optional 'preview.' and digits, followed by a dot
# (rh|cm)\. : Either 'rh.' or 'cm.'
# (x86_64|aarch64)\.rpm$ : Architecture and file extension
$rpmPackageNamePattern = 'powershell\-(preview-|lts-)?\d+\.\d+\.\d+(_[a-z]*\.\d+)?-1\.(preview\.\d+\.)?(rh|cm)\.(x86_64|aarch64)\.rpm'
# -1\. : Literal '-1.' (iteration part of Release)
# (rh|cm)\. : Either 'rh.' or 'cm.' (distribution part of Release)
# (x86_64|aarch64)\.rpm$ : Architecture and file extension
$rpmPackageNamePattern = 'powershell\-(preview-|lts-)?\d+\.\d+\.\d+(_[a-z]*\.\d+)?-1\.(rh|cm)\.(x86_64|aarch64)\.rpm'

Copilot uses AI. Check for mistakes.
Comment on lines +895 to +900
# Determine artifacts directory (GitHub Actions or Azure DevOps)
$artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') {
"${env:GITHUB_WORKSPACE}/../packages"
} else {
"${env:BUILD_ARTIFACTSTAGINGDIRECTORY}"
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The artifacts directory determination logic is duplicated on lines 878-882 and 895-900. This code duplication makes the function harder to maintain. Consider extracting this logic to a variable at the beginning of the function, outside the foreach loop, so it's only determined once and reused in both places.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +14
$env:SYSTEM_ARTIFACTSDIRECTORY
}

if (-not $artifactsDir) {
throw "Artifacts directory not found. GITHUB_WORKSPACE or SYSTEM_ARTIFACTSDIRECTORY must be set."
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a mismatch in the Azure DevOps environment variable used for the artifacts directory. The test uses $env:SYSTEM_ARTIFACTSDIRECTORY (line 10), but the packaging code in tools/ci.psm1 uses $env:BUILD_ARTIFACTSTAGINGDIRECTORY. In Azure DevOps, BUILD_ARTIFACTSTAGINGDIRECTORY is the standard variable for the staging directory where artifacts are placed before upload. The test should use the same variable to ensure it looks in the correct location. Change line 10 to use $env:BUILD_ARTIFACTSTAGINGDIRECTORY to match the packaging code.

Suggested change
$env:SYSTEM_ARTIFACTSDIRECTORY
}
if (-not $artifactsDir) {
throw "Artifacts directory not found. GITHUB_WORKSPACE or SYSTEM_ARTIFACTSDIRECTORY must be set."
$env:BUILD_ARTIFACTSTAGINGDIRECTORY
}
if (-not $artifactsDir) {
throw "Artifacts directory not found. GITHUB_WORKSPACE or BUILD_ARTIFACTSTAGINGDIRECTORY must be set."

Copilot uses AI. Check for mistakes.
foreach ($package in $tarPackages) {
# Pattern matches: powershell-7.6.0-preview.6-linux-x64.tar.gz or powershell-7.6.0-linux-x64.tar.gz
# Also matches various runtime configurations
if ($package.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?(linux|osx|linux-musl)+\-(x64\-fxdependent|x64|arm32|arm64|x64\-musl-noopt\-fxdependent)\.(tar\.gz)') {
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern for tar.gz package names has an unescaped dot in ([a-z]*.\d+\-)?. The dot should be escaped as \. to match a literal dot (e.g., "preview.6"). Currently, [a-z]*. matches any single character, not specifically a dot. This should be ([a-z]*\.\d+\-)? to correctly match preview versions like "preview.6-" in the package name.

Suggested change
if ($package.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?(linux|osx|linux-musl)+\-(x64\-fxdependent|x64|arm32|arm64|x64\-musl-noopt\-fxdependent)\.(tar\.gz)') {
if ($package.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*\.\d+\-)?(linux|osx|linux-musl)+\-(x64\-fxdependent|x64|arm32|arm64|x64\-musl-noopt\-fxdependent)\.(tar\.gz)') {

Copilot uses AI. Check for mistakes.
@daxian-dbw daxian-dbw merged commit 9acb52f into PowerShell:release/v7.5 Feb 12, 2026
40 of 43 checks passed
@daxian-dbw daxian-dbw deleted the backport/release/v7.5/26233-5661a5152 branch February 12, 2026 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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