diff --git a/go.mod b/go.mod index 816b9cba5..66ff58976 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect - github.com/Masterminds/semver/v3 v3.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect github.com/PaesslerAG/gval v1.2.0 // indirect github.com/PaesslerAG/jsonpath v0.1.1 // indirect diff --git a/go.sum b/go.sum index 2ef3338cc..4a3734ffd 100644 --- a/go.sum +++ b/go.sum @@ -98,6 +98,8 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Masterminds/squirrel v1.5.2/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= diff --git a/scripts/release/changelog.go b/scripts/release/changelog.go new file mode 100644 index 000000000..9cede4757 --- /dev/null +++ b/scripts/release/changelog.go @@ -0,0 +1,150 @@ +package main + +import ( + "encoding/json" + "fmt" + "net" + "net/http" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + "time" + + "github.com/Masterminds/semver/v3" + "gopkg.in/yaml.v3" +) + +func main() { + + if len(os.Args) < 2 { + fmt.Fprintln(os.Stderr, "argument required: version to add changelog entries under") + os.Exit(1) + } + + lastV := lastPublishedRelease() + response := commitList(lastV) + + // if commit message ends like (#444) then it is probably a PR reference + prPattern := regexp.MustCompile(`\s*\(\#(\d+)\)$`) + + for _, c := range response.Commits { + firstLine := strings.Split(strings.ReplaceAll(c.Commit.Message, "\r\n", "\n"), "\n")[0] + matches := prPattern.FindStringSubmatch(firstLine) + if matches == nil { + // no PR to reference! + fmt.Printf("Commit %s did not contain a PR number in its commit message in the expected place. Please add it manually. The commit message was:\n%s\n", c.SHA, c.Commit.Message) + continue + } + prNo, _ := strconv.Atoi(matches[1]) + + message := strings.TrimSuffix(firstLine, matches[0]) // trim PR number from changelog entry line + + cmd := exec.Command( + "../../scripts/go-tools/bin/elastic-package", + "changelog", "add", + "--description", message, + "--link", fmt.Sprintf("https://github.com/elastic/endpoint-package/pull/%d", prNo), + "--type", "enhancement", + "--version", os.Args[1]) + cmd.Dir = "./package/endpoint" + _, err := cmd.CombinedOutput() + if err != nil { + panic(err) + } + + //fmt.Printf("elastic-package changelog add --description \"%s\" --link https://github.com/elastic/endpoint-package/pull/%d --type enhancement --version \n", message, prNo) + + } + + fmt.Println("entries added, please review the changes in the changelog file and edit as needed.") + +} + +func makeClient(t time.Duration) *http.Client { + return &http.Client{ + Timeout: t, + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: t, + }).Dial, + }, + } +} + +// get last changelog version (without prerelease suffixes like -next) +func lastPublishedRelease() string { + f, err := os.OpenFile("package/endpoint/changelog.yml", os.O_RDONLY, 0644) + if err != nil { + panic(err) + } + defer f.Close() + + entries := make([]map[string]interface{}, 0, 50) + if err := yaml.NewDecoder(f).Decode(&entries); err != nil { + panic(err) + } + + if len(entries) == 0 { + fmt.Fprintln(os.Stderr, "previous changelog version not found") + os.Exit(1) + } + + for _, e := range entries { + if v, ok := e["version"].(string); ok { + semv, err := semver.NewVersion(v) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to parse changelog version '%s': %v\n", v, err) + continue + } + if semv.Prerelease() != "" { + //fmt.Fprintf(os.Stderr, "%s is a Prerelease version. Skipping\n", v) + continue + } + return v + } + + } + + fmt.Fprintln(os.Stderr, "previous changelog version not found") + os.Exit(1) + return "" +} + +type ghCompareResponse struct { + Commits []struct { + SHA string `json:"sha"` + Commit struct { + Message string `json:"message"` + } `json:"commit"` + HTMLurl string `json:"html_url"` + } `json:"commits"` +} + +func commitList(since string) ghCompareResponse { + client := makeClient(30 * time.Second) + + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://api.github.com/repos/elastic/endpoint-package/compare/v%s...main", since), nil) + if err != nil { + panic(err) + } + + req.Header.Set("Accept", "application/vnd.github+json") + req.Header.Set("X-Github-Api-Version", "2022-11-28") + resp, err := client.Do(req) + + if err != nil { + panic(err) + } + if resp.StatusCode != http.StatusOK { + panic(fmt.Errorf("%d status code when retrieving changelog commits", resp.StatusCode)) + } + + var r ghCompareResponse + defer resp.Body.Close() + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + panic(err) + } + return r +}