publish: github release plugin

This commit is contained in:
Rafael Garcia 2014-09-12 16:22:56 -07:00
parent 160f45b0a6
commit bbb8a4855b
3 changed files with 237 additions and 0 deletions

View file

@ -0,0 +1,128 @@
package publish
import (
"fmt"
"strings"
"github.com/drone/drone/pkg/build/buildfile"
"github.com/drone/drone/pkg/build/repo"
)
import ()
type Github struct {
// Script is an optional list of commands to run to prepare for a release.
Script []string `yaml:"script"`
// Artifacts is a list of files or directories to release.
Artifacts []string `yaml:"artifacts"`
// Tag is the name of the tag to create for this release.
Tag string `yaml:"tag"`
// Name is the name of the release. Defaults to tag.
Name string `yaml:"name"`
// Description describes the release. Defaults to empty string.
Description string `yaml:"description"`
// Draft is an identifier on a Github release.
Draft bool `yaml:"draft"`
// Prerelease is an identifier on a Github release.
Prerelease bool `yaml:"prerelease"`
// Token is the Github token to use when publishing the release.
Token string `yaml:"token"`
// User is the Github user for the repository you'd like to publish to.
User string `yaml:"user"`
// Repo is the name of the Github repostiory you like to publish to.
Repo string `yaml:"repo"`
// Branch to publish from.
Branch string `yaml:"branch"`
}
// Write adds commands to run that will publish a Github release.
func (g *Github) Write(f *buildfile.Buildfile, r *repo.Repo) {
if len(g.Artifacts) == 0 || g.Tag == "" || g.Token == "" || g.User == "" || g.Repo == "" {
f.WriteCmdSilent(`echo -e "Github Plugin: Missing argument(s)"\n\n`)
if len(g.Artifacts) == 0 {
f.WriteCmdSilent(`echo -e "\tartifacts not defined in yaml config" && false`)
}
if g.Tag == "" {
f.WriteCmdSilent(`echo -e "\ttag not defined in yaml config" && false`)
}
if g.Token == "" {
f.WriteCmdSilent(`echo -e "\ttoken not defined in yaml config" && false`)
}
if g.User == "" {
f.WriteCmdSilent(`echo -e "\tuser not defined in yaml config" && false`)
}
if g.Repo == "" {
f.WriteCmdSilent(`echo -e "\trepo not defined in yaml config" && false`)
}
return
}
// Default name is tag
if g.Name == "" {
g.Name = g.Tag
}
for _, cmd := range g.Script {
f.WriteCmd(cmd)
}
f.WriteEnv("GITHUB_TOKEN", g.Token)
// Install github-release
f.WriteCmd("curl -L -o /tmp/github-release.tar.bz2 https://github.com/aktau/github-release/releases/download/v0.5.2/linux-amd64-github-release.tar.bz2")
f.WriteCmd("tar jxf /tmp/github-release.tar.bz2 -C /tmp/ && sudo mv /tmp/bin/linux/amd64/github-release /usr/local/bin/github-release")
// Create the release. Ignore 422 errors, which indicate the tag has already been created.
// Doing otherwise would create the expectation that every commit should be tagged and released,
// which is not the norm.
draftStr := ""
if g.Draft {
draftStr = "--draft"
}
prereleaseStr := ""
if g.Prerelease {
prereleaseStr = "--pre-release"
}
f.WriteCmd(fmt.Sprintf(`
result=$(github-release release -u %s -r %s -t %s -n "%s" -d "%s" %s %s || true)
if [[ $result == *422* ]]; then
echo -e "Release already exists for this tag.";
exit 0
elif [[ $result == "" ]]; then
echo -e "Release created.";
else
echo -e "Error creating release: $result"
exit 1
fi
`, g.User, g.Repo, g.Tag, g.Name, g.Description, draftStr, prereleaseStr))
// Upload files
artifactStr := strings.Join(g.Artifacts, " ")
f.WriteCmd(fmt.Sprintf(`
for f in %s; do
# treat directories and files differently
if [ -d $f ]; then
for ff in $(ls $f); do
echo -e "uploading $ff"
github-release upload -u %s -r %s -t %s -n $ff -f $f/$ff
done
elif [ -f $f ]; then
echo -e "uploading $f"
github-release upload -u %s -r %s -t %s -n $f -f $f
else
echo -e "$f is not a file or directory"
exit 1
fi
done
`, artifactStr, g.User, g.Repo, g.Tag, g.User, g.Repo, g.Tag))
}

