mirror of
https://github.com/juanfont/headscale.git
synced 2026-10-03 05:13:36 +09:00
tools/bump: add the version bump tool
Keeps the interlocked pins current and reports what it could not move. Areas apply, gate and commit one at a time, so a dependency that breaks the build costs one commit rather than the whole pull request.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Gate levels, from cheapest to most thorough.
|
||||
const (
|
||||
gateNone = "none"
|
||||
gateQuick = "quick"
|
||||
gateFull = "full"
|
||||
)
|
||||
|
||||
var errUnknownGate = errors.New("unknown gate level (want none|quick|full)")
|
||||
|
||||
// flakeChecks are the same derivations nix-checks.yml evaluates on a pull
|
||||
// request. Running them here is close to free: this job runs on the default
|
||||
// branch, so its binary-cache writes are readable by every later pull request
|
||||
// job, which then gets a cache hit instead of a rebuild.
|
||||
var flakeChecks = []string{"build", "gotest", "golangci-lint", "formatting"}
|
||||
|
||||
// dockerGates stand in for the integration matrix. They are the two images
|
||||
// whose builder pin actually breaks, plus the wasm client, which is cheap and
|
||||
// exercises the go.mod pairing.
|
||||
var dockerGates = []struct {
|
||||
File string
|
||||
Target string
|
||||
}{
|
||||
{File: "Dockerfile.tailscale-HEAD", Target: "build-env"},
|
||||
{File: "Dockerfile.derper"},
|
||||
{File: "Dockerfile.wasmclient"},
|
||||
}
|
||||
|
||||
// finalGate judges the accumulated tree. The ~170-job arm integration matrix is
|
||||
// deliberately left to the pull request's own CI rather than duplicated here.
|
||||
func finalGate(ctx context.Context, r *repo, level string) error {
|
||||
switch level {
|
||||
case gateNone:
|
||||
return nil
|
||||
case gateQuick:
|
||||
return nixCheck(ctx, r, "build")
|
||||
case gateFull:
|
||||
default:
|
||||
return fmt.Errorf("%w: %s", errUnknownGate, level)
|
||||
}
|
||||
|
||||
for _, check := range flakeChecks {
|
||||
err := nixCheck(ctx, r, check)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, d := range dockerGates {
|
||||
argv := []string{"docker", "build", "--file", d.File}
|
||||
if d.Target != "" {
|
||||
argv = append(argv, "--target", d.Target)
|
||||
}
|
||||
|
||||
log.Printf("gate: %s", d.File)
|
||||
|
||||
if _, err := r.run(ctx, append(argv, ".")...); err != nil { //nolint:noinlineerr
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func nixCheck(ctx context.Context, r *repo, name string) error {
|
||||
log.Printf("gate: nix check %s", name)
|
||||
|
||||
_, err := r.run(ctx, "nix", "build", "--fallback", "-L",
|
||||
fmt.Sprintf(".#checks.%s.%s", r.System, name))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// enforceFinalGate drops committed areas newest-first until the tree passes.
|
||||
// Popping from the tip is safe because every area is exactly one commit, and it
|
||||
// is the cheapest correct answer: the gate cannot say which area broke, only
|
||||
// that the combination did.
|
||||
func enforceFinalGate(ctx context.Context, r *repo, results []result, level string) ([]result, error) {
|
||||
for {
|
||||
err := finalGate(ctx, r, level)
|
||||
if err == nil {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
newest := -1
|
||||
|
||||
for i, res := range results {
|
||||
if res.Commit != "" {
|
||||
newest = i
|
||||
}
|
||||
}
|
||||
|
||||
if newest < 0 {
|
||||
return results, fmt.Errorf("gate fails on an unmodified tree: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("gate failed, dropping area %s", results[newest].Area)
|
||||
|
||||
if _, err := r.run(ctx, "git", "reset", "--hard", "HEAD~1"); err != nil { //nolint:noinlineerr
|
||||
return results, err
|
||||
}
|
||||
|
||||
results[newest].State = stateDropped
|
||||
results[newest].Reason = reasonOf(err)
|
||||
results[newest].Log = logOf(err)
|
||||
results[newest].Commit = ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user