Compare commits

..

No commits in common. "852c08ed3d313e085e4fab12acf1bcdbf5585d4a" and "b3cb9e128ccc8d968949dc34fdee8a61d21b834a" have entirely different histories.

15 changed files with 171 additions and 179 deletions

View file

@ -0,0 +1,16 @@
name: "Setup mdbook"
inputs:
version:
description: "mdbook version"
runs:
using: composite
steps:
- name: Setup mdbook
shell: bash
env:
url: https://github.com/rust-lang/mdbook/releases/download/${{ inputs.version }}/mdbook-${{ inputs.version }}-x86_64-unknown-linux-gnu.tar.gz
run: |
mkdir mdbook
curl -sSL "$url" | tar -xz --directory=./mdbook
echo `pwd`/mdbook >> $GITHUB_PATH

View file

@ -69,15 +69,6 @@
': (?<currentValue>.+) # renovate: datasource=(?<datasource>[a-z-]+) depName=(?<depName>[^\\s]+)(?: lookupName=(?<packageName>[^\\s]+))?(?: versioning=(?<versioning>[a-z-]+))?(?: extractVersion=(?<extractVersion>[^\\s]+))?', ': (?<currentValue>.+) # renovate: datasource=(?<datasource>[a-z-]+) depName=(?<depName>[^\\s]+)(?: lookupName=(?<packageName>[^\\s]+))?(?: versioning=(?<versioning>[a-z-]+))?(?: extractVersion=(?<extractVersion>[^\\s]+))?',
], ],
}, },
{
customType: 'regex',
managerFilePatterns: [
'/.+\\.toml$/'
],
matchStrings: [
'= "(?<currentValue>.+)" # renovate: datasource=(?<datasource>[a-z-]+) depName=(?<depName>[^\\s]+)(?: lookupName=(?<packageName>[^\\s]+))?(?: versioning=(?<versioning>[a-z-]+))?(?: extractVersion=(?<extractVersion>[^\\s]+))?',
],
}
], ],
postUpdateOptions: [ postUpdateOptions: [
'gomodUpdateImportPaths', 'gomodUpdateImportPaths',

View file

@ -2,7 +2,7 @@ name: ci
on: on:
push: push:
branches: [ main ] branches: [main]
pull_request: pull_request:
jobs: jobs:
@ -10,23 +10,29 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
- uses: jdx/mise-action@5ac50f778e26fac95da98d50503682459e86d566 # v3 - name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
with:
go-version-file: go.mod
- name: Run golangci-lint - name: Run golangci-lint
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8 uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8
with: with:
install-mode: none version: v2.4.0 # renovate: datasource=github-releases depName=golangci/golangci-lint
args: --timeout 5m args: --timeout 5m
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
- uses: jdx/mise-action@5ac50f778e26fac95da98d50503682459e86d566 # v3 - name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
with:
go-version-file: go.mod
- name: Run tests - name: Run tests
run: go test -v -race -coverpkg=./... -coverprofile=coverage.txt ./... run: go test -v -race -coverpkg=./... -coverprofile=coverage.txt ./...
@ -40,9 +46,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
- uses: jdx/mise-action@5ac50f778e26fac95da98d50503682459e86d566 # v3 - name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
with:
go-version-file: go.mod
- name: Run go mod tidy - name: Run go mod tidy
run: go mod tidy run: go mod tidy

View file

@ -13,11 +13,13 @@ jobs:
id-token: write # To update the deployment status id-token: write # To update the deployment status
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
with: with:
lfs: "true" lfs: "true"
- uses: jdx/mise-action@5ac50f778e26fac95da98d50503682459e86d566 # v3 - uses: ./.github/actions/setup-mdbook
with:
version: v0.4.52 # renovate: datasource=github-releases depName=rust-lang/mdbook
- name: Build Book - name: Build Book
working-directory: docs working-directory: docs
@ -27,7 +29,7 @@ jobs:
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
- name: Upload artifact - name: Upload artifact
uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
with: with:
# Upload entire repository # Upload entire repository
path: "docs/book" path: "docs/book"

View file

@ -11,7 +11,7 @@ jobs:
REMOTE: mirror REMOTE: mirror
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
with: with:
# Need all to fetch all tags so we can push them # Need all to fetch all tags so we can push them
fetch-depth: 0 fetch-depth: 0

View file

@ -14,16 +14,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
- uses: jdx/mise-action@5ac50f778e26fac95da98d50503682459e86d566 # v3 - name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
- name: Prepare ko with:
run: | go-version-file: go.mod
echo "${{ github.token }}" | ko login ghcr.io --username "dummy" --password-stdin
repo=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
echo "KO_DOCKER_REPO=ghcr.io/${repo}"
echo "KO_DOCKER_REPO=ghcr.io/${repo}" >> $GITHUB_ENV
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
- run: ko build --bare --tags ${{ github.ref_name }} github.com/apricote/releaser-pleaser/cmd/rp - run: ko build --bare --tags ${{ github.ref_name }} github.com/apricote/releaser-pleaser/cmd/rp

View file

@ -2,7 +2,7 @@ name: releaser-pleaser
on: on:
push: push:
branches: [ main ] branches: [main]
# Using pull_request_target to avoid tainting the actual release PR with code from open feature pull requests # Using pull_request_target to avoid tainting the actual release PR with code from open feature pull requests
pull_request_target: pull_request_target:
types: types:
@ -17,7 +17,7 @@ concurrency:
group: releaser-pleaser group: releaser-pleaser
cancel-in-progress: true cancel-in-progress: true
permissions: { } permissions: {}
jobs: jobs:
releaser-pleaser: releaser-pleaser:
@ -25,18 +25,23 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
with: with:
ref: main ref: main
- uses: jdx/mise-action@5ac50f778e26fac95da98d50503682459e86d566 # v3 - name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
with:
go-version-file: go.mod
# Build container image from current commit and replace image ref in `action.yml` # Build container image from current commit and replace image ref in `action.yml`
# Without this, any new flags in `action.yml` would break the job in this repository until the new # Without this, any new flags in `action.yml` would break the job in this repository until the new
# version is released. But a new version can only be released if this job works. # version is released. But a new version can only be released if this job works.
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
- run: ko build --bare --local --platform linux/amd64 --tags ci github.com/apricote/releaser-pleaser/cmd/rp - run: ko build --bare --local --platform linux/amd64 --tags ci github.com/apricote/releaser-pleaser/cmd/rp
- run: "sed -i 's|image: .*$|image: docker://ko.local:ci|g' action.yml" - run: mkdir -p .github/actions/releaser-pleaser
- run: "sed -i 's|image: .*$|image: docker://ghcr.io/apricote/releaser-pleaser:ci|g' action.yml"
# Dogfood the action to make sure it works for users. # Dogfood the action to make sure it works for users.
- name: releaser-pleaser - name: releaser-pleaser

View file

@ -7,23 +7,21 @@ import (
"os/signal" "os/signal"
"runtime/debug" "runtime/debug"
"syscall" "syscall"
"time"
"github.com/lmittmann/tint"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func NewRootCmd() *cobra.Command { var logger *slog.Logger
var cmd = &cobra.Command{
Use: "rp",
Short: "",
Long: ``,
Version: version(),
SilenceUsage: true, // Makes it harder to find the actual error
SilenceErrors: true, // We log manually with slog
}
cmd.AddCommand(newRunCommand()) var rootCmd = &cobra.Command{
Use: "rp",
return cmd Short: "",
Long: ``,
Version: version(),
SilenceUsage: true, // Makes it harder to find the actual error
SilenceErrors: true, // We log manually with slog
} }
func version() string { func version() string {
@ -68,13 +66,24 @@ func Execute() {
// Make sure to stop listening on signals after receiving the first signal to hand control of the signal back // Make sure to stop listening on signals after receiving the first signal to hand control of the signal back
// to the runtime. The Go runtime implements a "force shutdown" if the signal is received again. // to the runtime. The Go runtime implements a "force shutdown" if the signal is received again.
<-ctx.Done() <-ctx.Done()
slog.InfoContext(ctx, "Received shutdown signal, stopping...") logger.InfoContext(ctx, "Received shutdown signal, stopping...")
stop() stop()
}() }()
err := NewRootCmd().ExecuteContext(ctx) err := rootCmd.ExecuteContext(ctx)
if err != nil { if err != nil {
slog.ErrorContext(ctx, err.Error()) logger.ErrorContext(ctx, err.Error())
os.Exit(1) os.Exit(1)
} }
} }
func init() {
logger = slog.New(
tint.NewHandler(os.Stderr, &tint.Options{
Level: slog.LevelDebug,
TimeFormat: time.RFC3339,
}),
)
slog.SetDefault(logger)
}

View file

@ -2,7 +2,6 @@ package cmd
import ( import (
"fmt" "fmt"
"log/slog"
"slices" "slices"
"strings" "strings"
@ -13,104 +12,103 @@ import (
"github.com/apricote/releaser-pleaser/internal/forge" "github.com/apricote/releaser-pleaser/internal/forge"
"github.com/apricote/releaser-pleaser/internal/forge/github" "github.com/apricote/releaser-pleaser/internal/forge/github"
"github.com/apricote/releaser-pleaser/internal/forge/gitlab" "github.com/apricote/releaser-pleaser/internal/forge/gitlab"
"github.com/apricote/releaser-pleaser/internal/log"
"github.com/apricote/releaser-pleaser/internal/updater" "github.com/apricote/releaser-pleaser/internal/updater"
"github.com/apricote/releaser-pleaser/internal/versioning" "github.com/apricote/releaser-pleaser/internal/versioning"
) )
func newRunCommand() *cobra.Command { var runCmd = &cobra.Command{
var ( Use: "run",
flagForge string RunE: run,
flagBranch string }
flagOwner string
flagRepo string var (
flagExtraFiles string flagForge string
flagUpdaters []string flagBranch string
flagOwner string
flagRepo string
flagExtraFiles string
flagUpdaters []string
)
func init() {
rootCmd.AddCommand(runCmd)
runCmd.PersistentFlags().StringVar(&flagForge, "forge", "", "")
runCmd.PersistentFlags().StringVar(&flagBranch, "branch", "main", "")
runCmd.PersistentFlags().StringVar(&flagOwner, "owner", "", "")
runCmd.PersistentFlags().StringVar(&flagRepo, "repo", "", "")
runCmd.PersistentFlags().StringVar(&flagExtraFiles, "extra-files", "", "")
runCmd.PersistentFlags().StringSliceVar(&flagUpdaters, "updaters", []string{}, "")
}
func run(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
var err error
logger.DebugContext(ctx, "run called",
"forge", flagForge,
"branch", flagBranch,
"owner", flagOwner,
"repo", flagRepo,
) )
var cmd = &cobra.Command{ var f forge.Forge
Use: "run",
RunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
logger := log.GetLogger(cmd.ErrOrStderr())
var err error forgeOptions := forge.Options{
Repository: flagRepo,
logger.DebugContext(ctx, "run called", BaseBranch: flagBranch,
"forge", flagForge,
"branch", flagBranch,
"owner", flagOwner,
"repo", flagRepo,
)
var f forge.Forge
forgeOptions := forge.Options{
Repository: flagRepo,
BaseBranch: flagBranch,
}
switch flagForge {
case "gitlab":
logger.DebugContext(ctx, "using forge GitLab")
f, err = gitlab.New(logger, &gitlab.Options{
Options: forgeOptions,
Path: fmt.Sprintf("%s/%s", flagOwner, flagRepo),
})
if err != nil {
slog.ErrorContext(ctx, "failed to create client", "err", err)
return fmt.Errorf("failed to create gitlab client: %w", err)
}
case "github":
logger.DebugContext(ctx, "using forge GitHub")
f = github.New(logger, &github.Options{
Options: forgeOptions,
Owner: flagOwner,
Repo: flagRepo,
})
default:
return fmt.Errorf("unknown --forge: %s", flagForge)
}
extraFiles := parseExtraFiles(flagExtraFiles)
updaterNames := parseUpdaters(flagUpdaters)
updaters := []updater.Updater{}
for _, name := range updaterNames {
switch name {
case "generic":
updaters = append(updaters, updater.Generic(extraFiles))
case "changelog":
updaters = append(updaters, updater.Changelog())
case "packagejson":
updaters = append(updaters, updater.PackageJson())
default:
return fmt.Errorf("unknown updater: %s", name)
}
}
releaserPleaser := rp.New(
f,
logger,
flagBranch,
conventionalcommits.NewParser(logger),
versioning.SemVer,
extraFiles,
updaters,
)
return releaserPleaser.Run(ctx)
},
} }
cmd.PersistentFlags().StringVar(&flagForge, "forge", "", "") switch flagForge {
cmd.PersistentFlags().StringVar(&flagBranch, "branch", "main", "") case "gitlab":
cmd.PersistentFlags().StringVar(&flagOwner, "owner", "", "") logger.DebugContext(ctx, "using forge GitLab")
cmd.PersistentFlags().StringVar(&flagRepo, "repo", "", "") f, err = gitlab.New(logger, &gitlab.Options{
cmd.PersistentFlags().StringVar(&flagExtraFiles, "extra-files", "", "") Options: forgeOptions,
cmd.PersistentFlags().StringSliceVar(&flagUpdaters, "updaters", []string{}, "") Path: fmt.Sprintf("%s/%s", flagOwner, flagRepo),
})
if err != nil {
logger.ErrorContext(ctx, "failed to create client", "err", err)
return fmt.Errorf("failed to create gitlab client: %w", err)
}
case "github":
logger.DebugContext(ctx, "using forge GitHub")
f = github.New(logger, &github.Options{
Options: forgeOptions,
Owner: flagOwner,
Repo: flagRepo,
})
default:
return fmt.Errorf("unknown --forge: %s", flagForge)
}
return cmd extraFiles := parseExtraFiles(flagExtraFiles)
updaterNames := parseUpdaters(flagUpdaters)
updaters := []updater.Updater{}
for _, name := range updaterNames {
switch name {
case "generic":
updaters = append(updaters, updater.Generic(extraFiles))
case "changelog":
updaters = append(updaters, updater.Changelog())
case "packagejson":
updaters = append(updaters, updater.PackageJson())
default:
return fmt.Errorf("unknown updater: %s", name)
}
}
releaserPleaser := rp.New(
f,
logger,
flagBranch,
conventionalcommits.NewParser(logger),
versioning.SemVer,
extraFiles,
updaters,
)
return releaserPleaser.Run(ctx)
} }
func parseExtraFiles(input string) []string { func parseExtraFiles(input string) []string {

View file

@ -2,7 +2,6 @@ package main
import ( import (
"github.com/apricote/releaser-pleaser/cmd/rp/cmd" "github.com/apricote/releaser-pleaser/cmd/rp/cmd"
_ "github.com/apricote/releaser-pleaser/internal/log"
) )
func main() { func main() {

4
go.mod
View file

@ -2,13 +2,13 @@ module github.com/apricote/releaser-pleaser
go 1.23.2 go 1.23.2
toolchain go1.25.0 toolchain go1.24.6
require ( require (
github.com/blang/semver/v4 v4.0.0 github.com/blang/semver/v4 v4.0.0
github.com/go-git/go-billy/v5 v5.6.2 github.com/go-git/go-billy/v5 v5.6.2
github.com/go-git/go-git/v5 v5.16.2 github.com/go-git/go-git/v5 v5.16.2
github.com/google/go-github/v74 v74.0.0 github.com/google/go-github/v72 v72.0.0
github.com/leodido/go-conventionalcommits v0.12.0 github.com/leodido/go-conventionalcommits v0.12.0
github.com/lmittmann/tint v1.1.2 github.com/lmittmann/tint v1.1.2
github.com/spf13/cobra v1.9.1 github.com/spf13/cobra v1.9.1

4
go.sum
View file

@ -40,8 +40,8 @@ github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUv
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v74 v74.0.0 h1:yZcddTUn8DPbj11GxnMrNiAnXH14gNs559AsUpNpPgM= github.com/google/go-github/v72 v72.0.0 h1:FcIO37BLoVPBO9igQQ6tStsv2asG4IPcYFi655PPvBM=
github.com/google/go-github/v74 v74.0.0/go.mod h1:ubn/YdyftV80VPSI26nSJvaEsTOnsjrxG3o9kJhcyak= github.com/google/go-github/v72 v72.0.0/go.mod h1:WWtw8GMRiL62mvIquf1kO3onRHeWWKmK01qdCY8c5fg=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=

View file

@ -12,7 +12,7 @@ import (
"github.com/blang/semver/v4" "github.com/blang/semver/v4"
"github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/go-git/go-git/v5/plumbing/transport/http"
"github.com/google/go-github/v74/github" "github.com/google/go-github/v72/github"
"github.com/apricote/releaser-pleaser/internal/forge" "github.com/apricote/releaser-pleaser/internal/forge"
"github.com/apricote/releaser-pleaser/internal/git" "github.com/apricote/releaser-pleaser/internal/git"

View file

@ -1,23 +0,0 @@
package log
import (
"io"
"log/slog"
"os"
"time"
"github.com/lmittmann/tint"
)
func GetLogger(w io.Writer) *slog.Logger {
return slog.New(
tint.NewHandler(w, &tint.Options{
Level: slog.LevelDebug,
TimeFormat: time.RFC3339,
}),
)
}
func init() {
slog.SetDefault(GetLogger(os.Stderr))
}

View file

@ -1,10 +0,0 @@
[tools]
go = "1.25.0"
golangci-lint = "v2.4.0"
goreleaser = "v2.9.0"
mdbook = "v0.4.52" # renovate: datasource=github-releases depName=rust-lang/mdbook
ko = "v0.18.0" # renovate: datasource=github-releases depName=ko-build/ko
[settings]
# Experimental features are needed for the Go backend
experimental = true