Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bradrydzewski committed Dec 13, 2017
1 parent 6c26457 commit 4aede0f
Show file tree
Hide file tree
Showing 261 changed files with 21,783 additions and 1 deletion.
9 changes: 9 additions & 0 deletions .drone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
workspace:
base: /go
path: src/github.com/drone/go-scm

pipeline:
test:
image: golang:1.9
commands:
- go test -v ./...
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.bak
*.env
*.out
_*.md
9 changes: 9 additions & 0 deletions BUILDING
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
1. Install go 1.9 or later
2. Install dependencies:

go get github.com/google/go-cmp

3. Compile and test:

go install ./...
go test ./...
3 changes: 3 additions & 0 deletions COPYRIGHT
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Copyright 2017 Drone.IO Inc. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (c) 2017, drone.io
Copyright (c) 2017, Drone.IO Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
188 changes: 188 additions & 0 deletions scm/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// Copyright 2017 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package scm

import (
"context"
"errors"
"io"
"net/http"
"net/url"
"strconv"
"strings"
)

var (
// ErrNotFound indicates a resource is not found.
ErrNotFound = errors.New("Not Found")

// ErrNotSupported indicates a resource endpoint is not
// supported or implemented.
ErrNotSupported = errors.New("Not Supported")
)

type (
// Request represents an HTTP request.
Request struct {
Method string
Path string
Header http.Header
Body io.Reader
}

// Response represents an HTTP response.
Response struct {
ID string
Status int
Header http.Header
Body io.ReadCloser

Page Page // Page values
Rate Rate // Rate limit snapshot
}

// Page represents parsed link rel values for
// pagination.
Page struct {
Next int
Last int
First int
Prev int
}

// Rate represents the rate limit for the current
// client.
Rate struct {
Limit int
Remaining int
Reset int64
}

// ListOptions specifies optional pagination
// parameters.
ListOptions struct {
Page int
Size int
}

// Client manages communication with a version control
// system API.
Client struct {
// HTTP client used to communicate with the API.
Client *http.Client

// Base URL for API requests.
BaseURL *url.URL

// Services used for communicating with the API.
Contents ContentService
Git GitService
Organizations OrganizationService
Issues IssueService
PullRequests PullRequestService
Repositories RepositoryService
Reviews ReviewService
Users UserService
Webhooks WebhookService
}
)

// Do sends an API request and returns the API response.
// The API response is JSON decoded and stored in the
// value pointed to by v, or returned as an error if an
// API error has occurred. If v implements the io.Writer
// interface, the raw response will be written to v,
// without attempting to decode it.
func (c *Client) Do(ctx context.Context, in *Request) (*Response, error) {
uri, err := c.BaseURL.Parse(in.Path)
if err != nil {
return nil, err
}

// creates a new http request with context.
req, err := http.NewRequest(in.Method, uri.String(), in.Body)
if err != nil {
return nil, err
}
// hack to prevent the client from un-escaping the
// encoded github path parameters when parsing the url.
if strings.Contains(in.Path, "%2F") {
req.URL.Opaque = strings.Split(req.URL.RawPath, "?")[0]
}

req = req.WithContext(ctx)
if in.Header != nil {
req.Header = in.Header
}

// use the default client if none provided.
client := c.Client
if client == nil {
client = http.DefaultClient
}
res, err := client.Do(req)
if err != nil {
return nil, err
}

return newResponse(res), nil
}

// newResponse creates a new Response for the provided
// http.Response. r must not be nil.
func newResponse(r *http.Response) *Response {
res := &Response{
Status: r.StatusCode,
Header: r.Header,
Body: r.Body,
}
res.populatePageValues()
return res
}

