Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d297dcf
WIP: templates, examples, and prototype code for autogenerating CHANG…
joelanford Apr 1, 2020
fc65972
change migration title to header, split things out into functions, ge…
joelanford Apr 2, 2020
d033d20
unexport types and functions
joelanford Apr 2, 2020
a541f3b
rename fragments/example.yaml to ensure PR discovery works through re…
joelanford Apr 2, 2020
b872de4
support PR discovery
joelanford Apr 2, 2020
0629fe4
generate separate migration guide doc for each release
joelanford Apr 3, 2020
04c8e04
Add make target and generate script, update release doc
joelanford Apr 6, 2020
cb71dfb
PR number is optional and for override purposes only
joelanford Apr 6, 2020
766b929
update fragment examples to use pull_request_override
joelanford Apr 6, 2020
8eac47a
move generate scripts to sub-directories to avoid multiple mains
joelanford Apr 6, 2020
b375ad5
copy release doc changes to ./website
joelanford Apr 7, 2020
b39497c
add validate-only flag
joelanford Apr 7, 2020
966c1a8
updated based on PR reviews
joelanford Apr 9, 2020
54cb58f
separate into library, use Go templates
joelanford Apr 10, 2020
6bbb65d
unexport ToChangelogEntry
joelanford Apr 12, 2020
808631e
hack/generate/changelog: unit tests for changelog generation
joelanford Apr 13, 2020
86feeb3
hach/generate/changelog: add unit tests for fragment parsing and migr…
joelanford Apr 14, 2020
90e8c97
fix sanity test checks
joelanford Apr 14, 2020
fa9f9f8
Makefile: include ./hack in unit tests
joelanford Apr 14, 2020
afb26e6
goimports picked the wrong log package :)
joelanford Apr 14, 2020
a7d79dc
fix order of imports
joelanford Apr 14, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ K8S_VERSION = v1.17.2
REPO = github.com/operator-framework/operator-sdk
BUILD_PATH = $(REPO)/cmd/operator-sdk
PKGS = $(shell go list ./... | grep -v /vendor/)
TEST_PKGS = $(shell go list ./... | grep -v -E 'github.com/operator-framework/operator-sdk/(hack/|test/)')
TEST_PKGS = $(shell go list ./... | grep -v -E 'github.com/operator-framework/operator-sdk/test/')
SOURCES = $(shell find . -name '*.go' -not -path "*/vendor/*")

ANSIBLE_BASE_IMAGE = quay.io/operator-framework/ansible-operator
Expand Down Expand Up @@ -98,6 +98,9 @@ gen-cli-doc: ## Generate CLI documentation
gen-test-framework: build/operator-sdk ## Run generate commands to update test/test-framework
./hack/generate/gen-test-framework.sh

gen-changelog: ## Generate CHANGELOG.md and migration guide updates
./hack/generate/gen-changelog.sh

generate: gen-cli-doc gen-test-framework ## Run all generate targets
.PHONY: generate gen-cli-doc gen-test-framework

Expand Down
36 changes: 36 additions & 0 deletions changelog/fragments/00-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# entries is a list of entries to include in
# release notes and/or the migration guide
entries:
- description: >
Description is the line that shows up in the CHANGELOG. This
should be formatted as markdown and be on a single line. Using
the YAML string '>' operator means you can write your entry
multiple lines and it will still be parsed as a single line.

# kind is one of:
# - addition
# - change
# - deprecation
# - removal
# - bugfix
kind: ""

# Is this a breaking change?
breaking: false

# NOTE: ONLY USE `pull_request_override` WHEN ADDING THIS
# FILE FOR A PREVIOUSLY MERGED PULL_REQUEST!
#
# The generator auto-detects the PR number from the commit
# message in which this file was originally added.
#
# What is the pull request number (without the "#")?
# pull_request_override: 0


# Migration can be defined to automatically add a section to
# the migration guide. This is required for breaking changes.
migration:
header: Header text for the migration section
body: >
Body of the migration section.
31 changes: 12 additions & 19 deletions doc/dev/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Making an Operator SDK release involves:

- Updating `CHANGELOG.md`.
- Updating `CHANGELOG.md` and migration guide.
- Tagging and signing a git commit and pushing the tag to GitHub.
- Building a release binary and signing the binary
- Creating a release by uploading binary, signature, and `CHANGELOG.md` updates for the release to GitHub.
Expand Down Expand Up @@ -193,7 +193,7 @@ $ git push origin release-v1.3.1

