Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2b6dcac
feat(scripts): detect modified-but-unreleased upstream deps during re…
sandersaares May 20, 2026
e296b92
refactor(scripts): drop legacy Invoke-GitCommand wrapper
sandersaares May 20, 2026
116e267
Merge branch 'main' into feat/release-deps-upstream-scan
sandersaares May 21, 2026
dbfdbcd
ci(release-deps): drop fragile delta.skip gate
sandersaares May 21, 2026
5db6f49
refactor(scripts): address PR review comments on git invocation
sandersaares May 21, 2026
8c0deb5
Merge branch 'main' into feat/release-deps-upstream-scan
sandersaares May 21, 2026
81deaff
fix(scripts): update existing release records when nested cascade upg…
sandersaares May 21, 2026
cedd750
fix(scripts): use per-crate baseline for unreleased-dep detection
sandersaares May 21, 2026
6c4cc5f
fix(scripts): address Copilot review on cedd7503
sandersaares May 21, 2026
0361fda
docs(scripts): move release-deps test cases into scripts/tests/
sandersaares May 22, 2026
034d5ca
Merge remote-tracking branch 'origin/main' into feat/release-deps-ups…
sandersaares May 22, 2026
f50bb86
docs(scripts): clarify per-crate baseline vs base-ref-anchored releas…
sandersaares May 22, 2026
38ff1eb
docs(scripts/tests): add harness crafting hints chapter
sandersaares May 22, 2026
9a435d0
fix(scripts): drop double-backslash in Get-EscapedRegexSpecialChars
sandersaares May 22, 2026
c56b7f5
chore: remove obsolete bump-crate-version prompt
sandersaares May 22, 2026
51da613
style(scripts): drop "(s)" from output strings
sandersaares May 22, 2026
d087928
fix(scripts): skip prompts for crates already cascade-bumped within I…
sandersaares May 22, 2026
4c673a4
test(scripts): Phase 1 — Pester foundation + topology presets
sandersaares May 22, 2026
d082d7b
refactor(scripts): Phase 2 — Invoke-ReleaseMain + Invoke-WorkspaceCheck
sandersaares May 22, 2026
507ed07
test(scripts): Phase 3 — pure-function unit tests (55 tests)
sandersaares May 22, 2026
46b346a
test(scripts): Phase 4 — git / filesystem unit tests (27 tests)
sandersaares May 22, 2026
4e4770a
test(scripts): Phase 5 — integration tests for release flow
sandersaares May 22, 2026
42903b7
test(scripts): add Phase 6 e2e scenario runner and 7 release scenarios
sandersaares May 22, 2026
3b36946
ci(scripts): Phase 7 - run Pester suite on Windows + Linux
sandersaares May 22, 2026
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
131 changes: 0 additions & 131 deletions .github/prompts/bump-crate-version.prompt.md

This file was deleted.

89 changes: 89 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,54 @@ jobs:
header: semver-check
delete: true

release-deps:
# Informational check: flags workspace crates that have unreleased modifications
# (changes newer than the crate's own last `version =` / `publish =` commit) and
# are transitively depended on by a crate this PR is releasing. The release set
# is derived from a PR-vs-base-ref version diff; the modification baseline is
# per-crate, so previously-merged-but-unreleased changes are flagged too. See
# scripts/check-unreleased-dependencies.ps1.
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Setup
uses: ./.github/actions/setup
with:
rust-toolchain: RUST_LATEST

- name: Fetch base ref
shell: bash
run: |
git fetch --no-tags origin "+refs/heads/${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }}"

- name: Analyze unreleased upstream dependencies
id: analyze
shell: pwsh
run: |
./scripts/check-unreleased-dependencies.ps1 `
-BaseRef "origin/${{ github.base_ref }}" `
-OutputFile release-deps-comment.md

- name: Post Unreleased-Dependency Comment
if: steps.analyze.outputs.has_findings == 'true' && github.event.pull_request.head.repo.full_name == github.repository
uses: marocchino/sticky-pull-request-comment@v3.0.4
with:
header: release-deps-check
path: release-deps-comment.md

- name: Remove Unreleased-Dependency Comment
if: steps.analyze.outputs.has_findings != 'true' && github.event.pull_request.head.repo.full_name == github.repository
uses: marocchino/sticky-pull-request-comment@v3.0.4
with:
header: release-deps-check
delete: true

extended-analysis:
name: extended-analysis (${{ matrix.os }})
if: github.event_name == 'pull_request' && needs.delta.outputs.skip != 'true'
Expand Down Expand Up @@ -451,6 +499,46 @@ jobs:
- name: Check External Type Exposure
run: cargo +${{ env.RUST_NIGHTLY_EXTERNAL_TYPES }} -Zscript scripts/check-external-types.rs ${{ env.RUST_NIGHTLY_EXTERNAL_TYPES }}

