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 Repository version string draft bool prerelease bool label string notes string artifacts []string } type Repository []string func NewRepository(r string) (Repository, error) { split := strings.Split(string(r), "/") if len(split) != 2 { return nil, fmt.Errorf("repository must be in the format '/'") } return split, nil } func (r Repository) Owner() string { return r[0] } func (r Repository) Repo() string { return r[1] } func (action *ReleaseAction) setup() error { var err error r, err := NewRepository(action.GetInput("repository")) if err != nil { return fmt.Errorf("input 'repository': %s", err) } action.repository = r 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.Owner(), action.repository.Repo(), 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{ Owner: action.repository.Owner(), Repo: action.repository.Repo(), Name: action.label, Body: action.notes, Draft: action.draft, PreRelease: action.prerelease, TagName: action.version, }, 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{ Id: release.Id, Owner: action.repository.Owner(), Repo: action.repository.Repo(), 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 }