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
91 changes: 84 additions & 7 deletions .github/workflows/Build Module.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ on:
required: false
workflow_dispatch:
pull_request:
paths:
- "src/**"
- "build/**"
- "tests/**"
- "tools/**"
- ".github/ci-scripts/**"
- ".github/workflows/Build Module.yml"
# No path filter: this workflow always triggers on PRs to main so its "Build and test module"
# checks always REPORT (a required status check from a path-filtered workflow that never triggers
# stays Pending and blocks the PR forever). The expensive matrix build is gated below by the
# `changes` job — on a PR that doesn't touch build-relevant paths the build job is skipped, and a
# skipped job satisfies the required check, so docs-/CI-only PRs are never blocked.
branches: [main]
#push:
# branches:
# - main
Expand All @@ -42,9 +41,63 @@ concurrency:

jobs:

changes:
name: Detect build-relevant changes
# Only meaningful for a directly-triggered PR. workflow_call (release) passes inputs.ref and must
# always build; workflow_dispatch must always build. Both skip this job (handled in build's `if`).
if: github.event_name == 'pull_request' && inputs.ref == ''
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
relevant: ${{ steps.detect.outputs.relevant }}
steps:
- name: Detect whether build-relevant paths changed
id: detect
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
# Detection is intentionally INLINE (not a shared .github/ci-scripts script): keeping the
# merge-gate logic in the workflow file benefits from GitHub's stricter workflow-edit review,
# so a PR can't relocate it to a less-scrutinized script and tamper the skip decision (#228).
# Fail-safe: default to relevant=true so any error enumerating changed files runs the build
# rather than silently skipping it. Use the PAGINATED REST files endpoint -- gh pr view
# --json files caps at 100 files and could miss a later src/ change on a large PR.
$Relevant = $true
try {
$ErrorActionPreference = 'Stop'
# Project previous_filename too, so a rename moving a tracked file OUT of a matched tree
# (reported as the new path in .filename, old path in .previous_filename) is still seen.
$Files = gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" --paginate --jq '.[] | .filename, (.previous_filename // empty)'
# Native non-zero exits don't reliably throw in pwsh, so check explicitly -> fail-safe.
if ($LASTEXITCODE -ne 0) { throw "gh api exited $LASTEXITCODE while listing PR files" }
$Patterns = @('^src/', '^build/', '^tests/', '^tools/', '^\.github/ci-scripts/', '^\.github/workflows/Build Module\.yml$')
$Relevant = $false
foreach ($File in $Files) {
foreach ($Pattern in $Patterns) {
if ($File -match $Pattern) { $Relevant = $true; break }
}
if ($Relevant) { break }
}
} catch {
Write-Host "::warning::Changed-file detection failed; defaulting to relevant=true (fail-safe). $_"
$Relevant = $true
}
"relevant=$($Relevant.ToString().ToLowerInvariant())" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
Write-Host "Build-relevant change detected: $Relevant"

build:

name: Build and test module (${{ matrix.os }})
needs: changes
# Always build for workflow_call (release; inputs.ref set) and workflow_dispatch. For a direct PR,
# build only when build-relevant paths changed; otherwise skip (a skipped job still satisfies the
# required "Build and test module" check). always() stops the skip of `changes` in the
# call/dispatch paths from cascading into a skip of build; the `!= 'false'` guard errs toward
# building on any ambiguity, so the release path is never accidentally skipped.
if: ${{ always() && (inputs.ref != '' || github.event_name == 'workflow_dispatch' || needs.changes.outputs.relevant != 'false') }}
Comment thread
SamErde marked this conversation as resolved.
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
Expand Down Expand Up @@ -178,3 +231,27 @@ jobs:
name: module-build
path: ./module/DLLPickle
if-no-files-found: warn

