diff --git a/README.md b/README.md index 610ad5d..6ff426c 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,17 @@ Fetches and creates versioned GitHub resources. ## Source Configuration -* `access_token`: *Required.* The GitHub access token that should be used to - access the API. - * `user`: *Required.* The GitHub username or organization name for the repository that the releases are in. * `repository`: *Required.* The repository name that contains the releases. +* `access_token`: *Optional.* The GitHub access token that should be used to + access the API. Only required for publishing releases. + +* `github_api_url`: *Optional.* If you use a non-public GitHub deployment then + you can set your API URL here. + ## Behavior ### `check`: Check for released versions. diff --git a/cmd/check/check.go b/cmd/check/check.go index 59c6293..469ef6d 100644 --- a/cmd/check/check.go +++ b/cmd/check/check.go @@ -11,7 +11,11 @@ func main() { var request resource.CheckRequest inputRequest(&request) - github := resource.NewGitHubClient(request.Source) + github, err := resource.NewGitHubClient(request.Source) + if err != nil { + resource.Fatal("constructing github client", err) + } + command := resource.NewCheckCommand(github) response, err := command.Run(request) if err != nil { diff --git a/cmd/in/in.go b/cmd/in/in.go index 2477fb0..c8a9b5e 100644 --- a/cmd/in/in.go +++ b/cmd/in/in.go @@ -18,7 +18,11 @@ func main() { destDir := os.Args[1] - github := resource.NewGitHubClient(request.Source) + github, err := resource.NewGitHubClient(request.Source) + if err != nil { + resource.Fatal("constructing github client", err) + } + command := resource.NewInCommand(github, os.Stderr) response, err := command.Run(destDir, request) if err != nil { diff --git a/cmd/out/out.go b/cmd/out/out.go index b8a15c1..7b92e3f 100644 --- a/cmd/out/out.go +++ b/cmd/out/out.go @@ -18,7 +18,11 @@ func main() { sourceDir := os.Args[1] - github := resource.NewGitHubClient(request.Source) + github, err := resource.NewGitHubClient(request.Source) + if err != nil { + resource.Fatal("constructing github client", err) + } + command := resource.NewOutCommand(github, os.Stderr) response, err := command.Run(sourceDir, request) if err != nil { diff --git a/github.go b/github.go index 24ee37e..76994d2 100644 --- a/github.go +++ b/github.go @@ -2,6 +2,7 @@ package resource import ( "errors" + "net/url" "os" "code.google.com/p/goauth2/oauth" @@ -28,20 +29,34 @@ type GitHubClient struct { repository string } -func NewGitHubClient(source Source) *GitHubClient { +func NewGitHubClient(source Source) (*GitHubClient, error) { transport := &oauth.Transport{ Token: &oauth.Token{ AccessToken: source.AccessToken, }, } - client := github.NewClient(transport.Client()) + var client *github.Client + + if transport.Token.AccessToken == "" { + client = github.NewClient(nil) + } else { + client = github.NewClient(transport.Client()) + } + + if source.GitHubAPIURL != "" { + var err error + client.BaseURL, err = url.Parse(source.GitHubAPIURL) + if err != nil { + return nil, err + } + } return &GitHubClient{ client: client, user: source.User, repository: source.Repository, - } + }, nil } func (g *GitHubClient) ListReleases() ([]github.RepositoryRelease, error) { diff --git a/github_test.go b/github_test.go new file mode 100644 index 0000000..cac082e --- /dev/null +++ b/github_test.go @@ -0,0 +1,79 @@ +package resource_test + +import ( + "net/http" + + . "github.com/concourse/github-release-resource" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/onsi/gomega/ghttp" +) + +var _ = Describe("GitHub Client", func() { + var server *ghttp.Server + var client *GitHubClient + var source Source + + BeforeEach(func() { + server = ghttp.NewServer() + }) + + JustBeforeEach(func() { + source.GitHubAPIURL = server.URL() + + var err error + client, err = NewGitHubClient(source) + Ω(err).ShouldNot(HaveOccurred()) + }) + + AfterEach(func() { + server.Close() + }) + + Context("with an OAuth Token", func() { + BeforeEach(func() { + source = Source{ + User: "concourse", + Repository: "concourse", + AccessToken: "abc123", + } + + server.AppendHandlers( + ghttp.CombineHandlers( + ghttp.VerifyRequest("GET", "/repos/concourse/concourse/releases"), + ghttp.RespondWith(200, "[]"), + ghttp.VerifyHeaderKV("Authorization", "Bearer abc123"), + ), + ) + }) + + It("sends one", func() { + _, err := client.ListReleases() + Ω(err).ShouldNot(HaveOccurred()) + }) + }) + + Context("without an OAuth Token", func() { + BeforeEach(func() { + source = Source{ + User: "concourse", + Repository: "concourse", + } + + server.AppendHandlers( + ghttp.CombineHandlers( + ghttp.VerifyRequest("GET", "/repos/concourse/concourse/releases"), + ghttp.RespondWith(200, "[]"), + ghttp.VerifyHeader(http.Header{"Authorization": nil}), + ), + ) + }) + + It("sends one", func() { + _, err := client.ListReleases() + Ω(err).ShouldNot(HaveOccurred()) + }) + }) +}) diff --git a/in_command.go b/in_command.go index 963961f..9da0ec4 100644 --- a/in_command.go +++ b/in_command.go @@ -25,9 +25,14 @@ func NewInCommand(github GitHub, writer io.Writer) *InCommand { } func (c *InCommand) Run(destDir string, request InRequest) (InResponse, error) { + err := os.MkdirAll(destDir, 0755) + if err != nil { + return InResponse{}, err + } + releases, err := c.github.ListReleases() if err != nil { - return InResponse{}, nil + return InResponse{}, err } sort.Sort(byVersion(releases)) @@ -55,7 +60,7 @@ func (c *InCommand) Run(destDir string, request InRequest) (InResponse, error) { assets, err := c.github.ListReleaseAssets(foundRelease) if err != nil { - return InResponse{}, nil + return InResponse{}, err } for _, asset := range assets { @@ -87,7 +92,7 @@ func (c *InCommand) Run(destDir string, request InRequest) (InResponse, error) { err := c.downloadFile(url, path) if err != nil { - return InResponse{}, nil + return InResponse{}, err } } diff --git a/in_command_test.go b/in_command_test.go index 69fbad0..8cc0473 100644 --- a/in_command_test.go +++ b/in_command_test.go @@ -1,6 +1,7 @@ package resource_test import ( + "errors" "io/ioutil" "os" "path/filepath" @@ -25,6 +26,7 @@ var _ = Describe("In Command", func() { inResponse resource.InResponse inErr error + tmpDir string destDir string ) @@ -34,9 +36,11 @@ var _ = Describe("In Command", func() { githubClient = &fakes.FakeGitHub{} command = resource.NewInCommand(githubClient, ioutil.Discard) - destDir, err = ioutil.TempDir("", "github-release") + tmpDir, err = ioutil.TempDir("", "github-release") Ω(err).ShouldNot(HaveOccurred()) + destDir = filepath.Join(tmpDir, "destination") + server = ghttp.NewServer() server.RouteToHandler("GET", "/example.txt", ghttp.RespondWith(200, "example.txt")) server.RouteToHandler("GET", "/example.rtf", ghttp.RespondWith(200, "example.rtf")) @@ -50,8 +54,11 @@ var _ = Describe("In Command", func() { }) AfterEach(func() { - server.Close() - Ω(os.RemoveAll(destDir)).Should(Succeed()) + if server != nil { + server.Close() + } + + Ω(os.RemoveAll(tmpDir)).Should(Succeed()) }) buildRelease := func(id int, tag string) github.RepositoryRelease { @@ -171,6 +178,29 @@ var _ = Describe("In Command", func() { Ω(err).ShouldNot(HaveOccurred()) }) }) + + Context("when downloading an asset fails", func() { + BeforeEach(func() { + server.Close() + server = nil + }) + + It("returns an error", func() { + Ω(inErr).Should(HaveOccurred()) + }) + }) + + Context("when listing release assets fails", func() { + disaster := errors.New("nope") + + BeforeEach(func() { + githubClient.ListReleaseAssetsReturns(nil, disaster) + }) + + It("returns the error", func() { + Ω(inErr).Should(Equal(disaster)) + }) + }) }) Context("when the specified version is not available", func() { @@ -228,4 +258,16 @@ var _ = Describe("In Command", func() { Ω(inErr).Should(HaveOccurred()) }) }) + + Context("when listing releases fails", func() { + disaster := errors.New("nope") + + BeforeEach(func() { + githubClient.ListReleasesReturns(nil, disaster) + }) + + It("returns the error", func() { + Ω(inErr).Should(Equal(disaster)) + }) + }) }) diff --git a/resources.go b/resources.go index f91efd1..fbb194a 100644 --- a/resources.go +++ b/resources.go @@ -1,10 +1,11 @@ package resource type Source struct { - AccessToken string `json:"access_token"` - User string `json:"user"` Repository string `json:"repository"` + + GitHubAPIURL string `json:"github_api_url"` + AccessToken string `json:"access_token"` } type CheckRequest struct {