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") }