11---
2- title :Constructing a basic CI server | GitHub API
2+ title :Delivering deployments | GitHub API
33---
44
5- #Constructing a basic CI server
5+ #Delivering deployments
66
77* TOC
88{: toc }
@@ -12,15 +12,15 @@ the capability to launch them on a production server that you own. Combined with
1212[ the status API] [ status API ] , you'll be able to coordinate your deployments
1313the moment your code lands on` master ` .
1414
15- This guide willcombine these two API to demonstratean end-to-end setup that
16- you can use. In our scenario, we will:
15+ This guide willuse that API to demonstratea setup that you can use.
16+ In our scenario, we will:
1717
18- * Run our CI suite when a Pull Request is opened (we'll set the CI status to pending).
18+ * Merge a Pull Request
1919* When the CI is finished, we'll set the Pull Request's status accordingly.
2020* When the Pull Request is merged, we'll run our deployment to our server.
2121
2222Our CI system and host server will be figments of our imagination. They could be
23- Travis, Jenkins, Heroku, orAmazon . The crux of this guide will be setting up
23+ Heroku, Amazon, orsomething else entirely . The crux of this guide will be setting up
2424and configuring the server managing the communication.
2525
2626If you haven't already, be sure to[ download ngrok] [ ngrok ] , and learn how
@@ -62,112 +62,50 @@ that ngrok gave you:
6262Click** Update webhook** . You should see a body response of` Well, it worked! ` .
6363Great! Click on** Let me select individual events.** , and select the following:
6464
65- * Status
6665* Deployment
6766* Deployment status
6867* Pull Request
6968
7069These are the events GitHub will send to our server whenever the relevant action
71- occurs.Let's update our server to* just* handle the Pull Request scenario right now:
70+ occurs.We'll configure our server to* just* handle the Pull Request scenario right now:
7271
7372#!ruby
7473post '/event_handler' do
7574 @payload = JSON.parse(params[:payload])
7675
7776 case request.env['HTTP_X_GITHUB_EVENT']
7877 when "pull_request"
79- if @payload["action"] == "opened"
80- process_pull_request(@payload["pull_request"])
78+ if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
79+ puts "A pull request was merged! A dpeloyment should start now..."
8180 end
8281 end
8382end
8483
85- helpers do
86- def process_pull_request(pull_request)
87- puts "It's #{pull_request['title']}"
88- end
89- end
90-
9184What's going on? Every event that GitHub sends out attached a` X-GitHub-Event `
92- HTTP header. We'll only care about the PR events for now. From there, we'll
93- take the payload of information, and return the title field. In an ideal scenario,
94- our server would be concerned with every time a pull request is updated, not just
95- when it's updated. That would make sure that every new push passes the CI tests.
96- But for this demo, we'll just worry about when it's opened.
85+ HTTP header. We'll only care about the PR events for now. When a pull request is
86+ merged (its state is` closed ` , and` merged ` is` true ` ), we'll kick off a deployment.
9787
9888To test out this proof-of-concept, make some changes in a branch in your test
99- repository, and open a pull request. Your server should respond accordingly!
100-
101- ##Working with statuses
102-
103- With our server in place, we're ready to start our first requirement, which is
104- setting (and updating) CI statuses. Note that at any time you update your server,
105- you can click** Redeliver** to send the same payload. There's no need to make a
106- new pull request every time you make a change!
107-
108- Since we're interacting with the GitHub API, we'll use[ Octokit.rb] [ octokit.rb ]
109- to manage our interactions. We'll configure that client with
110- [ a personal access token] [ access token ] :
111-
112- #!ruby
113- # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
114- # Instead, set and test environment variables, like below
115- ACCESS_TOKEN = ENV['MY_PERSONAL_TOKEN']
116-
117- before do
118- @client ||= Octokit::Client.new(:access_token => ACCESS_TOKEN)
119- end
120-
121- After that, we'll just need to update the pull request on GitHub to make clear
122- that we're processing on the CI:
123-
124- #!ruby
125- def process_pull_request(pull_request)
126- puts "Processing pull request..."
127- @client.create_status(pull_request['head']['repo']['full_name'], pull_request['head']['sha'], 'pending')
128- end
129-
130- We're doing three very basic things here:
131-
132- * we're looking up the full name of the repository
133- * we're looking up the last SHA of the pull request
134- * we're setting the status to "pending"
135-
136- That's it! From here, you can run whatever process you need to in order to execute
137- your test suite. Maybe you're going to pass off your code to Jenkins, or call
138- on another web service via its API, like[ Travis] [ travis api ] . After that, you'd
139- be sure to update the status once more. In our example, we'll just set it to` "success" ` :
140-
141- #!ruby
142- def process_pull_request(pull_request)
143- @client.create_status(pull_request['head']['repo']['full_name'], pull_request['head']['sha'], 'pending')
144- sleep 2 # do busy work...
145- @client.create_status(pull_request['head']['repo']['full_name'], pull_request['head']['sha'], 'success')
146- puts "Pull request processed!"
147- end
89+ repository, open a pull request, and merge it. Your server should respond accordingly!
14890
14991##Working with deployments
15092
151- Our CI tests have passed, and the codehas been reviewed. When the pull request
93+ With our server in place, the codebeing reviewed, and our pull request
15294is merged, we want our project to be deployed to the production server.
15395
154- We'll start by modifying our event listener topay attention when pull requests
155- have been merged :
96+ We'll start by modifying our event listener toprocess pull requests when they're
97+ merged, and start paying attention to deployments :
15698
15799#!ruby
158100when "pull_request"
159- if @payload["action"] == "opened"
160- process_pull_request(@payload["pull_request"])
161- elsif @payload["action"] == "closed" && @payload["pull_request"]["merged"]
101+ if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
162102 start_deployment(@payload["pull_request"])
163103 end
164104when "deployment"
165105 process_deployment(@payload)
166106end
167107
168- When a pull request is merged (its state is` closed ` , and` merged ` is` true ` ), we'll
169- kick off a deployment. Based on the information from the pull request, we'll fill
170- out the` start_deployment ` method:
108+ Based on the information from the pull request, we'll fill out the` start_deployment ` method:
171109
172110#!ruby
173111def start_deployment(pull_request)
@@ -225,25 +163,23 @@ that this pattern is the exact same as when we updated our CI status.
225163
226164##Conclusion
227165
228- At GitHub, we've usedversions of [ Janky ] [ janky ] and [ Heaven] [ heaven ] to manage
166+ At GitHub, we've useda version of [ Heaven] [ heaven ] to manage
229167our deployments for years. The basic flow is essentially the exact same as the
230168server we've built above. At GitHub, we:
231169
232- * Fire to Jenkins when a pull request is created or updated (via Janky)
233170* Wait for a response on the state of the CI
234171* If the code is green, we merge the pull request
235172* Heaven takes the merged code, and deploys it to our production servers
236173* In the meantime, Heaven also notifies everyone about the build, via[ Hubot] [ hubot ] sitting in our chat rooms
237174
238175That's it! You don't need to build your own CI or deployment setup to use this example.
239- You can always rely on third-party services like Travis CI, Heroku, or any number
240- [ of additional integrators] [ integrations ] .
176+ You can always rely on[ third-party services] [ integrations ] .
241177
242178[ deploy API ] :/v3/repos/deployments/
243- [ status API ] :/v3/repos/statuses/
179+ [ status API ] :/guides/building-a-ci-server
244180[ ngrok ] :https://ngrok.com/
245181[ using ngrok ] :/webhooks/configuring/#using-ngrok
246- [ platform samples ] :https://github.com/github/platform-samples/tree/master/api/ruby/building-a-deployment-server
182+ [ platform samples ] :https://github.com/github/platform-samples/tree/master/api/ruby/delivering-deployments
247183[ Sinatra ] :http://www.sinatrarb.com/
248184[ webhook ] :/webhooks/
249185[ octokit.rb ] :https://github.com/octokit/octokit.rb