diff --git a/DOCS.md b/DOCS.md index c39d797..4259020 100644 --- a/DOCS.md +++ b/DOCS.md @@ -3,7 +3,9 @@ can override the default configuration with the following parameters: * `api_key` - GitHub oauth token with public_repo or repo permission * `files` - Files to upload to GitHub Release, globs are allowed +* `file_exists` - What to do if an file asset already exists, supported values: **overwrite** (default), **skip** and **fail** * `checksum` - Checksum takes hash methods to include in your GitHub release for the files specified. Supported hash methods include md5, sha1, sha256, sha512, adler32, and crc32. +* `draft` - create a draft release if set to true * `base_url` - GitHub base URL, only required for GHE * `upload_url` - GitHub upload URL, only required for GHE diff --git a/main.go b/main.go index da4d3c2..f7f1336 100644 --- a/main.go +++ b/main.go @@ -37,6 +37,13 @@ func main() { os.Exit(0) } + if vargs.FileExists == "" { + vargs.FileExists = "overwrite" + } + if !fileExistsValues[vargs.FileExists] { + fmt.Printf("invalid value for file_exists: use [empty], overwrite, skip or fail") + } + if vargs.BaseURL == "" { vargs.BaseURL = "https://api.github.com/" } else if !strings.HasSuffix(vargs.BaseURL, "/") { @@ -98,22 +105,47 @@ func main() { client.BaseURL = baseURL client.UploadURL = uploadURL - release, err := buildRelease(client, repo.Owner, repo.Name, filepath.Base(build.Ref)) + rc := releaseClient{ + Client: client, + Owner: repo.Owner, + Repo: repo.Name, + Tag: filepath.Base(build.Ref), + Draft: vargs.Draft, + FileExists: vargs.FileExists, + } + + release, err := rc.buildRelease() if err != nil { fmt.Println(err) os.Exit(1) } - if err := uploadFiles(client, repo.Owner, repo.Name, *release.ID, files); err != nil { + if err := rc.uploadFiles(*release.ID, files); err != nil { fmt.Println(err) os.Exit(1) } } -func buildRelease(client *github.Client, owner string, repo string, tag string) (*github.RepositoryRelease, error) { +var fileExistsValues = map[string]bool{ + "overwrite": true, + "fail": true, + "skip": true, +} + +// Release holds ties the drone env data and github client together. +type releaseClient struct { + *github.Client + Owner string + Repo string + Tag string + Draft bool + FileExists string +} + +func (rc *releaseClient) buildRelease() (*github.RepositoryRelease, error) { // first attempt to get a release by that tag - release, err := getRelease(client, owner, repo, tag) + release, err := rc.getRelease() if err != nil && release == nil { fmt.Println(err) } else if release != nil { @@ -121,7 +153,7 @@ func buildRelease(client *github.Client, owner string, repo string, tag string) } // if no release was found by that tag, create a new one - release, err = newRelease(client, owner, repo, tag) + release, err = rc.newRelease() if err != nil { return nil, fmt.Errorf("Failed to retrieve or create a release: %s", err) } @@ -129,34 +161,58 @@ func buildRelease(client *github.Client, owner string, repo string, tag string) return release, nil } -func getRelease(client *github.Client, owner string, repo string, tag string) (*github.RepositoryRelease, error) { - release, _, err := client.Repositories.GetReleaseByTag(owner, repo, tag) +func (rc *releaseClient) getRelease() (*github.RepositoryRelease, error) { + release, _, err := rc.Client.Repositories.GetReleaseByTag(rc.Owner, rc.Repo, rc.Tag) if err != nil { - return nil, fmt.Errorf("Release %s not found", tag) + return nil, fmt.Errorf("Release %s not found", rc.Tag) } - fmt.Printf("Successfully retrieved %s release\n", tag) + fmt.Printf("Successfully retrieved %s release\n", rc.Tag) return release, nil } -func newRelease(client *github.Client, owner string, repo string, tag string) (*github.RepositoryRelease, error) { - rr := &github.RepositoryRelease{TagName: github.String(tag)} - release, _, err := client.Repositories.CreateRelease(owner, repo, rr) +func (rc *releaseClient) newRelease() (*github.RepositoryRelease, error) { + rr := &github.RepositoryRelease{ + TagName: github.String(rc.Tag), + Draft: &rc.Draft, + } + release, _, err := rc.Client.Repositories.CreateRelease(rc.Owner, rc.Repo, rr) if err != nil { return nil, fmt.Errorf("Failed to create release: %s", err) } - fmt.Printf("Successfully created %s release\n", tag) + fmt.Printf("Successfully created %s release\n", rc.Tag) return release, nil } -func uploadFiles(client *github.Client, owner string, repo string, id int, files []string) error { - assets, _, err := client.Repositories.ListReleaseAssets(owner, repo, id, &github.ListOptions{}) +func (rc *releaseClient) uploadFiles(id int, files []string) error { + assets, _, err := rc.Client.Repositories.ListReleaseAssets(rc.Owner, rc.Repo, id, &github.ListOptions{}) if err != nil { return fmt.Errorf("Failed to fetch existing assets: %s", err) } + var uploadFiles []string +files: for _, file := range files { + for _, asset := range assets { + if *asset.Name == path.Base(file) { + switch rc.FileExists { + case "overwrite": + // do nothing + case "fail": + return fmt.Errorf("Asset file %s already exists", path.Base(file)) + case "skip": + fmt.Printf("Skipping pre-existing %s artifact\n", *asset.Name) + continue files + default: + return fmt.Errorf("Internal error, unkown file_exist value %s", rc.FileExists) + } + } + } + uploadFiles = append(uploadFiles, file) + } + + for _, file := range uploadFiles { handle, err := os.Open(file) if err != nil { return fmt.Errorf("Failed to read %s artifact: %s", file, err) @@ -164,7 +220,7 @@ func uploadFiles(client *github.Client, owner string, repo string, id int, files for _, asset := range assets { if *asset.Name == path.Base(file) { - if _, err := client.Repositories.DeleteReleaseAsset(owner, repo, *asset.ID); err != nil { + if _, err := rc.Client.Repositories.DeleteReleaseAsset(rc.Owner, rc.Repo, *asset.ID); err != nil { return fmt.Errorf("Failed to delete %s artifact: %s", file, err) } fmt.Printf("Successfully deleted old %s artifact\n", *asset.Name) @@ -172,7 +228,7 @@ func uploadFiles(client *github.Client, owner string, repo string, id int, files } uo := &github.UploadOptions{Name: path.Base(file)} - if _, _, err = client.Repositories.UploadReleaseAsset(owner, repo, id, uo, handle); err != nil { + if _, _, err = rc.Client.Repositories.UploadReleaseAsset(rc.Owner, rc.Repo, id, uo, handle); err != nil { return fmt.Errorf("Failed to upload %s artifact: %s", file, err) } diff --git a/types.go b/types.go index 295d5f7..8deee02 100644 --- a/types.go +++ b/types.go @@ -4,9 +4,11 @@ import "github.com/drone/drone-go/drone" // Params are the parameters that the GitHub Release plugin can parse. type Params struct { - BaseURL string `json:"base_url"` - UploadURL string `json:"upload_url"` - APIKey string `json:"api_key"` - Files drone.StringSlice `json:"files"` - Checksum drone.StringSlice `json:"checksum"` + BaseURL string `json:"base_url"` + UploadURL string `json:"upload_url"` + APIKey string `json:"api_key"` + Files drone.StringSlice `json:"files"` + Checksum drone.StringSlice `json:"checksum"` + Draft bool `json:"draft"` + FileExists string `json:"file_exists"` }