script-tests:
# Pester test suite for the release-related PowerShell scripts
# (release-crate.ps1, lib/releasing.ps1, check-unreleased-dependencies.ps1).
# Always runs (no delta gate) because script-level changes don't move any
# Rust crates so delta would mark the PR skippable, but the scripts
# themselves may still need validation. Cross-platform matrix mirrors the
# platforms developers run the scripts on locally.
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
steps:
# prep
- name: Checkout
uses: actions/checkout@v6.0.2
- name: Setup
# The synthetic-workspace fixture builder shells out to `cargo metadata`,
# so Rust must be available even though no Rust code is compiled.
uses: ./.github/actions/setup
with:
rust-toolchain: RUST_LATEST

- name: Install Pester
shell: pwsh
run: |
$existing = Get-Module Pester -ListAvailable |
Sort-Object Version -Descending |
Select-Object -First 1
if ($null -eq $existing -or $existing.Version -lt [version]'5.7.0') {
Install-Module -Name Pester -MinimumVersion 5.7.1 -Force -Scope CurrentUser -SkipPublisherCheck
} else {
Write-Host "Pester $($existing.Version) already installed; skipping."
}

# execute
- name: Run Pester Suite
shell: pwsh
run: ./scripts/tests/Pester/Run-Tests.ps1

# Single aggregating ("fan-in") status check. Branch protection should
# require ONLY this context for the workflow jobs below: it succeeds when
# every dependency either succeeded or was skipped, and fails if any
Expand Down Expand Up @@ -496,6 +584,7 @@ jobs:
- pr-title
- license-headers
- external-type-exposure
- script-tests
runs-on: ubuntu-latest
steps:
- name: Validate Dependency Results
Expand Down
3 changes: 3 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ To run all repository tooling locally, you will need the following prerequisites
* [Latest version of Git](https://git-scm.com/downloads/win) with components:
* Git LFS (Large File Storage)
* [Latest version of PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows)
* [Pester 5.7+](https://pester.dev/) for the release-script test suite — installed automatically by `just install-tools`. To install manually: `Install-Module -Name Pester -MinimumVersion 5.7.1 -Force -Scope CurrentUser -SkipPublisherCheck`.

For detailed configuration of the above, use your own judgement - the defaults should work but customization is also generally fine.

Expand All @@ -47,6 +48,7 @@ After installing the Rust toolchain, we setup repository-specific tooling:

1. Execute `just build` to build the workspace. Verify that the build is successful.
1. Execute `just test` to execute all tests in the workspace. Verify that all tests pass.
1. Execute `just test-scripts` to run the Pester suite for the release-related PowerShell scripts. Verify that all tests pass.
1. Validate that debugging works by opening `crates/tick/examples/basic.rs` and pressing the `Debug` link that appears above `main()`. This should successfully launch the example app under the debugger.

# Linux (WSL) environment setup
Expand Down Expand Up @@ -91,6 +93,7 @@ After installing the Rust toolchains, we setup the build target directory for fa

1. Execute `just build` to build the workspace. Verify that the build is successful.
1. Execute `just test` to execute all tests in the workspace. Verify that all tests pass.
1. Execute `just test-scripts` to run the Pester suite for the release-related PowerShell scripts. Verify that all tests pass.

## Setup Visual Studio Code integration

Expand Down
8 changes: 8 additions & 0 deletions justfiles/basic.just
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ readme:
readme-check:
cargo workspaces exec --ignore-private cargo doc2readme --check --lib --template ../README.j2

# Run the Pester test suite for the release-related PowerShell scripts.
[script]
test-scripts SCOPE="":
$ErrorActionPreference = "Stop"
$PSNativeCommandUseErrorActionPreference = $true

& "$(git rev-parse --show-toplevel)/scripts/tests/Pester/Run-Tests.ps1" -Path "{{ SCOPE }}"

# Runs unit and integration tests.
[script]
test FILTER="":
Expand Down
10 changes: 10 additions & 0 deletions justfiles/setup.just
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,13 @@ install-tools:

# This tool is not well maintained and fails to actually build if using locked dependencies. Okay then.
cargo install cargo-spellcheck@$env:CARGO_SPELLCHECK_VERSION

# Pester powers the release-script test suite (just test-scripts). Skip the
# install if the user already has a compatible version, otherwise install the
# current-user copy.
$pester = Get-Module Pester -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1
if ($null -eq $pester -or $pester.Version -lt [version]'5.7.0') {
Install-Module -Name Pester -MinimumVersion 5.7.1 -Force -Scope CurrentUser -SkipPublisherCheck
} else {
Write-Host "Pester $($pester.Version) already installed; skipping."
}
4 changes: 2 additions & 2 deletions scripts/check-external-types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn main() {
println!("=== External Type Exposure Check ===");
println!();
println!("Toolchain: {}", args.toolchain);
println!("Checking {} crate(s)", filtered_packages.len());
println!("Checking {} crates", filtered_packages.len());
println!("Skipped internal crates: {}", automation::INTERNAL_CRATES.join(", "));
println!();

Expand Down Expand Up @@ -80,7 +80,7 @@ fn main() {

if !failed_crates.is_empty() {
eprintln!();
eprintln!("❌ {} crate(s) failed:", failed_crates.len());
eprintln!("❌ {} crates failed:", failed_crates.len());
for (name, error) in &failed_crates {
eprintln!(" - {name}: {error}");
}
Expand Down
Loading
Loading