1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-02-03 13:11:48 +02:00

feat: arch user repository integration (#2838)

* feat: aur PKGBUILD integration

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* feat: guess install, improve formatting

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: more deterministic

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* feat: binary releases, push, more tests

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* feat: accept key as text

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* feat: improvements

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* feat: srcinfo

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: compile

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: everything

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: lint

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* feat: renames, docs, etc

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* docs: link to docs

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: go mod tidy, title

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: srcinfo tmpl

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: missing close quote

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: templates

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: always defaults conflicts and provides

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: ssh command

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: maintainers can be a list

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: ensure -bin suffix, more tests and docs

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: this will never happen

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: whitespaces

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: goreleaser config

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>
This commit is contained in:
Carlos Alexandro Becker 2022-01-20 14:59:39 -03:00 committed by GitHub
parent 2c6b51cc65
commit b02bec962e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1855 additions and 10 deletions

View File

@ -9,6 +9,6 @@ trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8
[*.{md,yml}]
[*.{md,yml,yaml}]
indent_size = 2
indent_style = space

View File

@ -161,6 +161,33 @@ rigs:
description: Deliver Go binaries as fast and easily as possible
license: MIT
aurs:
- homepage: https://goreleaser.com
description: Deliver Go binaries as fast and easily as possible
maintainers:
- 'Fernandez Ludovic <lfernandez dot dev at gmail dot com>'
- 'Carlos Alexandro Becker <carlos at becker dot software>'
license: MIT
private_key: '{{ .Env.AUR_KEY }}'
git_url: 'ssh://aur@aur.archlinux.org/goreleaser-bin.git'
package: |-
# bin
install -Dm755 "./goreleaser" "${pkgdir}/usr/bin/goreleaser"
# license
install -Dm644 "./LICENSE.md" "${pkgdir}/usr/share/licenses/goreleaser/LICENSE"
# completions
mkdir -p "${pkgdir}/usr/share/bash-completion/completions/"
mkdir -p "${pkgdir}/usr/share/zsh/site-functions/"
mkdir -p "${pkgdir}/usr/share/fish/vendor_completions.d/"
install -Dm644 "./completions/goreleaser.bash" "${pkgdir}/usr/share/bash-completion/completions/goreleaser"
install -Dm644 "./completions/goreleaser.zsh" "${pkgdir}/usr/share/zsh/site-functions/_goreleaser"
install -Dm644 "./completions/goreleaser.fish" "${pkgdir}/usr/share/fish/vendor_completions.d/goreleaser.fish"
# man pages
install -Dm644 "./manpages/goreleaser.1.gz" "${pkgdir}/usr/share/man/man1/goreleaser.1.gz"
scoop:
bucket:
owner: goreleaser

4
go.mod
View File

@ -13,6 +13,7 @@ require (
github.com/caarlos0/env/v6 v6.9.1
github.com/caarlos0/go-reddit/v3 v3.0.1
github.com/caarlos0/go-shellwords v1.0.12
github.com/charmbracelet/keygen v0.1.2
github.com/dghubble/go-twitter v0.0.0-20211115160449-93a8679adecb
github.com/dghubble/oauth1 v0.7.1
github.com/fatih/color v1.13.0
@ -32,6 +33,7 @@ require (
github.com/ulikunitz/xz v0.5.10
github.com/xanzy/go-gitlab v0.52.2
gocloud.dev v0.24.0
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
gopkg.in/mail.v2 v2.3.1
@ -118,6 +120,7 @@ require (
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-ieproxy v0.0.1 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
@ -128,7 +131,6 @@ require (
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/xanzy/ssh-agent v0.3.1 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/text v0.3.7 // indirect

4
go.sum
View File

@ -268,6 +268,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/keygen v0.1.2 h1:Gr/gdIOjDIxCTRVXpwa9tsXPoJPS2eGNehPoMnZLvTQ=
github.com/charmbracelet/keygen v0.1.2/go.mod h1:kFQ3Cvop12fXWX1K29vxDxV9x8ujG4wBSXq//GySSSk=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@ -639,6 +641,8 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyex
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a h1:eU8j/ClY2Ty3qdHnn0TyW3ivFoPC/0F1gQZz8yTxbbE=
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a/go.mod h1:v8eSC2SMp9/7FTKUncp7fH9IwPfw+ysMObcEz5FWheQ=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=

View File

@ -57,6 +57,10 @@ const (
BrewTap
// GoFishRig is an uploadable Rigs rig food file.
GoFishRig
// PkgBuild is an Arch Linux AUR PKGBUILD file.
PkgBuild
// SrcInfo is an Arch Linux AUR .SRCINFO file.
SrcInfo
// KrewPluginManifest is a krew plugin manifest file.
KrewPluginManifest
// ScoopManifest is an uploadable scoop manifest file.
@ -99,6 +103,10 @@ func (t Type) String() string {
return "Scoop Manifest"
case SBOM:
return "SBOM"
case PkgBuild:
return "PKGBUILD"
case SrcInfo:
return "SRCINFO"
default:
return "unknown"
}
@ -244,6 +252,15 @@ func (artifacts Artifacts) List() []*Artifact {
return artifacts.items
}
// GroupByID groups the artifacts by their ID.
func (artifacts Artifacts) GroupByID() map[string][]*Artifact {
result := map[string][]*Artifact{}
for _, a := range artifacts.items {
result[a.ID()] = append(result[a.ID()], a)
}
return result
}
// GroupByPlatform groups the artifacts by their platform.
func (artifacts Artifacts) GroupByPlatform() map[string][]*Artifact {
result := map[string][]*Artifact{}

View File

@ -386,6 +386,8 @@ func TestTypeToString(t *testing.T) {
KrewPluginManifest,
ScoopManifest,
SBOM,
PkgBuild,
SrcInfo,
} {
t.Run(a.String(), func(t *testing.T) {
require.NotEqual(t, "unknown", a.String())

View File

@ -16,8 +16,7 @@ func IsRepo() bool {
return err == nil && strings.TrimSpace(out) == "true"
}
// Run runs a git command and returns its output or errors.
func Run(args ...string) (string, error) {
func RunWithEnv(env []string, args ...string) (string, error) {
// TODO: use exex.CommandContext here and refactor.
extraArgs := []string{
"-c", "log.showSignature=false",
@ -31,6 +30,7 @@ func Run(args ...string) (string, error) {
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.Env = append(cmd.Env, env...)
log.WithField("args", args).Debug("running git")
err := cmd.Run()
@ -46,6 +46,11 @@ func Run(args ...string) (string, error) {
return stdout.String(), nil
}
// Run runs a git command and returns its output or errors.
func Run(args ...string) (string, error) {
return RunWithEnv([]string{}, args...)
}
// Clean the output.
func Clean(output string, err error) (string, error) {
output = strings.ReplaceAll(strings.Split(output, "\n")[0], "'", "")

View File

@ -16,7 +16,12 @@ const golden = ".golden"
func RequireEqual(tb testing.TB, out []byte) {
tb.Helper()
doRequireEqual(tb, out, "", golden)
RequireEqualExt(tb, out, "")
}
func RequireEqualExt(tb testing.TB, out []byte, ext string) {
tb.Helper()
doRequireEqual(tb, out, ext, golden)
}
func RequireEqualTxt(tb testing.TB, out []byte) {

476
internal/pipe/aur/aur.go Normal file
View File

@ -0,0 +1,476 @@
package aur
import (
"bufio"
"bytes"
"errors"
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"text/template"
"github.com/apex/log"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/client"
"github.com/goreleaser/goreleaser/internal/commitauthor"
"github.com/goreleaser/goreleaser/internal/git"
"github.com/goreleaser/goreleaser/internal/pipe"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
"golang.org/x/crypto/ssh"
)
const (
pkgBuildExtra = "AURConfig"
defaultSSHCommand = "ssh -i {{ .KeyPath }} -F /dev/null"
defaultCommitMsg = "Update to {{ .Tag }}"
)
var ErrNoArchivesFound = errors.New("no linux archives found")
// Pipe for arch linux's AUR pkgbuild.
type Pipe struct{}
func (Pipe) String() string { return "arch user repositories" }
func (Pipe) Skip(ctx *context.Context) bool { return len(ctx.Config.AURs) == 0 }
func (Pipe) Default(ctx *context.Context) error {
for i := range ctx.Config.AURs {
pkg := &ctx.Config.AURs[i]
pkg.CommitAuthor = commitauthor.Default(pkg.CommitAuthor)
if pkg.CommitMessageTemplate == "" {
pkg.CommitMessageTemplate = defaultCommitMsg
}
if pkg.Name == "" {
pkg.Name = ctx.Config.ProjectName
}
if !strings.HasSuffix(pkg.Name, "-bin") {
pkg.Name += "-bin"
}
if len(pkg.Conflicts) == 0 {
pkg.Conflicts = []string{ctx.Config.ProjectName}
}
if len(pkg.Provides) == 0 {
pkg.Provides = []string{ctx.Config.ProjectName}
}
if pkg.Rel == "" {
pkg.Rel = "1"
}
if pkg.GitSSHCommand == "" {
pkg.GitSSHCommand = defaultSSHCommand
}
}
return nil
}
func (Pipe) Run(ctx *context.Context) error {
cli, err := client.New(ctx)
if err != nil {
return err
}
return runAll(ctx, cli)
}
func runAll(ctx *context.Context, cli client.Client) error {
for _, pkgbuild := range ctx.Config.AURs {
err := doRun(ctx, pkgbuild, cli)
if err != nil {
return err
}
}
return nil
}
func doRun(ctx *context.Context, pkgbuild config.AUR, cl client.Client) error {
name, err := tmpl.New(ctx).Apply(pkgbuild.Name)
if err != nil {
return err
}
pkgbuild.Name = name
filters := []artifact.Filter{
artifact.ByGoos("linux"),
artifact.Or(
artifact.ByGoarch("amd64"),
artifact.ByGoarch("arm64"),
artifact.ByGoarch("386"),
artifact.And(
artifact.ByGoarch("arm"),
artifact.Or(
artifact.ByGoarm("7"),
artifact.ByGoarm("6"),
),
),
),
artifact.Or(
artifact.ByType(artifact.UploadableArchive),
artifact.ByType(artifact.UploadableBinary),
),
}
if len(pkgbuild.IDs) > 0 {
filters = append(filters, artifact.ByIDs(pkgbuild.IDs...))
}
archives := ctx.Artifacts.Filter(artifact.And(filters...)).List()
if len(archives) == 0 {
return ErrNoArchivesFound
}
pkg, err := tmpl.New(ctx).Apply(pkgbuild.Package)
if err != nil {
return err
}
if strings.TrimSpace(pkg) == "" {
art := archives[0]
switch art.Type {
case artifact.UploadableBinary:
name := art.Name
bin := art.ExtraOr(artifact.ExtraBinary, art.Name).(string)
pkg = fmt.Sprintf(`install -Dm755 "./%s "${pkgdir}/usr/bin/%s"`, name, bin)
case artifact.UploadableArchive:
for _, bin := range art.ExtraOr(artifact.ExtraBinaries, []string{}).([]string) {
pkg = fmt.Sprintf(`install -Dm755 "./%s" "${pkgdir}/usr/bin/%[1]s"`, bin)
break
}
}
log.Warnf("guessing package to be %q", pkg)
}
pkgbuild.Package = pkg
for _, info := range []struct {
name, tpl, ext string
kind artifact.Type
}{
{
name: "PKGBUILD",
tpl: pkgBuildTemplate,
ext: ".pkgbuild",
kind: artifact.PkgBuild,
},
{
name: ".SRCINFO",
tpl: srcInfoTemplate,
ext: ".srcinfo",
kind: artifact.SrcInfo,
},
} {
pkgContent, err := buildPkgFile(ctx, pkgbuild, cl, archives, info.tpl)
if err != nil {
return err
}
path := filepath.Join(ctx.Config.Dist, "aur", pkgbuild.Name+info.ext)
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return fmt.Errorf("failed to write %s: %w", info.kind, err)
}
log.WithField("file", path).Info("writing")
if err := os.WriteFile(path, []byte(pkgContent), 0o644); err != nil { //nolint: gosec
return fmt.Errorf("failed to write %s: %w", info.kind, err)
}
ctx.Artifacts.Add(&artifact.Artifact{
Name: info.name,
Path: path,
Type: info.kind,
Extra: map[string]interface{}{
pkgBuildExtra: pkgbuild,
artifact.ExtraID: pkgbuild.Name,
},
})
}
return nil
}
func buildPkgFile(ctx *context.Context, pkg config.AUR, client client.Client, artifacts []*artifact.Artifact, tpl string) (string, error) {
data, err := dataFor(ctx, pkg, client, artifacts)
if err != nil {
return "", err
}
return applyTemplate(ctx, tpl, data)
}
func fixLines(s string) string {
lines := strings.Split(s, "\n")
var result []string
for _, line := range lines {
l := strings.TrimSpace(line)
if l == "" {
result = append(result, "")
continue
}
result = append(result, " "+l)
}
return strings.Join(result, "\n")
}
func applyTemplate(ctx *context.Context, tpl string, data templateData) (string, error) {
t := template.Must(
template.New(data.Name).
Funcs(template.FuncMap{
"fixLines": fixLines,
"pkgArray": toPkgBuildArray,
}).
Parse(tpl),
)
var out bytes.Buffer
if err := t.Execute(&out, data); err != nil {
return "", err
}
content, err := tmpl.New(ctx).Apply(out.String())
if err != nil {
return "", err
}
out.Reset()
// Sanitize the template output and get rid of trailing whitespace.
var (
r = strings.NewReader(content)
s = bufio.NewScanner(r)
)
for s.Scan() {
l := strings.TrimRight(s.Text(), " ")
_, _ = out.WriteString(l)
_ = out.WriteByte('\n')
}
if err := s.Err(); err != nil {
return "", err
}
return out.String(), nil
}
func toPkgBuildArray(ss []string) string {
result := make([]string, 0, len(ss))
for _, s := range ss {
result = append(result, fmt.Sprintf("'%s'", s))
}
return strings.Join(result, " ")
}
func toPkgBuildArch(arch string) string {
switch arch {
case "amd64":
return "x86_64"
case "386":
return "i686"
case "arm64":
return "aarch64"
case "arm6":
return "armv6h"
case "arm7":
return "armv7h"
default:
return "invalid" // should never get here
}
}
func dataFor(ctx *context.Context, cfg config.AUR, cl client.Client, artifacts []*artifact.Artifact) (templateData, error) {
result := templateData{
Name: cfg.Name,
Desc: cfg.Description,
Homepage: cfg.Homepage,
Version: ctx.Version,
License: cfg.License,
Rel: cfg.Rel,
Maintainers: cfg.Maintainers,
Contributors: cfg.Contributors,
Provides: cfg.Provides,
Conflicts: cfg.Conflicts,
Depends: cfg.Depends,
OptDepends: cfg.OptDepends,
Package: cfg.Package,
}
for _, art := range artifacts {
sum, err := art.Checksum("sha256")
if err != nil {
return result, err
}
if cfg.URLTemplate == "" {
url, err := cl.ReleaseURLTemplate(ctx)
if err != nil {
return result, err
}
cfg.URLTemplate = url
}
url, err := tmpl.New(ctx).WithArtifact(art, map[string]string{}).Apply(cfg.URLTemplate)
if err != nil {
return result, err
}
releasePackage := releasePackage{
DownloadURL: url,
SHA256: sum,
Arch: toPkgBuildArch(art.Goarch + art.Goarm),
}
result.ReleasePackages = append(result.ReleasePackages, releasePackage)
result.Arches = append(result.Arches, releasePackage.Arch)
}
sort.Strings(result.Arches)
sort.Slice(result.ReleasePackages, func(i, j int) bool {
return result.ReleasePackages[i].Arch < result.ReleasePackages[j].Arch
})
return result, nil
}
// Publish the PKGBUILD and .SRCINFO files to the AUR repository.
func (Pipe) Publish(ctx *context.Context) error {
skips := pipe.SkipMemento{}
for _, pkgs := range ctx.Artifacts.Filter(
artifact.Or(
artifact.ByType(artifact.PkgBuild),
artifact.ByType(artifact.SrcInfo),
),
).GroupByID() {
err := doPublish(ctx, pkgs)
if err != nil && pipe.IsSkip(err) {
skips.Remember(err)
continue
}
if err != nil {
return err
}
}
return skips.Evaluate()
}
func doPublish(ctx *context.Context, pkgs []*artifact.Artifact) error {
cfg := pkgs[0].Extra[pkgBuildExtra].(config.AUR)
if strings.TrimSpace(cfg.SkipUpload) == "true" {
return pipe.Skip("pkgbuild.skip_upload is set")
}
if strings.TrimSpace(cfg.SkipUpload) == "auto" && ctx.Semver.Prerelease != "" {
return pipe.Skip("prerelease detected with 'auto' upload, skipping aur publish")
}
key, err := tmpl.New(ctx).Apply(cfg.PrivateKey)
if err != nil {
return err
}
key, err = keyPath(key)
if err != nil {
return err
}
url, err := tmpl.New(ctx).Apply(cfg.GitURL)
if err != nil {
return err
}
if url == "" {
return pipe.Skip("pkgbuild.git_url is empty")
}
sshcmd, err := tmpl.New(ctx).WithExtraFields(tmpl.Fields{
"KeyPath": key,
}).Apply(cfg.GitSSHCommand)
if err != nil {
return err
}
msg, err := tmpl.New(ctx).Apply(cfg.CommitMessageTemplate)
if err != nil {
return err
}
author, err := commitauthor.Get(ctx, cfg.CommitAuthor)
if err != nil {
return err
}
parent := filepath.Join(ctx.Config.Dist, "aur", "repos")
cwd := filepath.Join(parent, cfg.Name)
if err := os.MkdirAll(parent, 0o755); err != nil {
return err
}
env := []string{fmt.Sprintf("GIT_SSH_COMMAND=%s", sshcmd)}
if err := runGitCmds(parent, env, [][]string{
{"clone", url, cfg.Name},
}); err != nil {
return fmt.Errorf("failed to setup local AUR repo: %w", err)
}
if err := runGitCmds(cwd, env, [][]string{
// setup auth et al
{"config", "--local", "user.name", author.Name},
{"config", "--local", "user.email", author.Email},
{"config", "--local", "commit.gpgSign", "false"},
{"config", "--local", "init.defaultBranch", "master"},
}); err != nil {
return fmt.Errorf("failed to setup local AUR repo: %w", err)
}
for _, pkg := range pkgs {
bts, err := os.ReadFile(pkg.Path)
if err != nil {
return fmt.Errorf("failed to read %s: %w", pkg.Name, err)
}
if err := os.WriteFile(filepath.Join(cwd, pkg.Name), bts, 0o644); err != nil {
return fmt.Errorf("failed to write %s: %w", pkg.Name, err)
}
}
log.WithField("repo", url).WithField("name", cfg.Name).Info("pushing")
if err := runGitCmds(cwd, env, [][]string{
{"add", "-A", "."},
{"commit", "-m", msg},
{"push", "origin", "HEAD"},
}); err != nil {
return fmt.Errorf("failed to push %q (%q): %w", cfg.Name, url, err)
}
return nil
}
func keyPath(key string) (string, error) {
if key == "" {
return "", pipe.Skip("pkgbuild.private_key is empty")
}
if _, err := ssh.ParsePrivateKey([]byte(key)); err == nil {
f, err := os.CreateTemp("", "id_*")
if err != nil {
return "", fmt.Errorf("failed to store private key: %w", err)
}
defer f.Close()
if _, err := fmt.Fprint(f, key); err != nil {
return "", fmt.Errorf("failed to store private key: %w", err)
}
if err := os.Chmod(f.Name(), 0o400); err != nil {
return "", fmt.Errorf("failed to store private key: %w", err)
}
return f.Name(), nil
}
if _, err := os.Stat(key); os.IsNotExist(err) {
return "", fmt.Errorf("key %q does not exist", key)
}
return key, nil
}
func runGitCmds(cwd string, env []string, cmds [][]string) error {
for _, cmd := range cmds {
args := append([]string{"-C", cwd}, cmd...)
if _, err := git.Clean(git.RunWithEnv(env, args...)); err != nil {
return fmt.Errorf("%q failed: %w", strings.Join(cmd, " "), err)
}
}
return nil
}

View File

@ -0,0 +1,757 @@
package aur
import (
"fmt"
"os"
"path/filepath"
"testing"
"github.com/charmbracelet/keygen"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/client"
"github.com/goreleaser/goreleaser/internal/git"
"github.com/goreleaser/goreleaser/internal/golden"
"github.com/goreleaser/goreleaser/internal/testlib"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
"github.com/stretchr/testify/require"
)
func TestDescription(t *testing.T) {
require.NotEmpty(t, Pipe{}.String())
}
func createTemplateData() templateData {
return templateData{
Name: "test-bin",
Desc: "Some desc",
Homepage: "https://example.com",
Conflicts: []string{"nope"},
Depends: []string{"nope"},
Arches: []string{"x86_64", "i686", "aarch64", "armv6h", "armv7h"},
Rel: "1",
Provides: []string{"test"},
OptDepends: []string{"nfpm"},
Maintainers: []string{
"Ciclano <ciclano@example.com>",
"Cicrano <cicrano@example.com>",
},
Contributors: []string{
"Fulano <fulano@example.com>",
"Beltrano <beltrano@example.com>",
},
License: "MIT",
Version: "0.1.3",
Package: `# bin
install -Dm755 "./goreleaser" "${pkgdir}/usr/bin/goreleaser"
# license
install -Dm644 "./LICENSE.md" "${pkgdir}/usr/share/licenses/goreleaser/LICENSE"
# completions
mkdir -p "${pkgdir}/usr/share/bash-completion/completions/"
mkdir -p "${pkgdir}/usr/share/zsh/site-functions/"
mkdir -p "${pkgdir}/usr/share/fish/vendor_completions.d/"
install -Dm644 "./completions/goreleaser.bash" "${pkgdir}/usr/share/bash-completion/completions/goreleaser"
install -Dm644 "./completions/goreleaser.zsh" "${pkgdir}/usr/share/zsh/site-functions/_goreleaser"
install -Dm644 "./completions/goreleaser.fish" "${pkgdir}/usr/share/fish/vendor_completions.d/goreleaser.fish"
# man pages
install -Dm644 "./manpages/goreleaser.1.gz" "${pkgdir}/usr/share/man/man1/goreleaser.1.gz"`,
ReleasePackages: []releasePackage{
{
Arch: "x86_64",
DownloadURL: "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_x86_64.tar.gz",
SHA256: "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67",
},
{
Arch: "armv6h",
DownloadURL: "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_Arm6.tar.gz",
SHA256: "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67",
},
{
Arch: "aarch64",
DownloadURL: "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_Arm64.tar.gz",
SHA256: "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67",
},
{
Arch: "i686",
DownloadURL: "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_386.tar.gz",
SHA256: "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67",
},
{
Arch: "armv7h",
DownloadURL: "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_arm7.tar.gz",
SHA256: "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67",
},
},
}
}
func TestFullPkgBuild(t *testing.T) {
data := createTemplateData()
pkg, err := applyTemplate(context.New(config.Project{
ProjectName: "foo",
}), pkgBuildTemplate, data)
require.NoError(t, err)
golden.RequireEqual(t, []byte(pkg))
}
func TestPkgBuildSimple(t *testing.T) {
pkg, err := applyTemplate(context.New(config.Project{}), pkgBuildTemplate, createTemplateData())
require.NoError(t, err)
require.Contains(t, pkg, `# Maintainer: Ciclano <ciclano@example.com>`)
require.Contains(t, pkg, `# Maintainer: Cicrano <cicrano@example.com>`)
require.Contains(t, pkg, `# Contributor: Fulano <fulano@example.com>`)
require.Contains(t, pkg, `# Contributor: Beltrano <beltrano@example.com>`)
require.Contains(t, pkg, `pkgname='test-bin'`)
require.Contains(t, pkg, `url='https://example.com'`)
require.Contains(t, pkg, `source_x86_64=('https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_x86_64.tar.gz')`)
require.Contains(t, pkg, `sha256sums_x86_64=('1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67')`)
require.Contains(t, pkg, `pkgver=0.1.3`)
}
func TestFullSrcInfo(t *testing.T) {
data := createTemplateData()
data.License = "MIT"
pkg, err := applyTemplate(context.New(config.Project{
ProjectName: "foo",
}), srcInfoTemplate, data)
require.NoError(t, err)
golden.RequireEqual(t, []byte(pkg))
}
func TestSrcInfoSimple(t *testing.T) {
pkg, err := applyTemplate(context.New(config.Project{}), srcInfoTemplate, createTemplateData())
require.NoError(t, err)
require.Contains(t, pkg, `pkgbase = test-bin`)
require.Contains(t, pkg, `pkgname = test-bin`)
require.Contains(t, pkg, `url = https://example.com`)
require.Contains(t, pkg, `source_x86_64 = https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_x86_64.tar.gz`)
require.Contains(t, pkg, `sha256sums_x86_64 = 1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67`)
require.Contains(t, pkg, `pkgver = 0.1.3`)
}
func TestFullPipe(t *testing.T) {
type testcase struct {
prepare func(ctx *context.Context)
expectedRunError string
expectedPublishError string
}
for name, tt := range map[string]testcase{
"default": {
prepare: func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitHub
ctx.Config.AURs[0].Homepage = "https://github.com/goreleaser"
},
},
"with-more-opts": {
prepare: func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitHub
ctx.Config.AURs[0].Homepage = "https://github.com/goreleaser"
ctx.Config.AURs[0].Maintainers = []string{"me"}
ctx.Config.AURs[0].Contributors = []string{"me as well"}
ctx.Config.AURs[0].Depends = []string{"curl", "bash"}
ctx.Config.AURs[0].OptDepends = []string{"wget: stuff", "foo: bar"}
ctx.Config.AURs[0].Provides = []string{"git", "svn"}
ctx.Config.AURs[0].Conflicts = []string{"libcurl", "cvs", "blah"}
},
},
"default-gitlab": {
prepare: func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitLab
ctx.Config.AURs[0].Homepage = "https://gitlab.com/goreleaser"
},
},
"invalid-name-template": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].Name = "{{ .Asdsa }"
},
expectedRunError: `template: tmpl:1: unexpected "}" in operand`,
},
"invalid-package-template": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].Package = "{{ .Asdsa }"
},
expectedRunError: `template: tmpl:1: unexpected "}" in operand`,
},
"invalid-commit-template": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].CommitMessageTemplate = "{{ .Asdsa }"
},
expectedPublishError: `template: tmpl:1: unexpected "}" in operand`,
},
"invalid-key-template": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].PrivateKey = "{{ .Asdsa }"
},
expectedPublishError: `template: tmpl:1: unexpected "}" in operand`,
},
"no-key": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].PrivateKey = ""
},
expectedPublishError: `pkgbuild.private_key is empty`,
},
"key-not-found": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].PrivateKey = "testdata/nope"
},
expectedPublishError: `key "testdata/nope" does not exist`,
},
"invalid-git-url-template": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].GitURL = "{{ .Asdsa }"
},
expectedPublishError: `template: tmpl:1: unexpected "}" in operand`,
},
"no-git-url": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].GitURL = ""
},
expectedPublishError: `pkgbuild.git_url is empty`,
},
"invalid-ssh-cmd-template": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].GitSSHCommand = "{{ .Asdsa }"
},
expectedPublishError: `template: tmpl:1: unexpected "}" in operand`,
},
"invalid-commit-author-template": {
prepare: func(ctx *context.Context) {
ctx.Config.AURs[0].CommitAuthor.Name = "{{ .Asdsa }"
},
expectedPublishError: `template: tmpl:1: unexpected "}" in operand`,
},
} {
t.Run(name, func(t *testing.T) {
url := makeBareRepo(t)
key := makeKey(t)
folder := t.TempDir()
ctx := &context.Context{
Git: context.GitInfo{
CurrentTag: "v1.0.1",
},
Version: "1.0.1",
Artifacts: artifact.New(),
Env: map[string]string{
"FOO": "foo_is_bar",
},
Config: config.Project{
Dist: folder,
ProjectName: name,
AURs: []config.AUR{
{
Name: name,
IDs: []string{"foo"},
PrivateKey: key,
License: "MIT",
GitURL: url,
Description: "A run pipe test fish food and FOO={{ .Env.FOO }}",
},
},
},
}
tt.prepare(ctx)
ctx.Artifacts.Add(&artifact.Artifact{
Name: "bar_bin.tar.gz",
Path: "doesnt matter",
Goos: "linux",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
artifact.ExtraID: "bar",
artifact.ExtraFormat: "tar.gz",
artifact.ExtraBinaries: []string{"bar"},
},
})
path := filepath.Join(folder, "bin.tar.gz")
ctx.Artifacts.Add(&artifact.Artifact{
Name: "bin.tar.gz",
Path: path,
Goos: "linux",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
artifact.ExtraID: "foo",
artifact.ExtraFormat: "tar.gz",
artifact.ExtraBinaries: []string{"name"},
},
})
f, err := os.Create(path)
require.NoError(t, err)
require.NoError(t, f.Close())
client := client.NewMock()
require.NoError(t, Pipe{}.Default(ctx))
if tt.expectedRunError != "" {
require.EqualError(t, runAll(ctx, client), tt.expectedRunError)
return
}
require.NoError(t, runAll(ctx, client))
if tt.expectedPublishError != "" {
require.EqualError(t, Pipe{}.Publish(ctx), tt.expectedPublishError)
return
}
require.NoError(t, Pipe{}.Publish(ctx))
requireEqualRepoFiles(t, folder, name, url)
})
}
}
func TestRunPipe(t *testing.T) {
url := makeBareRepo(t)
key := makeKey(t)
folder := t.TempDir()
ctx := &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{
CurrentTag: "v1.0.1",
},
Version: "1.0.1",
Artifacts: artifact.New(),
Env: map[string]string{
"FOO": "foo_is_bar",
},
Config: config.Project{
Dist: folder,
ProjectName: "foo",
AURs: []config.AUR{
{
License: "MIT",
Description: "A run pipe test pkgbuild and FOO={{ .Env.FOO }}",
Homepage: "https://github.com/goreleaser",
IDs: []string{"foo"},
GitURL: url,
PrivateKey: key,
},
},
GitHubURLs: config.GitHubURLs{
Download: "https://github.com",
},
Release: config.Release{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
},
}
for _, a := range []struct {
name string
goos string
goarch string
goarm string
}{
{
name: "bin",
goos: "darwin",
goarch: "amd64",
},
{
name: "bin",
goos: "darwin",
goarch: "arm64",
},
{
name: "bin",
goos: "windows",
goarch: "arm64",
},
{
name: "bin",
goos: "windows",
goarch: "amd64",
},
{
name: "bin",
goos: "linux",
goarch: "386",
},
{
name: "bin",
goos: "linux",
goarch: "amd64",
},
{
name: "arm64",
goos: "linux",
goarch: "arm64",
},
{
name: "armv5",
goos: "linux",
goarch: "arm",
goarm: "5",
},
{
name: "armv6",
goos: "linux",
goarch: "arm",
goarm: "6",
},
{
name: "armv7",
goos: "linux",
goarch: "arm",
goarm: "7",
},
} {
path := filepath.Join(folder, fmt.Sprintf("%s.tar.gz", a.name))
ctx.Artifacts.Add(&artifact.Artifact{
Name: fmt.Sprintf("%s.tar.gz", a.name),
Path: path,
Goos: a.goos,
Goarch: a.goarch,
Goarm: a.goarm,
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
artifact.ExtraID: "foo",
artifact.ExtraFormat: "tar.gz",
artifact.ExtraBinaries: []string{"foo"},
},
})
f, err := os.Create(path)
require.NoError(t, err)
require.NoError(t, f.Close())
}
client := client.NewMock()
require.NoError(t, Pipe{}.Default(ctx))
require.NoError(t, runAll(ctx, client))
require.NoError(t, Pipe{}.Publish(ctx))
requireEqualRepoFiles(t, folder, "foo", url)
}
func TestRunPipeNoBuilds(t *testing.T) {
ctx := &context.Context{
TokenType: context.TokenTypeGitHub,
Config: config.Project{
ProjectName: "foo",
AURs: []config.AUR{{}},
},
}
client := client.NewMock()
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, ErrNoArchivesFound, runAll(ctx, client))
require.False(t, client.CreatedFile)
}
func TestRunPipeBinaryRelease(t *testing.T) {
url := makeBareRepo(t)
key := makeKey(t)
folder := t.TempDir()
ctx := &context.Context{
Git: context.GitInfo{
CurrentTag: "v1.2.1",
},
Version: "1.2.1",
Artifacts: artifact.New(),
Config: config.Project{
Dist: folder,
ProjectName: "foo",
AURs: []config.AUR{{
GitURL: url,
PrivateKey: key,
}},
},
}
path := filepath.Join(folder, "dist/foo_linux_amd64/foo")
ctx.Artifacts.Add(&artifact.Artifact{
Name: "foo_linux_amd64",
Path: path,
Goos: "linux",
Goarch: "amd64",
Type: artifact.UploadableBinary,
Extra: map[string]interface{}{
artifact.ExtraID: "foo",
artifact.ExtraFormat: "binary",
artifact.ExtraBinary: "foo",
},
})
require.NoError(t, Pipe{}.Default(ctx))
require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755))
f, err := os.Create(path)
require.NoError(t, err)
require.NoError(t, f.Close())
client := client.NewMock()
require.NoError(t, runAll(ctx, client))
require.NoError(t, Pipe{}.Publish(ctx))
requireEqualRepoFiles(t, folder, "foo", url)
}
func TestRunPipeNoUpload(t *testing.T) {
folder := t.TempDir()
ctx := context.New(config.Project{
Dist: folder,
ProjectName: "foo",
Release: config.Release{},
AURs: []config.AUR{{}},
})
ctx.TokenType = context.TokenTypeGitHub
ctx.Git = context.GitInfo{CurrentTag: "v1.0.1"}
path := filepath.Join(folder, "whatever.tar.gz")
f, err := os.Create(path)
require.NoError(t, err)
require.NoError(t, f.Close())
ctx.Artifacts.Add(&artifact.Artifact{
Name: "bin",
Path: path,
Goos: "linux",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
artifact.ExtraID: "foo",
artifact.ExtraFormat: "tar.gz",
artifact.ExtraBinaries: []string{"foo"},
},
})
require.NoError(t, Pipe{}.Default(ctx))
client := client.NewMock()
assertNoPublish := func(t *testing.T) {
t.Helper()
require.NoError(t, runAll(ctx, client))
testlib.AssertSkipped(t, Pipe{}.Publish(ctx))
require.False(t, client.CreatedFile)
}
t.Run("skip upload true", func(t *testing.T) {
ctx.Config.AURs[0].SkipUpload = "true"
ctx.Semver.Prerelease = ""
assertNoPublish(t)
})
t.Run("skip upload auto", func(t *testing.T) {
ctx.Config.AURs[0].SkipUpload = "auto"
ctx.Semver.Prerelease = "beta1"
assertNoPublish(t)
})
}
func TestRunEmptyTokenType(t *testing.T) {
folder := t.TempDir()
ctx := context.New(config.Project{
Dist: folder,
ProjectName: "foo",
Release: config.Release{},
Rigs: []config.GoFish{
{
Rig: config.RepoRef{
Owner: "test",
Name: "test",
},
},
},
})
ctx.Git = context.GitInfo{CurrentTag: "v1.0.1"}
path := filepath.Join(folder, "whatever.tar.gz")
f, err := os.Create(path)
require.NoError(t, err)
require.NoError(t, f.Close())
ctx.Artifacts.Add(&artifact.Artifact{
Name: "bin",
Path: path,
Goos: "darwin",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
artifact.ExtraID: "foo",
artifact.ExtraFormat: "tar.gz",
artifact.ExtraBinaries: []string{"foo"},
},
})
client := client.NewMock()
require.NoError(t, runAll(ctx, client))
}
func TestDefault(t *testing.T) {
t.Run("empty", func(t *testing.T) {
ctx := &context.Context{
TokenType: context.TokenTypeGitHub,
Config: config.Project{
ProjectName: "myproject",
AURs: []config.AUR{
{},
},
},
}
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, config.AUR{
Name: "myproject-bin",
Conflicts: []string{"myproject"},
Provides: []string{"myproject"},
Rel: "1",
CommitMessageTemplate: defaultCommitMsg,
GitSSHCommand: defaultSSHCommand,
CommitAuthor: config.CommitAuthor{
Name: "goreleaserbot",
Email: "goreleaser@carlosbecker.com",
},
}, ctx.Config.AURs[0])
})
t.Run("name-without-bin-suffix", func(t *testing.T) {
ctx := &context.Context{
TokenType: context.TokenTypeGitHub,
Config: config.Project{
ProjectName: "myproject",
AURs: []config.AUR{
{
Name: "foo",
},
},
},
}
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, config.AUR{
Name: "foo-bin",
Conflicts: []string{"myproject"},
Provides: []string{"myproject"},
Rel: "1",
CommitMessageTemplate: defaultCommitMsg,
GitSSHCommand: defaultSSHCommand,
CommitAuthor: config.CommitAuthor{
Name: "goreleaserbot",
Email: "goreleaser@carlosbecker.com",
},
}, ctx.Config.AURs[0])
})
t.Run("partial", func(t *testing.T) {
ctx := &context.Context{
TokenType: context.TokenTypeGitHub,
Config: config.Project{
ProjectName: "myproject",
AURs: []config.AUR{
{
Conflicts: []string{"somethingelse"},
},
},
},
}
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, config.AUR{
Name: "myproject-bin",
Conflicts: []string{"somethingelse"},
Provides: []string{"myproject"},
Rel: "1",
CommitMessageTemplate: defaultCommitMsg,
GitSSHCommand: defaultSSHCommand,
CommitAuthor: config.CommitAuthor{
Name: "goreleaserbot",
Email: "goreleaser@carlosbecker.com",
},
}, ctx.Config.AURs[0])
})
}
func TestSkip(t *testing.T) {
t.Run("skip", func(t *testing.T) {
require.True(t, Pipe{}.Skip(context.New(config.Project{})))
})
t.Run("dont skip", func(t *testing.T) {
ctx := context.New(config.Project{
AURs: []config.AUR{
{},
},
})
require.False(t, Pipe{}.Skip(ctx))
})
}
func TestKeyPath(t *testing.T) {
t.Run("with valid path", func(t *testing.T) {
path := makeKey(t)
result, err := keyPath(path)
require.NoError(t, err)
require.Equal(t, path, result)
})
t.Run("with invalid path", func(t *testing.T) {
result, err := keyPath("testdata/nope")
require.EqualError(t, err, `key "testdata/nope" does not exist`)
require.Equal(t, "", result)
})
t.Run("with key", func(t *testing.T) {
for _, algo := range []keygen.KeyType{keygen.Ed25519, keygen.RSA} {
t.Run(string(algo), func(t *testing.T) {
path := makeKey(t, algo)
bts, err := os.ReadFile(path)
require.NoError(t, err)
result, err := keyPath(string(bts))
require.NoError(t, err)
resultbts, err := os.ReadFile(result)
require.NoError(t, err)
require.Equal(t, string(bts), string(resultbts))
})
}
})
t.Run("empty", func(t *testing.T) {
result, err := keyPath("")
require.EqualError(t, err, `pkgbuild.private_key is empty`)
require.Equal(t, "", result)
})
}
func makeBareRepo(tb testing.TB) string {
tb.Helper()
dir := tb.TempDir()
_, err := git.Run(
"-C", dir,
"-c", "init.defaultBranch=master",
"init",
"--bare",
".",
)
require.NoError(tb, err)
return dir
}
func makeKey(tb testing.TB, algo ...keygen.KeyType) string {
tb.Helper()
if len(algo) == 0 {
algo = append(algo, keygen.Ed25519)
}
dir := tb.TempDir()
k, err := keygen.NewWithWrite(dir, "id", nil, algo[0])
require.NoError(tb, err)
return filepath.Join(dir, k.Filename)
}
func requireEqualRepoFiles(tb testing.TB, folder, name, url string) {
tb.Helper()
dir := tb.TempDir()
_, err := git.Run("-C", dir, "clone", url, "repo")
require.NoError(tb, err)
for reponame, ext := range map[string]string{
"PKGBUILD": ".pkgbuild",
".SRCINFO": ".srcinfo",
} {
path := filepath.Join(folder, "aur", name+"-bin"+ext)
bts, err := os.ReadFile(path)
require.NoError(tb, err)
golden.RequireEqualExt(tb, bts, ext)
bts, err = os.ReadFile(filepath.Join(dir, "repo", reponame))
require.NoError(tb, err)
golden.RequireEqualExt(tb, bts, ext)
}
}

