Skip to content

Commit

Permalink
chore: improve internal release command (#2315)
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez authored Oct 28, 2024
1 parent d0708fc commit 4809501
Show file tree
Hide file tree
Showing 15 changed files with 311 additions and 284 deletions.
4 changes: 2 additions & 2 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ builds:
- -s -w -X main.version={{.Version}}

goos:
- windows
- darwin
- linux
- darwin
- windows
- freebsd
- openbsd
- solaris
Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ checks:
.PHONY: patch minor major detach

patch:
go run ./internal/useragent/ release -m patch
go run ./internal/releaser/ release -m patch

minor:
go run ./internal/useragent/ release -m minor
go run ./internal/releaser/ release -m minor

major:
go run ./internal/useragent/ release -m major
go run ./internal/releaser/ release -m major

detach:
go run ./internal/useragent/ detach
go run ./internal/releaser/ detach

# Docs
.PHONY: docs-build docs-serve docs-themes
Expand Down
2 changes: 1 addition & 1 deletion acme/api/internal/sender/useragent.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions cmd/lego/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,14 @@ import (
"github.com/urfave/cli/v2"
)

var version = "dev"

func main() {
app := cli.NewApp()
app.Name = "lego"
app.HelpName = "lego"
app.Usage = "Let's Encrypt client written in Go"
app.EnableBashCompletion = true

app.Version = version
app.Version = getVersion()
cli.VersionPrinter = func(c *cli.Context) {
fmt.Printf("lego version %s %s/%s\n", c.App.Version, runtime.GOOS, runtime.GOARCH)
}
Expand Down
15 changes: 15 additions & 0 deletions cmd/lego/zz_gen_version.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ require (
github.com/gophercloud/gophercloud v1.14.0
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/hashicorp/go-version v1.7.0
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.114
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df
github.com/infobloxopen/infoblox-go-client v1.1.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,8 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
Expand Down
84 changes: 84 additions & 0 deletions internal/releaser/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package main

import (
"bytes"
"embed"
"fmt"
"go/format"
"os"
"path/filepath"
"text/template"
)

const (
dnsTemplate = "templates/dns.go.tmpl"
dnsTargetFile = "./providers/dns/internal/useragent/useragent.go"
)

const (
senderTemplate = "templates/sender.go.tmpl"
senderTargetFile = "./acme/api/internal/sender/useragent.go"
)

const (
versionTemplate = "templates/version.go.tmpl"
versionTargetFile = "./cmd/lego/zz_gen_version.go"
)

//go:embed templates
var templateFS embed.FS

type Generator struct {
templatePath string
targetFile string
}

func NewGenerator(templatePath string, targetFile string) *Generator {
return &Generator{templatePath: templatePath, targetFile: targetFile}
}

func (g *Generator) Generate(version, comment string) error {
tmpl, err := template.New(filepath.Base(g.templatePath)).ParseFS(templateFS, g.templatePath)
if err != nil {
return fmt.Errorf("parsing template (%s): %w", g.templatePath, err)
}

b := &bytes.Buffer{}

err = tmpl.Execute(b, map[string]string{
"version": version,
"comment": comment,
})
if err != nil {
return fmt.Errorf("execute template (%s): %w", g.templatePath, err)
}

source, err := format.Source(b.Bytes())
if err != nil {
return fmt.Errorf("format generated content (%s): %w", g.targetFile, err)
}

err = os.WriteFile(g.targetFile, source, 0o644)
if err != nil {
return fmt.Errorf("write file (%s): %w", g.targetFile, err)
}

return nil
}

func generate(targetVersion, comment string) error {
generators := []*Generator{
NewGenerator(dnsTemplate, dnsTargetFile),
NewGenerator(senderTemplate, senderTargetFile),
NewGenerator(versionTemplate, versionTargetFile),
}

for _, generator := range generators {
err := generator.Generate(targetVersion, comment)
if err != nil {
return fmt.Errorf("generate file(s): %w", err)
}
}

return nil
}
183 changes: 183 additions & 0 deletions internal/releaser/releaser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package main

import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
"os"
"strconv"

hcversion "github.com/hashicorp/go-version"
"github.com/urfave/cli/v2"
)

const flgMode = "mode"

const (
modePatch = "patch"
modeMinor = "minor"
modeMajor = "major"
)

const versionSourceFile = "./cmd/lego/zz_gen_version.go"

const (
commentRelease = "release"
commentDetach = "detach"
)

func main() {
app := cli.NewApp()
app.Name = "lego-releaser"
app.Usage = "Lego releaser"
app.HelpName = "releaser"
app.Commands = []*cli.Command{
{
Name: "release",
Usage: "Update file for a release",
Action: release,
Before: func(ctx *cli.Context) error {
mode := ctx.String("mode")
switch mode {
case modePatch, modeMinor, modeMajor:
return nil
default:
return fmt.Errorf("invalid mode: %s", mode)
}
},
Flags: []cli.Flag{
&cli.StringFlag{
Name: flgMode,
Aliases: []string{"m"},
Value: modePatch,
Usage: fmt.Sprintf("The release mode: %s|%s|%s", modePatch, modeMinor, modeMajor),
},
},
},
{
Name: "detach",
Usage: "Update file post release",
Action: detach,
},
}

err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}

func release(ctx *cli.Context) error {
mode := ctx.String(flgMode)

currentVersion, err := readCurrentVersion(versionSourceFile)
if err != nil {
return fmt.Errorf("read current version: %w", err)
}

nextVersion, err := bumpVersion(mode, currentVersion)
if err != nil {
return fmt.Errorf("bump version: %w", err)
}

err = generate(nextVersion, commentRelease)
if err != nil {
return err
}

return nil
}

func detach(_ *cli.Context) error {
currentVersion, err := readCurrentVersion(versionSourceFile)
if err != nil {
return fmt.Errorf("read current version: %w", err)
}

v := currentVersion.Core().String()

err = generate(v, commentDetach)
if err != nil {
return err
}

return nil
}

func readCurrentVersion(filename string) (*hcversion.Version, error) {
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
if err != nil {
return nil, err
}

v := visitor{data: make(map[string]string)}
ast.Walk(v, file)

current, err := hcversion.NewSemver(v.data["defaultVersion"])
if err != nil {
return nil, err
}

return current, nil
}

type visitor struct {
data map[string]string
}

func (v visitor) Visit(n ast.Node) ast.Visitor {
if n == nil {
return nil
}

switch d := n.(type) {
case *ast.GenDecl:
if d.Tok == token.CONST {
for _, spec := range d.Specs {
valueSpec, ok := spec.(*ast.ValueSpec)
if !ok {
continue
}
if len(valueSpec.Names) != 1 || len(valueSpec.Values) != 1 {
continue
}

va, ok := valueSpec.Values[0].(*ast.BasicLit)
if !ok {
continue
}
if va.Kind != token.STRING {
continue
}

s, err := strconv.Unquote(va.Value)
if err != nil {
continue
}

v.data[valueSpec.Names[0].String()] = s
}
}
default:
// noop
}
return v
}

func bumpVersion(mode string, v *hcversion.Version) (string, error) {
segments := v.Segments()

switch mode {
case modePatch:
return fmt.Sprintf("%d.%d.%d", segments[0], segments[1], segments[2]+1), nil
case modeMinor:
return fmt.Sprintf("%d.%d.0", segments[0], segments[1]+1), nil
case modeMajor:
return fmt.Sprintf("%d.0.0", segments[0]+1), nil
default:
return "", fmt.Errorf("invalid mode: %s", mode)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by 'internal/useragent'; DO NOT EDIT.
// Code generated by 'internal/releaser'; DO NOT EDIT.

package useragent

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by 'internal/useragent'; DO NOT EDIT.
// Code generated by 'internal/releaser'; DO NOT EDIT.

package sender

Expand Down
15 changes: 15 additions & 0 deletions internal/releaser/templates/version.go.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Code generated by 'internal/releaser'; DO NOT EDIT.

package main

const defaultVersion = "v{{ .version }}+dev{{ if .comment }}-{{ .comment }}{{end}}"

var version = ""

func getVersion() string {
if version == "" {
return defaultVersion
}

return version
}
Loading

0 comments on commit 4809501

Please sign in to comment.