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.
132 lines
3.7 KiB
Go
132 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// generatedPaths is every file the generators are allowed to touch. Anything
|
|
// outside it means a generator reached further than expected, and the area is
|
|
// dropped rather than committed.
|
|
var generatedPaths = map[string]bool{
|
|
"hscontrol/types/types_clone.go": true,
|
|
"hscontrol/types/types_view.go": true,
|
|
"hscontrol/capver/capver_generated.go": true,
|
|
"hscontrol/capver/capver_test_data.go": true,
|
|
"gen/client/v1/client.gen.go": true,
|
|
"gen/client/v2/client.gen.go": true,
|
|
".github/workflows/test-integration.yaml": true,
|
|
}
|
|
|
|
// oapiPin finds the oapi-codegen version the Makefile pins, so the clients are
|
|
// regenerated with the same tool a developer running `make client` would get.
|
|
var oapiPin = regexp.MustCompile(`github\.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@(v[\w.\-]+)`)
|
|
|
|
var (
|
|
errNoOapiPin = errors.New("no oapi-codegen pin found in Makefile")
|
|
errStrayWrite = errors.New("generator wrote outside the generated set")
|
|
)
|
|
|
|
func oapiVersion(r *repo) (string, error) {
|
|
mk, err := r.readFile("Makefile")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
m := oapiPin.FindStringSubmatch(mk)
|
|
if m == nil {
|
|
return "", errNoOapiPin
|
|
}
|
|
|
|
return m[1], nil
|
|
}
|
|
|
|
// generateClients mirrors the Makefile's client recipe. The bot does not shell
|
|
// out to make, but check-generated.yml still runs the real target and diffs, so
|
|
// any drift between the two surfaces on the bot's own pull request.
|
|
func generateClients(ctx context.Context, r *repo) error {
|
|
version, err := oapiVersion(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tmp, err := os.CreateTemp("", "headscale-openapi-3.0.*.yaml")
|
|
if err != nil {
|
|
return fmt.Errorf("creating temporary spec: %w", err)
|
|
}
|
|
|
|
spec := tmp.Name()
|
|
|
|
tmp.Close()
|
|
defer os.Remove(spec)
|
|
|
|
tool := "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@" + version
|
|
|
|
for _, step := range [][]string{
|
|
{"go", "run", "./cmd/gen-openapi", "-downgrade", spec},
|
|
{"go", "run", tool, "-generate", "types,client", "-package", "clientv1", "-o", "gen/client/v1/client.gen.go", spec},
|
|
{"go", "run", "./cmd/gen-openapi", "-api", "v2", "-downgrade", spec},
|
|
{"go", "run", tool, "-generate", "types,client", "-package", "clientv2", "-o", "gen/client/v2/client.gen.go", spec},
|
|
} {
|
|
if _, err := r.nixRun(ctx, step...); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// applyGenerate refreshes every checked-in generated file. Most of the churn
|
|
// here is not caused by this repository at all: the capability-version table is
|
|
// scraped from tailscale's published tags, so it goes stale on an untouched
|
|
// tree the moment upstream ships a release.
|
|
func applyGenerate(ctx context.Context, r *repo) (change, error) {
|
|
if _, err := r.nixRun(ctx, "go", "generate", "./..."); err != nil {
|
|
return change{}, err
|
|
}
|
|
|
|
if err := generateClients(ctx, r); err != nil {
|
|
return change{}, err
|
|
}
|
|
|
|
// go generate ./... skips dot-directories, so the integration matrix
|
|
// generator has to be invoked from inside .github/workflows.
|
|
if _, err := r.nixRunIn(ctx, ".github/workflows", "go", "generate"); err != nil {
|
|
return change{}, err
|
|
}
|
|
|
|
touched, err := changedFiles(ctx, r)
|
|
if err != nil {
|
|
return change{}, err
|
|
}
|
|
|
|
if len(touched) == 0 {
|
|
return change{Empty: true}, nil
|
|
}
|
|
|
|
return change{
|
|
Summary: strings.Join(touched, ", "),
|
|
Detail: touched,
|
|
}, nil
|
|
}
|
|
|
|
// gateGenerate refuses a generator run that reached outside the known set.
|
|
func gateGenerate(ctx context.Context, r *repo) error {
|
|
touched, err := changedFiles(ctx, r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, f := range touched {
|
|
if !generatedPaths[f] {
|
|
return fmt.Errorf("%w: %s", errStrayWrite, f)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|