feat: initial stamp implementation
- stamp add: create .stamp/*.md changeset files (interactive + --no-interactive) - stamp status: show pending stamps and projected next versions (plain + --json) - stamp version: consume stamps, bump semver, update CHANGELOGs, commit - stamp publish: create git tags, GitHub/Gitea releases, upload artifacts - stamp comment: post/update idempotent PR comments via GitHub/Gitea API - Supports monorepos via stamp.toml [[projects]] blocks - Changeset files support YAML (---) and TOML (+++) frontmatter - Semver + pre-release support (alpha, beta, rc) - Examples and workflow documentation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
98
internal/gitea/gitea.go
Normal file
98
internal/gitea/gitea.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package gitea
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
giteaSDK "code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
// Client wraps the Gitea API.
|
||||
type Client struct {
|
||||
client *giteaSDK.Client
|
||||
owner string
|
||||
repo string
|
||||
}
|
||||
|
||||
const commentMarker = "<!-- stamp-pr-comment -->"
|
||||
|
||||
// NewClient creates a Gitea client from GITEA_TOKEN and GITEA_BASE_URL environment variables.
|
||||
// The repoSlug must be in "owner/repo" format.
|
||||
func NewClient(repoSlug string) (*Client, error) {
|
||||
token := os.Getenv("GITEA_TOKEN")
|
||||
if token == "" {
|
||||
return nil, fmt.Errorf("GITEA_TOKEN environment variable is not set")
|
||||
}
|
||||
baseURL := os.Getenv("GITEA_BASE_URL")
|
||||
if baseURL == "" {
|
||||
return nil, fmt.Errorf("GITEA_BASE_URL environment variable is not set")
|
||||
}
|
||||
|
||||
parts := strings.SplitN(repoSlug, "/", 2)
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid repo slug %q: expected owner/repo", repoSlug)
|
||||
}
|
||||
|
||||
client, err := giteaSDK.NewClient(baseURL, giteaSDK.SetToken(token))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating Gitea client: %w", err)
|
||||
}
|
||||
return &Client{client: client, owner: parts[0], repo: parts[1]}, nil
|
||||
}
|
||||
|
||||
// CreateRelease creates a Gitea release for the given tag.
|
||||
func (c *Client) CreateRelease(tag, name, body string, draft, prerelease bool) (int64, error) {
|
||||
rel, _, err := c.client.CreateRelease(c.owner, c.repo, giteaSDK.CreateReleaseOption{
|
||||
TagName: tag,
|
||||
Title: name,
|
||||
Note: body,
|
||||
IsDraft: draft,
|
||||
IsPrerelease: prerelease,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("creating Gitea release %s: %w", tag, err)
|
||||
}
|
||||
return rel.ID, nil
|
||||
}
|
||||
|
||||
// UploadAsset uploads a file to an existing Gitea release.
|
||||
func (c *Client) UploadAsset(releaseID int64, filePath string) error {
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("opening %s: %w", filePath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
name := strings.Split(filePath, "/")
|
||||
fileName := name[len(name)-1]
|
||||
|
||||
_, _, err = c.client.CreateReleaseAttachment(c.owner, c.repo, releaseID, f, fileName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("uploading %s to release %d: %w", fileName, releaseID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpsertPRComment posts or updates a stamped PR comment.
|
||||
func (c *Client) UpsertPRComment(prNumber int, body string) error {
|
||||
markedBody := commentMarker + "\n" + body
|
||||
|
||||
comments, _, err := c.client.ListIssueComments(c.owner, c.repo, int64(prNumber),
|
||||
giteaSDK.ListIssueCommentOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing PR comments: %w", err)
|
||||
}
|
||||
|
||||
for _, comment := range comments {
|
||||
if strings.Contains(comment.Body, commentMarker) {
|
||||
_, _, err = c.client.EditIssueComment(c.owner, c.repo, comment.ID,
|
||||
giteaSDK.EditIssueCommentOption{Body: markedBody})
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, _, err = c.client.CreateIssueComment(c.owner, c.repo, int64(prNumber),
|
||||
giteaSDK.CreateIssueCommentOption{Body: markedBody})
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user