github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/releaser/releasenotes_writer.go (about)

     1  // Copyright 2017-present The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // Package releaser implements a set of utilities and a wrapper around Goreleaser
    15  // to help automate the Hugo release process.
    16  package releaser
    17  
    18  import (
    19  	"bytes"
    20  	"fmt"
    21  	"io"
    22  	"io/ioutil"
    23  	"net/http"
    24  	"os"
    25  	"path/filepath"
    26  	"strings"
    27  	"text/template"
    28  )
    29  
    30  const (
    31  	issueLinkTemplate                        = "#%d"
    32  	linkTemplate                             = "[%s](%s)"
    33  	releaseNotesMarkdownTemplatePatchRelease = `
    34  {{ if eq (len .All) 1 }}
    35  This is a bug-fix release with one important fix.
    36  {{ else }}
    37  This is a bug-fix release with a couple of important fixes.
    38  {{ end }}
    39  {{ range .All }}
    40  {{- if .GitHubCommit -}}
    41  * {{ .Subject }} {{ .Hash }} {{ . | authorURL }} {{ range .Issues }}{{ . | issue }} {{ end }}
    42  {{ else -}}
    43  * {{ .Subject }} {{ range .Issues }}{{ . | issue }} {{ end }}
    44  {{ end -}}
    45  {{- end }}
    46  
    47  
    48  `
    49  	releaseNotesMarkdownTemplate = `
    50  {{- $contribsPerAuthor := .All.ContribCountPerAuthor -}}
    51  {{- $docsContribsPerAuthor := .Docs.ContribCountPerAuthor -}}
    52  
    53  This release represents **{{ len .All }} contributions by {{ len $contribsPerAuthor }} contributors** to the main Hugo code base.
    54  
    55  {{- if  gt (len $contribsPerAuthor) 3 -}}
    56  {{- $u1 := index $contribsPerAuthor 0 -}}
    57  {{- $u2 := index $contribsPerAuthor 1 -}}
    58  {{- $u3 := index $contribsPerAuthor 2 -}}
    59  {{- $u4 := index $contribsPerAuthor 3 -}}
    60  {{- $u1.AuthorLink }} leads the Hugo development with a significant amount of contributions, but also a big shoutout to {{ $u2.AuthorLink }}, {{ $u3.AuthorLink }}, and {{ $u4.AuthorLink }} for their ongoing contributions.
    61  And thanks to [@digitalcraftsman](https://github.com/digitalcraftsman) for his ongoing work on keeping the themes site in pristine condition.
    62  {{ end }}
    63  Many have also been busy writing and fixing the documentation in [hugoDocs](https://github.com/gohugoio/hugoDocs),
    64  which has received **{{ len .Docs }} contributions by {{ len $docsContribsPerAuthor }} contributors**.
    65  {{- if  gt (len $docsContribsPerAuthor) 3 -}}
    66  {{- $u1 := index $docsContribsPerAuthor 0 -}}
    67  {{- $u2 := index $docsContribsPerAuthor 1 -}}
    68  {{- $u3 := index $docsContribsPerAuthor 2 -}}
    69  {{- $u4 := index $docsContribsPerAuthor 3 }} A special thanks to {{ $u1.AuthorLink }}, {{ $u2.AuthorLink }}, {{ $u3.AuthorLink }}, and {{ $u4.AuthorLink }} for their work on the documentation site.
    70  {{ end }}
    71  
    72  Hugo now has:
    73  
    74  {{ with .Repo -}}
    75  * {{ .Stars }}+ [stars](https://github.com/gohugoio/hugo/stargazers)
    76  * {{ len .Contributors }}+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors)
    77  {{- end -}}
    78  {{ with .ThemeCount }}
    79  * {{ . }}+ [themes](http://themes.gohugo.io/)
    80  {{ end }}
    81  {{ with .Notes }}
    82  ## Notes
    83  {{ template "change-section" . }}
    84  {{- end -}}
    85  {{ with .All }}
    86  ## Changes
    87  {{ template "change-section" . }}
    88  {{ end }}
    89  
    90  {{ define "change-section" }}
    91  {{ range . }}
    92  {{- if .GitHubCommit -}}
    93  * {{ .Subject }} {{ .Hash }} {{ . | authorURL }} {{ range .Issues }}{{ . | issue }} {{ end }}
    94  {{ else -}}
    95  * {{ .Subject }} {{ range .Issues }}{{ . | issue }} {{ end }}
    96  {{ end -}}
    97  {{- end }}
    98  {{ end }}
    99  `
   100  )
   101  
   102  var templateFuncs = template.FuncMap{
   103  	"isPatch": func(c changeLog) bool {
   104  		return !strings.HasSuffix(c.Version, "0")
   105  	},
   106  	"issue": func(id int) string {
   107  		return fmt.Sprintf(issueLinkTemplate, id)
   108  	},
   109  	"commitURL": func(info gitInfo) string {
   110  		if info.GitHubCommit.HTMLURL == "" {
   111  			return ""
   112  		}
   113  		return fmt.Sprintf(linkTemplate, info.Hash, info.GitHubCommit.HTMLURL)
   114  	},
   115  	"authorURL": func(info gitInfo) string {
   116  		if info.GitHubCommit.Author.Login == "" {
   117  			return ""
   118  		}
   119  		return fmt.Sprintf(linkTemplate, "@"+info.GitHubCommit.Author.Login, info.GitHubCommit.Author.HTMLURL)
   120  	},
   121  }
   122  
   123  func writeReleaseNotes(version string, infosMain, infosDocs gitInfos, to io.Writer) error {
   124  	client := newGitHubAPI("hugo")
   125  	changes := newChangeLog(infosMain, infosDocs)
   126  	changes.Version = version
   127  	repo, err := client.fetchRepo()
   128  	if err == nil {
   129  		changes.Repo = &repo
   130  	}
   131  	themeCount, err := fetchThemeCount()
   132  	if err == nil {
   133  		changes.ThemeCount = themeCount
   134  	}
   135  
   136  	mtempl := releaseNotesMarkdownTemplate
   137  
   138  	if !strings.HasSuffix(version, "0") {
   139  		mtempl = releaseNotesMarkdownTemplatePatchRelease
   140  	}
   141  
   142  	tmpl, err := template.New("").Funcs(templateFuncs).Parse(mtempl)
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	err = tmpl.Execute(to, changes)
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	return nil
   153  }
   154  
   155  func fetchThemeCount() (int, error) {
   156  	resp, err := http.Get("https://raw.githubusercontent.com/gohugoio/hugoThemesSiteBuilder/main/themes.txt")
   157  	if err != nil {
   158  		return 0, err
   159  	}
   160  	defer resp.Body.Close()
   161  
   162  	b, _ := ioutil.ReadAll(resp.Body)
   163  	return bytes.Count(b, []byte("\n")) - bytes.Count(b, []byte("#")), nil
   164  }
   165  
   166  func getReleaseNotesFilename(version string) string {
   167  	return filepath.FromSlash(fmt.Sprintf("temp/%s-relnotes-ready.md", version))
   168  
   169  }
   170  
   171  func (r *ReleaseHandler) writeReleaseNotesToTemp(version string, isPatch bool, infosMain, infosDocs gitInfos) (string, error) {
   172  	filename := getReleaseNotesFilename(version)
   173  
   174  	var w io.WriteCloser
   175  
   176  	if !r.try {
   177  		f, err := os.Create(filename)
   178  		if err != nil {
   179  			return "", err
   180  		}
   181  
   182  		defer f.Close()
   183  
   184  		w = f
   185  
   186  	} else {
   187  		w = os.Stdout
   188  	}
   189  
   190  	if err := writeReleaseNotes(version, infosMain, infosDocs, w); err != nil {
   191  		return "", err
   192  	}
   193  
   194  	return filename, nil
   195  }