2
internal/pipe/aur/doc.go Normal file
View File

@ -0,0 +1,2 @@
// Package aur provides the Arch User Repository (AUR) integration to GoReleaser.
package aur

View File

@ -0,0 +1,18 @@
# This file was generated by GoReleaser. DO NOT EDIT.
pkgname='default-gitlab-bin'
pkgver=1.0.1
pkgrel=1
pkgdesc='A run pipe test fish food and FOO=foo_is_bar'
url='https://gitlab.com/goreleaser'
arch=('x86_64')
license=('MIT')
provides=('default-gitlab')
conflicts=('default-gitlab')
source_x86_64=('https://dummyhost/download/v1.0.1/bin.tar.gz')
sha256sums_x86_64=('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
package() {
install -Dm755 "./name" "${pkgdir}/usr/bin/name"
}

View File

@ -0,0 +1,13 @@
pkgbase = default-gitlab-bin
pkgdesc = A run pipe test fish food and FOO=foo_is_bar
pkgver = 1.0.1
pkgrel = 1
url = https://gitlab.com/goreleaser
license = MIT
conflicts = default-gitlab
provides = default-gitlab
arch = x86_64
source_x86_64 = https://dummyhost/download/v1.0.1/bin.tar.gz
sha256sums_x86_64 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
pkgname = default-gitlab-bin

View File

@ -0,0 +1,18 @@
# This file was generated by GoReleaser. DO NOT EDIT.
pkgname='default-bin'
pkgver=1.0.1
pkgrel=1
pkgdesc='A run pipe test fish food and FOO=foo_is_bar'
url='https://github.com/goreleaser'
arch=('x86_64')
license=('MIT')
provides=('default')
conflicts=('default')
source_x86_64=('https://dummyhost/download/v1.0.1/bin.tar.gz')
sha256sums_x86_64=('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
package() {
install -Dm755 "./name" "${pkgdir}/usr/bin/name"
}

View File

@ -0,0 +1,13 @@
pkgbase = default-bin
pkgdesc = A run pipe test fish food and FOO=foo_is_bar
pkgver = 1.0.1
pkgrel = 1
url = https://github.com/goreleaser
license = MIT
conflicts = default
provides = default
arch = x86_64
source_x86_64 = https://dummyhost/download/v1.0.1/bin.tar.gz
sha256sums_x86_64 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
pkgname = default-bin

View File

@ -0,0 +1,22 @@
# This file was generated by GoReleaser. DO NOT EDIT.
# Maintainer: me
# Contributor: me as well
pkgname='with-more-opts-bin'
pkgver=1.0.1
pkgrel=1
pkgdesc='A run pipe test fish food and FOO=foo_is_bar'
url='https://github.com/goreleaser'
arch=('x86_64')
license=('MIT')
provides=('git' 'svn')
conflicts=('libcurl' 'cvs' 'blah')
depends=('curl' 'bash')
optdepends=('wget: stuff' 'foo: bar')
source_x86_64=('https://dummyhost/download/v1.0.1/bin.tar.gz')
sha256sums_x86_64=('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
package() {
install -Dm755 "./name" "${pkgdir}/usr/bin/name"
}

View File

@ -0,0 +1,20 @@
pkgbase = with-more-opts-bin
pkgdesc = A run pipe test fish food and FOO=foo_is_bar
pkgver = 1.0.1
pkgrel = 1
url = https://github.com/goreleaser
license = MIT
optdepends = wget: stuff
optdepends = foo: bar
depends = curl
depends = bash
conflicts = libcurl
conflicts = cvs
conflicts = blah
provides = git
provides = svn
arch = x86_64
source_x86_64 = https://dummyhost/download/v1.0.1/bin.tar.gz
sha256sums_x86_64 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
pkgname = with-more-opts-bin

View File

@ -0,0 +1,51 @@
# This file was generated by GoReleaser. DO NOT EDIT.
# Maintainer: Ciclano <ciclano@example.com>
# Maintainer: Cicrano <cicrano@example.com>
# Contributor: Fulano <fulano@example.com>
# Contributor: Beltrano <beltrano@example.com>
pkgname='test-bin'
pkgver=0.1.3
pkgrel=1
pkgdesc='Some desc'
url='https://example.com'
arch=('x86_64' 'i686' 'aarch64' 'armv6h' 'armv7h')
license=('MIT')
provides=('test')
conflicts=('nope')
depends=('nope')
optdepends=('nfpm')
source_x86_64=('https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_x86_64.tar.gz')
sha256sums_x86_64=('1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67')
source_armv6h=('https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_Arm6.tar.gz')
sha256sums_armv6h=('1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67')
source_aarch64=('https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_Arm64.tar.gz')
sha256sums_aarch64=('1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67')
source_i686=('https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_386.tar.gz')
sha256sums_i686=('1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67')
source_armv7h=('https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_arm7.tar.gz')
sha256sums_armv7h=('1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67')
package() {
# bin
install -Dm755 "./goreleaser" "${pkgdir}/usr/bin/goreleaser"
# license
install -Dm644 "./LICENSE.md" "${pkgdir}/usr/share/licenses/goreleaser/LICENSE"
# completions
mkdir -p "${pkgdir}/usr/share/bash-completion/completions/"
mkdir -p "${pkgdir}/usr/share/zsh/site-functions/"
mkdir -p "${pkgdir}/usr/share/fish/vendor_completions.d/"
install -Dm644 "./completions/goreleaser.bash" "${pkgdir}/usr/share/bash-completion/completions/goreleaser"
install -Dm644 "./completions/goreleaser.zsh" "${pkgdir}/usr/share/zsh/site-functions/_goreleaser"
install -Dm644 "./completions/goreleaser.fish" "${pkgdir}/usr/share/fish/vendor_completions.d/goreleaser.fish"
# man pages
install -Dm644 "./manpages/goreleaser.1.gz" "${pkgdir}/usr/share/man/man1/goreleaser.1.gz"
}

View File

@ -0,0 +1,27 @@
pkgbase = test-bin
pkgdesc = Some desc
pkgver = 0.1.3
pkgrel = 1
url = https://example.com
license = MIT
optdepends = nfpm
depends = nope
conflicts = nope
provides = test
arch = x86_64
source_x86_64 = https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_x86_64.tar.gz
sha256sums_x86_64 = 1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67
arch = armv6h
source_armv6h = https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_Arm6.tar.gz
sha256sums_armv6h = 1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67
arch = aarch64
source_aarch64 = https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_Arm64.tar.gz
sha256sums_aarch64 = 1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67
arch = i686
source_i686 = https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_386.tar.gz
sha256sums_i686 = 1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67
arch = armv7h
source_armv7h = https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_arm7.tar.gz
sha256sums_armv7h = 1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67
pkgname = test-bin

View File

@ -0,0 +1,30 @@
# This file was generated by GoReleaser. DO NOT EDIT.
pkgname='foo-bin'
pkgver=1.0.1
pkgrel=1
pkgdesc='A run pipe test pkgbuild and FOO=foo_is_bar'
url='https://github.com/goreleaser'
arch=('aarch64' 'armv6h' 'armv7h' 'i686' 'x86_64')
license=('MIT')
provides=('foo')
conflicts=('foo')
source_aarch64=('https://dummyhost/download/v1.0.1/arm64.tar.gz')
sha256sums_aarch64=('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
source_armv6h=('https://dummyhost/download/v1.0.1/armv6.tar.gz')
sha256sums_armv6h=('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
source_armv7h=('https://dummyhost/download/v1.0.1/armv7.tar.gz')
sha256sums_armv7h=('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
source_i686=('https://dummyhost/download/v1.0.1/bin.tar.gz')
sha256sums_i686=('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
source_x86_64=('https://dummyhost/download/v1.0.1/bin.tar.gz')
sha256sums_x86_64=('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
package() {
install -Dm755 "./foo" "${pkgdir}/usr/bin/foo"
}

View File

@ -0,0 +1,25 @@
pkgbase = foo-bin
pkgdesc = A run pipe test pkgbuild and FOO=foo_is_bar
pkgver = 1.0.1
pkgrel = 1
url = https://github.com/goreleaser
license = MIT
conflicts = foo
provides = foo
arch = aarch64
source_aarch64 = https://dummyhost/download/v1.0.1/arm64.tar.gz
sha256sums_aarch64 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
arch = armv6h
source_armv6h = https://dummyhost/download/v1.0.1/armv6.tar.gz
sha256sums_armv6h = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
arch = armv7h
source_armv7h = https://dummyhost/download/v1.0.1/armv7.tar.gz
sha256sums_armv7h = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
arch = i686
source_i686 = https://dummyhost/download/v1.0.1/bin.tar.gz
sha256sums_i686 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
arch = x86_64
source_x86_64 = https://dummyhost/download/v1.0.1/bin.tar.gz
sha256sums_x86_64 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
pkgname = foo-bin

View File

@ -0,0 +1,18 @@
# This file was generated by GoReleaser. DO NOT EDIT.
pkgname='foo-bin'
pkgver=1.2.1
pkgrel=1
pkgdesc=''
url=''
arch=('x86_64')
license=('')
provides=('foo')
conflicts=('foo')
source_x86_64=('https://dummyhost/download/v1.2.1/foo_linux_amd64')
sha256sums_x86_64=('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
package() {
install -Dm755 "./foo_linux_amd64 "${pkgdir}/usr/bin/foo"
}

View File

@ -0,0 +1,11 @@
pkgbase = foo-bin
pkgdesc =
pkgver = 1.2.1
pkgrel = 1
conflicts = foo
provides = foo
arch = x86_64
source_x86_64 = https://dummyhost/download/v1.2.1/foo_linux_amd64
sha256sums_x86_64 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
pkgname = foo-bin

97
internal/pipe/aur/tmpl.go Normal file
View File

@ -0,0 +1,97 @@
package aur
type templateData struct {
Name string
Desc string
Homepage string
Version string
License string
ReleasePackages []releasePackage
Maintainers []string
Contributors []string
Provides []string
Conflicts []string
Depends []string
OptDepends []string
Arches []string
Rel string
Package string
}
type releasePackage struct {
DownloadURL string
SHA256 string
Arch string
}
const pkgBuildTemplate = `# This file was generated by GoReleaser. DO NOT EDIT.
{{- range .Maintainers }}
# Maintainer: {{ . }}
{{- end }}
{{- range .Contributors }}
# Contributor: {{ . }}
{{- end }}
pkgname='{{ .Name }}'
pkgver={{ .Version }}
pkgrel={{ .Rel }}
pkgdesc='{{ .Desc }}'
url='{{ .Homepage }}'
arch=({{ pkgArray .Arches }})
license=('{{ .License }}')
{{- with .Provides }}
provides=({{ pkgArray . }})
{{- end }}
{{- with .Conflicts }}
conflicts=({{ pkgArray . }})
{{- end }}
{{- with .Depends }}
depends=({{ pkgArray . }})
{{- end }}
{{- with .OptDepends }}
optdepends=({{ pkgArray . }})
{{- end }}
{{ range .ReleasePackages -}}
source_{{ .Arch }}=('{{ .DownloadURL }}')
sha256sums_{{ .Arch }}=('{{ .SHA256 }}')
{{ printf "" }}
{{ end }}
{{- with .Package -}}
package() {
{{ fixLines . }}
}
{{ end }}`
const srcInfoTemplate = `pkgbase = {{ .Name }}
pkgdesc = {{ .Desc }}
pkgver = {{ .Version }}
pkgrel = {{ .Rel }}
{{ with .Homepage -}}
url = {{ . }}
{{ end -}}
{{ with .License -}}
license = {{ . }}
{{ end -}}
{{ range .OptDepends -}}
optdepends = {{ . }}
{{ end -}}
{{ range .Depends -}}
depends = {{ . }}
{{ end -}}
{{ range .Conflicts -}}
conflicts = {{ . }}
{{ end -}}
{{ range .Provides -}}
provides = {{ . }}
{{ end -}}
{{ range .ReleasePackages -}}
arch = {{ .Arch }}
source_{{ .Arch }} = {{ .DownloadURL }}
sha256sums_{{ .Arch }} = {{ .SHA256 }}
{{ end -}}
{{ printf "\n" -}}
pkgname = {{ .Name }}
`

View File

@ -8,6 +8,7 @@ import (
"github.com/goreleaser/goreleaser/internal/middleware/logging"
"github.com/goreleaser/goreleaser/internal/middleware/skip"
"github.com/goreleaser/goreleaser/internal/pipe/artifactory"
"github.com/goreleaser/goreleaser/internal/pipe/aur"
"github.com/goreleaser/goreleaser/internal/pipe/blob"
"github.com/goreleaser/goreleaser/internal/pipe/brew"
"github.com/goreleaser/goreleaser/internal/pipe/custompublishers"
@ -43,8 +44,9 @@ var publishers = []Publisher{
snapcraft.Pipe{},
// This should be one of the last steps
release.Pipe{},
// brew and scoop use the release URL, so, they should be last
// brew et al use the release URL, so, they should be last
brew.Pipe{},
aur.Pipe{},
gofish.Pipe{},
krew.Pipe{},
scoop.Pipe{},

View File

@ -7,6 +7,7 @@ import (
"github.com/goreleaser/goreleaser/internal/pipe/announce"
"github.com/goreleaser/goreleaser/internal/pipe/archive"
"github.com/goreleaser/goreleaser/internal/pipe/artifacts"
"github.com/goreleaser/goreleaser/internal/pipe/aur"
"github.com/goreleaser/goreleaser/internal/pipe/before"
"github.com/goreleaser/goreleaser/internal/pipe/brew"
"github.com/goreleaser/goreleaser/internal/pipe/build"
@ -74,6 +75,7 @@ var Pipeline = append(
sourcearchive.Pipe{}, // archive the source code using git-archive
nfpm.Pipe{}, // archive via fpm (deb, rpm) using "native" go impl
snapcraft.Pipe{}, // archive via snapcraft (snap)
aur.Pipe{}, // create arch linux aur pkgbuild
brew.Pipe{}, // create brew tap
gofish.Pipe{}, // create gofish rig
krew.Pipe{}, // krew plugins

View File

@ -107,6 +107,29 @@ func (a HomebrewDependency) JSONSchemaType() *jsonschema.Type {
}
}
type AUR struct {
Name string `yaml:"name,omitempty"`
IDs []string `yaml:"ids,omitempty"`
CommitAuthor CommitAuthor `yaml:"commit_author,omitempty"`
CommitMessageTemplate string `yaml:"commit_msg_template,omitempty"`
Description string `yaml:"description,omitempty"`
Homepage string `yaml:"homepage,omitempty"`
License string `yaml:"license,omitempty"`
SkipUpload string `yaml:"skip_upload,omitempty"`
URLTemplate string `yaml:"url_template,omitempty"`
Maintainers []string `yaml:"maintainers,omitempty"`
Contributors []string `yaml:"contributors,omitempty"`
Provides []string `yaml:"provides,omitempty"`
Conflicts []string `yaml:"conflicts,omitempty"`
Depends []string `yaml:"depends,omitempty"`
OptDepends []string `yaml:"optdepends,omitempty"`
Rel string `yaml:"rel,omitempty"`
Package string `yaml:"package,omitempty"`
GitURL string `yaml:"git_url,omitempty"`
GitSSHCommand string `yaml:"git_ssh_command,omitempty"`
PrivateKey string `yaml:"private_key,omitempty"`
}
// GoFish contains the gofish section.
type GoFish struct {
Name string `yaml:"name,omitempty"`
@ -827,6 +850,7 @@ type Project struct {
Milestones []Milestone `yaml:"milestones,omitempty"`
Brews []Homebrew `yaml:"brews,omitempty"`
Rigs []GoFish `yaml:"rigs,omitempty"`
AURs []AUR `yaml:"aurs,omitempty"`
Krews []Krew `yaml:"krews,omitempty"`
Scoop Scoop `yaml:"scoop,omitempty"`
Builds []Build `yaml:"builds,omitempty"`

View File

@ -7,6 +7,7 @@ import (
"github.com/goreleaser/goreleaser/internal/pipe/archive"
"github.com/goreleaser/goreleaser/internal/pipe/artifactory"
"github.com/goreleaser/goreleaser/internal/pipe/aur"
"github.com/goreleaser/goreleaser/internal/pipe/blob"
"github.com/goreleaser/goreleaser/internal/pipe/brew"
"github.com/goreleaser/goreleaser/internal/pipe/build"
@ -69,6 +70,7 @@ var Defaulters = []Defaulter{
docker.ManifestPipe{},
artifactory.Pipe{},
blob.Pipe{},
aur.Pipe{},
brew.Pipe{},
krew.Pipe{},
gofish.Pipe{},

View File

@ -0,0 +1,155 @@
# Arch User Repositories
After releasing to GitHub or GitLab, GoReleaser can generate and publish
a `PKGBUILD` to an _Arch User Repository_.
!!! warning
Before going further on this, make sure to read
[AUR's Submission Guidelines](https://wiki.archlinux.org/title/AUR_submission_guidelines).
This page describes the available options.
```yaml
# .goreleaser.yaml
aurs:
-
# The package name.
#
# Defaults to the Project Name with a -bin suffix.
#
# Note that since this integration does not create a PKGBUILD to build from
# source, per Arch's guidelines.
# That said, GoReleaser will enforce a `-bin` suffix if its not present.
name: package-bin
# Artifact IDs to filter for.
#
# Defaults to empty, which includes all artifacts.
ids:
- foo
- bar
# Your app's homepage.
# Default is empty.
homepage: "https://example.com/"
# Template of your app's description.
# Default is empty.
description: "Software to create fast and easy drum rolls."
# The maintainers of the package.
# Defaults to empty.
maintainers:
- 'Foo Bar <foo at bar dot com>'
# The contributors of the package.
# Defaults to empty.
contributors:
- 'Foo Zaz <foo at zaz dot com>'
# SPDX identifier of your app's license.
# Default is empty.
license: "MIT"
# The SSH private key that should be used to commit to the Git repository.
# This can either be a path or the key contents.
#
# WARNING: do not expose your private key in the config file!
private_key: '{{ .Env.AUR_KEY }}'
# The AUR Git URL for this package.
# Defaults to empty.
git_url: 'ssh://aur@aur.archlinux.org/mypackage-bin.git'
# Setting this will prevent goreleaser to actually try to commit the updated
# formula - instead, the formula file will be stored on the dist folder only,
# leaving the responsibility of publishing it to the user.
#
# If set to auto, the release will not be uploaded to the homebrew tap
# in case there is an indicator for prerelease in the tag e.g. v1.0.0-rc1.
#
# Default is false.
skip_upload: true
# List of additional packages that the software provides the features of.
#
# Defaults to the project name.
provides:
- mybin
# List of packages that conflict with, or cause problems with the package.
#
# Defaults to the project name.
conflicts:
- mybin
# List of packages that must be installed to install this.
#
# Defaults to empty.
depends:
- curl
# List of packages that are not needed for the software to function,
# but provide additional features.
#
# Must be in the format `package: short description of the extra functionality`.
#
# Defaults to empty.
optdepends:
- 'wget: for downloading things'
# Custom package instructions.
#
# Defaults to `install -Dm755 "./PROJECT_NAME" "${pkgdir}/usr/bin/PROJECT_NAME",
# which is not always correct.
#
# We recommend you override this, installing the binary, license and
# everything else your package needs.
package: |-
# bin
install -Dm755 "./mybin" "${pkgdir}/usr/bin/mybin"
# license
install -Dm644 "./LICENSE.md" "${pkgdir}/usr/share/licenses/mybin/LICENSE"
# completions
mkdir -p "${pkgdir}/usr/share/bash-completion/completions/"
mkdir -p "${pkgdir}/usr/share/zsh/site-functions/"
mkdir -p "${pkgdir}/usr/share/fish/vendor_completions.d/"
install -Dm644 "./completions/mybin.bash" "${pkgdir}/usr/share/bash-completion/completions/mybin"
install -Dm644 "./completions/mybin.zsh" "${pkgdir}/usr/share/zsh/site-functions/_mybin"
install -Dm644 "./completions/mybin.fish" "${pkgdir}/usr/share/fish/vendor_completions.d/mybin.fish"
# man pages
install -Dm644 "./manpages/mybin.1.gz" "${pkgdir}/usr/share/man/man1/mybin.1.gz"
# Git author used to commit to the repository.
# Defaults are shown below.
commit_author:
name: goreleaserbot
email: goreleaser@carlosbecker.com
# Commit message template.
# Defaults to `Update to {{ .Tag }}`.
commit_msg_template: "pkgbuild updates"
# The value to be passed to `GIT_SSH_COMMAND`.
# This is mainly used to specify the SSH private key used to pull/push to
# the Git URL.
#
# Defaults to `ssh -i {{ .KeyPath }} -F /dev/null`.
git_ssh_command: 'ssh -i {{ .Env.KEY }} -o SomeOption=yes'
# Template for the url which is determined by the given Token
# (github, gitlab or gitea).
#
# Default depends on the client.
url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}"
```
!!! tip
Learn more about the [name template engine](/customization/templates/).
!!! tip
For more info about what each field does, please refer to
[Arch's PKGBUILD reference](https://wiki.archlinux.org/title/PKGBUILD).

View File

@ -42,10 +42,9 @@ brews:
# Optionally a token can be provided, if it differs from the token provided to GoReleaser
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
# Template for the url which is determined by the given Token (github or gitlab)
# Default for github is "https://github.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
# Default for gitlab is "https://gitlab.com/<repo_owner>/<repo_name>/-/releases/{{ .Tag }}/downloads/{{ .ArtifactName }}"
# Default for gitea is "https://gitea.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
# Template for the url which is determined by the given Token (github, gitlab or gitea)
#
# Default depends on the client.
url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}"
# Allows you to set a custom download strategy. Note that you'll need

View File

@ -100,6 +100,7 @@ nav:
- customization/blob.md
- customization/fury.md
- customization/homebrew.md
- customization/aur.md
- customization/gofish.md
- customization/krew.md
- customization/scoop.md