chore: migrate mail themes to shared framework and locked upstream inputs
This commit is contained in:
1 parent
5c0589f6f6
commit
fec3ace600
225 files changed
+4718
-15807
No files matched your search
@@ -0,0 +1,164 @@
|
||||
package upstream
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var tagPattern = regexp.MustCompile(`^v([0-9]+)\.[0-9]+\.[0-9]+$`)
|
||||
|
||||
func validTag(tag string) bool {
|
||||
m := tagPattern.FindStringSubmatch(tag)
|
||||
if m == nil {
|
||||
return false
|
||||
}
|
||||
major, err := strconv.Atoi(m[1])
|
||||
return err == nil && major >= 28
|
||||
}
|
||||
|
||||
// Sync downloads by resolved commit, validates in memory, then swaps the whole
|
||||
// snapshot. Network/adapter failures leave the existing snapshot untouched.
|
||||
func Sync(ctx context.Context, tag, dir string) error {
|
||||
return syncFrom(ctx, tag, dir, "https://api.github.com/repos/go-gitea/gitea/", "https://raw.githubusercontent.com/go-gitea/gitea/")
|
||||
}
|
||||
|
||||
func syncFrom(ctx context.Context, tag, dir, api, raw string) error {
|
||||
if !validTag(tag) {
|
||||
return fmt.Errorf("expected a stable Gitea 28+ tag, e.g. v28.0.0")
|
||||
}
|
||||
client := &http.Client{Timeout: 45 * time.Second}
|
||||
get := func(url string) ([]byte, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("User-Agent", "GiteaMailTemplates-snapshot")
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("%s: HTTP %d", url, resp.StatusCode)
|
||||
}
|
||||
b, err := io.ReadAll(io.LimitReader(resp.Body, 16<<20))
|
||||
return b, err
|
||||
}
|
||||
b, err := get(api + "commits/" + tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var commit struct {
|
||||
SHA string `json:"sha"`
|
||||
Commit struct {
|
||||
Tree struct {
|
||||
SHA string `json:"sha"`
|
||||
} `json:"tree"`
|
||||
} `json:"commit"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &commit); err != nil {
|
||||
return err
|
||||
}
|
||||
b, err = get(api + "git/trees/" + commit.Commit.Tree.SHA + "?recursive=1")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var tree struct {
|
||||
Truncated bool `json:"truncated"`
|
||||
Tree []struct {
|
||||
Path string `json:"path"`
|
||||
Type string `json:"type"`
|
||||
} `json:"tree"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &tree); err != nil {
|
||||
return err
|
||||
}
|
||||
if tree.Truncated {
|
||||
return fmt.Errorf("upstream tree is truncated")
|
||||
}
|
||||
s := &Snapshot{Lock: Lock{Schema: 1, Repository: "https://github.com/go-gitea/gitea", Tag: tag, Commit: commit.SHA, Files: map[string]string{}}, Files: map[string][]byte{}}
|
||||
for _, item := range tree.Tree {
|
||||
p := item.Path
|
||||
_, adapter := AdapterSources[p]
|
||||
selected := adapter || p == "LICENSE" || p == "public/assets/img/favicon.png" || (strings.HasPrefix(p, "templates/mail/") && strings.HasSuffix(p, ".tmpl")) || (strings.HasPrefix(p, "options/locale/locale_") && strings.HasSuffix(p, ".json"))
|
||||
if !selected || item.Type != "blob" {
|
||||
continue
|
||||
}
|
||||
b, err := get(raw + commit.SHA + "/" + p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Files[p] = b
|
||||
s.Lock.Files[p] = Digest(b)
|
||||
}
|
||||
if err := s.validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
abs, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Never replace a checkout or arbitrary non-snapshot directory.
|
||||
if filepath.Base(abs) != "upstream" {
|
||||
return fmt.Errorf("snapshot destination must be named upstream")
|
||||
}
|
||||
if entries, err := os.ReadDir(abs); err == nil && len(entries) > 0 {
|
||||
if _, err := loadFiles(abs); err != nil {
|
||||
return fmt.Errorf("refusing to replace invalid existing snapshot: %w", err)
|
||||
}
|
||||
}
|
||||
stage, err := os.MkdirTemp(filepath.Dir(abs), ".upstream-stage-")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(stage)
|
||||
for p, data := range s.Files {
|
||||
filename := filepath.Join(stage, filepath.FromSlash(p))
|
||||
if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(filename, data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
b, err = json.MarshalIndent(s.Lock, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b = append(b, '\n')
|
||||
if err := os.WriteFile(filepath.Join(stage, "lock.json"), b, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := os.Stat(abs); err == nil {
|
||||
backup, err := os.MkdirTemp(filepath.Dir(abs), ".upstream-backup-")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Remove(backup); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(abs, backup); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(stage, abs); err != nil {
|
||||
_ = os.Rename(backup, abs)
|
||||
return err
|
||||
}
|
||||
if err := os.RemoveAll(backup); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := os.Rename(stage, abs); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("[PASS] Locked %s (%s): %d templates, %d languages\n", tag, commit.SHA, len(s.Templates), len(s.Locales))
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user