release/main.go

164 lines
4.1 KiB
Go

package main
import (
"context"
"fmt"
"os"
"os/signal"
"path/filepath"
"regexp"
"strconv"
"strings"
"sync"
"git.geekeey.de/actions/sdk"
)
func main() {
action := &ReleaseAction{Action: sdk.New()}
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
if err := action.run(ctx); err != nil {
action.Errorf("%s", err)
os.Exit(1)
}
}
type ReleaseAction struct {
*sdk.Action
repository string
version string
draft bool
prerelease bool
label string
notes string
artifacts []string
}
func (action *ReleaseAction) setup() error {
var err error
action.repository = action.GetInput("repository")
if ok, err := regexp.MatchString(`^(\w+)/(\w+)$`, action.repository); !ok || err != nil {
return fmt.Errorf("input 'repository': is empty or does not match <onwer>/<repo>")
}
action.version = action.GetInput("version")
if len(action.version) == 0 {
return fmt.Errorf("input 'version': is empty")
}
pattern := func(name string) (bool, error) {
input := action.GetInput(name)
if len(input) == 0 {
return false, fmt.Errorf("input %q: is empty", name)
}
value, err := strconv.ParseBool(input)
if err != nil {
expr, err := regexp.Compile(input)
if err != nil {
return false, fmt.Errorf("input %q: is not a bool or a valid regex", name)
}
value = expr.MatchString(action.version)
}
return value, nil
}
// draft might be a bool constant or a regex which determins if it is
// a draft by matching against the input version
action.draft, err = pattern("draft")
if err != nil {
return fmt.Errorf("input 'draft': is not a bool or a valid regex")
}
// prerelease might be a bool constant or a regex which determins if it is
// a prelease by matching against the input version
action.prerelease, err = pattern("prerelease")
if err != nil {
return fmt.Errorf("input 'prerelease': is not a bool or a valid regex")
}
action.label = action.GetInput("label")
action.notes = action.GetInput("notes")
// attachements can be a multline string, treat each line as a pattern
patterns := strings.Split(strings.TrimSuffix(action.GetInput("attachments"), "\n"), "\n")
action.artifacts = []string{}
for _, pattern := range patterns {
if len(pattern) == 0 {
continue
}
matches, err := filepath.Glob(pattern)
if err != nil {
return fmt.Errorf("input 'attachments': pattern '%s' was malformatted: %s", pattern, err)
}
action.artifacts = append(action.artifacts, matches...)
}
return nil
}
func (action *ReleaseAction) run(ctx context.Context) error {
if err := action.setup(); err != nil {
return err
}
github := NewGitHub(action.Client())
// only get the commit info when we are missing a name or a text
if len(action.label) == 0 || len(action.notes) == 0 {
action.Debugf("Getting git tag information from repository")
tag, err := github.GetGitTagInfo(action.repository, action.version, ctx)
if err != nil {
return err
}
if len(action.label) == 0 {
action.label = tag.Name
}
if len(action.notes) == 0 {
action.notes = tag.Message
}
}
action.Debugf("Creating release %s", action.version)
release, err := github.CreateRelease(&CreateReleaseRequest{
Repository: action.repository,
TagName: action.version,
Name: action.label,
Body: action.notes,
Draft: action.draft,
PreRelease: action.prerelease,
}, ctx)
if err != nil {
return fmt.Errorf("cannot create release for %s: %s", action.version, err)
}
action.Noticef("Created release %s: %s", release.Name, release.HtmlURL)
wg := sync.WaitGroup{}
for _, artifact := range action.artifacts {
wg.Add(1)
go func() {
defer wg.Done()
f, err := os.Open(artifact)
if err != nil {
action.Warningf("Unable to open file %s", artifact)
return
}
a, err := github.CreateReleaseArtifact(&CreateReleaseArtifactRequest{
Repository: action.repository,
Id: release.Id,
Name: f.Name(), // unused?
Attachment: f,
}, ctx)
if err != nil {
action.Warningf("Unable to create artifact for %s", artifact)
return
}
action.Debugf("Uploaded artifact %s (%d)", a.Name, a.Size)
}()
}
wg.Wait()
return nil
}