// populatePageValues parses the HTTP Link response headers
// and populates the various pagination link values in the
// Response.
//
// Copyright 2013 The go-github AUTHORS. All rights reserved.
// https://github.com/google/go-github
func (r *Response) populatePageValues() {
links := strings.Split(r.Header.Get("Link"), ",")
for _, link := range links {
segments := strings.Split(strings.TrimSpace(link), ";")

if len(segments) < 2 {
continue
}

if !strings.HasPrefix(segments[0], "<") ||
!strings.HasSuffix(segments[0], ">") {
continue
}

url, err := url.Parse(segments[0][1 : len(segments[0])-1])
if err != nil {
continue
}

page := url.Query().Get("page")
if page == "" {
continue
}

for _, segment := range segments[1:] {
switch strings.TrimSpace(segment) {
case `rel="next"`:
r.Page.Next, _ = strconv.Atoi(page)
case `rel="prev"`:
r.Page.Prev, _ = strconv.Atoi(page)
case `rel="first"`:
r.Page.First, _ = strconv.Atoi(page)
case `rel="last"`:
r.Page.Last, _ = strconv.Atoi(page)
}
}
}
}
41 changes: 41 additions & 0 deletions scm/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2017 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package scm

import (
"net/http"
"testing"
)

func TestClient(t *testing.T) {
t.Skip()
}

func TestResponse(t *testing.T) {
res := newResponse(&http.Response{
StatusCode: 200,
Header: http.Header{
"Link": {`<https://api.github.com/resource?page=4>; rel="next",
<https://api.github.com/resource?page=2>; rel="prev",
<https://api.github.com/resource?page=1>; rel="first",
<https://api.github.com/resource?page=5>; rel="last"`},
},
})
if got, want := res.Status, 200; got != want {
t.Errorf("Want status code %d, got %d", want, got)
}
if got, want := res.Page.First, 1; got != want {
t.Errorf("Want rel first %d, got %d", want, got)
}
if got, want := res.Page.Last, 5; got != want {
t.Errorf("Want rel last %d, got %d", want, got)
}
if got, want := res.Page.Prev, 2; got != want {
t.Errorf("Want rel prev %d, got %d", want, got)
}
if got, want := res.Page.Next, 4; got != want {
t.Errorf("Want rel next %d, got %d", want, got)
}
}
106 changes: 106 additions & 0 deletions scm/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2017 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package scm

import (
"encoding/json"
)

// State represents the commit state.
type State int

// State values.
const (
StateUnknown State = iota
StatePending
StateRunning
StateSuccess
StateFailure
StateCanceled
StateError
)

// Action identifies webhook actions.
type Action int

// Action values.
const (
ActionCreate Action = iota + 1
ActionUpdate
ActionDelete
// issues
ActionOpen
ActionReopen
ActionClose
ActionLabel
ActionUnlabel
// pull requests
ActionSync
ActionMerge
)

// String returns the string representation of Action.
func (a Action) String() (s string) {
switch a {
case ActionCreate:
return "created"
case ActionUpdate:
return "updated"
case ActionDelete:
return "deleted"
case ActionLabel:
return "labeled"
case ActionUnlabel:
return "unlabeled"
case ActionOpen:
return "opened"
case ActionReopen:
return "reopened"
case ActionClose:
return "closed"
case ActionSync:
return "synchronized"
case ActionMerge:
return "merged"
default:
return
}
}

// MarshalJSON returns the JSON-encoded Action.
func (a Action) MarshalJSON() ([]byte, error) {
return json.Marshal(a.String())
}

// UnmarshalJSON unmarshales the JSON-encoded Action.
func (a *Action) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
switch s {
case "created":
*a = ActionCreate
case "updated":
*a = ActionUpdate
case "deleted":
*a = ActionDelete
case "labeled":
*a = ActionLabel
case "unlabeled":
*a = ActionUnlabel
case "opened":
*a = ActionOpen
case "reopened":
*a = ActionReopen
case "closed":
*a = ActionClose
case "synchronized":
*a = ActionSync
case "merged":
*a = ActionMerge
}
return nil
}
Loading

0 comments on commit 4aede0f

Please sign in to comment.