Generates a new repo from mathias/template-go-web via Gitea's generate API, then substitutes __PROJECT_NAME__ and __MODULE_PATH__ placeholders in six known files (best-effort, partial failure surfaced in result). Validates name regex, allowlist, template flag, and destination non-existence before generating. Adds Template field to gitea.Repo. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
73 lines
2.2 KiB
Go
73 lines
2.2 KiB
Go
package gitea
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// GenerateFromTemplateArgs is the request body for POST /repos/{owner}/{repo}/generate.
|
|
type GenerateFromTemplateArgs struct {
|
|
Owner string `json:"owner"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
Private bool `json:"private"`
|
|
DefaultBranch string `json:"default_branch,omitempty"`
|
|
GitContent bool `json:"git_content"` // include all template files
|
|
}
|
|
|
|
// GenerateFromTemplate creates a new repository from a template via POST /repos/{tmplOwner}/{tmplName}/generate.
|
|
func (c *Client) GenerateFromTemplate(ctx context.Context, tmplOwner, tmplName string, args GenerateFromTemplateArgs) (*Repo, error) {
|
|
p := fmt.Sprintf("/api/v1/repos/%s/%s/generate", tmplOwner, tmplName)
|
|
payload, err := json.Marshal(args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
body, status, err := c.PostJSON(ctx, p, payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := MapStatus(status, body); err != nil {
|
|
return nil, err
|
|
}
|
|
var r Repo
|
|
if err := json.Unmarshal(body, &r); err != nil {
|
|
return nil, err
|
|
}
|
|
return &r, nil
|
|
}
|
|
|
|
// SubstituteFile reads a file from the given branch, applies string replacements,
|
|
// and writes it back if any changes were made. Best-effort — returns a wrapped error
|
|
// that includes the file path.
|
|
func (c *Client) SubstituteFile(ctx context.Context, owner, repo, branch, path string, replacements map[string]string) error {
|
|
fc, err := c.GetFileContents(ctx, owner, repo, path, branch)
|
|
if err != nil {
|
|
return fmt.Errorf("read %s: %w", path, err)
|
|
}
|
|
decoded, err := base64.StdEncoding.DecodeString(fc.Content)
|
|
if err != nil {
|
|
return fmt.Errorf("decode %s: %w", path, err)
|
|
}
|
|
content := string(decoded)
|
|
for k, v := range replacements {
|
|
content = strings.ReplaceAll(content, k, v)
|
|
}
|
|
if content == string(decoded) {
|
|
return nil // no changes, skip write
|
|
}
|
|
encoded := base64.StdEncoding.EncodeToString([]byte(content))
|
|
_, err = c.UpsertFile(ctx, owner, repo, path, UpsertFileArgs{
|
|
Branch: branch,
|
|
Content: encoded,
|
|
Message: "Apply template substitutions",
|
|
Sha: fc.Sha,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("write %s: %w", path, err)
|
|
}
|
|
return nil
|
|
}
|