feat: post command and cleanup
Signed-off-by: jolheiser <john.olheiser@gmail.com>main v0.0.4
parent
c404599204
commit
42853c9e12
40
DOCS.md
40
DOCS.md
|
@ -10,6 +10,7 @@ git-ea
|
||||||
├─ frontport
|
├─ frontport
|
||||||
├─ ide
|
├─ ide
|
||||||
├─ init
|
├─ init
|
||||||
|
├─ post
|
||||||
└─ pr
|
└─ pr
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ backport --from [release=main] --to [release=latest]
|
||||||
**--list,-l**: Open repository to see needed backports
|
**--list,-l**: Open repository to see needed backports
|
||||||
|
|
||||||
|
|
||||||
**--to,-t**="": Release to backport to (ex: `1.17`, default: `latest`)
|
**--to,-t**="": Release to backport to (ex: `17`, default: `latest`)
|
||||||
|
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
@ -133,7 +134,7 @@ frontport cherry-picks a commit and applies it to a clean branch based on `relea
|
||||||
frontport --from [release=latest] --to [release=main]
|
frontport --from [release=latest] --to [release=main]
|
||||||
```
|
```
|
||||||
|
|
||||||
**--from,-f**="": Release to frontport from (ex: `1.17`, default: <latest>)
|
**--from,-f**="": Release to frontport from (ex: `17`, default: <latest>)
|
||||||
|
|
||||||
|
|
||||||
**--help**: Show help
|
**--help**: Show help
|
||||||
|
@ -180,6 +181,41 @@ init
|
||||||
**--help**: Show help
|
**--help**: Show help
|
||||||
|
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## post
|
||||||
|
|
||||||
|
post creates a new blog release post
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
[--author,-a]=[value]
|
||||||
|
[--changelog,-c]=[value]
|
||||||
|
[--help]
|
||||||
|
[--milestone,-m]=[value]
|
||||||
|
[--output,-o]=[value]
|
||||||
|
```
|
||||||
|
**Usage**:
|
||||||
|
|
||||||
|
```
|
||||||
|
post
|
||||||
|
```
|
||||||
|
|
||||||
|
**--author,-a**="": Post author
|
||||||
|
|
||||||
|
|
||||||
|
**--changelog,-c**="": Post changelog (no header)
|
||||||
|
|
||||||
|
|
||||||
|
**--help**: Show help
|
||||||
|
|
||||||
|
|
||||||
|
**--milestone,-m**="": Post milestone
|
||||||
|
|
||||||
|
|
||||||
|
**--output,-o**="": Output file (default: `content/post/release-of-${milestone}.md`)
|
||||||
|
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
## pr
|
## pr
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package blog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pullGiteaURL = "https://github.com/go-gitea/gitea/pull/"
|
||||||
|
pullRegex = regexp.MustCompile(`#(\d+)\)`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// FormatPR formats input by replacing pull refs #1234 with markdown links [#1234](...pull/1234)
|
||||||
|
func FormatPR(r io.Reader) ([]byte, error) {
|
||||||
|
data, err := io.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pullURL := pullGiteaURL
|
||||||
|
|
||||||
|
repl := pullRegex.ReplaceAll(data, []byte(`[#$1](`+pullURL+`$1))`))
|
||||||
|
return repl, nil
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package blog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
_ "embed"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/skratchdot/open-golang/open"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mergedURLFmt = "https://api.github.com/search/issues?q=repo:go-gitea/gitea+is:pr+is:merged+milestone:%s"
|
||||||
|
changelogURLFmt = "https://api.github.com/search/issues?q=repo:go-gitea/gitea+is:pr+is:merged+Changelog+%s"
|
||||||
|
|
||||||
|
//go:embed release.md
|
||||||
|
tmplContent string
|
||||||
|
tmpl = template.Must(template.New("").Parse(tmplContent))
|
||||||
|
)
|
||||||
|
|
||||||
|
// Merged is the API response for getting count of merged PRs in a milestone
|
||||||
|
type Merged struct {
|
||||||
|
TotalCount int `json:"total_count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatRelease formats a release template and injects author, milestone, changelog, and merged PR counts
|
||||||
|
func FormatRelease(author, milestone, changelog string) ([]byte, error) {
|
||||||
|
resp, err := http.Get(fmt.Sprintf(mergedURLFmt, milestone))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var merged Merged
|
||||||
|
if err := json.Unmarshal(body, &merged); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
date := time.Now()
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"Author": author,
|
||||||
|
"Milestone": milestone,
|
||||||
|
"Changelog": changelog,
|
||||||
|
"Merged": merged.TotalCount,
|
||||||
|
"DateLong": date.Format("2006-01-02T15:04:05+07:00"),
|
||||||
|
"DateShort": date.Format("2006-01-02"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := tmpl.Execute(&buf, m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release is the API response for a release
|
||||||
|
type Release struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
PublishedAt time.Time `json:"published_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LatestRelease gets the latest release, used as a default for the generator
|
||||||
|
func LatestRelease() (Release, error) {
|
||||||
|
var rel Release
|
||||||
|
resp, err := http.Get("https://api.github.com/repos/go-gitea/gitea/releases/latest")
|
||||||
|
if err != nil {
|
||||||
|
return rel, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return rel, json.NewDecoder(resp.Body).Decode(&rel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangelogPR is the API response when searching for the milestone changelog PR
|
||||||
|
type ChangelogPR struct {
|
||||||
|
Items []struct {
|
||||||
|
HTMLURL string `json:"html_url"`
|
||||||
|
} `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenChangelogPullRequest attempts to open a browser to the changelog PR of a given milestone
|
||||||
|
func OpenChangelogPullRequest(milestone string) error {
|
||||||
|
resp, err := http.Get(fmt.Sprintf(changelogURLFmt, milestone))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var pr ChangelogPR
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&pr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pr.Items) == 0 {
|
||||||
|
return errors.New("could not find changelog PR")
|
||||||
|
}
|
||||||
|
|
||||||
|
return open.Start(pr.Items[0].HTMLURL + "/files")
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
date: "{{.DateLong}}"
|
||||||
|
author: "{{.Author}}"
|
||||||
|
title: "Gitea {{.Milestone}} is released"
|
||||||
|
tags: ["release"]
|
||||||
|
draft: false
|
||||||
|
---
|
||||||
|
|
||||||
|
We are proud to present the release of Gitea version {{.Milestone}}.
|
||||||
|
|
||||||
|
We highly encourage users to update to this version for some important bug-fixes.
|
||||||
|
|
||||||
|
We have merged [{{.Merged}}](https://github.com/go-gitea/gitea/pulls?q=is%3Apr+milestone%3A{{.Milestone}}+is%3Amerged) pull requests to release this version.
|
||||||
|
|
||||||
|
<!-- Security Thanks! -->
|
||||||
|
|
||||||
|
You can download one of our pre-built binaries from our [downloads page](https://dl.gitea.io/gitea/{{.Milestone}}/) - make sure to select the correct platform! For further details on how to install, follow our [installation guide](https://docs.gitea.io/en-us/install-from-binary/).
|
||||||
|
|
||||||
|
|
||||||
|
We would also like to thank all of our supporters on [Open Collective](https://opencollective.com/gitea) who are helping to sustain us financially.
|
||||||
|
|
||||||
|
**Have you heard? We now have a [swag shop](https://shop.gitea.io)! :shirt: :tea:**
|
||||||
|
|
||||||
|
<!--more-->
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
## [{{.Milestone}}](https://github.com/go-gitea/gitea/releases/tag/v{{.Milestone}}) - {{.DateShort}}
|
||||||
|
|
||||||
|
<!-- Changelog Details -->
|
||||||
|
{{.Changelog}}
|
|
@ -4,21 +4,23 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
"github.com/skratchdot/open-golang/open"
|
"github.com/skratchdot/open-golang/open"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var indexRe = regexp.MustCompile(`\(#(\d+)\)`)
|
||||||
|
|
||||||
func (h *Handler) Backport() *ffcli.Command {
|
func (h *Handler) Backport() *ffcli.Command {
|
||||||
fs := flag.NewFlagSet("backport", flag.ContinueOnError)
|
fs := flag.NewFlagSet("backport", flag.ContinueOnError)
|
||||||
fromFlag := fs.String("from", "", "Release to backport from (ex: `main`, default: main)")
|
fromFlag := fs.String("from", "", "Release to backport from (ex: `main`, default: main)")
|
||||||
fs.StringVar(fromFlag, "f", *fromFlag, "--from")
|
fs.StringVar(fromFlag, "f", *fromFlag, "--from")
|
||||||
toFlag := fs.String("to", "", "Release to backport to (ex: `1.17`, default: `latest`)")
|
toFlag := fs.String("to", "", "Release to backport to (ex: `17`, default: `latest`)")
|
||||||
fs.StringVar(toFlag, "t", *toFlag, "--to")
|
fs.StringVar(toFlag, "t", *toFlag, "--to")
|
||||||
listFlag := fs.Bool("list", false, "Open repository to see needed backports")
|
listFlag := fs.Bool("list", false, "Open repository to see needed backports")
|
||||||
fs.BoolVar(listFlag, "l", *listFlag, "--list")
|
fs.BoolVar(listFlag, "l", *listFlag, "--list")
|
||||||
|
@ -58,12 +60,12 @@ func (h *Handler) Backport() *ffcli.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
optMap := make(map[string]plumbing.Hash)
|
optMap := make(map[string]string)
|
||||||
var opts []string
|
var opts []string
|
||||||
if err := commits.ForEach(func(c *object.Commit) error {
|
if err := commits.ForEach(func(c *object.Commit) error {
|
||||||
title := strings.Split(c.Message, "\n")[0]
|
title := strings.Split(c.Message, "\n")[0]
|
||||||
opts = append(opts, title)
|
opts = append(opts, title)
|
||||||
optMap[title] = c.Hash
|
optMap[title] = c.Hash.String()
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -77,14 +79,19 @@ func (h *Handler) Backport() *ffcli.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := optMap[resp]
|
index := optMap[resp]
|
||||||
branch := fmt.Sprintf("backport-%s", hash)
|
m := indexRe.FindStringSubmatch(resp)
|
||||||
|
if m != nil {
|
||||||
|
index = m[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
branch := fmt.Sprintf("backport-%s", index)
|
||||||
base := fmt.Sprintf("upstream/release/v1.%s", to)
|
base := fmt.Sprintf("upstream/release/v1.%s", to)
|
||||||
if err := h.Branch().ParseAndRun(ctx, []string{"--base", base, branch}); err != nil {
|
if err := h.Branch().ParseAndRun(ctx, []string{"--base", base, branch}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return run(ctx, h.Config.WorkspaceBranch(branch), "git", "cherry-pick", hash.String())
|
return run(ctx, h.Config.WorkspaceBranch(branch), "git", "cherry-pick", optMap[resp])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
cmd/cmd.go
19
cmd/cmd.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -50,6 +51,7 @@ func New() (*ffcli.Command, error) {
|
||||||
handler.Frontport(),
|
handler.Frontport(),
|
||||||
handler.IDE(),
|
handler.IDE(),
|
||||||
handler.Init(),
|
handler.Init(),
|
||||||
|
handler.Post(),
|
||||||
handler.PR(),
|
handler.PR(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -100,15 +102,6 @@ func (h *Handler) fetch(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isClean() bool {
|
|
||||||
c := exec.Command("git", "status", "--porcelain")
|
|
||||||
o, err := c.Output()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().Err(err).Msg("could not get git status")
|
|
||||||
}
|
|
||||||
return len(o) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) repo() *git.Repository {
|
func (h *Handler) repo() *git.Repository {
|
||||||
repo, err := git.PlainOpen(h.Config.Base)
|
repo, err := git.PlainOpen(h.Config.Base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -157,3 +150,11 @@ func (h *Handler) latestRelease() string {
|
||||||
|
|
||||||
return strings.TrimLeft(latest, "0")
|
return strings.TrimLeft(latest, "0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func currentUser() string {
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return u.Username
|
||||||
|
}
|
||||||
|
|
|
@ -8,14 +8,13 @@ import (
|
||||||
|
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) Frontport() *ffcli.Command {
|
func (h *Handler) Frontport() *ffcli.Command {
|
||||||
fs := flag.NewFlagSet("frontport", flag.ContinueOnError)
|
fs := flag.NewFlagSet("frontport", flag.ContinueOnError)
|
||||||
fromFlag := fs.String("from", "", "Release to frontport from (ex: `1.17`, default: <latest>)")
|
fromFlag := fs.String("from", "", "Release to frontport from (ex: `17`, default: <latest>)")
|
||||||
fs.StringVar(fromFlag, "f", *fromFlag, "--from")
|
fs.StringVar(fromFlag, "f", *fromFlag, "--from")
|
||||||
toFlag := fs.String("to", "", "Release to frontport to (ex: `main`, default: `main`)")
|
toFlag := fs.String("to", "", "Release to frontport to (ex: `main`, default: `main`)")
|
||||||
fs.StringVar(toFlag, "t", *toFlag, "--to")
|
fs.StringVar(toFlag, "t", *toFlag, "--to")
|
||||||
|
@ -46,12 +45,12 @@ func (h *Handler) Frontport() *ffcli.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
optMap := make(map[string]plumbing.Hash)
|
optMap := make(map[string]string)
|
||||||
var opts []string
|
var opts []string
|
||||||
if err := commits.ForEach(func(c *object.Commit) error {
|
if err := commits.ForEach(func(c *object.Commit) error {
|
||||||
title := strings.Split(c.Message, "\n")[0]
|
title := strings.Split(c.Message, "\n")[0]
|
||||||
opts = append(opts, title)
|
opts = append(opts, title)
|
||||||
optMap[title] = c.Hash
|
optMap[title] = c.Hash.String()
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -65,8 +64,13 @@ func (h *Handler) Frontport() *ffcli.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := optMap[resp]
|
index := optMap[resp]
|
||||||
branch := fmt.Sprintf("frontport-%s", hash)
|
m := indexRe.FindStringSubmatch(resp)
|
||||||
|
if m != nil {
|
||||||
|
index = m[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
branch := fmt.Sprintf("frontport-%s", index)
|
||||||
|
|
||||||
base := *toFlag
|
base := *toFlag
|
||||||
if base == "" {
|
if base == "" {
|
||||||
|
@ -79,7 +83,7 @@ func (h *Handler) Frontport() *ffcli.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return run(ctx, h.Config.WorkspaceBranch(branch), "git", "cherry-pick", hash.String())
|
return run(ctx, h.Config.WorkspaceBranch(branch), "git", "cherry-pick", optMap[resp])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ func (h *Handler) IDE() *ffcli.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
path := h.Config.WorkspaceBranch(branch)
|
path := h.Config.WorkspaceBranch(branch)
|
||||||
return exec.Command("nvim", path).Start()
|
return exec.Command("hx", path).Start()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"go.jolheiser.com/git-ea/blog"
|
||||||
|
|
||||||
|
"github.com/AlecAivazis/survey/v2"
|
||||||
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Handler) Post() *ffcli.Command {
|
||||||
|
fs := flag.NewFlagSet("post", flag.ContinueOnError)
|
||||||
|
authorFlag := fs.String("author", "", "Post author")
|
||||||
|
fs.StringVar(authorFlag, "a", *authorFlag, "--author")
|
||||||
|
milestoneFlag := fs.String("milestone", "", "Post milestone")
|
||||||
|
fs.StringVar(milestoneFlag, "m", *milestoneFlag, "--milestone")
|
||||||
|
changelogFlag := fs.String("changelog", "", "Post changelog (no header)")
|
||||||
|
fs.StringVar(changelogFlag, "c", *changelogFlag, "--changelog")
|
||||||
|
outputFlag := fs.String("output", "content/post/release-of-${milestone}.md", "Output file")
|
||||||
|
fs.StringVar(outputFlag, "o", *outputFlag, "--output")
|
||||||
|
return &ffcli.Command{
|
||||||
|
Name: "post",
|
||||||
|
FlagSet: fs,
|
||||||
|
ShortUsage: "post",
|
||||||
|
ShortHelp: "post creates a new blog release post",
|
||||||
|
Exec: func(ctx context.Context, args []string) error {
|
||||||
|
author := *authorFlag
|
||||||
|
if author == "" {
|
||||||
|
if err := survey.AskOne(&survey.Input{
|
||||||
|
Message: "Blog post author",
|
||||||
|
Default: currentUser(),
|
||||||
|
}, &author, survey.WithValidator(survey.Required)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
milestone := *milestoneFlag
|
||||||
|
if milestone == "" {
|
||||||
|
var defMilestone blog.Release
|
||||||
|
r, err := blog.LatestRelease()
|
||||||
|
if err == nil {
|
||||||
|
defMilestone = r
|
||||||
|
}
|
||||||
|
if err := survey.AskOne(&survey.Input{
|
||||||
|
Message: "Release milestone",
|
||||||
|
Default: strings.TrimPrefix(defMilestone.Name, "v"),
|
||||||
|
Help: fmt.Sprintf("Default was published on %s", defMilestone.PublishedAt.Format("01/02/2006")),
|
||||||
|
}, &milestone, survey.WithValidator(survey.Required)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changelog := *changelogFlag
|
||||||
|
if changelog == "" {
|
||||||
|
if err := blog.OpenChangelogPullRequest(milestone); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
if err := survey.AskOne(&survey.Editor{
|
||||||
|
Message: "Blog post changelog",
|
||||||
|
FileName: "*.md",
|
||||||
|
}, &changelog, survey.WithValidator(survey.Required)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post, err := blog.FormatRelease(author, milestone, changelog)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
complete, err := blog.FormatPR(bytes.NewReader(post))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
output := os.Expand(*outputFlag, func(s string) string {
|
||||||
|
switch s {
|
||||||
|
case "milestone":
|
||||||
|
return milestone
|
||||||
|
default:
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
fi, err := os.Create(output)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fi.Close()
|
||||||
|
|
||||||
|
if _, err := fi.Write(complete); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Blog post created at %q\n", output)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue