mirror of
https://github.com/juanfont/headscale.git
synced 2026-10-03 05:13:36 +09:00
tools/bump: bump the pinned developer tools
The oapi-codegen pin stays the single source of truth: the generate area reads it back out of the Makefile, so the clients are regenerated with whatever this lands on.
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const githubAPI = "https://api.github.com"
|
||||
|
||||
var errNoRelease = errors.New("no published release")
|
||||
|
||||
// githubToken is resolved once. Unauthenticated GitHub allows sixty requests an
|
||||
// hour, which the action-pin sweep alone would exhaust, so a token is worth
|
||||
// looking for even outside CI.
|
||||
var githubToken = sync.OnceValue(func() string {
|
||||
for _, env := range []string{"GH_TOKEN", "GITHUB_TOKEN"} {
|
||||
if v := os.Getenv(env); v != "" {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
out, err := exec.Command("gh", "auth", "token").Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(out))
|
||||
})
|
||||
|
||||
// githubJSON performs an authenticated GET against the GitHub REST API.
|
||||
func githubJSON(ctx context.Context, path string, out any) error {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, githubAPI+path, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("building request for %s: %w", path, err)
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", "application/vnd.github+json")
|
||||
|
||||
if token := githubToken(); token != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: proxyTimeout}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GET %s: %w", path, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("GET %s: %w: %s", path, errHTTPStatus, resp.Status)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading %s: %w", path, err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, out); err != nil { //nolint:noinlineerr
|
||||
return fmt.Errorf("decoding %s: %w", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// latestRelease is the tag of a repository's newest published release.
|
||||
func latestRelease(ctx context.Context, owner, name string) (string, error) {
|
||||
var release struct {
|
||||
TagName string `json:"tag_name"`
|
||||
}
|
||||
|
||||
err := githubJSON(ctx, fmt.Sprintf("/repos/%s/%s/releases/latest", owner, name), &release)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if release.TagName == "" {
|
||||
return "", fmt.Errorf("%w for %s/%s", errNoRelease, owner, name)
|
||||
}
|
||||
|
||||
return release.TagName, nil
|
||||
}
|
||||
Reference in New Issue
Block a user