mirror of
https://github.com/juanfont/headscale.git
synced 2026-09-27 02:26:21 +09:00
c3d771e23e
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.
148 lines
3.4 KiB
Go
148 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// lockNode is the slice of a flake.lock entry that identifies what an input is
|
|
// pinned to.
|
|
type lockNode struct {
|
|
Locked struct {
|
|
Rev string `json:"rev"`
|
|
LastModified int64 `json:"lastModified"`
|
|
} `json:"locked"`
|
|
}
|
|
|
|
type flakeLock struct {
|
|
Nodes map[string]lockNode `json:"nodes"`
|
|
}
|
|
|
|
func readLock(r *repo) (flakeLock, error) {
|
|
var lock flakeLock
|
|
|
|
b, err := r.readFile("flake.lock")
|
|
if err != nil {
|
|
return lock, err
|
|
}
|
|
|
|
if err := json.Unmarshal([]byte(b), &lock); err != nil { //nolint:noinlineerr
|
|
return lock, fmt.Errorf("parsing flake.lock: %w", err)
|
|
}
|
|
|
|
return lock, nil
|
|
}
|
|
|
|
// lockDiff reports the inputs whose revision moved: one detailed line each,
|
|
// plus the bare names for the commit subject.
|
|
func lockDiff(before, after flakeLock) ([]string, []string) {
|
|
var detail, names []string
|
|
|
|
for name, post := range after.Nodes {
|
|
pre, ok := before.Nodes[name]
|
|
if !ok || post.Locked.Rev == "" || pre.Locked.Rev == post.Locked.Rev {
|
|
continue
|
|
}
|
|
|
|
detail = append(detail, fmt.Sprintf("%s %s -> %s", name, short(pre.Locked.Rev), short(post.Locked.Rev)))
|
|
names = append(names, name)
|
|
}
|
|
|
|
sort.Strings(detail)
|
|
sort.Strings(names)
|
|
|
|
return detail, names
|
|
}
|
|
|
|
func short(rev string) string {
|
|
if len(rev) > 7 {
|
|
return rev[:7]
|
|
}
|
|
|
|
return rev
|
|
}
|
|
|
|
// applyFlake refreshes every flake input. Because flake.nix asks for
|
|
// buildGoLatestModule and go_latest, this is also how Go and every devShell
|
|
// tool get a new version.
|
|
func applyFlake(ctx context.Context, r *repo) (change, error) {
|
|
before, err := readLock(r)
|
|
if err != nil {
|
|
return change{}, err
|
|
}
|
|
|
|
if _, err := r.run(ctx, "nix", "flake", "update"); err != nil { //nolint:noinlineerr
|
|
return change{}, err
|
|
}
|
|
|
|
after, err := readLock(r)
|
|
if err != nil {
|
|
return change{}, err
|
|
}
|
|
|
|
moved, names := lockDiff(before, after)
|
|
if len(moved) == 0 {
|
|
return change{Empty: true}, nil
|
|
}
|
|
|
|
detail := moved
|
|
|
|
if tools, err := toolVersions(ctx, r); err == nil { //nolint:noinlineerr
|
|
detail = append(detail, tools...)
|
|
}
|
|
|
|
return change{
|
|
Summary: shortList(names),
|
|
Detail: detail,
|
|
}, nil
|
|
}
|
|
|
|
// shortList keeps a commit subject readable when many inputs move at once.
|
|
func shortList(names []string) string {
|
|
const maxNamed = 3
|
|
|
|
if len(names) <= maxNamed {
|
|
return strings.Join(names, ", ")
|
|
}
|
|
|
|
return fmt.Sprintf("%s and %d more", strings.Join(names[:maxNamed], ", "), len(names)-maxNamed)
|
|
}
|
|
|
|
// gateFlake proves the flake still evaluates before anything expensive runs.
|
|
func gateFlake(ctx context.Context, r *repo) error {
|
|
_, err := r.run(ctx, "nix", "eval", "--raw",
|
|
fmt.Sprintf(".#packages.%s.headscale.name", r.System))
|
|
|
|
return err
|
|
}
|
|
|
|
// goVersion is the Go the devShell now provides, without the "go" prefix.
|
|
func goVersion(ctx context.Context, r *repo) (string, error) {
|
|
out, err := r.nixRun(ctx, "go", "env", "GOVERSION")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return strings.TrimPrefix(strings.TrimSpace(out), "go"), nil
|
|
}
|
|
|
|
// toolVersions reports the versions that most often decide whether a lock bump
|
|
// turns the pull request red.
|
|
func toolVersions(ctx context.Context, r *repo) ([]string, error) {
|
|
goVer, err := goVersion(ctx, r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
versions := []string{"go " + goVer}
|
|
|
|
if out, err := r.nixRun(ctx, "golangci-lint", "version"); err == nil { //nolint:noinlineerr
|
|
versions = append(versions, strings.TrimSpace(strings.SplitN(out, "\n", 2)[0]))
|
|
}
|
|
|
|
return versions, nil
|
|
}
|