Skip to content

Commit

Permalink
Publish pre-built binaries (#39)
Browse files Browse the repository at this point in the history
Set up automatic publishing of pre-built binaries to GitHub with [goreleaser].

  [goreleaser]: https://github.com/goreleaser/goreleaser

By default, `goreleaser` generates a changelog based on your commit log.
However, since we maintain our own CHANGELOG.md with user-facing changes only,
I'd much rather we use that. To that end, this includes a new tool
"extract-changelog" in the tools submodule that extracts the relevant changelog
section and prints it to stdout. Its implementation is very similar to
[yab's extract_changelog script]

  [yab's extract_changelog script]: https://github.com/yarpc/yab/blob/90c6eefb1b0fb80283901835b1102b023923abd3/scripts/extract_changelog.go

The release build job uses extract-changelog to extract the release notes for
the given release and dumps them to changes.v1.2.3.txt, and then invokes
goreleaser with that as input.

goreleaser will cross-compile the binary for various systems and architectures
and upload it to GitHub. goreleaser will also stamp the binary with version
information which we can use to ensure that the output of `--version` is always
in-sync.

Refs GO-782
Resolves #27
  • Loading branch information
abhinav authored Aug 19, 2021
2 parents 208e50e + 421ede7 commit 67d5037
Show file tree
Hide file tree
Showing 15 changed files with 450 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.16
go-version: 1.17.x

- name: Load cached dependencies
uses: actions/cache@v2
Expand Down
61 changes: 61 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: release

on:
push:
tags: ['v*']

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest

steps:
- name: Setup Go
uses: actions/setup-go@v1
with:
go-version: 1.17.x

- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Load cached dependencies
uses: actions/cache@v1
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Prepare release
run: |
set -eou pipefail
make bin/extract-changelog
# Extract target version number from the git tag and post it to
# GITHUB_ENV to make it accessible via env.VERSION in other steps.
VERSION=${{ github.ref }}
VERSION="${VERSION#refs/tags/}" # refs/tags/v1.2.3 => v1.2.3
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "Releasing $VERSION"
# Place the release notes in changes.v1.2.3.txt to grab them in the
# release step.
echo "Release notes:"
echo "----"
bin/extract-changelog $VERSION | tee changes.$VERSION.txt
echo "----"
- name: Release
uses: goreleaser/goreleaser-action@v2
with:
distribution: goreleaser
version: latest
args: release --rm-dist --release-notes changes.${{ env.VERSION }}.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_CURRENT_TAG: ${{ env.VERSION }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
/bin
/cover.out
/cover.html
/dist
/changes.*.txt
33 changes: 33 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
# The default flags from goreleaser set a "version" variable instead of our
# preferred "_version". The "-w" skips DWARF generation to reduce the
# binary size (https://github.com/golang/go/issues/26074). This will not
# affect usability of panics and profiling.
ldflags: '-w -X main._version={{.Version}}'

# List of replacements generated by goreleaser to match the output of `uname`
# on various systems. This will make the binary more easily curl-able.
archives:
- replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64

checksum:
name_template: 'checksums.txt'

# Snapshot releases should have the -dev suffix.
snapshot:
name_template: "{{ incpatch .Tag }}-dev"

changelog:
# Skip commit log generation because we'll build ours from the CHANGELOG.md.
skip: true
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
Starting this release, we will include pre-built binaries of gopatch for
different systems.

### Added
- ([#7]): Add support for verbose logging with a `-v` flag.
- Add [introductory documentation] and [patch guide].
Expand Down
14 changes: 10 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
BIN = bin

export GO111MODULE=on
export GOBIN ?= $(shell pwd)/bin
export GOBIN ?= $(shell pwd)/$(BIN)

GO_FILES = $(shell find . \
-path '*/.*' -prune -o \
'(' -type f -a -name '*.go' ')' -print)

GOLINT = $(GOBIN)/golint
STATICCHECK = $(GOBIN)/staticcheck
TOOLS = $(GOLINT) $(STATICCHECK)
GOLINT = $(BIN)/golint
STATICCHECK = $(BIN)/staticcheck
EXTRACT_CHANGELOG = $(BIN)/extract-changelog
TOOLS = $(GOLINT) $(STATICCHECK) $(EXTRACT_CHANGELOG)

.PHONY: all
all: build lint test
Expand Down Expand Up @@ -52,3 +55,6 @@ $(GOLINT): tools/go.mod

$(STATICCHECK): tools/go.mod
cd tools && go install honnef.co/go/tools/cmd/staticcheck

$(EXTRACT_CHANGELOG): tools/cmd/extract-changelog/main.go
cd tools && go install github.com/uber-go/gopatch/tools/cmd/extract-changelog
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,16 @@ we have a number of features planned for gopatch.
[#11]: https://github.com/uber-go/gopatch/issues/11
# Contributing
If you'd like to contribute to gopatch, you may find the following documents
useful:
- [HACKING](docs/HACKING.md) documents the architecture, code organization, and
other information necessary to contribute to the project.
- [RELEASE](docs/RELEASE.md) documents the process for releasing a new version
of gopatch.
# Similar Projects
- [rf] is a refactoring tool with a custom DSL
Expand Down
28 changes: 28 additions & 0 deletions docs/RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Take the following steps to release a new version of gopatch.

1. Ensure that the CHANGELOG.md has an entry for every **user-facing** change.
Do not add entries for changes that are not user-facing.

2. Change the "Unreleased" header to the target version number *without* the
`v` prefix and add today's date in YYYY-MM-DD format. For example, if the
target version is `v1.2.3`, add:

```diff
-## Unreleased
+## 1.2.3 - 2021-08-18
```

3. Create a new PR with the change and the following title:

```
Preparing release v1.2.3
```

4. After landing the PR, tag the release with an **annotated** git tag and push
the tag.

```
$ git pull
$ git tag -a v1.2.3 -m v1.2.3
$ git push origin v1.2.3
```
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func run(args []string, stdin io.Reader, stderr io.Writer) error {
}

if opts.DisplayVersion {
fmt.Fprintln(stderr, "gopatch v"+Version)
fmt.Fprintln(stderr, "gopatch "+_version)
return nil
}

Expand Down
140 changes: 140 additions & 0 deletions tools/cmd/extract-changelog/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// extract-changelog extracts the release notes for a specific version from a
// file matching the format prescribed by https://keepachangelog.com/en/1.0.0/.
package main

import (
"bufio"
"bytes"
"errors"
"flag"
"fmt"
"io"
"os"
"strings"
)

func main() {
cmd := mainCmd{
Stdout: os.Stdout,
Stderr: os.Stderr,
}
if err := cmd.Run(os.Args[1:]); err != nil && err != flag.ErrHelp {
fmt.Fprintln(cmd.Stderr, err)
os.Exit(1)
}
}

type mainCmd struct {
Stdout io.Writer
Stderr io.Writer
}

const _usage = `USAGE
%v [OPTIONS] VERSION
Retrieves the release notes for VERSION from a CHANGELOG.md file and prints
them to stdout.
EXAMPLES
extract-changelog -i CHANGELOG.md v1.2.3
extract-changelog 0.2.5
OPTIONS
`

func (cmd *mainCmd) Run(args []string) error {
flag := flag.NewFlagSet("extract-changelog", flag.ContinueOnError)
flag.SetOutput(cmd.Stderr)
flag.Usage = func() {
fmt.Fprintf(flag.Output(), _usage, flag.Name())
flag.PrintDefaults()
}

file := flag.String("i", "CHANGELOG.md", "input file")

if err := flag.Parse(args); err != nil {
return err
}

var version string
if args := flag.Args(); len(args) > 0 {
version = args[0]
}
version = strings.TrimPrefix(version, "v")

if len(version) == 0 {
return errors.New("please provide a version")
}

f, err := os.Open(*file)
if err != nil {
return fmt.Errorf("open changelog: %v", err)
}
defer f.Close()

s, err := extract(f, version)
if err != nil {
return err
}
_, err = io.WriteString(cmd.Stdout, s)
return err
}

func extract(r io.Reader, version string) (string, error) {
type _state int

const (
initial _state = iota
foundHeader
)

var (
state _state
buff bytes.Buffer
scanner = bufio.NewScanner(r)
)

scan:
for scanner.Scan() {
line := scanner.Text()

switch state {
case initial:
// Version headers take one of the following forms:
//
// ## 0.1.3 - 2021-08-18
// ## [0.1.3] - 2021-08-18
switch {
case strings.HasPrefix(line, "## "+version+" "),
strings.HasPrefix(line, "## ["+version+"]"):
fmt.Fprintln(&buff, line)
state = foundHeader
}

case foundHeader:
// Found a new version header. Stop extracting.
if strings.HasPrefix(line, "## ") {
break scan
}
fmt.Fprintln(&buff, line)

default:
// unreachable but guard against it.
return "", fmt.Errorf("unexpected state %v at %q", state, line)
}
}

if err := scanner.Err(); err != nil {
return "", err
}

if state < foundHeader {
return "", fmt.Errorf("changelog for %q not found", version)
}

out := buff.String()
out = strings.TrimSpace(out) + "\n" // always end with a single newline
return out, nil
}
Loading

0 comments on commit 67d5037

Please sign in to comment.