diff options
-rw-r--r-- | .circleci/config.yml | 127 | ||||
-rw-r--r-- | commands/release.go | 23 | ||||
-rw-r--r-- | goreleaser.yml | 214 | ||||
-rw-r--r-- | hugoreleaser.env | 6 | ||||
-rw-r--r-- | hugoreleaser.toml | 232 | ||||
-rwxr-xr-x | release-hook-post-linux.sh (renamed from goreleaser-hook-post-linux.sh) | 0 | ||||
-rw-r--r-- | releaser/git.go | 253 | ||||
-rw-r--r-- | releaser/git_test.go | 86 | ||||
-rw-r--r-- | releaser/github.go | 143 | ||||
-rw-r--r-- | releaser/github_test.go | 46 | ||||
-rw-r--r-- | releaser/releasenotes_writer.go | 191 | ||||
-rw-r--r-- | releaser/releasenotes_writer_test.go | 46 | ||||
-rw-r--r-- | releaser/releaser.go | 254 |
13 files changed, 438 insertions, 1183 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 07008673b..9f16e900c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,51 +1,114 @@ +parameters: + +# v2: 11m. defaults: &defaults + resource_class: large docker: - - image: bepsays/ci-goreleaser:1.21900.20000 - environment: - CGO_ENABLED: "0" - + - image: bepsays/ci-hugoreleaser:1.21900.20000 +environment: &buildenv + GOMODCACHE: /root/project/gomodcache version: 2 jobs: - build: - <<: *defaults + prepare_release: + <<: *defaults + environment: &buildenv + GOMODCACHE: /root/project/gomodcache steps: - - checkout: + - &remote-docker + setup_remote_docker: + version: 20.10.14 + - checkout: path: hugo + - &git-config + run: + command: | + git config --global user.email "bjorn.erik.pedersen+hugoreleaser@gmail.com" + git config --global user.name "hugoreleaser" - run: - command: | - git clone git@github.com:gohugoio/hugoDocs.git - cd hugo - go mod download - sleep 5 - go mod verify - - persist_to_workspace: - root: . - paths: . - release: - <<: *defaults + command: | + cd hugo + go mod download + go run -tags release main.go release --step 1 + - save_cache: + key: git-sha-{{ .Revision }} + paths: + - hugo + - gomodcache + build_container1: + <<: [*defaults] + environment: + <<: [*buildenv] steps: - - attach_workspace: - at: /root/project + - &restore-cache + restore_cache: + key: git-sha-{{ .Revision }} - run: - command: | - cd hugo - git config --global user.email "bjorn.erik.pedersen+hugoreleaser@gmail.com" - git config --global user.name "hugoreleaser" - go run -tags release main.go release -r ${CIRCLE_BRANCH} - + no_output_timeout: 20m + command: | + mkdir -p /tmp/files/dist1 + cd hugo + hugoreleaser build -paths "builds/container1/**" -workers 3 -dist /tmp/files/dist1 -chunks $CIRCLE_NODE_TOTAL -chunk-index $CIRCLE_NODE_INDEX + - &persist-workspace + persist_to_workspace: + root: /tmp/files + paths: + - dist1 + - dist2 + parallelism: 7 + build_container2: + <<: [*defaults] + environment: + <<: [*buildenv] + docker: + - image: bepsays/ci-hugoreleaser-linux-arm64:1.21900.20000 + steps: + - *restore-cache + - &attach-workspace + attach_workspace: + at: /tmp/workspace + - run: + command: | + mkdir -p /tmp/files/dist2 + cd hugo + hugoreleaser build -paths "builds/container2/**" -workers 1 -dist /tmp/files/dist2 + - *persist-workspace + archive_and_release: + <<: [*defaults] + environment: + <<: [*buildenv] + steps: + - *restore-cache + - *attach-workspace + - *git-config + - run: + command: | + cp -a /tmp/workspace/dist1/. ./hugo/dist + cp -a /tmp/workspace/dist2/. ./hugo/dist + - run: + command: | + cd hugo + hugoreleaser archive + hugoreleaser release + go run -tags release main.go release --step 2 workflows: version: 2 release: jobs: - - build: + - prepare_release: filters: branches: only: /release-.*/ - - hold: - type: approval + - build_container1: + requires: + - prepare_release + - build_container2: requires: - - build - - release: + - prepare_release + - archive_and_release: context: org-global requires: - - hold + - build_container1 + - build_container2 + + + diff --git a/commands/release.go b/commands/release.go index 6decda9ea..2072f3eb2 100644 --- a/commands/release.go +++ b/commands/release.go @@ -17,8 +17,6 @@ package commands import ( - "errors" - "github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/releaser" "github.com/spf13/cobra" @@ -29,10 +27,9 @@ var _ cmder = (*releaseCommandeer)(nil) type releaseCommandeer struct { cmd *cobra.Command - version string - - skipPublish bool - try bool + step int + skipPush bool + try bool } func createReleaser() cmder { @@ -50,9 +47,9 @@ func createReleaser() cmder { return r.release() } - r.cmd.PersistentFlags().StringVarP(&r.version, "rel", "r", "", "new release version, i.e. 0.25.1") - r.cmd.PersistentFlags().BoolVarP(&r.skipPublish, "skip-publish", "", false, "skip all publishing pipes of the release") - r.cmd.PersistentFlags().BoolVarP(&r.try, "try", "", false, "simulate a release, i.e. no changes") + r.cmd.PersistentFlags().BoolVarP(&r.skipPush, "skip-push", "", false, "skip pushing to remote") + r.cmd.PersistentFlags().BoolVarP(&r.try, "try", "", false, "no changes") + r.cmd.PersistentFlags().IntVarP(&r.step, "step", "", 0, "step to run (1: set new version 2: prepare next dev version)") return r } @@ -65,8 +62,10 @@ func (c *releaseCommandeer) flagsToConfig(cfg config.Provider) { } func (r *releaseCommandeer) release() error { - if r.version == "" { - return errors.New("must set the --rel flag to the relevant version number") + rel, err := releaser.New(r.skipPush, r.try, r.step) + if err != nil { + return err } - return releaser.New(r.version, r.skipPublish, r.try).Run() + + return rel.Run() } diff --git a/goreleaser.yml b/goreleaser.yml deleted file mode 100644 index d2cd273ce..000000000 --- a/goreleaser.yml +++ /dev/null @@ -1,214 +0,0 @@ -project_name: hugo -env: - - GO111MODULE=on - - GOPROXY=https://proxy.golang.org -before: - hooks: - - go mod download -builds: - - - binary: hugo - id: hugo - ldflags: -s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio - env: - - CGO_ENABLED=0 - flags: - - -buildmode - - exe - goos: - - darwin - - linux - - windows - goarch: - - amd64 - - 386 - - arm - - arm64 - goarm: - - 7 - ignore: - - goos: darwin - goarch: 386 - - - binary: hugo - id: hugo_unix - ldflags: -s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio - env: - - CGO_ENABLED=0 - flags: - - -buildmode - - exe - goos: - - freebsd - - netbsd - - openbsd - - dragonfly - goarch: - - amd64 - - - binary: hugo - id: hugo_extended_windows - ldflags: - - -s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio - - "-extldflags '-static'" - env: - - CGO_ENABLED=1 - - CC=x86_64-w64-mingw32-gcc - - CXX=x86_64-w64-mingw32-g++ - flags: - - -buildmode - - exe - - -tags - - extended - goos: - - windows - goarch: - - amd64 - - binary: hugo - id: hugo_extended_darwin - ldflags: -s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio - env: - - CGO_ENABLED=1 - - CC=o64-clang - - CXX=o64-clang++ - flags: - - -buildmode - - exe - - -tags - - extended - goos: - - darwin - goarch: - - amd64 - - arm64 - - binary: hugo - id: hugo_extended_linux - ldflags: -s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio - env: - - CGO_ENABLED=1 - flags: - - -buildmode - - exe - - -tags - - extended - goos: - - linux - goarch: - - amd64 - hooks: - post: ./goreleaser-hook-post-linux.sh -release: - draft: true - -archives: - - - id: "hugo" - builds: ['hugo', 'hugo_unix', 'hugo_fat_darwin'] - format: tar.gz - format_overrides: - - goos: windows - format: zip - name_template: "{{.ProjectName}}_{{.Version}}_{{.Os}}-{{.Arch}}" - replacements: - amd64: 64bit - 386: 32bit - arm: ARM - arm64: ARM64 - darwin: macOS - linux: Linux - windows: Windows - openbsd: OpenBSD - netbsd: NetBSD - freebsd: FreeBSD - dragonfly: DragonFlyBSD - files: - - README.md - - LICENSE - - - id: "hugo_extended" - builds: ['hugo_extended_windows', 'hugo_extended_linux', 'hugo_extended_fat_darwin'] - format: tar.gz - format_overrides: - - goos: windows - format: zip - name_template: "{{.ProjectName}}_extended_{{.Version}}_{{.Os}}-{{.Arch}}" - replacements: - amd64: 64bit - 386: 32bit - arm: ARM - arm64: ARM64 - darwin: macOS - linux: Linux - windows: Windows - openbsd: OpenBSD - netbsd: NetBSD - freebsd: FreeBSD - dragonfly: DragonFlyBSD - files: - - README.md - - LICENSE - -universal_binaries: -- - id: hugo_fat_darwin - - ids: - - hugo - - replace: true - -- - id: hugo_extended_fat_darwin - - ids: - - hugo_extended_darwin - - replace: true - -nfpms: - - - id: "hugo" - builds: ['hugo'] - formats: - - deb - vendor: "gohugo.io" - homepage: "https://gohugo.io/" - maintainer: "Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>" - description: "A Fast and Flexible Static Site Generator built with love in GoLang." - license: "Apache-2.0" - file_name_template: "{{.ProjectName}}_{{.Version}}_{{.Os}}-{{.Arch}}" - replacements: - amd64: 64bit - 386: 32bit - arm: ARM - arm64: ARM64 - darwin: macOS - linux: Linux - windows: Windows - openbsd: OpenBSD - netbsd: NetBSD - freebsd: FreeBSD - dragonfly: DragonFlyBSD - - - id: "hugo_extended" - builds: ['hugo_extended_linux'] - formats: - - deb - vendor: "gohugo.io" - homepage: "https://gohugo.io/" - maintainer: "Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>" - description: "A Fast and Flexible Static Site Generator built with love in GoLang." - license: "Apache-2.0" - file_name_template: "{{.ProjectName}}_extended_{{.Version}}_{{.Os}}-{{.Arch}}" - replacements: - amd64: 64bit - 386: 32bit - arm: ARM - arm64: ARM64 - darwin: macOS - linux: Linux - windows: Windows - openbsd: OpenBSD - netbsd: NetBSD - freebsd: FreeBSD - dragonfly: DragonFlyBSD diff --git a/hugoreleaser.env b/hugoreleaser.env new file mode 100644 index 000000000..2c8d64913 --- /dev/null +++ b/hugoreleaser.env @@ -0,0 +1,6 @@ +HUGO_RELEASE_NAME=New release setup + +# Release env. +# These will be replaced by script before release. +HUGORELEASER_TAG=xxx +HUGORELEASER_COMMITISH=xxx
\ No newline at end of file diff --git a/hugoreleaser.toml b/hugoreleaser.toml new file mode 100644 index 000000000..e9bf8b6f1 --- /dev/null +++ b/hugoreleaser.toml @@ -0,0 +1,232 @@ +project = "hugo" + +[go_settings] + go_proxy = "https://proxy.golang.org" + go_exe = "go" + +[build_settings] + binary = "hugo" + flags = ["-buildmode", "exe"] + env = ["CGO_ENABLED=0"] + ldflags = "-s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio" + +[archive_settings] + name_template = "{{ .Project }}_{{ .Tag | trimPrefix `v` }}_{{ .Goos }}-{{ .Goarch }}" + extra_files = [ + { source_path = "README.md", target_path = "README.md" }, + { source_path = "LICENSE", target_path = "LICENSE" }, + ] + [archive_settings.type] + format = "tar.gz" + extension = ".tar.gz" + [archive_settings.replacements] + amd64 = "64bit" + 386 = "32bit" + arm = "ARM" + arm64 = "ARM64" + darwin = "macOS" + linux = "Linux" + windows = "Windows" + openbsd = "OpenBSD" + netbsd = "NetBSD" + freebsd = "FreeBSD" + dragonfly = "DragonFlyBSD" + +[release_settings] + name = "${HUGO_RELEASE_NAME}" + type = "github" + repository = "hugo" + repository_owner = "gohugoio" + draft = true + prerelease = false + + [release_settings.release_notes_settings] + # Use Hugoreleaser's autogenerated release notes. + generate = true + + # Collapse relases with < 10 changes below one title. + short_threshold = 10 + short_title = "What's Changed" + + groups = [ + # Group the changes in the release notes by title. + # You need at least one. + # The groups will be tested in order until a match is found. + # The titles will so be listed in the given order in the release note. + # Any match with ignore=true title will be dropped. + { regexp = "Merge commit|Squashed", ignore = true }, + { title = "Bug fixes", regexp = "fix", ordinal = 10 }, + { title = "Dependency Updates", regexp = "deps", ordinal = 30 }, + { title = "Build Setup", regexp = "(snap|release|update to)", ordinal = 40 }, + { title = "Documentation", regexp = "(doc|readme)", ordinal = 40 }, + { title = "Improvements", regexp = ".*", ordinal = 20 }, + ] + +[[builds]] + path = "container1/unix/regular" + + [[builds.os]] + goos = "darwin" + [[builds.os.archs]] + goarch = "universal" + [[builds.os]] + goos = "linux" + [[builds.os.archs]] + goarch = "amd64" + [[builds.os.archs]] + goarch = "arm64" + [[builds.os.archs]] + goarch = "arm" + [builds.os.archs.build_settings] + env = ["CGO_ENABLED=0", "GOARM=7"] + + # Unix BSD variants + [[builds.os]] + goos = "dragonfly" + [[builds.os.archs]] + goarch = "amd64" + [[builds.os]] + goos = "freebsd" + [[builds.os.archs]] + goarch = "amd64" + [[builds.os]] + goos = "netbsd" + [[builds.os.archs]] + goarch = "amd64" + [[builds.os]] + goos = "openbsd" + [[builds.os.archs]] + goarch = "amd64" + +[[builds]] + path = "container1/unix/extended" + + [builds.build_settings] + flags = ["-buildmode", "exe", "-tags", "extended"] + env = ["CGO_ENABLED=1"] + + [[builds.os]] + goos = "darwin" + [builds.os.build_settings] + env = ["CGO_ENABLED=1", "CC=o64-clang", "CXX=o64-clang++"] + [[builds.os.archs]] + goarch = "universal" + [[builds.os]] + goos = "linux" + [[builds.os.archs]] + goarch = "amd64" + +[[builds]] + path = "container2/linux/extended" + + [builds.build_settings] + flags = ["-buildmode", "exe", "-tags", "extended"] + + [[builds.os]] + goos = "linux" + [builds.os.build_settings] + env = [ + "CGO_ENABLED=1", + "CC=aarch64-linux-gnu-gcc", + "CXX=aarch64-linux-gnu-g++", + ] + [[builds.os.archs]] + goarch = "arm64" + +[[builds]] + path = "container1/windows/regular" + + [[builds.os]] + goos = "windows" + [builds.os.build_settings] + binary = "hugo.exe" + [[builds.os.archs]] + goarch = "amd64" + [[builds.os.archs]] + goarch = "arm64" + +[[builds]] + path = "container1/windows/extended" + + [builds.build_settings] + flags = ["-buildmode", "exe", "-tags", "extended"] + env = [ + "CGO_ENABLED=1", + "CC=x86_64-w64-mingw32-gcc", + "CXX=x86_64-w64-mingw32-g++", + ] + ldflags = "-s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio -extldflags '-static'" + + [[builds.os]] + goos = "windows" + [builds.os.build_settings] + binary = "hugo.exe" + [[builds.os.archs]] + goarch = "amd64" + +[[archives]] + paths = ["builds/container1/unix/regular/**"] +[[archives]] + paths = ["builds/container1/unix/extended/**"] + [archives.archive_settings] + name_template = "{{ .Project }}_extended_{{ .Tag | trimPrefix `v` }}_{{ .Goos }}-{{ .Goarch }}" +[[archives]] + # Only extended builds in container2. + paths = ["builds/container2/**"] + [archives.archive_settings] + name_template = "{{ .Project }}_extended_{{ .Tag | trimPrefix `v` }}_{{ .Goos }}-{{ .Goarch }}" +[[archives]] + paths = ["builds/**/windows/regular/**"] + [archives.archive_settings.type] + format = "zip" + extension = ".zip" +[[archives]] + paths = ["builds/**/windows/extended/**"] + [archives.archive_settings] + name_template = "{{ .Project }}_extended_{{ .Tag | trimPrefix `v` }}_{{ .Goos }}-{{ .Goarch }}" + [archives.archive_settings.type] + format = "zip" + extension = ".zip" +[[archives]] + paths = ["builds/**/regular/linux/{arm64,amd64}"] + [archives.archive_settings] + [archives.archive_settings.type] + format = "_plugin" + extension = ".deb" + [archives.archive_settings.plugin] + id = "deb" + type = "gorun" + command = "github.com/gohugoio/hugoreleaser-archive-plugins/deb@v0.5.0" + [archives.archive_settings.custom_settings] + vendor = "gohugo.io" + homepage = "https://github.com/gohugoio/hugoreleaser" + maintainer = "Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>" + description = "Build, archive and release Go programs." + license = "Apache-2.0" +[[archives]] + paths = ["builds/**/extended/linux/{arm64,amd64}"] + [archives.archive_settings] + name_template = "{{ .Project }}_extended_{{ .Tag | trimPrefix `v` }}_{{ .Goos }}-{{ .Goarch }}" + [archives.archive_settings.type] + format = "_plugin" + extension = ".deb" + [archives.archive_settings.plugin] + id = "deb" + type = "gorun" + command = "github.com/gohugoio/hugoreleaser-archive-plugins/deb@latest" + [archives.archive_settings.custom_settings] + vendor = "gohugo.io" + homepage = "https://github.com/gohugoio/hugoreleaser" + maintainer = "Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>" + description = "Build, archive and release Go programs." + license = "Apache-2.0" + +[[releases]] + paths = ["archives/**"] + path = "r1" + + # The above should allow the following build commands: + # hugoreleaser build -paths "builds/container1/**" + # hugoreleaser build -paths "builds/container2/**" + # hugoreleaser archive + # hugoreleaser release diff --git a/goreleaser-hook-post-linux.sh b/release-hook-post-linux.sh index e97e274a8..e97e274a8 100755 --- a/goreleaser-hook-post-linux.sh +++ b/release-hook-post-linux.sh diff --git a/releaser/git.go b/releaser/git.go deleted file mode 100644 index ced363a9d..000000000 --- a/releaser/git.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2017-present The Hugo Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package releaser - -import ( - "fmt" - "regexp" - "sort" - "strconv" - "strings" - - "github.com/gohugoio/hugo/common/hexec" -) - -var issueRe = regexp.MustCompile(`(?i)(?:Updates?|Closes?|Fix.*|See) #(\d+)`) - -type changeLog struct { - Version string - Notes gitInfos - All gitInfos - Docs gitInfos - - // Overall stats - Repo *gitHubRepo - ContributorCount int - ThemeCount int -} - -func newChangeLog(infos, docInfos gitInfos) *changeLog { - log := &changeLog{ - Docs: docInfos, - } - - for _, info := range infos { - // TODO(bep) improve - if regexp.MustCompile("(?i)deprecate|note").MatchString(info.Subject) { - log.Notes = append(log.Notes, info) - } - - log.All = append(log.All, info) - info.Subject = strings.TrimSpace(info.Subject) - - } - - return log -} - -type gitInfo struct { - Hash string - Author string - Subject string - Body string - - GitHubCommit *gitHubCommit -} - -func (g gitInfo) Issues() []int { - return extractIssues(g.Body) -} - -func (g gitInfo) AuthorID() string { - if g.GitHubCommit != nil { - return g.GitHubCommit.Author.Login - } - return g.Author -} - -func extractIssues(body string) []int { - var i []int - m := issueRe.FindAllStringSubmatch(body, -1) - for _, mm := range m { - issueID, err := strconv.Atoi(mm[1]) - if err != nil { - continue - } - i = append(i, issueID) - } - return i -} - -type gitInfos []gitInfo - -func git(args ...string) (string, error) { - cmd, _ := hexec.SafeCommand("git", args...) - out, err := cmd.CombinedOutput() - if err != nil { - return "", fmt.Errorf("git failed: %q: %q (%q)", err, out, args) - } - return string(out), nil -} - -func getGitInfos(tag, repo, repoPath string, remote bool) (gitInfos, error) { - return getGitInfosBefore("HEAD", tag, repo, repoPath, remote) -} - -type countribCount struct { - Author string - GitHubAuthor gitHubAuthor - Count int -} - -func (c countribCount) AuthorLink() string { - if c.GitHubAuthor.HTMLURL != "" { - return fmt.Sprintf("[@%s](%s)", c.GitHubAuthor.Login, c.GitHubAuthor.HTMLURL) - } - - if !strings.Contains(c.Author, "@") { - return c.Author - } - - return c.Author[:strings.Index(c.Author, "@")] -} - -type contribCounts []countribCount - -func (c contribCounts) Less(i, j int) bool { return c[i].Count > c[j].Count } -func (c contribCounts) Len() int { return len(c) } -func (c contribCounts) Swap(i, j int) { c[i], c[j] = c[j], c[i] } - -func (g gitInfos) ContribCountPerAuthor() contribCounts { - var c contribCounts - - counters := make(map[string]countribCount) - - for _, gi := range g { - authorID := gi.AuthorID() - if count, ok := counters[authorID]; ok { - count.Count = count.Count + 1 - counters[authorID] = count - } else { - var ghA gitHubAuthor - if gi.GitHubCommit != nil { - ghA = gi.GitHubCommit.Author - } - authorCount := countribCount{Count: 1, Author: gi.Author, GitHubAuthor: ghA} - counters[authorID] = authorCount - } - } - - for _, v := range counters { - c = append(c, v) - } - - sort.Sort(c) - return c -} - -func getGitInfosBefore(ref, tag, repo, repoPath string, remote bool) (gitInfos, error) { - client := newGitHubAPI(repo) - var g gitInfos - - log, err := gitLogBefore(ref, tag, repoPath) - if err != nil { - return g, err - } - - log = strings.Trim(log, "\n\x1e'") - entries := strings.Split(log, "\x1e") - - for _, entry := range entries { - items := strings.Split(entry, "\x1f") - gi := gitInfo{} - - if len(items) > 0 { - gi.Hash = items[0] - } - if len(items) > 1 { - gi.Author = items[1] - } - if len(items) > 2 { - gi.Subject = items[2] - } - if len(items) > 3 { - gi.Body = items[3] - } - - if remote && gi.Hash != "" { - gc, err := client.fetchCommit(gi.Hash) - if err == nil { - gi.GitHubCommit = &gc - } - } - g = append(g, gi) - } - - return g, nil -} - -// Ignore autogenerated commits et |