Skip to content

Commit d0409dc

Browse files
Fcursoragent
andcommitted
fix(git): keep pre-push fast by default
Heavy validate and changed-shard Pester are opt-in so git push no longer re-runs multi-minute checks that hung local pushes. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 8476749 commit d0409dc

3 files changed

Lines changed: 75 additions & 63 deletions

File tree

docs/guides/TESTING.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -635,17 +635,20 @@ pwsh -NoProfile -File scripts/utils/code-quality/run-pester-changed-shards.ps1 -
635635
pwsh -NoProfile -File scripts/utils/code-quality/run-pester-changed-shards.ps1 -ListOnly
636636
```
637637

638-
Pre-push runs the same changed-shard filters by default (after validate-profile with
639-
cspell/markdownlint gating). Opt out with `PS_PROFILE_SKIP_PUSH_TESTS=1` or
640-
`PS_PROFILE_PUSH_TESTS=0`. Override the diff base with
641-
`PS_PROFILE_PUSH_TESTS_SINCE=origin/main`. Pre-commit stays format + validate only.
638+
Pre-push stays fast by default (no validate / no local shard run — pre-commit and CI
639+
already cover those). Opt into heavier local gates when you want them:
642640

643641
```bash
642+
PS_PROFILE_PUSH_VALIDATE=1 git push # re-run validate-profile before push
643+
PS_PROFILE_PUSH_TESTS=1 git push # run changed CI Pester shards before push
644+
# optional: PS_PROFILE_PUSH_TESTS_SINCE=origin/main
644645
just pre-push-checks
645646
# or
646647
pwsh -NoProfile -File scripts/git/hooks/pre-push.ps1
647648
```
648649

650+
Pre-commit stays format + validate only.
651+
649652
Each enabled shard is a bounded path set executed via `run-pester-ci-shard.ps1`:
650653

651654
```powershell

scripts/git/hooks/pre-push.ps1

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,33 @@
22
scripts/git/hooks/pre-push.ps1
33
44
.SYNOPSIS
5-
Runs validation and CI-aligned checks before pushing to remote.
5+
Lightweight gate before push; heavy checks are opt-in.
66
77
.DESCRIPTION
8-
Invoked by the wrapper installed into .git/hooks/pre-push (via install-githooks.ps1),
9-
which calls this file under scripts/git/hooks/. Runs validate-profile with the same
10-
cspell/markdownlint gating as pre-commit, then runs changed CI Pester shards
11-
(same filters as GitHub Actions) by default.
12-
13-
Environment variables:
14-
- PS_PROFILE_SKIP_PUSH_VALIDATE=1 Skip validate-profile
15-
- PS_PROFILE_SKIP_PUSH_TESTS=1 Skip changed-shard Pester run
16-
- PS_PROFILE_PUSH_TESTS=0 Skip changed-shard tests (legacy opt-out)
17-
- PS_PROFILE_PUSH_TESTS=1 Force changed-shard tests (default is already on)
18-
- PS_PROFILE_PUSH_TESTS_SINCE Diff base for shards (default: origin/main)
8+
Invoked by the wrapper in .git/hooks/pre-push (via install-githooks.ps1).
9+
10+
Default behavior is intentionally fast so `git push` does not hang:
11+
- Does NOT re-run validate-profile (pre-commit already covers format + validate).
12+
- Does NOT run changed-shard Pester (use CI / opt-in env).
13+
14+
Opt-in heavier gates (expected to take minutes):
15+
- PS_PROFILE_PUSH_VALIDATE=1 Run validate-profile (cspell, lint, markdownlint, …)
16+
- PS_PROFILE_PUSH_TESTS=1 Run changed CI Pester shards (same filters as GHA)
17+
- PS_PROFILE_PUSH_TESTS_SINCE Diff base for shards (default: origin/main)
18+
19+
Explicit skip (overrides opt-in):
20+
- PS_PROFILE_SKIP_PUSH_VALIDATE=1
21+
- PS_PROFILE_SKIP_PUSH_TESTS=1 or PS_PROFILE_PUSH_TESTS=0
1922
2023
.EXAMPLE
2124
git push
2225
23-
This hook is automatically invoked by git before pushing.
26+
Fast push (no validate / no local shard run).
2427
2528
.EXAMPLE
26-
pwsh -NoProfile -File scripts/git/hooks/pre-push.ps1
29+
PS_PROFILE_PUSH_TESTS=1 git push
2730
28-
Run the pre-push checks manually.
31+
Also run changed-shard Pester before push.
2932
#>
3033

