]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Add linux/arm64 extended to release setup
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 5 Aug 2022 14:35:24 +0000 (16:35 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sun, 28 Aug 2022 16:23:01 +0000 (18:23 +0200)
Fixes #8257

14 files changed:
.circleci/config.yml
commands/release.go
goreleaser-hook-post-linux.sh [deleted file]
goreleaser.yml [deleted file]
hugoreleaser.env [new file with mode: 0644]
hugoreleaser.toml [new file with mode: 0644]
release-hook-post-linux.sh [new file with mode: 0755]
releaser/git.go [deleted file]
releaser/git_test.go [deleted file]
releaser/github.go [deleted file]
releaser/github_test.go [deleted file]
releaser/releasenotes_writer.go [deleted file]
releaser/releasenotes_writer_test.go [deleted file]
releaser/releaser.go

index 07008673bfb5c0afeda896867c60969d19e2e1f4..9f16e900c701b71311b07a534535024ce25ec0b1 100644 (file)
+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
+     
+  
+       
index 6decda9ea5d638421a3b7e19ebe65f278ea35404..2072f3eb233b3b546f5dc3eaa119404a739a5d2d 100644 (file)
@@ -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-hook-post-linux.sh b/goreleaser-hook-post-linux.sh
deleted file mode 100755 (executable)
index e97e274..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-# Se https://github.com/gohugoio/hugo/issues/8955
-objdump -T dist/hugo_extended_linux_linux_amd64/hugo | grep -E -q 'GLIBC_2.2[0-9]'
-RESULT=$?
-if [ $RESULT -eq 0 ]; then
-    echo "Found  GLIBC_2.2x in Linux binary, this will not work in older Vercel/Netlify images.";
-    exit -1;
-fi
diff --git a/goreleaser.yml b/goreleaser.yml
deleted file mode 100644 (file)
index d2cd273..0000000
+++ /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 (file)
index 0000000..2c8d649
--- /dev/null
@@ -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 (file)
index 0000000..e9bf8b6
--- /dev/null
@@ -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/release-hook-post-linux.sh b/release-hook-post-linux.sh
new file mode 100755 (executable)
index 0000000..e97e274
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# Se https://github.com/gohugoio/hugo/issues/8955
+objdump -T dist/hugo_extended_linux_linux_amd64/hugo | grep -E -q 'GLIBC_2.2[0-9]'
+RESULT=$?
+if [ $RESULT -eq 0 ]; then
+    echo "Found  GLIBC_2.2x in Linux binary, this will not work in older Vercel/Netlify images.";
+    exit -1;
+fi
diff --git a/releaser/git.go b/releaser/git.go
deleted file mode 100644 (file)
index ced363a..0000000
+++ /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 etc. in change log. This is a regexp.
-const ignoredCommits = "snapcraft:|Merge commit|Squashed"
-
-func gitLogBefore(ref, tag, repoPath string) (string, error) {
-       var prevTag string
-       var err error
-       if tag != "" {
-               prevTag = tag
-       } else {
-               prevTag, err = gitVersionTagBefore(ref)
-               if err != nil {
-                       return "", err
-               }
-       }
-
-       defaultArgs := []string{"log", "-E", fmt.Sprintf("--grep=%s", ignoredCommits), "--invert-grep", "--pretty=format:%x1e%h%x1f%aE%x1f%s%x1f%b", "--abbrev-commit", prevTag + ".." + ref}
-
-       var args []string
-
-       if repoPath != "" {
-               args = append([]string{"-C", repoPath}, defaultArgs...)
-       } else {
-               args = defaultArgs
-       }
-
-       log, err := git(args...)
-       if err != nil {
-               return ",", err
-       }
-
-       return log, err
-}
-
-func gitVersionTagBefore(ref string) (string, error) {
-       return gitShort("describe", "--tags", "--abbrev=0", "--always", "--match", "v[0-9]*", ref+"^")
-}
-
-func gitShort(args ...string) (output string, err error) {
-       output, err = git(args...)
-       return strings.Replace(strings.Split(output, "\n")[0], "'", "", -1), err
-}
-
-func tagExists(tag string) (bool, error) {
-       out, err := git("tag", "-l", tag)
-       if err != nil {
-               return false, err
-       }
-
-       if strings.Contains(out, tag) {
-               return true, nil
-       }
-
-       return false, nil
-}
diff --git a/releaser/git_test.go b/releaser/git_test.go
deleted file mode 100644 (file)
index ff77eb8..0000000
+++ /dev/null
@@ -1,86 +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 (
-       "testing"
-
-       qt "github.com/frankban/quicktest"
-)
-
-func TestGitInfos(t *testing.T) {
-       c := qt.New(t)
-       skipIfCI(t)
-       infos, err := getGitInfos("v0.20", "hugo", "", false)
-
-       c.Assert(err, qt.IsNil)
-       c.Assert(len(infos) > 0, qt.Equals, true)
-}
-
-func TestIssuesRe(t *testing.T) {
-       c := qt.New(t)
-
-       body := `
-This is a commit message.
-
-Updates #123
-Fix #345
-closes #543
-See #456
-       `
-
-       issues := extractIssues(body)
-
-       c.Assert(len(issues), qt.Equals, 4)
-       c.Assert(issues[0], qt.Equals, 123)
-       c.Assert(issues[2], qt.Equals, 543)
-
-       bodyNoIssues := `
-This is a commit message without issue refs.
-
-But it has e #10 to make old regexp confused.
-Streets #20.
-       `
-
-       emptyIssuesList := extractIssues(bodyNoIssues)
-       c.Assert(len(emptyIssuesList), qt.Equals, 0)
-}
-
-func TestGitVersionTagBefore(t *testing.T) {
-       skipIfCI(t)
-       c := qt.New(t)
-       v1, err := gitVersionTagBefore("v0.18")
-       c.Assert(err, qt.IsNil)
-       c.Assert(v1, qt.Equals, "v0.17")
-}
-
-func TestTagExists(t *testing.T) {
-       skipIfCI(t)
-       c := qt.New(t)
-       b1, err := tagExists("v0.18")
-       c.Assert(err, qt.IsNil)
-       c.Assert(b1, qt.Equals, true)
-
-       b2, err := tagExists("adfagdsfg")
-       c.Assert(err, qt.IsNil)
-       c.Assert(b2, qt.Equals, false)
-}
-
-func skipIfCI(t *testing.T) {
-       if isCI() {
-               // Travis has an ancient git with no --invert-grep: https://github.com/travis-ci/travis-ci/issues/6328
-               // Also Travis clones very shallowly, making some of the tests above shaky.
-               t.Skip("Skip git test on Linux to make Travis happy.")
-       }
-}
diff --git a/releaser/github.go b/releaser/github.go
deleted file mode 100644 (file)
index ffb8804..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-package releaser
-
-import (
-       "encoding/json"
-       "fmt"
-       "io/ioutil"
-       "net/http"
-       "os"
-       "strings"
-)
-
-var (
-       gitHubCommitsAPI      = "https://api.github.com/repos/gohugoio/REPO/commits/%s"
-       gitHubRepoAPI         = "https://api.github.com/repos/gohugoio/REPO"
-       gitHubContributorsAPI = "https://api.github.com/repos/gohugoio/REPO/contributors"
-)
-
-type gitHubAPI struct {
-       commitsAPITemplate      string
-       repoAPI                 string
-       contributorsAPITemplate string
-}
-
-func newGitHubAPI(repo string) *gitHubAPI {
-       return &gitHubAPI{
-               commitsAPITemplate:      strings.Replace(gitHubCommitsAPI, "REPO", repo, -1),
-               repoAPI:                 strings.Replace(gitHubRepoAPI, "REPO", repo, -1),
-               contributorsAPITemplate: strings.Replace(gitHubContributorsAPI, "REPO", repo, -1),
-       }
-}
-
-type gitHubCommit struct {
-       Author  gitHubAuthor `json:"author"`
-       HTMLURL string       `json:"html_url"`
-}
-
-type gitHubAuthor struct {
-       ID        int    `json:"id"`
-       Login     string `json:"login"`
-       HTMLURL   string `json:"html_url"`
-       AvatarURL string `json:"avatar_url"`
-}
-
-type gitHubRepo struct {
-       ID           int    `json:"id"`
-       Name         string `json:"name"`
-       Description  string `json:"description"`
-       HTMLURL      string `json:"html_url"`
-       Stars        int    `json:"stargazers_count"`
-       Contributors []gitHubContributor
-}
-
-type gitHubContributor struct {
-       ID            int    `json:"id"`
-       Login         string `json:"login"`
-       HTMLURL       string `json:"html_url"`
-       Contributions int    `json:"contributions"`
-}
-
-func (g *gitHubAPI) fetchCommit(ref string) (gitHubCommit, error) {
-       var commit gitHubCommit
-
-       u := fmt.Sprintf(g.commitsAPITemplate, ref)
-
-       req, err := http.NewRequest("GET", u, nil)
-       if err != nil {
-               return commit, err
-       }
-
-       err = doGitHubRequest(req, &commit)
-
-       return commit, err
-}
-
-func (g *gitHubAPI) fetchRepo() (gitHubRepo, error) {
-       var repo gitHubRepo
-
-       req, err := http.NewRequest("GET", g.repoAPI, nil)
-       if err != nil {
-               return repo, err
-       }
-
-       err = doGitHubRequest(req, &repo)
-       if err != nil {
-               return repo, err
-       }
-
-       var contributors []gitHubContributor
-       page := 0
-       for {
-               page++
-               var currPage []gitHubContributor
-               url := fmt.Sprintf(g.contributorsAPITemplate+"?page=%d", page)
-
-               req, err = http.NewRequest("GET", url, nil)
-               if err != nil {
-                       return repo, err
-               }
-
-               err = doGitHubRequest(req, &currPage)
-               if err != nil {
-                       return repo, err
-               }
-               if len(currPage) == 0 {
-                       break
-               }
-
-               contributors = append(contributors, currPage...)
-
-       }
-
-       repo.Contributors = contributors
-
-       return repo, err
-}
-
-func doGitHubRequest(req *http.Request, v any) error {
-       addGitHubToken(req)
-
-       resp, err := http.DefaultClient.Do(req)
-       if err != nil {
-               return err
-       }
-       defer resp.Body.Close()
-
-       if isError(resp) {
-               b, _ := ioutil.ReadAll(resp.Body)
-               return fmt.Errorf("GitHub lookup failed: %s", string(b))
-       }
-
-       return json.NewDecoder(resp.Body).Decode(v)
-}
-
-func isError(resp *http.Response) bool {
-       return resp.StatusCode < 200 || resp.StatusCode > 299
-}
-
-func addGitHubToken(req *http.Request) {
-       gitHubToken := os.Getenv("GITHUB_TOKEN")
-       if gitHubToken != "" {
-               req.Header.Add("Authorization", "token "+gitHubToken)
-       }
-}
diff --git a/releaser/github_test.go b/releaser/github_test.go
deleted file mode 100644 (file)
index 23331bf..0000000
+++ /dev/null
@@ -1,46 +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"
-       "os"
-       "testing"
-
-       qt "github.com/frankban/quicktest"
-)
-
-func TestGitHubLookupCommit(t *testing.T) {
-       skipIfNoToken(t)
-       c := qt.New(t)
-       client := newGitHubAPI("hugo")
-       commit, err := client.fetchCommit("793554108763c0984f1a1b1a6ee5744b560d78d0")
-       c.Assert(err, qt.IsNil)
-       fmt.Println(commit)
-}
-
-func TestFetchRepo(t *testing.T) {
-       skipIfNoToken(t)
-       c := qt.New(t)
-       client := newGitHubAPI("hugo")
-       repo, err := client.fetchRepo()
-       c.Assert(err, qt.IsNil)
-       fmt.Println(">>", len(repo.Contributors))
-}
-
-func skipIfNoToken(t *testing.T) {
-       if os.Getenv("GITHUB_TOKEN") == "" {
-               t.Skip("Skip test against GitHub as no GITHUB_TOKEN set.")
-       }
-}
diff --git a/releaser/releasenotes_writer.go b/releaser/releasenotes_writer.go
deleted file mode 100644 (file)
index 5c50e4d..0000000
+++ /dev/null
@@ -1,191 +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 implements a set of utilities and a wrapper around Goreleaser
-// to help automate the Hugo release process.
-package releaser
-
-import (
-       "bytes"
-       "fmt"
-       "io"
-       "io/ioutil"
-       "net/http"
-       "os"
-       "path/filepath"
-       "strings"
-       "text/template"
-)
-
-const (
-       issueLinkTemplate                        = "#%d"
-       linkTemplate                             = "[%s](%s)"
-       releaseNotesMarkdownTemplatePatchRelease = `
-{{ if eq (len .All) 1 }}
-This is a bug-fix release with one important fix.
-{{ else }}
-This is a bug-fix release with a couple of important fixes.
-{{ end }}
-{{ range .All }}
-{{- if .GitHubCommit -}}
-* {{ .Subject }} {{ .Hash }} {{ . | author }} {{ range .Issues }}{{ . | issue }} {{ end }}
-{{ else -}}
-* {{ .Subject }} {{ range .Issues }}{{ . | issue }} {{ end }}
-{{ end -}}
-{{- end }}
-
-
-`
-       releaseNotesMarkdownTemplate = `
-{{- $contribsPerAuthor := .All.ContribCountPerAuthor -}}
-{{- $docsContribsPerAuthor := .Docs.ContribCountPerAuthor -}}
-
-This release represents **{{ len .All }} contributions by {{ len $contribsPerAuthor }} contributors** to the main Hugo code base.
-
-{{- if  gt (len $contribsPerAuthor) 3 -}}
-{{- $u1 := index $contribsPerAuthor 0 -}}
-{{- $u2 := index $contribsPerAuthor 1 -}}
-{{- $u3 := index $contribsPerAuthor 2 -}}
-{{- $u4 := index $contribsPerAuthor 3 -}}
-{{- $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.
-And thanks to [@digitalcraftsman](https://github.com/digitalcraftsman) for his ongoing work on keeping the themes site in pristine condition.
-{{ end }}
-Many have also been busy writing and fixing the documentation in [hugoDocs](https://github.com/gohugoio/hugoDocs),
-which has received **{{ len .Docs }} contributions by {{ len $docsContribsPerAuthor }} contributors**.
-{{- if  gt (len $docsContribsPerAuthor) 3 -}}
-{{- $u1 := index $docsContribsPerAuthor 0 -}}
-{{- $u2 := index $docsContribsPerAuthor 1 -}}
-{{- $u3 := index $docsContribsPerAuthor 2 -}}
-{{- $u4 := index $docsContribsPerAuthor 3 }} A special thanks to {{ $u1.AuthorLink }}, {{ $u2.AuthorLink }}, {{ $u3.AuthorLink }}, and {{ $u4.AuthorLink }} for their work on the documentation site.
-{{ end }}
-
-Hugo now has:
-
-{{ with .Repo -}}
-* {{ .Stars }}+ [stars](https://github.com/gohugoio/hugo/stargazers)
-* {{ len .Contributors }}+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors)
-{{- end -}}
-{{ with .ThemeCount }}
-* {{ . }}+ [themes](http://themes.gohugo.io/)
-{{ end }}
-{{ with .Notes }}
-## Notes
-{{ template "change-section" . }}
-{{- end -}}
-{{ with .All }}
-## Changes
-{{ template "change-section" . }}
-{{ end }}
-
-{{ define "change-section" }}
-{{ range . }}
-{{- if .GitHubCommit -}}
-* {{ .Subject }} {{ .Hash }} {{ . | author }} {{ range .Issues }}{{ . | issue }} {{ end }}
-{{ else -}}
-* {{ .Subject }} {{ range .Issues }}{{ . | issue }} {{ end }}
-{{ end -}}
-{{- end }}
-{{ end }}
-`
-)
-
-var templateFuncs = template.FuncMap{
-       "isPatch": func(c changeLog) bool {
-               return !strings.HasSuffix(c.Version, "0")
-       },
-       "issue": func(id int) string {
-               return fmt.Sprintf(issueLinkTemplate, id)
-       },
-       "commitURL": func(info gitInfo) string {
-               if info.GitHubCommit.HTMLURL == "" {
-                       return ""
-               }
-               return fmt.Sprintf(linkTemplate, info.Hash, info.GitHubCommit.HTMLURL)
-       },
-       "author": func(info gitInfo) string {
-               return "@" + info.GitHubCommit.Author.Login
-       },
-}
-
-func writeReleaseNotes(version string, infosMain, infosDocs gitInfos, to io.Writer) error {
-       client := newGitHubAPI("hugo")
-       changes := newChangeLog(infosMain, infosDocs)
-       changes.Version = version
-       repo, err := client.fetchRepo()
-       if err == nil {
-               changes.Repo = &repo
-       }
-       themeCount, err := fetchThemeCount()
-       if err == nil {
-               changes.ThemeCount = themeCount
-       }
-
-       mtempl := releaseNotesMarkdownTemplate
-
-       if !strings.HasSuffix(version, "0") {
-               mtempl = releaseNotesMarkdownTemplatePatchRelease
-       }
-
-       tmpl, err := template.New("").Funcs(templateFuncs).Parse(mtempl)
-       if err != nil {
-               return err
-       }
-
-       err = tmpl.Execute(to, changes)
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func fetchThemeCount() (int, error) {
-       resp, err := http.Get("https://raw.githubusercontent.com/gohugoio/hugoThemesSiteBuilder/main/themes.txt")
-       if err != nil {
-               return 0, err
-       }
-       defer resp.Body.Close()
-
-       b, _ := ioutil.ReadAll(resp.Body)
-       return bytes.Count(b, []byte("\n")) - bytes.Count(b, []byte("#")), nil
-}
-
-func getReleaseNotesFilename(version string) string {
-       return filepath.FromSlash(fmt.Sprintf("temp/%s-relnotes-ready.md", version))
-}
-
-func (r *ReleaseHandler) writeReleaseNotesToTemp(version string, isPatch bool, infosMain, infosDocs gitInfos) (string, error) {
-       filename := getReleaseNotesFilename(version)
-
-       var w io.WriteCloser
-
-       if !r.try {
-               f, err := os.Create(filename)
-               if err != nil {
-                       return "", err
-               }
-
-               defer f.Close()
-
-               w = f
-
-       } else {
-               w = os.Stdout
-       }
-
-       if err := writeReleaseNotes(version, infosMain, infosDocs, w); err != nil {
-               return "", err
-       }
-
-       return filename, nil
-}
diff --git a/releaser/releasenotes_writer_test.go b/releaser/releasenotes_writer_test.go
deleted file mode 100644 (file)
index 7dcd0cc..0000000
+++ /dev/null
@@ -1,46 +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 commands defines and implements command-line commands and flags
-// used by Hugo. Commands and flags are implemented using Cobra.
-
-package releaser
-
-import (
-       "bytes"
-       "fmt"
-       "os"
-       "testing"
-
-       qt "github.com/frankban/quicktest"
-)
-
-func _TestReleaseNotesWriter(t *testing.T) {
-       skipIfNoToken(t)
-       if os.Getenv("CI") != "" {
-               // Travis has an ancient git with no --invert-grep: https://github.com/travis-ci/travis-ci/issues/6328
-               t.Skip("Skip git test on CI to make Travis happy..")
-       }
-
-       c := qt.New(t)
-
-       var b bytes.Buffer
-
-       // TODO(bep) consider to  query GitHub directly for the gitlog with author info, probably faster.
-       infos, err := getGitInfosBefore("HEAD", "v0.89.0", "hugo", "", false)
-       c.Assert(err, qt.IsNil)
-
-       c.Assert(writeReleaseNotes("0.89.0", infos, infos, &b), qt.IsNil)
-
-       fmt.Println(b.String())
-}
index ebc344e981955262639b08add025b428e7db6d89..fc16a2572e3e3787f35682b3b5f9fe0a2fdca8b2 100644 (file)
@@ -17,7 +17,6 @@ package releaser
 
 import (
        "fmt"
-       "io/ioutil"
        "log"
        "os"
        "path/filepath"
@@ -25,167 +24,105 @@ import (
        "strings"
 
        "github.com/gohugoio/hugo/common/hexec"
-
-       "errors"
-
        "github.com/gohugoio/hugo/common/hugo"
 )
 
 const commitPrefix = "releaser:"
 
-// ReleaseHandler provides functionality to release a new version of Hugo.
-// Test this locally without doing an actual release:
-// go run -tags release main.go release --skip-publish --try -r 0.90.0
-// Or a variation of the above -- the skip-publish flag makes sure that any changes are performed to the local Git only.
-type ReleaseHandler struct {
-       cliVersion string
-
-       skipPublish bool
-
-       // Just simulate, no actual changes.
-       try bool
-
-       git func(args ...string) (string, error)
-}
-
-func (r ReleaseHandler) calculateVersions() (hugo.Version, hugo.Version) {
-       newVersion := hugo.MustParseVersion(r.cliVersion)
-       finalVersion := newVersion.Next()
-       finalVersion.PatchLevel = 0
+// New initialises a ReleaseHandler.
+func New(skipPush, try bool, step int) (*ReleaseHandler, error) {
+       if step < 1 || step > 2 {
+               return nil, fmt.Errorf("step must be 1 or 2")
+       }
 
-       if newVersion.Suffix != "-test" {
-               newVersion.Suffix = ""
+       prefix := "release-"
+       branch, err := git("rev-parse", "--abbrev-ref", "HEAD")
+       if err != nil {
+               return nil, err
+       }
+       if !strings.HasPrefix(branch, prefix) {
+               return nil, fmt.Errorf("branch %q is not a release branch", branch)
        }
 
-       finalVersion.Suffix = "-DEV"
+       logf("Branch: %s\n", branch)
 
-       return newVersion, finalVersion
-}
-
-// New initialises a ReleaseHandler.
-func New(version string, skipPublish, try bool) *ReleaseHandler {
-       // When triggered from CI release branch
-       version = strings.TrimPrefix(version, "release-")
+       version := strings.TrimPrefix(branch, prefix)
        version = strings.TrimPrefix(version, "v")
-       rh := &ReleaseHandler{cliVersion: version, skipPublish: skipPublish, try: try}
+       rh := &ReleaseHandler{branchVersion: version, skipPush: skipPush, try: try, step: step}
 
        if try {
                rh.git = func(args ...string) (string, error) {
-                       fmt.Println("git", strings.Join(args, " "))
+                       logln("git", strings.Join(args, " "))
                        return "", nil
                }
        } else {
                rh.git = git
        }
 
-       return rh
+       return rh, nil
 }
 
-// Run creates a new release.
-func (r *ReleaseHandler) Run() error {
-       if os.Getenv("GITHUB_TOKEN") == "" {
-               return errors.New("GITHUB_TOKEN not set, create one here with the repo scope selected: https://github.com/settings/tokens/new")
-       }
+// ReleaseHandler provides functionality to release a new version of Hugo.
+// Test this locally without doing an actual release:
+// go run -tags release main.go release --skip-publish --try -r 0.90.0
+// Or a variation of the above -- the skip-publish flag makes sure that any changes are performed to the local Git only.
+type ReleaseHandler struct {
+       branchVersion string
 
-       fmt.Printf("Start release from %q\n", wd())
+       // 1 or 2.
+       step int
 
-       newVersion, finalVersion := r.calculateVersions()
+       // No remote pushes.
+       skipPush bool
+
+       // Just simulate, no actual changes.
+       try bool
+
+       git func(args ...string) (string, error)
+}
 
+// Run creates a new release.
+func (r *ReleaseHandler) Run() error {
+       newVersion, finalVersion := r.calculateVersions()
        version := newVersion.String()
        tag := "v" + version
-       isPatch := newVersion.PatchLevel > 0
        mainVersion := newVersion
        mainVersion.PatchLevel = 0
 
-       // Exit early if tag already exists
-       exists, err := tagExists(tag)
-       if err != nil {
-               return err
-       }
-
-       if exists {
-               return fmt.Errorf("tag %q already exists", tag)
-       }
-
-       var changeLogFromTag string
+       defer r.gitPush()
 
-       if newVersion.PatchLevel == 0 {
-               // There may have been patch releases between, so set the tag explicitly.
-               changeLogFromTag = "v" + newVersion.Prev().String()
-               exists, _ := tagExists(changeLogFromTag)
-               if !exists {
-                       // fall back to one that exists.
-                       changeLogFromTag = ""
+       if r.step == 1 {
+               if err := r.bumpVersions(newVersion); err != nil {
+                       return err
                }
-       }
-
-       var (
-               gitCommits     gitInfos
-               gitCommitsDocs gitInfos
-       )
 
-       defer r.gitPush() // TODO(bep)
-
-       gitCommits, err = getGitInfos(changeLogFromTag, "hugo", "", !r.try)
-       if err != nil {
-               return err
-       }
-
-       // TODO(bep) explicit tag?
-       gitCommitsDocs, err = getGitInfos("", "hugoDocs", "../hugoDocs", !r.try)
-       if err != nil {
-               return err
-       }
-
-       releaseNotesFile, err := r.writeReleaseNotesToTemp(version, isPatch, gitCommits, gitCommitsDocs)
-       if err != nil {
-               return err
-       }
-
-       if _, err := r.git("add", releaseNotesFile); err != nil {
-               return err
-       }
-
-       commitMsg := fmt.Sprintf("%s Add release notes for %s", commitPrefix, newVersion)
-       commitMsg += "\n[ci skip]"
-
-       if _, err := r.git("commit", "-m", commitMsg); err != nil {
-               return err
-       }
-
-       if err := r.bumpVersions(newVersion); err != nil {
-               return err
-       }
-
-       if _, err := r.git("commit", "-a", "-m", fmt.Sprintf("%s Bump versions for release of %s\n\n[ci skip]", commitPrefix, newVersion)); err != nil {
-               return err
-       }
+               if _, err := r.git("commit", "-a", "-m", fmt.Sprintf("%s Bump versions for release of %s\n\n[ci skip]", commitPrefix, newVersion)); err != nil {
+                       return err
+               }
 
-       if _, err := r.git("tag", "-a", tag, "-m", fmt.Sprintf("%s %s\n\n[ci skip]", commitPrefix, newVersion)); err != nil {
-               return err
-       }
+               // The above commit will be the target for this release, so print it to the console in a env friendly way.
+               sha, err := git("rev-parse", "HEAD")
+               if err != nil {
+                       return err
+               }
 
-       if !r.skipPublish {
-               if _, err := r.git("push", "origin", tag); err != nil {
+               // Hugoreleaser will do the actual release using these values.
+               if err := r.replaceInFile("hugoreleaser.env",
+                       `HUGORELEASER_TAG=(\S*)`, "HUGORELEASER_TAG="+tag,
+                       `HUGORELEASER_COMMITISH=(\S*)`, "HUGORELEASER_COMMITISH="+sha,
+               ); err != nil {
                        return err
                }
-       }
+               logf("HUGORELEASER_TAG=%s\n", tag)
+               logf("HUGORELEASER_COMMITISH=%s\n", sha)
 
-       if err := r.release(releaseNotesFile); err != nil {
-               return err
+               return nil
        }
 
        if err := r.bumpVersions(finalVersion); err != nil {
                return err
        }
 
-       if !r.try {
-               // No longer needed.
-               if err := os.Remove(releaseNotesFile); err != nil {
-                       return err
-               }
-       }
-
        if _, err := r.git("commit", "-a", "-m", fmt.Sprintf("%s Prepare repository for %s\n\n[ci skip]", commitPrefix, finalVersion)); err != nil {
                return err
        }
@@ -193,36 +130,6 @@ func (r *ReleaseHandler) Run() error {
        return nil
 }
 
-func (r *ReleaseHandler) gitPush() {
-       if r.skipPublish {
-               return
-       }
-       if _, err := r.git("push", "origin", "HEAD"); err != nil {
-               log.Fatal("push failed:", err)
-       }
-}
-
-func (r *ReleaseHandler) release(releaseNotesFile string) error {
-       if r.try {
-               fmt.Println("Skip goreleaser...")
-               return nil
-       }
-
-       args := []string{"--parallelism", "2", "--timeout", "120m", "--rm-dist", "--release-notes", releaseNotesFile}
-       if r.skipPublish {
-               args = append(args, "--skip-publish")
-       }
-
-       cmd, _ := hexec.SafeCommand("goreleaser", args...)
-       cmd.Stdout = os.Stdout
-       cmd.Stderr = os.Stderr
-       err := cmd.Run()
-       if err != nil {
-               return fmt.Errorf("goreleaser failed: %w", err)
-       }
-       return nil
-}
-
 func (r *ReleaseHandler) bumpVersions(ver hugo.Version) error {
        toDev := ""
 
@@ -264,6 +171,29 @@ func (r *ReleaseHandler) bumpVersions(ver hugo.Version) error {
        return nil
 }
 
+func (r ReleaseHandler) calculateVersions() (hugo.Version, hugo.Version) {
+       newVersion := hugo.MustParseVersion(r.branchVersion)
+       finalVersion := newVersion.Next()
+       finalVersion.PatchLevel = 0
+
+       if newVersion.Suffix != "-test" {
+               newVersion.Suffix = ""
+       }
+
+       finalVersion.Suffix = "-DEV"
+
+       return newVersion, finalVersion
+}
+
+func (r *ReleaseHandler) gitPush() {
+       if r.skipPush {
+               return
+       }
+       if _, err := r.git("push", "origin", "HEAD"); err != nil {
+               log.Fatal("push failed:", err)
+       }
+}
+
 func (r *ReleaseHandler) replaceInFile(filename string, oldNew ...string) error {
        filename = filepath.FromSlash(filename)
        fi, err := os.Stat(filename)
@@ -272,11 +202,11 @@ func (r *ReleaseHandler) replaceInFile(filename string, oldNew ...string) error
        }
 
        if r.try {
-               fmt.Printf("Replace in %q: %q\n", filename, oldNew)
+               logf("Replace in %q: %q\n", filename, oldNew)
                return nil
        }
 
-       b, err := ioutil.ReadFile(filename)
+       b, err := os.ReadFile(filename)
        if err != nil {
                return err
        }
@@ -287,18 +217,22 @@ func (r *ReleaseHandler) replaceInFile(filename string, oldNew ...string) error
                newContent = re.ReplaceAllString(newContent, oldNew[i+1])
        }
 
-       return ioutil.WriteFile(filename, []byte(newContent), fi.Mode())
-}
-
-func isCI() bool {
-       return os.Getenv("CI") != ""
+       return os.WriteFile(filename, []byte(newContent), fi.Mode())
 }
 
-func wd() string {
-       p, err := os.Getwd()
+func git(args ...string) (string, error) {
+       cmd, _ := hexec.SafeCommand("git", args...)
+       out, err := cmd.CombinedOutput()
        if err != nil {
-               log.Fatal(err)
+               return "", fmt.Errorf("git failed: %q: %q (%q)", err, out, args)
        }
-       return p
+       return string(out), nil
+}
+
+func logf(format string, args ...interface{}) {
+       fmt.Fprintf(os.Stderr, format, args...)
+}
 
+func logln(args ...interface{}) {
+       fmt.Fprintln(os.Stderr, args...)
 }