gitea-release-drafter/src/action.go

180 lines
4.4 KiB
Go

package src
import (
"bytes"
"context"
"fmt"
"strings"
"code.gitea.io/sdk/gitea"
"git.beisel.it/florian/gitea-release-drafter/src/config"
"github.com/sethvargo/go-githubactions"
)
type Action struct {
config *config.DrafterConfig
globalContext context.Context
client *gitea.Client
}
// NewAction factory for a new action
func NewAction(ctx *context.Context, cfg *config.DrafterConfig) (*Action, error) {
gitea, err := gitea.NewClient(cfg.ApiUrl, gitea.SetToken(cfg.Token))
if err != nil {
return nil, err
}
return &Action{
config: cfg,
globalContext: *ctx,
client: gitea,
}, nil
}
// updateOrCreateDraftRelease
func updateOrCreateDraftRelease(a *Action, cfg *config.RepoConfig) (*gitea.Release, error) {
draft, last, err := FindReleases(a.client, a.config.RepoOwner, a.config.RepoName)
if err != nil {
return nil, err
}
changelog, err := GenerateChangelog(a.client, a.config.RepoOwner, a.config.RepoName, last, cfg.Categories)
if err != nil {
return nil, err
}
if len(*changelog) == 0 {
githubactions.Infof("No updates found")
return nil, nil
}
// Create a map to hold categorized PRs
categorizedPRs := make(map[string][]*gitea.PullRequest)
for _, prs := range *changelog {
for _, pr := range prs {
categorized := false
for _, category := range cfg.Categories {
if !categorized && prHasLabel(pr, category.Labels) {
categorizedPRs[category.Title] = append(categorizedPRs[category.Title], pr)
categorized = true
break // Break out of the category loop
}
}
if !categorized {
// Add to a default category if not categorized
categorizedPRs["Other Changes"] = append(categorizedPRs["Other Changes"], pr)
}
if categorized {
break // Break out of the PR loop once categorized
}
}
}
// Build the changelog string
var b strings.Builder
b.WriteString("# What's Changed\n\n")
for _, category := range cfg.Categories {
prs, exists := categorizedPRs[category.Title]
if exists && len(prs) > 0 {
fmt.Fprintf(&b, "## %s\n\n", category.Title)
for _, pr := range prs {
fmt.Fprintf(&b, "* %s (#%d) @%s\n", pr.Title, pr.Index, pr.Poster.UserName)
}
b.WriteString("\n")
}
}
nextVersion, err := ResolveVersion(cfg, last, changelog)
if err != nil {
return nil, err
}
title := FillVariables(cfg.NameTemplate, TemplateVariables{
ReleaseVersion: nextVersion.String(),
})
// FIXME: require RESOLVED_VERSION to be set?
tag := FillVariables(cfg.TagTemplate, TemplateVariables{
ReleaseVersion: nextVersion.String(),
})
if draft != nil {
updatedDraft, err := UpdateExistingDraft(a.client, a.config.RepoOwner, a.config.RepoName, draft, title, tag, b.String())
if err != nil {
return nil, err
}
return updatedDraft, nil
}
newDraft, err := CreateDraftRelease(a.client, a.config.RepoOwner, a.config.RepoName, cfg.DefaultBranch, title, tag, b.String())
if err != nil {
return nil, err
}
return newDraft, nil
}
// GetConfigFile reads the local configuration file in `.gitea/` in the ref branch (probably main/master)
func (a *Action) GetConfigFile(ref string) (*bytes.Reader, error) {
data, _, err := a.client.GetFile(a.config.RepoOwner, a.config.RepoName, ref, a.config.ConfigPath)
if err != nil {
return nil, err
}
return bytes.NewReader(data), err
}
// Run builds the configuration and executes the action logic
func (a *Action) Run() error {
// fetch the repo to retrieve the default branch to be set as the config default
repo, err := GetRepo(a.client, a.config.RepoOwner, a.config.RepoName)
if err != nil {
return err
}
githubactions.Debugf("Found default branch %s", repo.DefaultBranch)
// build repo config
configReader, err := a.GetConfigFile(repo.DefaultBranch)
if err != nil {
if err.Error() != "404 Not Found" {
return err
} else {
// no config file found
githubactions.Warningf("No such config file: .gitea/%s", a.config.ConfigPath)
configReader = bytes.NewReader([]byte{})
}
}
config, err := config.ReadRepoConfig(configReader, repo.DefaultBranch)
if err != nil {
return err
}
draft, err := updateOrCreateDraftRelease(a, config)
if err != nil {
return err
}
if draft != nil {
githubactions.Infof("created draft release %s", draft.Title)
}
return nil
}
func prHasLabel(pr *gitea.PullRequest, labels []string) bool {
for _, prLabel := range pr.Labels {
for _, label := range labels {
if prLabel.Name == label {
return true
}
}
}
return false
}