mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-01-30 04:50:45 +02:00
add: Scoop manifest support
Finished the Scoop.sh manifest generator for Windows releases! See #387
This commit is contained in:
parent
0a37305745
commit
c8d36813cb
@ -49,6 +49,15 @@ type Homebrew struct {
|
||||
DownloadStrategy string `yaml:"download_strategy,omitempty"`
|
||||
}
|
||||
|
||||
// Scoop contains the scoop.sh section
|
||||
type Scoop struct {
|
||||
Bucket Repo `yaml:",omitempty"`
|
||||
CommitAuthor CommitAuthor `yaml:"commit_author,omitempty"`
|
||||
Homepage string `yaml:",omitempty"`
|
||||
Description string `yaml:",omitempty"`
|
||||
License string `yaml:",omitempty"`
|
||||
}
|
||||
|
||||
// CommitAuthor is the author of a Git commit
|
||||
type CommitAuthor struct {
|
||||
Name string `yaml:",omitempty"`
|
||||
@ -205,6 +214,7 @@ type Project struct {
|
||||
ProjectName string `yaml:"project_name,omitempty"`
|
||||
Release Release `yaml:",omitempty"`
|
||||
Brew Homebrew `yaml:",omitempty"`
|
||||
Scoop Scoop `yaml:",omitempty"`
|
||||
Builds []Build `yaml:",omitempty"`
|
||||
Archive Archive `yaml:",omitempty"`
|
||||
FPM FPM `yaml:",omitempty"`
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
"github.com/goreleaser/goreleaser/pipeline/fpm"
|
||||
"github.com/goreleaser/goreleaser/pipeline/git"
|
||||
"github.com/goreleaser/goreleaser/pipeline/release"
|
||||
"github.com/goreleaser/goreleaser/pipeline/scoop"
|
||||
"github.com/goreleaser/goreleaser/pipeline/sign"
|
||||
"github.com/goreleaser/goreleaser/pipeline/snapcraft"
|
||||
)
|
||||
@ -60,6 +61,7 @@ var pipes = []pipeline.Piper{
|
||||
artifactory.Pipe{}, // push to artifactory
|
||||
release.Pipe{}, // release to github
|
||||
brew.Pipe{}, // push to brew tap
|
||||
scoop.Pipe{}, // push to scoop bucket
|
||||
}
|
||||
|
||||
// Flags interface represents an extractor of cli flags
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/goreleaser/goreleaser/pipeline/env"
|
||||
"github.com/goreleaser/goreleaser/pipeline/fpm"
|
||||
"github.com/goreleaser/goreleaser/pipeline/release"
|
||||
"github.com/goreleaser/goreleaser/pipeline/scoop"
|
||||
"github.com/goreleaser/goreleaser/pipeline/sign"
|
||||
"github.com/goreleaser/goreleaser/pipeline/snapcraft"
|
||||
"github.com/goreleaser/goreleaser/pipeline/snapshot"
|
||||
@ -40,6 +41,7 @@ var defaulters = []pipeline.Defaulter{
|
||||
docker.Pipe{},
|
||||
artifactory.Pipe{},
|
||||
brew.Pipe{},
|
||||
scoop.Pipe{},
|
||||
}
|
||||
|
||||
// Run the pipe
|
||||
|
165
pipeline/scoop/scoop.go
Normal file
165
pipeline/scoop/scoop.go
Normal file
@ -0,0 +1,165 @@
|
||||
// Package scoop provides a Pipe that generates a scoop.sh App Manifest and pushes it to a bucket
|
||||
package scoop
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/goreleaser/goreleaser/config"
|
||||
"github.com/goreleaser/goreleaser/context"
|
||||
"github.com/goreleaser/goreleaser/internal/artifact"
|
||||
"github.com/goreleaser/goreleaser/internal/client"
|
||||
"github.com/goreleaser/goreleaser/pipeline"
|
||||
)
|
||||
|
||||
// ErrNoWindows when there is no build for windows (goos doesn't contain windows)
|
||||
var ErrNoWindows = errors.New("scoop requires a windows build")
|
||||
|
||||
// Pipe for build
|
||||
type Pipe struct{}
|
||||
|
||||
func (Pipe) String() string {
|
||||
return "creating Scoop Manifest"
|
||||
}
|
||||
|
||||
// Run the pipe
|
||||
func (Pipe) Run(ctx *context.Context) error {
|
||||
client, err := client.NewGitHub(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return doRun(ctx, client)
|
||||
}
|
||||
|
||||
// Default sets the pipe defaults
|
||||
func (Pipe) Default(ctx *context.Context) error {
|
||||
if ctx.Config.Scoop.CommitAuthor.Name == "" {
|
||||
ctx.Config.Scoop.CommitAuthor.Name = "goreleaserbot"
|
||||
}
|
||||
if ctx.Config.Scoop.CommitAuthor.Email == "" {
|
||||
ctx.Config.Scoop.CommitAuthor.Email = "goreleaser@carlosbecker.com"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isScoopBuild(build config.Build) bool {
|
||||
for _, ignore := range build.Ignore {
|
||||
if ignore.Goos == "windows" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return contains(build.Goos, "darwin")
|
||||
}
|
||||
|
||||
func contains(ss []string, s string) bool {
|
||||
for _, zs := range ss {
|
||||
if zs == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func doRun(ctx *context.Context, client client.Client) error {
|
||||
if ctx.Config.Scoop.Bucket.Name == "" {
|
||||
return pipeline.Skip("scoop section is not configured")
|
||||
}
|
||||
if ctx.Config.Archive.Format == "binary" {
|
||||
return pipeline.Skip("archive format is binary")
|
||||
}
|
||||
|
||||
var archives = ctx.Artifacts.Filter(
|
||||
artifact.And(
|
||||
artifact.ByGoos("windows"),
|
||||
artifact.ByType(artifact.UploadableArchive),
|
||||
),
|
||||
).List()
|
||||
if len(archives) == 0 {
|
||||
return ErrNoWindows
|
||||
}
|
||||
|
||||
path := ctx.Config.ProjectName + ".json"
|
||||
|
||||
content, err := buildManifest(ctx, client, archives)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !ctx.Publish {
|
||||
return pipeline.ErrSkipPublish
|
||||
}
|
||||
if ctx.Config.Release.Draft {
|
||||
return pipeline.Skip("release is marked as draft")
|
||||
}
|
||||
|
||||
return client.CreateFile(
|
||||
ctx,
|
||||
ctx.Config.Scoop.CommitAuthor,
|
||||
ctx.Config.Scoop.Bucket,
|
||||
content,
|
||||
path)
|
||||
}
|
||||
|
||||
// Manifest represents a scoop.sh App Manifest, more info:
|
||||
// https://github.com/lukesampson/scoop/wiki/App-Manifests
|
||||
type Manifest struct {
|
||||
Version string `json:"version"` // The version of the app that this manifest installs.
|
||||
Architecture map[string]Resource `json:"architecture"` // `architecture`: If the app has 32- and 64-bit versions, architecture can be used to wrap the differences.
|
||||
Homepage string `json:"homepage,omitempty"` // `homepage`: The home page for the program.
|
||||
License string `json:"license,omitempty"` // `license`: The software license for the program. For well-known licenses, this will be a string like "MIT" or "GPL2". For custom licenses, this should be the URL of the license.
|
||||
Description string `json:"description,omitempty"` // Description of the app
|
||||
}
|
||||
|
||||
// Resource represents a combination of a url and a binary name for an architecture
|
||||
type Resource struct {
|
||||
URL string `json:"url"` // URL to the archive
|
||||
Bin string `json:"bin"` // name of binary inside the archive
|
||||
}
|
||||
|
||||
func buildManifest(ctx *context.Context, client client.Client, artifacts []artifact.Artifact) (result bytes.Buffer, err error) {
|
||||
var githubURL = "https://github.com"
|
||||
if ctx.Config.GitHubURLs.Download != "" {
|
||||
githubURL = ctx.Config.GitHubURLs.Download
|
||||
}
|
||||
|
||||
manifest := Manifest{
|
||||
Version: ctx.Version,
|
||||
Architecture: make(map[string]Resource),
|
||||
Homepage: ctx.Config.Scoop.Homepage,
|
||||
License: ctx.Config.Scoop.License,
|
||||
Description: ctx.Config.Scoop.Description,
|
||||
}
|
||||
|
||||
for _, artifact := range artifacts {
|
||||
if artifact.Goarch == "amd64" {
|
||||
manifest.Architecture["64bit"] = Resource{
|
||||
URL: getDownloadURL(ctx, githubURL, artifact.Name),
|
||||
Bin: ctx.Config.Builds[0].Binary + ".exe",
|
||||
}
|
||||
} else if artifact.Goarch == "386" {
|
||||
manifest.Architecture["32bit"] = Resource{
|
||||
URL: getDownloadURL(ctx, githubURL, artifact.Name),
|
||||
Bin: ctx.Config.Builds[0].Binary + ".exe",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(manifest, "", " ")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = result.Write(data)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getDownloadURL(ctx *context.Context, githubURL, file string) (url string) {
|
||||
return fmt.Sprintf("%s/%s/%s/releases/download/%s/%s",
|
||||
githubURL,
|
||||
ctx.Config.Release.GitHub.Owner,
|
||||
ctx.Config.Release.GitHub.Name,
|
||||
ctx.Version,
|
||||
file)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user