View file

@ -0,0 +1,103 @@
package publish
import (
"fmt"
"strings"
"testing"
"gopkg.in/v1/yaml"
)
var validcfg = map[string]interface{}{
"artifacts": []string{"release/"},
"tag": "v1.0",
"token": "github-token",
"user": "drone",
"repo": "drone",
}
func buildfileForConfig(config map[string]interface{}) (string, error) {
yml, err := yaml.Marshal(map[string]interface{}{
"publish": config,
})
if err != nil {
return "", err
}
return setUpWithDrone(string(yml))
}
func TestRequiredConfig(t *testing.T) {
for _, required := range []string{"artifacts", "tag", "token", "user", "repo"} {
invalidcfg := make(map[string]interface{})
for k, v := range validcfg {
if k != required {
invalidcfg[k] = v
}
}
buildfilestr, err := buildfileForConfig(map[string]interface{}{"github": invalidcfg})
if err != nil {
t.Fatal(err)
}
contains := fmt.Sprintf("%s not defined", required)
if !strings.Contains(buildfilestr, contains) {
t.Fatalf("Expected buildfile to contain error '%s': %s", contains, buildfilestr)
}
}
}
func TestScript(t *testing.T) {
cmd := "echo run me!"
scriptcfg := make(map[string]interface{})
scriptcfg["script"] = []string{cmd}
for k, v := range validcfg {
scriptcfg[k] = v
}
buildfilestr, err := buildfileForConfig(map[string]interface{}{"github": scriptcfg})
if err != nil {
t.Fatal(err)
}
if !strings.Contains(buildfilestr, cmd) {
t.Fatalf("Expected buildfile to contain command '%s': %s", cmd, buildfilestr)
}
}
func TestDefaultBehavior(t *testing.T) {
buildfilestr, err := buildfileForConfig(map[string]interface{}{"github": validcfg})
if err != nil {
t.Fatal(err)
}
defaultname := fmt.Sprintf(`-n "%s"`, validcfg["tag"].(string))
if !strings.Contains(buildfilestr, defaultname) {
t.Fatalf("Expected buildfile to contain name default to tag '%s': %s", defaultname, buildfilestr)
}
if strings.Contains(buildfilestr, "--draft") {
t.Fatalf("Should not create a draft release by default: %s", buildfilestr)
}
if strings.Contains(buildfilestr, "--pre-release") {
t.Fatalf("Should not create a pre-release release by default: %s", buildfilestr)
}
if !strings.Contains(buildfilestr, "github-release release") {
t.Fatalf("Should create a release: %s", buildfilestr)
}
if !strings.Contains(buildfilestr, "github-release upload") {
t.Fatalf("Should upload a file: %s", buildfilestr)
}
}
func TestOpts(t *testing.T) {
optscfg := make(map[string]interface{})
optscfg["draft"] = true
optscfg["prerelease"] = true
for k, v := range validcfg {
optscfg[k] = v
}
buildfilestr, err := buildfileForConfig(map[string]interface{}{"github": optscfg})
if err != nil {
t.Fatal(err)
}
for _, flag := range []string{"--draft", "--pre-release"} {
if !strings.Contains(buildfilestr, flag) {
t.Fatalf("Expected buildfile to contain flag '%s': %s", flag, buildfilestr)
}
}
}

View file

@ -14,6 +14,7 @@ type Publish struct {
PyPI *PyPI `yaml:"pypi,omitempty"`
NPM *NPM `yaml:"npm,omitempty"`
Docker *Docker `yaml:"docker,omitempty"`
Github *Github `yaml:"github,omitempty"`
}
func (p *Publish) Write(f *buildfile.Buildfile, r *repo.Repo) {
@ -41,4 +42,9 @@ func (p *Publish) Write(f *buildfile.Buildfile, r *repo.Repo) {
if p.Docker != nil && (len(p.Docker.Branch) == 0 || (len(p.Docker.Branch) > 0 && r.Branch == p.Docker.Branch)) {
p.Docker.Write(f, r)
}
// Github
if p.Github != nil && (len(p.Github.Branch) == 0 || (len(p.Github.Branch) > 0 && r.Branch == p.Github.Branch)) {
p.Github.Write(f, r)
}
}