Create a PR from `release-v1.3.1` to `v1.3.x`. Once CI passes and your PR is merged, continue to step 1.

### 1. Create a PR for release version and CHANGELOG.md updates
### 1. Create a PR for release version, CHANGELOG.md, and migration guide updates

Once all PR's needed for a release have been merged, branch from `master`:

Expand All @@ -215,14 +215,22 @@ Create a new branch to push release commits:
$ git checkout -b release-v1.3.0
```

Run the CHANGELOG and migration guide generator:

```sh
$ GEN_CHANGELOG_TAG=v1.3.0 make gen-changelog
```

Commit the following changes:

- `version/version.go`: update `Version` to `v1.3.0`.
- `internal/scaffold/go_mod.go`, change the `require` line version for `github.com/operator-framework/operator-sdk` from `master` to `v1.3.0`.
- `internal/scaffold/helm/go_mod.go`: same as for `internal/scaffold/go_mod.go`.
- `internal/scaffold/ansible/go_mod.go`: same as for `internal/scaffold/go_mod.go`.
- `CHANGELOG.md`: update the `## Unreleased` header to `## v1.3.0`.
- `doc/user/install-operator-sdk.md`: update the linux and macOS URLs to point to the new release URLs.
- `CHANGELOG.md`: commit changes (updated by changelog generation).
- `website/content/en/docs/migration/v1.3.0.md`: commit changes (created by changelog generation).
- `changelog/fragments/*`: commit deleted fragment files (deleted by changelog generation).

