-
Notifications
You must be signed in to change notification settings - Fork 24
/
deploy.go
109 lines (90 loc) · 2.79 KB
/
deploy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package deployments
import (
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"github.com/Scalingo/cli/config"
"github.com/Scalingo/go-scalingo/debug"
"github.com/Scalingo/go-scalingo"
scalingoio "github.com/Scalingo/go-scalingo/io"
"gopkg.in/errgo.v1"
)
type DeployRes struct {
Deployment *scalingo.Deployment `json:"deployment"`
}
func Deploy(app, archivePath, gitRef string) error {
c, err := config.ScalingoClient()
if err != nil {
return errgo.Notef(err, "fail to get Scalingo client")
}
var archiveURL string
// If archivePath is a remote resource
if strings.HasPrefix(archivePath, "http://") || strings.HasPrefix(archivePath, "https://") {
archiveURL = archivePath
} else { // if archivePath is a file
archiveURL, err = uploadArchivePath(c, archivePath)
if err != nil {
return errgo.Mask(err, errgo.Any)
}
}
params := &scalingo.DeploymentsCreateParams{
SourceURL: archiveURL,
}
// TODO gitRef cannot be anything. It is used in the docker tag image. For example, it cannot
// start with a dash
if strings.TrimSpace(gitRef) != "" {
params.GitRef = &gitRef
}
deployment, err := c.DeploymentsCreate(app, params)
if err != nil {
return errgo.Mask(err, errgo.Any)
}
scalingoio.Info("Deployment started, streaming output:")
debug.Println("Streaming deployment logs of", app, ":", deployment.ID)
err = Stream(&StreamOpts{
AppName: app,
DeploymentID: deployment.ID,
})
if err != nil {
return errgo.Mask(err, errgo.Any)
}
return nil
}
func uploadArchivePath(c *scalingo.Client, archivePath string) (string, error) {
archiveFd, err := os.OpenFile(archivePath, os.O_RDONLY, 0640)
if err != nil {
return "", errgo.Notef(err, "fail to open archive: %v", archivePath)
}
defer archiveFd.Close()
stat, err := archiveFd.Stat()
if err != nil {
return "", errgo.Notef(err, "fail to stat archive: %v", archivePath)
}
sources, err := c.SourcesCreate()
if err != nil {
return "", errgo.Mask(err, errgo.Any)
}
res, err := uploadArchive(sources.UploadURL, archiveFd, stat.Size())
if err != nil {
return "", errgo.Notef(err, "fail to upload archive: %v", archivePath)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
body, _ := ioutil.ReadAll(res.Body)
return "", errgo.Newf("wrong status code after upload %s, body: %s", res.Status, string(body))
}
return sources.DownloadURL, nil
}
func uploadArchive(uploadURL string, archiveReader io.Reader, archiveSize int64) (*http.Response, error) {
scalingoio.Status("Uploading archive…")
req, err := http.NewRequest("PUT", uploadURL, archiveReader)
if err != nil {
return nil, errgo.Mask(err, errgo.Any)
}
req.Header.Set("Content-Type", "application/x-gzip")
req.ContentLength = archiveSize
debug.Println("Uploading archive to ", uploadURL, "with headers", req.Header)
return http.DefaultClient.Do(req)
}