build-gate:
name: Build gate
# Aggregate required-check target. GitHub evaluates a matrix job's `if` BEFORE expanding the
# matrix, so skipping the `build` job does NOT create the per-OS "Build and test module (...)"
# check contexts -- requiring those directly would leave non-bundle PRs stuck "Expected - waiting
# for status". This single, always-running job is the stable check to require instead: it passes
Comment thread
SamErde marked this conversation as resolved.
Comment thread
SamErde marked this conversation as resolved.
# when the matrix build succeeded OR was skipped (no build-relevant changes) and fails when the
# build failed or was cancelled.
Comment thread
SamErde marked this conversation as resolved.
needs: build
if: ${{ always() }}
runs-on: ubuntu-latest
steps:
- name: Aggregate build result
shell: pwsh
run: |
$Result = '${{ needs.build.result }}'
Write-Host "build job result: $Result"
if ($Result -eq 'success' -or $Result -eq 'skipped') {
Write-Host 'Build gate passed.'
exit 0
}
Write-Host "::error::Build gate failed (build result: $Result)."
exit 1
62 changes: 55 additions & 7 deletions .github/workflows/Upstream-Compatibility.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ on:
schedule:
- cron: "34 8 * * 1"
pull_request:
paths:
- "build/dependency-policy.json"
- "src/DLLPickle.Build/**"
- "tests/**"
- "tools/**"
- ".github/workflows/Upstream-Compatibility.yml"
# No path filter: always trigger on PRs to main so the "Validate upstream compatibility tooling"
# required check always reports. The job is gated below by `pr-changes` — skipped (== passing
# required check) on PRs that don't touch the tooling/policy paths.
branches: [main]

permissions:
contents: read
Expand All @@ -26,9 +24,59 @@ concurrency:
cancel-in-progress: false

jobs:
pr-changes:
name: Detect tooling/policy changes
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
relevant: ${{ steps.detect.outputs.relevant }}
steps:
- name: Detect whether upstream-compatibility paths changed
id: detect
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
# Detection is intentionally INLINE (not a shared .github/ci-scripts script): keeping the
# merge-gate logic in the workflow file benefits from GitHub's stricter workflow-edit review,
# so a PR can't relocate it to a less-scrutinized script and tamper the skip decision (#228).
# Fail-safe: default relevant=true so any error enumerating changed files runs the
# validation rather than silently skipping a required check. Paginated REST files endpoint
# (gh pr view --json files caps at 100 files and could miss a later build/ or tools/ change).
$Relevant = $true
try {
$ErrorActionPreference = 'Stop'
# Project previous_filename too, so a rename moving a tracked file OUT of a matched tree
# (reported as the new path in .filename, old path in .previous_filename) is still seen.
$Files = gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" --paginate --jq '.[] | .filename, (.previous_filename // empty)'
# Native non-zero exits don't reliably throw in pwsh, so check explicitly -> fail-safe.
if ($LASTEXITCODE -ne 0) { throw "gh api exited $LASTEXITCODE while listing PR files" }
$Patterns = @('^build/', '^src/DLLPickle\.Build/', '^tests/', '^tools/', '^\.github/workflows/Upstream-Compatibility\.yml$')
$Relevant = $false
foreach ($File in $Files) {
foreach ($Pattern in $Patterns) {
if ($File -match $Pattern) { $Relevant = $true; break }
}
if ($Relevant) { break }
}
} catch {
Write-Host "::warning::Changed-file detection failed; defaulting to relevant=true (fail-safe). $_"
$Relevant = $true
}
"relevant=$($Relevant.ToString().ToLowerInvariant())" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
Write-Host "Upstream-compatibility-relevant change detected: $Relevant"

pr-smoke-validation:
name: Validate upstream compatibility tooling
if: github.event_name == 'pull_request'
needs: pr-changes
# Runs on PRs that touch the tooling/policy paths; skipped (== passing required check) only when
# detection conclusively says false. always() + `!= 'false'` makes it FAIL-SAFE: if pr-changes
# fails or its output is unknown, the validation still runs rather than being skipped (which would
# otherwise satisfy the required check without actually validating a relevant PR).
if: ${{ always() && github.event_name == 'pull_request' && needs.pr-changes.outputs.relevant != 'false' }}
runs-on: windows-2025
permissions:
contents: read
Expand Down
Loading