146 lines
4.2 KiB
Go
146 lines
4.2 KiB
Go
package gitea
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
giteaSDK "code.gitea.io/sdk/gitea"
|
|
)
|
|
|
|
const prMarker = "<!-- stamp-release-pr -->"
|
|
|
|
// 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
|
|
}
|
|
|
|
// UpsertPR creates or updates a stamp release PR on the given base branch.
|
|
// It identifies the existing PR by scanning open PRs for the hidden marker in the body.
|
|
func (c *Client) UpsertPR(head, base, title, body string) (int64, string, error) {
|
|
markedBody := prMarker + "\n" + body
|
|
|
|
// Search open PRs for an existing stamp release PR (Gitea SDK does not support
|
|
// filtering by head branch, so we filter client-side).
|
|
prs, _, err := c.client.ListRepoPullRequests(c.owner, c.repo, giteaSDK.ListPullRequestsOptions{
|
|
State: giteaSDK.StateOpen,
|
|
})
|
|
if err != nil {
|
|
return 0, "", fmt.Errorf("listing pull requests: %w", err)
|
|
}
|
|
|
|
for _, pr := range prs {
|
|
if pr.Head != nil && pr.Head.Name != head {
|
|
continue
|
|
}
|
|
if strings.Contains(pr.Body, prMarker) {
|
|
// Update existing PR.
|
|
updated, _, err := c.client.EditPullRequest(c.owner, c.repo, pr.Index,
|
|
giteaSDK.EditPullRequestOption{
|
|
Title: title,
|
|
Body: &markedBody,
|
|
})
|
|
if err != nil {
|
|
return 0, "", fmt.Errorf("updating pull request #%d: %w", pr.Index, err)
|
|
}
|
|
return updated.Index, updated.HTMLURL, nil
|
|
}
|
|
}
|
|
|
|
// Create a new PR.
|
|
pr, _, err := c.client.CreatePullRequest(c.owner, c.repo, giteaSDK.CreatePullRequestOption{
|
|
Head: head,
|
|
Base: base,
|
|
Title: title,
|
|
Body: markedBody,
|
|
})
|
|
if err != nil {
|
|
return 0, "", fmt.Errorf("creating pull request: %w", err)
|
|
}
|
|
return pr.Index, pr.HTMLURL, 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
|
|
}
|