3134
# This script lives at scripts/git/hooks/pre-push.ps1 → scripts/ is two levels up.
@@ -55,17 +58,18 @@ catch {
5558
}
5659

5760
$psExe = Get-PowerShellExecutable
58-
$skipValidate = $env:PS_PROFILE_SKIP_PUSH_VALIDATE -eq '1'
5961

60-
if (-not $skipValidate) {
62+
# Heavy validate is opt-in. Pre-commit already ran it on commits; repeating here
63+
# routinely stuck pushes for several minutes.
64+
$wantValidate = ($env:PS_PROFILE_PUSH_VALIDATE -eq '1') -and ($env:PS_PROFILE_SKIP_PUSH_VALIDATE -ne '1')
65+
if ($wantValidate) {
6166
$validate = Join-Path $repoRoot 'scripts' 'checks' 'validate-profile.ps1'
6267
if (-not (Test-Path -LiteralPath $validate)) {
6368
Exit-WithCode -ExitCode $EXIT_SETUP_ERROR -Message "pre-push: validate-profile not found: $validate"
6469
}
6570

66-
Write-ScriptMessage -Message 'pre-push: running validate-profile (security, lint, cspell, markdownlint, comment help, idempotency, duplicates)'
71+
Write-ScriptMessage -Message 'pre-push: running validate-profile (PS_PROFILE_PUSH_VALIDATE=1)'
6772

68-
# Match pre-commit / CI: require cspell when local Node tooling is present.
6973
$localCspell = @(
7074
(Join-Path $repoRoot 'node_modules' '.bin' 'cspell')
7175
(Join-Path $repoRoot 'node_modules' '.bin' 'cspell.cmd')
@@ -81,23 +85,18 @@ if (-not $skipValidate) {
8185
}
8286
}
8387
else {
84-
Write-ScriptMessage -Message 'pre-push: skipping validate-profile (PS_PROFILE_SKIP_PUSH_VALIDATE=1)'
88+
Write-ScriptMessage -Message 'pre-push: skipping validate-profile (set PS_PROFILE_PUSH_VALIDATE=1 to enable; pre-commit already validated commits)'
8589
}
8690

87-
# Changed CI shards — on by default (same filters as GitHub Actions Test - Pester).
88-
# Opt out: PS_PROFILE_SKIP_PUSH_TESTS=1 or PS_PROFILE_PUSH_TESTS=0
89-
$runPushTests = $true
90-
if (($env:PS_PROFILE_SKIP_PUSH_TESTS -eq '1') -or ($env:PS_PROFILE_PUSH_TESTS -eq '0')) {
91-
$runPushTests = $false
92-
}
93-
if ($env:PS_PROFILE_PUSH_TESTS -eq '1') {
94-
$runPushTests = $true
95-
}
91+
# Changed CI shards — opt-in only (can expand to many shards and hang pushes).
92+
$wantTests = ($env:PS_PROFILE_PUSH_TESTS -eq '1') -and
93+
($env:PS_PROFILE_SKIP_PUSH_TESTS -ne '1') -and
94+
($env:PS_PROFILE_PUSH_TESTS -ne '0')
9695

97-
if ($runPushTests) {
96+
if ($wantTests) {
9897
$changedShards = Join-Path $repoRoot 'scripts' 'utils' 'code-quality' 'run-pester-changed-shards.ps1'
9998
if (Test-Path -LiteralPath $changedShards) {
100-
Write-ScriptMessage -Message 'pre-push: running Pester CI shards for local changes (same filters as GitHub Actions)'
99+
Write-ScriptMessage -Message 'pre-push: running Pester CI shards for local changes (PS_PROFILE_PUSH_TESTS=1)'
101100
$since = if ($env:PS_PROFILE_PUSH_TESTS_SINCE) { $env:PS_PROFILE_PUSH_TESTS_SINCE } else { 'origin/main' }
102101
& $psExe -NoProfile -File $changedShards -ChangedSince $since -IncludeUntracked -Quiet
103102
if ($LASTEXITCODE -ne 0) {
@@ -109,7 +108,7 @@ if ($runPushTests) {
109108
}
110109
}
111110
else {
112-
Write-ScriptMessage -Message 'pre-push: skipping changed-shard tests (PS_PROFILE_SKIP_PUSH_TESTS=1 or PS_PROFILE_PUSH_TESTS=0)'
111+
Write-ScriptMessage -Message 'pre-push: skipping changed-shard tests (set PS_PROFILE_PUSH_TESTS=1 to enable; CI runs shards on PR)'
113112
}
114113

115114
Exit-WithCode -ExitCode $EXIT_SUCCESS -Message 'pre-push: all checks passed'

tests/unit/utility/pre/utility-pre-push.tests.ps1

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ function global:New-PrePushTestRepository {
3030
Set-Content -LiteralPath (Join-Path $cqDir 'run-pester-changed-shards.ps1') -Value "exit $ChangedShardsExitCode" -NoNewline
3131
}
3232

33-
# Mirror real layout: scripts/git/hooks/pre-push.ps1 (install-githooks wrappers call this path)
3433
$hooksDir = Join-Path $scriptsDir 'git' 'hooks'
3534
New-Item -ItemType Directory -Path $hooksDir -Force | Out-Null
3635
Copy-Item -LiteralPath $script:PrePushHookScript -Destination (Join-Path $hooksDir 'pre-push.ps1') -Force
@@ -87,58 +86,69 @@ BeforeAll {
8786
}
8887

8988
Describe 'pre-push.ps1 execution' {
90-
It 'Passes when validate-profile and changed-shards succeed' {
91-
$repo = New-PrePushTestRepository -ValidateExitCode 0 -ChangedShardsExitCode 0
89+
It 'Passes quickly by default without running validate or shard tests' {
90+
$repo = New-PrePushTestRepository -ValidateExitCode 1 -ChangedShardsExitCode 1
9291
$result = Invoke-PrePushHook -RepositoryRoot $repo
9392
$result.ExitCode | Should -Be 0
93+
$result.Output | Should -Match 'skipping validate-profile'
94+
$result.Output | Should -Match 'skipping changed-shard tests'
95+
$result.Output | Should -Match 'pre-push: all checks passed'
9496
}
9597

96-
It 'Prints validate-profile and changed-shard status before completing successfully' {
97-
$repo = New-PrePushTestRepository -ValidateExitCode 0 -ChangedShardsExitCode 0
98-
$result = Invoke-PrePushHook -RepositoryRoot $repo
99-
98+
It 'Runs validate-profile when PS_PROFILE_PUSH_VALIDATE=1' {
99+
$repo = New-PrePushTestRepository -ValidateExitCode 0 -ChangedShardsExitCode 1
100+
$result = Invoke-PrePushHook -RepositoryRoot $repo -Environment @{
101+
PS_PROFILE_PUSH_VALIDATE = '1'
102+
}
100103
$result.ExitCode | Should -Be 0
101-
$result.Output | Should -Match 'pre-push: running validate-profile'
102-
$result.Output | Should -Match 'pre-push: running Pester CI shards'
103-
$result.Output | Should -Match 'pre-push: all checks passed'
104+
$result.Output | Should -Match 'running validate-profile'
105+
$result.Output | Should -Match 'skipping changed-shard tests'
104106
}
105107

106-
It 'Fails when validate-profile returns a non-zero exit code' {
108+
It 'Fails when opt-in validate-profile returns non-zero' {
107109
$repo = New-PrePushTestRepository -ValidateExitCode 1
108-
$result = Invoke-PrePushHook -RepositoryRoot $repo
110+
$result = Invoke-PrePushHook -RepositoryRoot $repo -Environment @{
111+
PS_PROFILE_PUSH_VALIDATE = '1'
112+
}
109113
$result.ExitCode | Should -BeIn @(1, 2)
110114
$result.Output | Should -Match 'validate-profile failed|pre-push: validate-profile failed'
111115
}
112116

113-
It 'Fails when validate-profile.ps1 is missing from the repository' {
117+
It 'Fails when validate-profile.ps1 is missing and validate is opted in' {
114118
$repo = New-PrePushTestRepository -OmitValidateScript
115-
$result = Invoke-PrePushHook -RepositoryRoot $repo
119+
$result = Invoke-PrePushHook -RepositoryRoot $repo -Environment @{
120+
PS_PROFILE_PUSH_VALIDATE = '1'
121+
}
116122
$result.ExitCode | Should -BeIn @(1, 2, 3)
117-
$result.Output | Should -Match 'validate-profile|Cannot bind|not found|failed'
123+
$result.Output | Should -Match 'validate-profile|not found|failed'
118124
}
119125

120-
It 'Fails when changed-shard runner returns a non-zero exit code' {
126+
It 'Runs changed-shard tests when PS_PROFILE_PUSH_TESTS=1' {
127+
$repo = New-PrePushTestRepository -ValidateExitCode 1 -ChangedShardsExitCode 0
128+
$result = Invoke-PrePushHook -RepositoryRoot $repo -Environment @{
129+
PS_PROFILE_PUSH_TESTS = '1'
130+
}
131+
$result.ExitCode | Should -Be 0
132+
$result.Output | Should -Match 'running Pester CI shards'
133+
$result.Output | Should -Match 'skipping validate-profile'
134+
}
135+
136+
It 'Fails when opt-in changed-shard runner returns non-zero' {
121137
$repo = New-PrePushTestRepository -ValidateExitCode 0 -ChangedShardsExitCode 1
122-
$result = Invoke-PrePushHook -RepositoryRoot $repo
138+
$result = Invoke-PrePushHook -RepositoryRoot $repo -Environment @{
139+
PS_PROFILE_PUSH_TESTS = '1'
140+
}
123141
$result.ExitCode | Should -BeIn @(1, 2)
124142
$result.Output | Should -Match 'changed-shard Pester run failed'
125143
}
126144

127-
It 'Skips changed-shard tests when PS_PROFILE_SKIP_PUSH_TESTS=1' {
145+
It 'Skips opt-in tests when PS_PROFILE_SKIP_PUSH_TESTS=1' {
128146
$repo = New-PrePushTestRepository -ValidateExitCode 0 -ChangedShardsExitCode 1
129147
$result = Invoke-PrePushHook -RepositoryRoot $repo -Environment @{
148+
PS_PROFILE_PUSH_TESTS = '1'
130149
PS_PROFILE_SKIP_PUSH_TESTS = '1'
131150
}
132151
$result.ExitCode | Should -Be 0
133152
$result.Output | Should -Match 'skipping changed-shard tests'
134153
}
135-
136-
It 'Skips validate-profile when PS_PROFILE_SKIP_PUSH_VALIDATE=1' {
137-
$repo = New-PrePushTestRepository -ValidateExitCode 1 -ChangedShardsExitCode 0
138-
$result = Invoke-PrePushHook -RepositoryRoot $repo -Environment @{
139-
PS_PROFILE_SKIP_PUSH_VALIDATE = '1'
140-
}
141-
$result.ExitCode | Should -Be 0
142-
$result.Output | Should -Match 'skipping validate-profile'
143-
}
144154
}

0 commit comments

Comments
 (0)