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
7 changes: 5 additions & 2 deletions .github/workflows/blink_parity_mautic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ jobs:
common: true,
standaloneLine: true,
cleanCode: true,
);
)
// single process: parallel workers overflow the NDJSON buffer on
// large mautic files and abort the PHP run (blink ignores this)
->withoutParallel();
PHP
cp /tmp/mautic/ecs.php /tmp/mautic/ecs-copy.php

Expand All @@ -92,7 +95,7 @@ jobs:
- name: Compare the two trees
run: |
# ratchet gate: fail once the differing share crosses this; lower it as parity improves
MAX_DIFF_PERCENT=1.7
MAX_DIFF_PERCENT=1.6
total=0
differ=0
differing_files=""
Expand Down
2 changes: 2 additions & 0 deletions blink/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/blink
/check-sources
63 changes: 44 additions & 19 deletions blink/cmd/check-sources/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Command check-sources verifies that every registered fixer links to a
// reachable PHP-CS-Fixer source file on GitHub. It is run in CI so a renamed or
// removed upstream rule fails the build.
// removed upstream rule fails the build. GitHub rate-limits bursts of HEAD
// requests with 503/429, so each URL is retried with backoff before failing.
package main

import (
Expand All @@ -12,34 +13,58 @@ import (
"blink/internal/fixer/rules"
)

func main() {
client := &http.Client{Timeout: 20 * time.Second}
failed := false

for _, f := range rules.All() {
url := f.SourceURL()
const maxAttempts = 4

// checkURL returns the final status code (or an error) for url, retrying on a
// 5xx or 429 that GitHub returns when throttling a burst of requests.
func checkURL(client *http.Client, url string) (int, error) {
var lastStatus int
var lastErr error
for attempt := 1; attempt <= maxAttempts; attempt++ {
req, err := http.NewRequest(http.MethodHead, url, nil)
if err != nil {
fmt.Printf("FAIL %s: %v\n", f.Name(), err)
failed = true
continue
return 0, err
}

req.Header.Set("User-Agent", "blink-check-sources")
resp, err := client.Do(req)
if err != nil {
fmt.Printf("FAIL %s: %v\n", f.Name(), err)
failed = true
continue
lastErr = err
} else {
_ = resp.Body.Close()
lastStatus, lastErr = resp.StatusCode, nil
if resp.StatusCode == http.StatusOK {
return resp.StatusCode, nil
}
// a 4xx other than 429 is a genuine missing/renamed source, not throttling
if resp.StatusCode != http.StatusTooManyRequests && resp.StatusCode < 500 {
return resp.StatusCode, nil
}
}
_ = resp.Body.Close()
if attempt < maxAttempts {
time.Sleep(time.Duration(attempt) * 2 * time.Second)
}
}
return lastStatus, lastErr
}

if resp.StatusCode != http.StatusOK {
fmt.Printf("FAIL %s: %s -> %d\n", f.Name(), url, resp.StatusCode)
func main() {
client := &http.Client{Timeout: 20 * time.Second}
failed := false

for _, f := range rules.All() {
url := f.SourceURL()
status, err := checkURL(client, url)
switch {
case err != nil:
fmt.Printf("FAIL %s: %v\n", f.Name(), err)
failed = true
case status != http.StatusOK:
fmt.Printf("FAIL %s: %s -> %d\n", f.Name(), url, status)
failed = true
continue
default:
fmt.Printf("OK %s\n", url)
}
fmt.Printf("OK %s\n", url)
time.Sleep(150 * time.Millisecond) // throttle so GitHub does not rate-limit the burst
}

if failed {
Expand Down
Loading