UNPKG

5.37 kBtext/coffeescriptView Raw
1###
2CLI to automatically deploy stuff, kind of like heroku.
3Ubuntu only! (upstart)
4
5TODO remember last command again
6TODO multiple services
7TODO multiple cron
8
9###
10
11CONFIG = "ggg"
12
13LOGS_LINES = 40
14COMMIT_HISTORY = 5
15VERSION = "0.4.4"
16
17{exec} = require "child_process"
18fs = require 'fs'
19path = require 'path'
20
21program = require 'commander'
22
23MainConfig = require "./lib/MainConfig"
24Layer = require "./lib/Layer"
25
26program
27 .version(VERSION)
28 .option("-l, --local", "deploy locally for bootstrapping")
29
30program
31 .command("init")
32 .description("creates a ggg.js config file for you")
33 .action ->
34 init finish
35
36
37program
38 .command("deploy <name> [branch]")
39 .description("deploys a branch (defaults to origin/master) to named server")
40 .action (name, branch) ->
41 getLayer name, (err, layer) ->
42 return finish err if err?
43
44 branch = branch || "origin/master"
45
46 layer.deploy branch, finish
47
48
49program
50 .command("restart <name>")
51 .description("restarts named server")
52 .action (name) ->
53 getLayer name, (err, layer) ->
54 return finish err if err?
55 layer.restart finish
56
57
58program
59 .command("start <name>")
60 .description("starts named server")
61 .action (name) ->
62 getLayer name, (err, layer) ->
63 return finish err if err?
64 layer.start finish
65
66program
67 .command("stop <name>")
68 .description("stops named server")
69 .action (name) ->
70 getLayer name, (err, layer) ->
71 return finish err if err?
72 layer.stop finish
73
74program
75 .command("logs <name>")
76 .description("Logs #{LOGS_LINES} lines of named servers log files")
77 .option("-l, --lines <num>", "the number of lines to log")
78 .action (name) ->
79 getLayer name, (err, layer) ->
80 return finish err if err?
81 lines = program.lines || LOGS_LINES
82 layer.serverLogs lines, finish
83
84program
85 .command("history <name>")
86 .description("Shows a history of #{COMMIT_HISTORY} last commits deployed")
87 .option("-r, --revisions <num>", "the number of commits to show")
88 .action (name) ->
89 getLayer name, (err, layer) ->
90 return finish err if err?
91 revisions = program.args.revisions || COMMIT_HISTORY
92 layer.commitHistory revisions, finish
93
94program
95 .command("list")
96 .description("lists all the servers")
97 .action ->
98 getConfigRepo (err, repoName, mainConfig) ->
99 return finish err if err?
100
101 list mainConfig, finish
102
103program
104 .command("help")
105 .description("display this help")
106 .action ->
107 console.log program.helpInformation()
108 finish()
109
110program
111 .command("*")
112 .action ->
113 finish new Error "bad command!"
114
115## ACTIONS #########################################################
116
117# creates the init file for you
118init = (cb) ->
119 initConfigContent = """
120 // example ggg.js. Delete what you don't need
121 module.exports = {
122
123 // services
124 start: "node app.js",
125
126 // install
127 install: "npm install",
128
129 // cron jobs (from your app folder)
130 cron: {
131 someTask: { time: "0 3 * * *", command: "node sometask.js"},
132 }
133
134 // servers to deploy to
135 servers: {
136 dev: "deploy@dev.mycompany.com",
137 staging: ["deploy@staging.mycompany.com", "deploy@staging2.mycompany.com"]
138 prod: {
139 hosts: ["deploy@mycompany.com", "deploy@backup.mycompany.com"],
140 cron: {
141 someTask: {time: "0 3 * * *", command: "node sometask.js"},
142 anotherTask: {time: "0 3 * * *", command: "node secondTask.js"}
143 },
144 start: "prodstart app.js"
145 }
146 }
147 }
148 """
149
150 console.log "GOGOGO INITIALIZING!"
151 console.log "*** Written to ggg.js ***"
152 console.log initConfigContent
153
154 fs.writeFile mainConfigPath() + ".js", initConfigContent, 0o0755, cb
155
156list = (mainConfig, cb) ->
157 console.log "GOGOGO servers (see ggg.js)"
158 console.log " - " + mainConfig.getLayerNames().join("\n - ")
159
160## HELPERS #################################################
161# gets the repo url for the current directory
162# if it doesn't exist, use the directory name
163reponame = (dir, cb) ->
164 exec "git config --get remote.origin.url", {cwd:dir}, (err, stdout, stderr) ->
165 if err?
166 cb null, path.basename(dir)
167 else
168 url = stdout.replace("\n","")
169 cb null, path.basename(url).replace(".git","")
170
171
172# gets the main path for config
173mainConfigPath = -> path.join process.cwd(), CONFIG
174
175# returns the config object and the repoName
176getConfigRepo = (cb) ->
177 reponame process.cwd(), (err, repoName) ->
178 return cb err if err?
179 MainConfig.loadFromFile mainConfigPath(), (err, mainConfig) ->
180 if err then return cb new Error "Bad gogogo config file, ggg.js. Run 'gogogo init' to create one. Err=#{err.message}"
181
182 cb null, repoName, mainConfig
183
184#returns the layer object
185getLayer = (name, cb) ->
186 getConfigRepo (err, repoName, mainConfig) ->
187 return cb err if err?
188
189 layerConfig = mainConfig.getLayerByName name
190 if !layerConfig then return cb new Error("Invalid Layer Name: #{name}")
191
192 layer = new Layer name, layerConfig, repoName, mainConfig, program.local
193 layer.on "error", (err) -> return cb err
194 layer.on "ready", ->
195 cb null, layer
196
197# our handler on the finish
198finish = (err) ->
199 if err?
200 console.log "!!! " + err.message
201 console.log "stack follows:\n\n #{err.stack}"
202 process.exit 1
203 console.log "OK"
204
205# just export our program object
206module.exports = program