Skip to content

Commit 1c9d1c9

Browse files
feat(hooks): add builder hooks api (#69)
1 parent d8ae200 commit 1c9d1c9

10 files changed

Lines changed: 491 additions & 1 deletion

File tree

api/builds.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,13 @@ type CreateBuildRequest struct {
1818
Image string `json:"image"`
1919
Procfile map[string]string `json:"procfile,omitempty"`
2020
}
21+
22+
// BuildHookRequest is a hook request to create a new build.
23+
type BuildHookRequest struct {
24+
Sha string `json:"sha"`
25+
User string `json:"receive_user"`
26+
App string `json:"receive_repo"`
27+
Image string `json:"image"`
28+
Procfile ProcessType `json:"procfile"`
29+
Dockerfile string `json:"dockerfile"`
30+
}

api/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ type Config struct {
4646
UUID string `json:"uuid,omitempty"`
4747
}
4848

49+
// ConfigHookRequest defines the request for configuration from the config hook.
50+
type ConfigHookRequest struct {
51+
User string `json:"receive_user"`
52+
App string `json:"receive_repo"`
53+
}
54+
4955
// Healthcheck is the structure for an application healthcheck.
5056
// Healthchecks only need to provide information about themselves.
5157
// All the information is pushed to the server and handled by kubernetes.

api/ps.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ package api
22

33
import "github.com/deis/controller-sdk-go/pkg/time"
44

5+
// ProcessType represents the key/value mappings of a process type to a process inside
6+
// a Heroku Procfile.
7+
//
8+
// See https://devcenter.heroku.com/articles/procfile
9+
type ProcessType map[string]string
10+
511
// Pods defines the structure of a process.
612
type Pods struct {
713
Release string `json:"release"`

api/push.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package api
2+
3+
// PushRequest is used to define the structure of the push hook
4+
type PushRequest struct {
5+
Sha string `json:"sha"`
6+
User string `json:"receive_user"`
7+
App string `json:"receive_repo"`
8+
Fingerprint string `json:"fingerprint"`
9+
Connection string `json:"ssh_connection"`
10+
Command string `json:"ssh_original_command"`
11+
}

api/users.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,9 @@ type Users []User
4040
func (u Users) Len() int { return len(u) }
4141
func (u Users) Swap(i, j int) { u[i], u[j] = u[j], u[i] }
4242
func (u Users) Less(i, j int) bool { return u[i].Username < u[j].Username }
43+
44+
// UserApps is a definition of the UserFromKey Hook response.
45+
type UserApps struct {
46+
Username string `json:"username"`
47+
Apps []string `json:"apps"`
48+
}

deis.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ type Client struct {
8282

8383
// Token is used to authenticate the request against the API.
8484
Token string
85+
86+
// HooksToken is the controller token used with the hooks resource.
87+
// The hooks resource isn't intended to be used by users, so it requires
88+
// a service token rather than a user token.
89+
HooksToken string
8590
}
8691

8792
// APIVersion is the api version compatible with the SDK.

hooks/hooks.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Package hooks implements the controller's builder hooks api.
2+
//
3+
// This is primarily intended to be consumed by the builder to communicate with the controller.
4+
package hooks
5+
6+
import (
7+
"encoding/json"
8+
"fmt"
9+
"io"
10+
"io/ioutil"
11+
12+
"github.com/deis/controller-sdk-go"
13+
"github.com/deis/controller-sdk-go/api"
14+
)
15+
16+
// UserFromKey retrives a user from their SSH key fingerprint.
17+
func UserFromKey(c *deis.Client, fingerprint string) (api.UserApps, error) {
18+
res, reqErr := c.Request("GET", fmt.Sprintf("/v2/hooks/key/%s", fingerprint), nil)
19+
if reqErr != nil && !deis.IsErrAPIMismatch(reqErr) {
20+
return api.UserApps{}, reqErr
21+
}
22+
23+
// Fix json.Decoder bug in <go1.7
24+
defer func() {
25+
io.Copy(ioutil.Discard, res.Body)
26+
res.Body.Close()
27+
}()
28+
29+
resUser := api.UserApps{}
30+
if err := json.NewDecoder(res.Body).Decode(&resUser); err != nil {
31+
return api.UserApps{}, err
32+
}
33+
34+
return resUser, reqErr
35+
}
36+
37+
// GetAppConfig retrives an app's configuration from the controller.
38+
func GetAppConfig(c *deis.Client, username, app string) (api.Config, error) {
39+
req := api.ConfigHookRequest{User: username, App: app}
40+
b, err := json.Marshal(req)
41+
if err != nil {
42+
return api.Config{}, err
43+
}
44+
45+
res, reqErr := c.Request("POST", "/v2/hooks/config/", b)
46+
if reqErr != nil && !deis.IsErrAPIMismatch(reqErr) {
47+
return api.Config{}, reqErr
48+
}
49+
// Fix json.Decoder bug in <go1.7
50+
defer func() {
51+
io.Copy(ioutil.Discard, res.Body)
52+
res.Body.Close()
53+
}()
54+
55+
config := api.Config{}
56+
if err := json.NewDecoder(res.Body).Decode(&config); err != nil {
57+
return api.Config{}, err
58+
}
59+
60+
return config, reqErr
61+
}
62+
63+
// CreateBuild creates a new release of an application. It returns the version of the new release.
64+
// gitSha should be the first 8 charecters of the git commit sha. Image is either the docker image
65+
// location for the dockerfile app the absolute url to the tar file for a buldpack app.
66+
func CreateBuild(c *deis.Client, username, app, image, gitSha string, procfile api.ProcessType,
67+
usingDockerifle bool) (int, error) {
68+
req := api.BuildHookRequest{
69+
Sha: gitSha,
70+
User: username,
71+
App: app,
72+
Image: image,
73+
Procfile: procfile,
74+
}
75+
76+
if usingDockerifle {
77+
req.Dockerfile = "true"
78+
}
79+
80+
b, err := json.Marshal(req)
81+
if err != nil {
82+
return -1, err
83+
}
84+
85+
res, reqErr := c.Request("POST", "/v2/hooks/build/", b)
86+
if reqErr != nil && !deis.IsErrAPIMismatch(reqErr) {
87+
return -1, reqErr
88+
}
89+
// Fix json.Decoder bug in <go1.7
90+
defer func() {
91+
io.Copy(ioutil.Discard, res.Body)
92+
res.Body.Close()
93+
}()
94+
95+
resMap := make(map[string]map[string]int)
96+
if err := json.NewDecoder(res.Body).Decode(&resMap); err != nil {
97+
return -1, err
98+
}
99+
100+
return resMap["release"]["version"], reqErr
101+
}
102+
103+
// CreatePush creates a new push for an application.
104+
// gitSha should be the first 8 charecters of the git commit sha.
105+
func CreatePush(c *deis.Client, username, app, gitSha, fingerprint, conn, cmd string) error {
106+
req := api.PushRequest{
107+
Sha: gitSha,
108+
User: username,
109+
App: app,
110+
Fingerprint: fingerprint,
111+
Connection: conn,
112+
Command: cmd,
113+
}
114+
115+
b, err := json.Marshal(req)
116+
if err != nil {
117+
return err
118+
}
119+
120+
res, reqErr := c.Request("POST", "/v2/hooks/push/", b)
121+
if reqErr == nil {
122+
res.Body.Close()
123+
}
124+
return reqErr
125+
}

0 commit comments

Comments
 (0)