Files
stalwart-migrator/internal/preflight/release.go
T
jcoffey-dev 4b0bec8956 Add SPDX headers to every Go file
GPLv3's "How to Apply These Terms" asks for a notice in each source file;
this is the modern two-line SPDX form of it rather than the full paragraph.
82 files, including tests.

The blank line after the header is load-bearing. In Go a comment block
immediately preceding `package X` becomes the package doc comment, so
without the separator the SPDX lines would be absorbed into the doc for the
eleven packages whose doc.go (or main.go) opens with one, and `go doc` would
print them. Verified it doesn't.
2026-08-23 18:03:15 -07:00

78 lines
2.3 KiB
Go

// SPDX-FileCopyrightText: 2026 LINUXexpert-org
// SPDX-License-Identifier: GPL-3.0-or-later
package preflight
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
)
// githubAPIBase is a var, not a const, so tests can point it at an
// httptest server instead of hitting the real GitHub API.
var githubAPIBase = "https://api.github.com/repos/stalwartlabs/stalwart/releases"
type ReleaseAsset struct {
Name string `json:"name"`
DownloadURL string `json:"browser_download_url"`
SizeBytes int64 `json:"size"`
}
type Release struct {
TagName string `json:"tag_name"`
Assets []ReleaseAsset `json:"assets"`
}
// ResolveRelease looks up a Stalwart release from the public GitHub API.
// version is either an exact tag like "0.16.14" (a "v" prefix is added if
// missing) or "latest".
func ResolveRelease(ctx context.Context, httpClient *http.Client, version string) (*Release, error) {
url := githubAPIBase + "/latest"
if version != "" && version != "latest" {
tag := version
if !strings.HasPrefix(tag, "v") {
tag = "v" + tag
}
url = githubAPIBase + "/tags/" + tag
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}
req.Header.Set("Accept", "application/vnd.github+json")
if httpClient == nil {
httpClient = &http.Client{Timeout: 30 * time.Second}
}
resp, err := httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("preflight: fetch release %s: %w", url, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("preflight: fetch release %s: unexpected status %s", url, resp.Status)
}
var rel Release
if err := json.NewDecoder(resp.Body).Decode(&rel); err != nil {
return nil, fmt.Errorf("preflight: parse release response from %s: %w", url, err)
}
return &rel, nil
}
// ChecksumAsset returns the release asset that looks like a published
// checksum manifest, if any. Its presence isn't guaranteed by Stalwart's
// release process, so callers must treat a nil result as "no independently
// published checksum to verify the download against", not an error.
func ChecksumAsset(rel *Release) *ReleaseAsset {
for i := range rel.Assets {
name := strings.ToLower(rel.Assets[i].Name)
if strings.Contains(name, "sha256") || strings.Contains(name, "checksum") {
return &rel.Assets[i]
}
}
return nil
}