2018-02-10 14:38:07 +02:00
// 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/internal/artifact"
"github.com/goreleaser/goreleaser/internal/client"
2018-09-12 19:18:01 +02:00
"github.com/goreleaser/goreleaser/internal/pipe"
2018-08-21 03:06:55 +02:00
"github.com/goreleaser/goreleaser/internal/tmpl"
2018-08-15 04:50:20 +02:00
"github.com/goreleaser/goreleaser/pkg/context"
2018-02-10 14:38:07 +02:00
)
// 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 {
2018-09-30 16:04:32 +02:00
if ctx . Config . Scoop . Name == "" {
ctx . Config . Scoop . Name = ctx . Config . ProjectName
}
2018-02-10 14:38:07 +02:00
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"
}
2018-08-21 03:20:04 +02:00
if ctx . Config . Scoop . URLTemplate == "" {
ctx . Config . Scoop . URLTemplate = fmt . Sprintf (
"%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}" ,
ctx . Config . GitHubURLs . Download ,
ctx . Config . Release . GitHub . Owner ,
ctx . Config . Release . GitHub . Name ,
)
}
2018-02-10 14:38:07 +02:00
return nil
}
func doRun ( ctx * context . Context , client client . Client ) error {
if ctx . Config . Scoop . Bucket . Name == "" {
2018-09-12 19:18:01 +02:00
return pipe . Skip ( "scoop section is not configured" )
2018-02-10 14:38:07 +02:00
}
if ctx . Config . Archive . Format == "binary" {
2018-09-12 19:18:01 +02:00
return pipe . Skip ( "archive format is binary" )
2018-02-10 14:38:07 +02:00
}
var archives = ctx . Artifacts . Filter (
artifact . And (
artifact . ByGoos ( "windows" ) ,
artifact . ByType ( artifact . UploadableArchive ) ,
) ,
) . List ( )
if len ( archives ) == 0 {
return ErrNoWindows
}
2018-09-30 16:04:32 +02:00
var path = ctx . Config . Scoop . Name + ".json"
2018-02-10 14:38:07 +02:00
2018-07-04 09:42:24 +02:00
content , err := buildManifest ( ctx , archives )
2018-02-10 14:38:07 +02:00
if err != nil {
return err
}
2018-03-01 06:12:58 +02:00
if ctx . SkipPublish {
2018-09-12 19:18:01 +02:00
return pipe . ErrSkipPublishEnabled
2018-02-10 14:38:07 +02:00
}
if ctx . Config . Release . Draft {
2018-09-12 19:18:01 +02:00
return pipe . Skip ( "release is marked as draft" )
2018-02-10 14:38:07 +02:00
}
return client . CreateFile (
ctx ,
ctx . Config . Scoop . CommitAuthor ,
ctx . Config . Scoop . Bucket ,
content ,
2018-02-15 04:13:57 +02:00
path ,
2018-03-10 19:13:00 +02:00
fmt . Sprintf ( "Scoop update for %s version %s" , ctx . Config . ProjectName , ctx . Git . CurrentTag ) ,
2018-02-15 04:13:57 +02:00
)
2018-02-10 14:38:07 +02:00
}
// 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
2018-08-25 22:24:42 +02:00
Persist [ ] string ` json:"persist,omitempty" ` // Persist data between updates
2018-02-10 14:38:07 +02:00
}
// Resource represents a combination of a url and a binary name for an architecture
type Resource struct {
2018-09-06 12:20:12 +02:00
URL string ` json:"url" ` // URL to the archive
Bin string ` json:"bin" ` // name of binary inside the archive
Hash string ` json:"hash" ` // the archive checksum
2018-02-10 14:38:07 +02:00
}
2018-08-21 03:20:04 +02:00
func buildManifest ( ctx * context . Context , artifacts [ ] artifact . Artifact ) ( bytes . Buffer , error ) {
var result bytes . Buffer
var manifest = Manifest {
2018-02-10 14:38:07 +02:00
Version : ctx . Version ,
Architecture : make ( map [ string ] Resource ) ,
Homepage : ctx . Config . Scoop . Homepage ,
License : ctx . Config . Scoop . License ,
Description : ctx . Config . Scoop . Description ,
2018-08-25 22:24:42 +02:00
Persist : ctx . Config . Scoop . Persist ,
2018-02-10 14:38:07 +02:00
}
for _ , artifact := range artifacts {
2018-02-15 04:13:57 +02:00
var arch = "64bit"
if artifact . Goarch == "386" {
arch = "32bit"
}
2018-08-21 03:06:55 +02:00
2018-08-21 03:20:04 +02:00
url , err := tmpl . New ( ctx ) .
WithArtifact ( artifact , map [ string ] string { } ) .
Apply ( ctx . Config . Scoop . URLTemplate )
2018-08-21 03:06:55 +02:00
if err != nil {
2018-08-21 03:20:04 +02:00
return result , err
2018-08-21 03:06:55 +02:00
}
2018-09-06 12:20:12 +02:00
sum , err := artifact . Checksum ( )
if err != nil {
return result , err
}
2018-02-15 04:13:57 +02:00
manifest . Architecture [ arch ] = Resource {
2018-09-06 12:20:12 +02:00
URL : url ,
2018-09-30 16:04:32 +02:00
Bin : ctx . Config . Builds [ 0 ] . Binary + ".exe" , // TODO: this is wrong
2018-09-06 12:20:12 +02:00
Hash : sum ,
2018-02-10 14:38:07 +02:00
}
}
data , err := json . MarshalIndent ( manifest , "" , " " )
if err != nil {
2018-08-21 03:20:04 +02:00
return result , err
2018-02-10 14:38:07 +02:00
}
_ , err = result . Write ( data )
2018-08-21 03:20:04 +02:00
return result , err
2018-02-10 14:38:07 +02:00
}