github.com/droot/goreleaser@v0.66.2-0.20180420030140-c2db5fb17157/pipeline/scoop/scoop.go (about) 1 // Package scoop provides a Pipe that generates a scoop.sh App Manifest and pushes it to a bucket 2 package scoop 3 4 import ( 5 "bytes" 6 "encoding/json" 7 "errors" 8 "fmt" 9 10 "github.com/goreleaser/goreleaser/context" 11 "github.com/goreleaser/goreleaser/internal/artifact" 12 "github.com/goreleaser/goreleaser/internal/client" 13 "github.com/goreleaser/goreleaser/pipeline" 14 ) 15 16 // ErrNoWindows when there is no build for windows (goos doesn't contain windows) 17 var ErrNoWindows = errors.New("scoop requires a windows build") 18 19 // Pipe for build 20 type Pipe struct{} 21 22 func (Pipe) String() string { 23 return "creating Scoop Manifest" 24 } 25 26 // Run the pipe 27 func (Pipe) Run(ctx *context.Context) error { 28 client, err := client.NewGitHub(ctx) 29 if err != nil { 30 return err 31 } 32 return doRun(ctx, client) 33 } 34 35 // Default sets the pipe defaults 36 func (Pipe) Default(ctx *context.Context) error { 37 if ctx.Config.Scoop.CommitAuthor.Name == "" { 38 ctx.Config.Scoop.CommitAuthor.Name = "goreleaserbot" 39 } 40 if ctx.Config.Scoop.CommitAuthor.Email == "" { 41 ctx.Config.Scoop.CommitAuthor.Email = "goreleaser@carlosbecker.com" 42 } 43 return nil 44 } 45 46 func doRun(ctx *context.Context, client client.Client) error { 47 if ctx.Config.Scoop.Bucket.Name == "" { 48 return pipeline.Skip("scoop section is not configured") 49 } 50 if ctx.Config.Archive.Format == "binary" { 51 return pipeline.Skip("archive format is binary") 52 } 53 54 var archives = ctx.Artifacts.Filter( 55 artifact.And( 56 artifact.ByGoos("windows"), 57 artifact.ByType(artifact.UploadableArchive), 58 ), 59 ).List() 60 if len(archives) == 0 { 61 return ErrNoWindows 62 } 63 64 path := ctx.Config.ProjectName + ".json" 65 66 content, err := buildManifest(ctx, client, archives) 67 if err != nil { 68 return err 69 } 70 71 if ctx.SkipPublish { 72 return pipeline.ErrSkipPublishEnabled 73 } 74 if ctx.Config.Release.Draft { 75 return pipeline.Skip("release is marked as draft") 76 } 77 return client.CreateFile( 78 ctx, 79 ctx.Config.Scoop.CommitAuthor, 80 ctx.Config.Scoop.Bucket, 81 content, 82 path, 83 fmt.Sprintf("Scoop update for %s version %s", ctx.Config.ProjectName, ctx.Git.CurrentTag), 84 ) 85 } 86 87 // Manifest represents a scoop.sh App Manifest, more info: 88 // https://github.com/lukesampson/scoop/wiki/App-Manifests 89 type Manifest struct { 90 Version string `json:"version"` // The version of the app that this manifest installs. 91 Architecture map[string]Resource `json:"architecture"` // `architecture`: If the app has 32- and 64-bit versions, architecture can be used to wrap the differences. 92 Homepage string `json:"homepage,omitempty"` // `homepage`: The home page for the program. 93 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. 94 Description string `json:"description,omitempty"` // Description of the app 95 } 96 97 // Resource represents a combination of a url and a binary name for an architecture 98 type Resource struct { 99 URL string `json:"url"` // URL to the archive 100 Bin string `json:"bin"` // name of binary inside the archive 101 } 102 103 func buildManifest(ctx *context.Context, client client.Client, artifacts []artifact.Artifact) (result bytes.Buffer, err error) { 104 manifest := Manifest{ 105 Version: ctx.Version, 106 Architecture: make(map[string]Resource), 107 Homepage: ctx.Config.Scoop.Homepage, 108 License: ctx.Config.Scoop.License, 109 Description: ctx.Config.Scoop.Description, 110 } 111 112 for _, artifact := range artifacts { 113 var arch = "64bit" 114 if artifact.Goarch == "386" { 115 arch = "32bit" 116 } 117 manifest.Architecture[arch] = Resource{ 118 URL: getDownloadURL(ctx, ctx.Config.GitHubURLs.Download, artifact.Name), 119 Bin: ctx.Config.Builds[0].Binary + ".exe", 120 } 121 } 122 123 data, err := json.MarshalIndent(manifest, "", " ") 124 if err != nil { 125 return 126 } 127 _, err = result.Write(data) 128 return 129 } 130 131 func getDownloadURL(ctx *context.Context, githubURL, file string) string { 132 return fmt.Sprintf( 133 "%s/%s/%s/releases/download/%s/%s", 134 githubURL, 135 ctx.Config.Release.GitHub.Owner, 136 ctx.Config.Release.GitHub.Name, 137 ctx.Git.CurrentTag, 138 file, 139 ) 140 }