_(Non-patch releases only)_ Lock down the master branch to prevent further commits between this and step 4. See [this section](#locking-down-branches) for steps to do so.

Expand Down Expand Up @@ -254,29 +262,14 @@ Once this tag passes CI, go to step 3. For more info on tagging, see the [releas

**Note:** If CI fails for some reason, you will have to revert the tagged commit, re-commit, and make a new PR.

### 3. Create a PR for post-release version and CHANGELOG.md updates
### 3. Create a PR for post-release version updates

Check out a new branch from master (or use your `release-v1.3.0` branch) and commit the following changes:

- `version/version.go`: update `Version` to `v1.3.0+git`.
- `internal/scaffold/go_mod.go`, change the `require` line version for `github.com/operator-framework/operator-sdk` from `v1.3.0` to `master`.
- `internal/scaffold/helm/go_mod.go`: same as for `internal/scaffold/go_mod.go`.
- `internal/scaffold/ansible/go_mod.go`: same as for `internal/scaffold/go_mod.go`.
- `CHANGELOG.md`: add the following as a new set of headers above `## v1.3.0`:

```markdown
## Unreleased

### Added

### Changed

### Deprecated

### Removed

### Bug Fixes
```

Create a new PR for this branch, targetting the `master` branch. Once this PR passes CI and is merged, `master` can be unfrozen.

Expand Down
73 changes: 73 additions & 0 deletions hack/generate/changelog/gen-changelog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package main

import (
"flag"
"fmt"
"path/filepath"
"strings"

"github.com/blang/semver"
log "github.com/sirupsen/logrus"

"github.com/operator-framework/operator-sdk/hack/generate/changelog/util"
)

const repo = "github.com/operator-framework/operator-sdk"

func main() {
var (
tag string
fragmentsDir string
changelogFile string
migrationDir string
validateOnly bool
)

flag.StringVar(&tag, "tag", "",
"Title for generated CHANGELOG and migration guide sections")
flag.StringVar(&fragmentsDir, "fragments-dir", filepath.Join("changelog", "fragments"),
"Path to changelog fragments directory")
flag.StringVar(&changelogFile, "changelog", "CHANGELOG.md",
"Path to CHANGELOG")
flag.StringVar(&migrationDir, "migration-guide-dir",
filepath.Join("website", "content", "en", "docs", "migration"),
"Path to migration guide directory")
flag.BoolVar(&validateOnly, "validate-only", false,
"Only validate fragments")
flag.Parse()

if tag == "" && !validateOnly {
log.Fatalf("flag '-tag' is required without '-validate-only'")
}

entries, err := util.LoadEntries(fragmentsDir, repo)
if err != nil {
log.Fatalf("failed to load fragments: %v", err)
}
if len(entries) == 0 {
log.Warnf("no entries found")
}

if validateOnly {
return
}

version, err := semver.Parse(strings.TrimPrefix(tag, "v"))
if err != nil {
log.Fatalf("flag '-tag' is not a valid semantic version: %v", err)
}
if len(version.Pre) > 0 || len(version.Build) > 0 {
log.Fatalf("flag '-tag' must not include a build number or pre-release identifiers")
}

cl := util.ChangelogFromEntries(version, entries)
if err := cl.WriteFile(changelogFile); err != nil {
log.Fatalf("failed to update CHANGELOG: %v", err)
}

mg := util.MigrationGuideFromEntries(version, entries)
mgFile := filepath.Join(migrationDir, fmt.Sprintf("v%s.md", version))
if err := mg.WriteFile(mgFile); err != nil {
log.Fatalf("failed to create migration guide: %v", err)
}
}
9 changes: 9 additions & 0 deletions hack/generate/changelog/gen-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

source ./hack/lib/common.sh
set -e
shopt -s extglob

[[ -n "$GEN_CHANGELOG_TAG" ]] || fatal "Must set GEN_CHANGELOG_TAG (e.g. export GEN_CHANGELOG_TAG=v1.2.3)"
go run ./hack/generate/changelog/gen-changelog.go -tag="${GEN_CHANGELOG_TAG}"
rm ./changelog/fragments/!(00-template.yaml)
129 changes: 129 additions & 0 deletions hack/generate/changelog/util/changelog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package util

import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
"text/template"

"github.com/blang/semver"
)

type Changelog struct {
Version string
Additions []ChangelogEntry
Changes []ChangelogEntry
Removals []ChangelogEntry
Deprecations []ChangelogEntry
Bugfixes []ChangelogEntry

Repo string
}

type ChangelogEntry struct {
Description string
Link string
}

const changelogTemplate = `## {{ .Version }}
{{- if or .Additions .Changes .Removals .Deprecations .Bugfixes -}}
{{- with .Additions }}

### Additions
{{ range . }}
- {{ .Description }}{{ if .Link }} ({{ .Link }}){{ end }}
{{- end }}{{- end }}
{{- with .Changes }}

### Changes
{{ range . }}
- {{ .Description }}{{ if .Link }} ({{ .Link }}){{ end }}
{{- end }}{{- end }}
{{- with .Removals }}

### Removals
{{ range . }}
- {{ .Description }}{{ if .Link }} ({{ .Link }}){{ end }}
{{- end }}{{- end }}
{{- with .Deprecations }}

### Deprecations
{{ range . }}
- {{ .Description }}{{ if .Link }} ({{ .Link }}){{ end }}
{{- end }}{{- end }}
{{- with .Bugfixes }}

### Bug Fixes
{{ range . }}
- {{ .Description }}{{ if .Link }} ({{ .Link }}){{ end }}
{{- end }}{{- end }}{{- else }}

No changes for this release!{{ end }}
`

var changelogTmpl = template.Must(template.New("changelog").Parse(changelogTemplate))

func (c *Changelog) Template() ([]byte, error) {
w := &bytes.Buffer{}
if err := changelogTmpl.Execute(w, c); err != nil {
return nil, err
}
return w.Bytes(), nil
}

func (c *Changelog) WriteFile(path string) error {
data, err := c.Template()
if err != nil {
return err
}
existingFile, err := ioutil.ReadFile(path)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
if errors.Is(err, os.ErrNotExist) || len(existingFile) == 0 {
return ioutil.WriteFile(path, data, 0644)
}

data = append(data, '\n')
data = append(data, existingFile...)
return ioutil.WriteFile(path, data, 0644)
}

func ChangelogFromEntries(version semver.Version, entries []FragmentEntry) Changelog {
cl := Changelog{
Version: fmt.Sprintf("v%s", version),
}
for _, e := range entries {
cle := e.toChangelogEntry()
switch e.Kind {
case Addition:
cl.Additions = append(cl.Additions, cle)
case Change:
cl.Changes = append(cl.Changes, cle)
case Removal:
cl.Removals = append(cl.Removals, cle)
case Deprecation:
cl.Deprecations = append(cl.Deprecations, cle)
case Bugfix:
cl.Bugfixes = append(cl.Bugfixes, cle)
}
}
return cl
}

func (e *FragmentEntry) toChangelogEntry() ChangelogEntry {
cle := ChangelogEntry{}
desc := strings.TrimSpace(e.Description)
if e.Breaking {
desc = fmt.Sprintf("**Breaking change**: %s", desc)
}
if !strings.HasSuffix(desc, ".") && !strings.HasSuffix(desc, "!") {
desc = fmt.Sprintf("%s.", desc)
}
cle.Description = desc
cle.Link = e.PullRequestLink
return cle
}
Loading