diff --git a/cmd/check/check.go b/cmd/check/main.go similarity index 75% rename from cmd/check/check.go rename to cmd/check/main.go index f97489d..7bc4c15 100644 --- a/cmd/check/check.go +++ b/cmd/check/main.go @@ -4,19 +4,19 @@ import ( "encoding/json" "os" - "github.com/concourse/github-release-resource" + "github.com/edtan/gitlab-release-resource" ) func main() { request := resource.NewCheckRequest() inputRequest(&request) - github, err := resource.NewGitHubClient(request.Source) + gitlab, err := resource.NewGitLabClient(request.Source) if err != nil { - resource.Fatal("constructing github client", err) + resource.Fatal("constructing gitlab client", err) } - command := resource.NewCheckCommand(github) + command := resource.NewCheckCommand(gitlab) response, err := command.Run(request) if err != nil { resource.Fatal("running command", err) diff --git a/cmd/in/in.go b/cmd/in/main.go similarity index 78% rename from cmd/in/in.go rename to cmd/in/main.go index 80c96b2..38fcca7 100644 --- a/cmd/in/in.go +++ b/cmd/in/main.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" - "github.com/concourse/github-release-resource" + "github.com/edtan/gitlab-release-resource" ) func main() { @@ -18,12 +18,12 @@ func main() { destDir := os.Args[1] - github, err := resource.NewGitHubClient(request.Source) + gitlab, err := resource.NewGitLabClient(request.Source) if err != nil { - resource.Fatal("constructing github client", err) + resource.Fatal("constructing gitlab client", err) } - command := resource.NewInCommand(github, os.Stderr) + command := resource.NewInCommand(gitlab, os.Stderr) response, err := command.Run(destDir, request) if err != nil { resource.Fatal("running command", err) diff --git a/cmd/out/out.go b/cmd/out/main.go similarity index 78% rename from cmd/out/out.go rename to cmd/out/main.go index d1cb9ad..b6a4ddb 100644 --- a/cmd/out/out.go +++ b/cmd/out/main.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" - "github.com/concourse/github-release-resource" + "github.com/edtan/gitlab-release-resource" ) func main() { @@ -18,12 +18,12 @@ func main() { sourceDir := os.Args[1] - github, err := resource.NewGitHubClient(request.Source) + gitlab, err := resource.NewGitLabClient(request.Source) if err != nil { - resource.Fatal("constructing github client", err) + resource.Fatal("constructing gitlab client", err) } - command := resource.NewOutCommand(github, os.Stderr) + command := resource.NewOutCommand(gitlab, os.Stderr) response, err := command.Run(sourceDir, request) if err != nil { resource.Fatal("running command", err) diff --git a/gitlab.go b/gitlab.go index 2f79406..704f429 100644 --- a/gitlab.go +++ b/gitlab.go @@ -3,8 +3,12 @@ package resource import ( "crypto/tls" "errors" + "fmt" + "io" "net/http" "net/url" + "os" + "path/filepath" "golang.org/x/oauth2" @@ -21,17 +25,19 @@ type GitLab interface { GetTag(tag_name string) (*gitlab.Tag, error) CreateTag(tag_name string, ref string) (*gitlab.Tag, error) CreateRelease(tag_name string, description string) (*gitlab.Release, error) - UpdateRelease(description string) (*gitlab.Release, error) + UpdateRelease(tag_name string, description string) (*gitlab.Release, error) UploadProjectFile(file string) (*gitlab.ProjectFile, error) + DownloadProjectFile(url, file string) error } type gitlabClient struct { client *gitlab.Client - repository string + accessToken string + repository string } -func NewGitlabClient(source Source) (*gitlabClient, error) { +func NewGitLabClient(source Source) (*gitlabClient, error) { var httpClient = &http.Client{} var ctx = context.TODO() @@ -214,3 +220,41 @@ func (g *gitlabClient) UploadProjectFile(file string) (*gitlab.ProjectFile, erro return projectFile, nil } + +func (g *gitlabClient) DownloadProjectFile(filePath, destPath string) error { + out, err := os.Create(destPath) + if err != nil { + return err + } + defer out.Close() + + filePathRef, err := url.Parse(g.repository + filePath) + if err != nil { + return err + } + + projectFileUrl := g.client.BaseURL().ResolveReference(filePathRef) + + client := &http.Client{} + req, err := http.NewRequest("GET", projectFileUrl.String(), nil) + if err != nil { + return err + } + req.Header.Add("Private-Token", g.accessToken) + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("failed to download file `%s`: HTTP status %d", filepath.Base(destPath), resp.StatusCode) + } + + _, err = io.Copy(out, resp.Body) + if err != nil { + return err + } + + return nil +} diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..86b2c8e --- /dev/null +++ b/go.sum @@ -0,0 +1,21 @@ +github.com/concourse/github-release-resource v1.0.0 h1:jpN453IQGRXNZcyKdmIznnBNXU1p1ALKFDRYq6KblY4= +github.com/concourse/github-release-resource v1.0.0/go.mod h1:fTyLw17ZewAEU8MSqLNKj5cM4MSNhhi2uVHUALGZ1Zo= +github.com/cppforlife/go-semi-semantic v0.0.0-20160921010311-576b6af77ae4 h1:J+ghqo7ZubTzelkjo9hntpTtP/9lUCWH9icEmAW+B+Q= +github.com/cppforlife/go-semi-semantic v0.0.0-20160921010311-576b6af77ae4/go.mod h1:socxpf5+mELPbosI149vWpNlHK6mbfWFxSWOoSndXR8= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286 h1:KHyL+3mQOF9sPfs26lsefckcFNDcIZtiACQiECzIUkw= +github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/xanzy/go-gitlab v0.12.0 h1:rs40DfrKvJoIluarQJcFmOADVMlgFGDMXvnEeQpjqGg= +github.com/xanzy/go-gitlab v0.12.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181108082009-03003ca0c849 h1:FSqE2GGG7wzsYUsWiQ8MZrvEd1EOyU3NCF0AW3Wtltg= +golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 h1:JIqe8uIcRBHXDQVvZtHwp80ai3Lw3IJAeJEs55Dc1W0= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/in_command.go b/in_command.go index 6063935..094090d 100644 --- a/in_command.go +++ b/in_command.go @@ -5,22 +5,26 @@ import ( "fmt" "io" "io/ioutil" - "net/http" "os" "path/filepath" - "strconv" + "strings" - "github.com/google/go-github/github" + "github.com/xanzy/go-gitlab" ) type InCommand struct { - github GitHub + gitlab GitLab writer io.Writer } -func NewInCommand(github GitHub, writer io.Writer) *InCommand { +type attachment struct { + Name string + URL string +} + +func NewInCommand(gitlab GitLab, writer io.Writer) *InCommand { return &InCommand{ - github: github, + gitlab: gitlab, writer: writer, } } @@ -31,81 +35,65 @@ func (c *InCommand) Run(destDir string, request InRequest) (InResponse, error) { return InResponse{}, err } - var foundRelease *github.RepositoryRelease - var commitSHA string + var foundTag *gitlab.Tag - if request.Version.Tag != "" { - foundRelease, err = c.github.GetReleaseByTag(request.Version.Tag) + foundTag, err = c.gitlab.GetTag(request.Version.Tag) + if err != nil { + return InResponse{}, err + } + + if foundTag == nil { + return InResponse{}, errors.New("could not find tag") + } + + tagPath := filepath.Join(destDir, "tag") + err = ioutil.WriteFile(tagPath, []byte(foundTag.Name), 0644) + if err != nil { + return InResponse{}, err + } + + versionParser, err := newVersionParser(request.Source.TagFilter) + if err != nil { + return InResponse{}, err + } + version := versionParser.parse(foundTag.Name) + versionPath := filepath.Join(destDir, "version") + err = ioutil.WriteFile(versionPath, []byte(version), 0644) + if err != nil { + return InResponse{}, err + } + + commitPath := filepath.Join(destDir, "commit_sha") + err = ioutil.WriteFile(commitPath, []byte(foundTag.Commit.ID), 0644) + if err != nil { + return InResponse{}, err + } + + if foundTag.Release != nil && foundTag.Release != nil && foundTag.Release.Description != "" { + body := foundTag.Release.Description + bodyPath := filepath.Join(destDir, "body") + err = ioutil.WriteFile(bodyPath, []byte(body), 0644) + if err != nil { + return InResponse{}, err + } } else { - id, _ := strconv.Atoi(request.Version.ID) - foundRelease, err = c.github.GetRelease(id) + return InResponse{}, errors.New("release notes for the tag was empty") } + + attachments, err := c.getAttachments(foundTag.Release.Description) if err != nil { return InResponse{}, err } - if foundRelease == nil { - return InResponse{}, errors.New("no releases") - } - - if foundRelease.TagName != nil && *foundRelease.TagName != "" { - tagPath := filepath.Join(destDir, "tag") - err = ioutil.WriteFile(tagPath, []byte(*foundRelease.TagName), 0644) - if err != nil { - return InResponse{}, err - } - - versionParser, err := newVersionParser(request.Source.TagFilter) - if err != nil { - return InResponse{}, err - } - version := versionParser.parse(*foundRelease.TagName) - versionPath := filepath.Join(destDir, "version") - err = ioutil.WriteFile(versionPath, []byte(version), 0644) - if err != nil { - return InResponse{}, err - } - - if foundRelease.Draft != nil && !*foundRelease.Draft { - commitPath := filepath.Join(destDir, "commit_sha") - commitSHA, err = c.resolveTagToCommitSHA(*foundRelease.TagName) - if err != nil { - return InResponse{}, err - } - - if commitSHA != "" { - err = ioutil.WriteFile(commitPath, []byte(commitSHA), 0644) - if err != nil { - return InResponse{}, err - } - } - } - - if foundRelease.Body != nil && *foundRelease.Body != "" { - body := *foundRelease.Body - bodyPath := filepath.Join(destDir, "body") - err = ioutil.WriteFile(bodyPath, []byte(body), 0644) - if err != nil { - return InResponse{}, err - } - } - - } - - assets, err := c.github.ListReleaseAssets(*foundRelease) - if err != nil { - return InResponse{}, err - } - - for _, asset := range assets { - path := filepath.Join(destDir, *asset.Name) + for _, attachment := range attachments { + path := filepath.Join(destDir, attachment.Name) var matchFound bool if len(request.Params.Globs) == 0 { matchFound = true } else { for _, glob := range request.Params.Globs { - matches, err := filepath.Match(glob, *asset.Name) + matches, err := filepath.Match(glob, attachment.Name) if err != nil { return InResponse{}, err } @@ -121,98 +109,36 @@ func (c *InCommand) Run(destDir string, request InRequest) (InResponse, error) { continue } - fmt.Fprintf(c.writer, "downloading asset: %s\n", *asset.Name) - - err := c.downloadAsset(asset, path) + fmt.Fprintf(c.writer, "downloading file: %s\n", attachment.Name) + err := c.gitlab.DownloadProjectFile(attachment.URL, path) if err != nil { return InResponse{}, err } } - if request.Params.IncludeSourceTarball { - u, err := c.github.GetTarballLink(request.Version.Tag) - if err != nil { - return InResponse{}, err - } - fmt.Fprintln(c.writer, "downloading source tarball to source.tar.gz") - if err := c.downloadFile(u.String(), filepath.Join(destDir, "source.tar.gz")); err != nil { - return InResponse{}, err - } - } - - if request.Params.IncludeSourceZip { - u, err := c.github.GetZipballLink(request.Version.Tag) - if err != nil { - return InResponse{}, err - } - fmt.Fprintln(c.writer, "downloading source zip to source.zip") - if err := c.downloadFile(u.String(), filepath.Join(destDir, "source.zip")); err != nil { - return InResponse{}, err - } - } - return InResponse{ - Version: versionFromRelease(foundRelease), - Metadata: metadataFromRelease(foundRelease, commitSHA), + Version: Version{Tag: foundTag.Name}, + Metadata: metadataFromTag(foundTag), }, nil } -func (c *InCommand) downloadAsset(asset *github.ReleaseAsset, destPath string) error { - out, err := os.Create(destPath) - if err != nil { - return err - } - defer out.Close() +// This resource stores the attachments as line-separated markdown links. +func (c *InCommand) getAttachments(releaseBody string) ([]attachment, error) { + var attachments []attachment - content, err := c.github.DownloadReleaseAsset(*asset) - if err != nil { - return err - } - defer content.Close() + lines := strings.Split(releaseBody, "\n") + for _, line := range lines { + nameStart := strings.Index(line, "[") + 1 + nameEnd := strings.Index(line, "]") - 1 + urlStart := strings.Index(line, "(") + 1 + urlEnd := strings.Index(line, ")") - 1 + + attachments = append(attachments, attachment{ + Name: line[nameStart:nameEnd], + URL: line[urlStart:urlEnd], + }) - _, err = io.Copy(out, content) - if err != nil { - return err } - return nil -} - -func (c *InCommand) downloadFile(url, destPath string) error { - out, err := os.Create(destPath) - if err != nil { - return err - } - defer out.Close() - - resp, err := http.Get(url) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("failed to download file `%s`: HTTP status %d", filepath.Base(destPath), resp.StatusCode) - } - - _, err = io.Copy(out, resp.Body) - if err != nil { - return err - } - - return nil -} - -func (c *InCommand) resolveTagToCommitSHA(tag string) (string, error) { - reference, err := c.github.GetRef(tag) - if err != nil { - return "", err - } - - if *reference.Object.Type != "commit" { - fmt.Fprintf(c.writer, "could not resolve tag '%s' to commit: returned type is not 'commit' - only lightweight tags are supported\n", tag) - return "", err - } - - return *reference.Object.SHA, err + return attachments, nil } diff --git a/metadata.go b/metadata.go index 54fb51c..7f45273 100644 --- a/metadata.go +++ b/metadata.go @@ -1,63 +1,31 @@ package resource -import "github.com/google/go-github/github" +import "github.com/xanzy/go-gitlab" -func metadataFromRelease(release *github.RepositoryRelease, commitSHA string) []MetadataPair { +func metadataFromTag(tag *gitlab.Tag) []MetadataPair { metadata := []MetadataPair{} - if release.Name != nil { + if tag.Name != "" { nameMeta := MetadataPair{ Name: "name", - Value: *release.Name, - } - - if release.HTMLURL != nil { - nameMeta.URL = *release.HTMLURL + Value: tag.Name, } metadata = append(metadata, nameMeta) } - if release.HTMLURL != nil { - metadata = append(metadata, MetadataPair{ - Name: "url", - Value: *release.HTMLURL, - }) - } - - if release.Body != nil { + if tag.Release.Description != "" { metadata = append(metadata, MetadataPair{ Name: "body", - Value: *release.Body, + Value: tag.Release.Description, Markdown: true, }) } - if release.TagName != nil { - metadata = append(metadata, MetadataPair{ - Name: "tag", - Value: *release.TagName, - }) - } - - if commitSHA != "" { + if tag.Commit.ID != "" { metadata = append(metadata, MetadataPair{ Name: "commit_sha", - Value: commitSHA, - }) - } - - if *release.Draft { - metadata = append(metadata, MetadataPair{ - Name: "draft", - Value: "true", - }) - } - - if *release.Prerelease { - metadata = append(metadata, MetadataPair{ - Name: "pre-release", - Value: "true", + Value: tag.Commit.ID, }) } return metadata diff --git a/out_command.go b/out_command.go index ab56028..e89c207 100644 --- a/out_command.go +++ b/out_command.go @@ -1,13 +1,12 @@ package resource import ( + "errors" "fmt" "io" "io/ioutil" "path/filepath" "strings" - - "github.com/xanzy/go-gitlab" ) type OutCommand struct { @@ -25,10 +24,10 @@ func NewOutCommand(gitlab GitLab, writer io.Writer) *OutCommand { func (c *OutCommand) Run(sourceDir string, request OutRequest) (OutResponse, error) { params := request.Params - name, err := c.fileContents(filepath.Join(sourceDir, request.Params.NamePath)) - if err != nil { - return OutResponse{}, err - } + // name, err := c.fileContents(filepath.Join(sourceDir, request.Params.NamePath)) + // if err != nil { + // return OutResponse{}, err + // } tag, err := c.fileContents(filepath.Join(sourceDir, request.Params.TagPath)) if err != nil { @@ -37,31 +36,20 @@ func (c *OutCommand) Run(sourceDir string, request OutRequest) (OutResponse, err tag = request.Params.TagPrefix + tag - targetCommitish, err = c.fileContents(filepath.Join(sourceDir, request.Params.CommitishPath)) + targetCommitish, err := c.fileContents(filepath.Join(sourceDir, request.Params.CommitishPath)) if err != nil { return OutResponse{}, err } - var body string - bodySpecified := false - if request.Params.BodyPath != "" { - bodySpecified = true - - body, err = c.fileContents(filepath.Join(sourceDir, request.Params.BodyPath)) - if err != nil { - return OutResponse{}, err - } - } - - release := &gitlab.RepositoryRelease{ - Name: gitlab.String(name), - TagName: gitlab.String(tag), - Body: gitlab.String(body), - TargetCommitish: gitlab.String(targetCommitish), - } + // if request.Params.BodyPath != "" { + // _, err := c.fileContents(filepath.Join(sourceDir, request.Params.BodyPath)) + // if err != nil { + // return OutResponse{}, err + // } + // } tagExists := false - existingTag, err := c.gitlab.GetTag(tag) + _, err = c.gitlab.GetTag(tag) if err != nil { //TODO: improve the check to be based on the specific error tagExists = true @@ -69,7 +57,7 @@ func (c *OutCommand) Run(sourceDir string, request OutRequest) (OutResponse, err // create the tag first, as next sections assume the tag exists if !tagExists { - tag, err := c.gitlab.CreateTag(targetCommitish, tag) + _, err := c.gitlab.CreateTag(targetCommitish, tag) if err != nil { return OutResponse{}, err } @@ -97,7 +85,7 @@ func (c *OutCommand) Run(sourceDir string, request OutRequest) (OutResponse, err } for _, filePath := range matches { - projectFile, err := c.UploadProjectFile(filePath) + projectFile, err := c.gitlab.UploadProjectFile(filePath) if err != nil { return OutResponse{}, err } @@ -106,11 +94,17 @@ func (c *OutCommand) Run(sourceDir string, request OutRequest) (OutResponse, err } // update the release - release, err = c.gitlab.UpdateRelease(tag, fileLinks.Join("\n")) + _, err = c.gitlab.UpdateRelease(tag, strings.Join(fileLinks, "\n")) + + // get tag + savedTag, err := c.gitlab.GetTag(tag) + if err != nil { + return OutResponse{}, errors.New("could not get saved tag") + } return OutResponse{ - Version: versionFromRelease(release), - Metadata: metadataFromRelease(release, ""), + Version: Version{Tag: tag}, + Metadata: metadataFromTag(savedTag), }, nil }