Skip to content

Commit 0435711

Browse files
committed
the rest of the scripting chapter
1 parent f4f9a87 commit 0435711

File tree

4 files changed

+137
-6
lines changed

4 files changed

+137
-6
lines changed
841 KB
Loading
114 KB
Loading
670 KB
Loading

book/06-github/sections/5-scripting.asc

Lines changed: 137 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,32 +102,163 @@ This is where the GitHub API comes in handy. GitHub has tons of API endpoints fo
102102

103103
The most basic thing you can do is a simple GET request on an endpoint that doesn't require authentication. This could be a user or read-only information on an open source project. For example, if we want to know more about a user named ``schacon'', we can run something like this:
104104

105-
[source,shell]
105+
[source,javascript]
106106
----
107-
$ curl https://api.github.com/user/schacon
107+
$ curl https://api.github.com/users/schacon
108108
{
109109
"login": "schacon",
110110
"id": 70,
111-
"avatar_url": "https://avatars.githubusercontent.com/u/70?",
111+
"avatar_url": "https://avatars.githubusercontent.com/u/70",
112112
# …
113+
"name": "Scott Chacon",
114+
"company": "GitHub",
113115
"following": 19,
114116
"created_at": "2008-01-27T17:19:28Z",
115117
"updated_at": "2014-06-10T02:37:23Z"
116118
}
117119
----
118120

121+
There are tons of endpoints like this to get information about organizations, projects, issues, commits -- just about anything you can publicly see on GitHub. You can even use the API to render arbitrary Markdown or find a `.gitignore` template.
122+
123+
[source,javascript]
124+
----
125+
$ curl https://api.github.com/gitignore/templates/Java
126+
{
127+
"name": "Java",
128+
"source": "*.class
129+
130+
# Mobile Tools for Java (J2ME)
131+
.mtj.tmp/
132+
133+
# Package Files #
134+
*.jar
135+
*.war
136+
*.ear
137+
138+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
139+
hs_err_pid*
140+
"
141+
}
142+
----
143+
144+
119145
==== Commenting on an Issue
120146

121-
- Issues API
147+
However, if you want to do an action on the website such as comment on an Issue or Pull Request or if you want to view or interact with private content, you'll need to authenticate.
148+
149+
This also has the added advantage of increasing your rate limit. Without authenticating, you will be limited to 60 requests per hour. If you authenticate you can make up to 5,000 requests per hour.
150+
151+
There are several ways to authenticate. You can use basic authentication with just your username and password, but generally it's a better idea to use a personal access token.
152+
You can generate this from the ``Applications'' tab of your settings page.
153+
154+
[[_access_token]]
155+
.Generate your access token from the ``Applications'' tab of your settings page.
156+
image::images/scripting-05-access-token.png[Access Token]
157+
158+
It will ask you which scopes you want for this token and a description. Make sure to use a good description so you feel comfortable removing the token when your script or application is no longer used.
159+
160+
GitHub will only show you the token once, so be sure to copy it. You can now use this to authenticate in your script instead of using a username and password. This is nice because you can limit the scope of what you want to do and the token is revokable.
161+
162+
So let's use it to make a comment on one of our issues. Let's say we want to leave a comment on a specific issue, Issue #6. To do so we have to do an HTTP POST request to `repos/<user>/<repo>/issues/<num>/comments` with the token we just generated as an Authorization header.
163+
164+
[source,javascript]
165+
----
166+
$ curl -H "Content-Type: application/json" \
167+
-H "Authorization: token TOKEN" \
168+
--data '{"body":"A new comment, :+1:"}' \
169+
https://api.github.com/repos/schacon/blink/issues/6/comments
170+
{
171+
"id": 58322100,
172+
"html_url": "https://github.com/schacon/blink/issues/6#issuecomment-58322100",
173+
...
174+
"user": {
175+
"login": "tonychacon",
176+
"id": 7874698,
177+
"avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2",
178+
"type": "User",
179+
},
180+
"created_at": "2014-10-08T07:48:19Z",
181+
"updated_at": "2014-10-08T07:48:19Z",
182+
"body": "A new comment, :+1:"
183+
}
184+
----
185+
186+
Now if you go to that issue, you can see the comment that we just successfully posted as in <<_api_comment>>.
187+
188+
[[_api_comment]]
189+
.A comment posted from the GitHub API.
190+
image::images/scripting-06-comment.png[API Comment]
191+
192+
You can use the API to do just about anything you can do on the website -- creating and setting milestones, assigning people to Issues and Pull Requests, creating and changing labels, accessing commit data, creating new commits and branches, opening, closing or merging Pull Requests, creating and editing teams, commenting on lines of code in a Pull Request, searching the site and on and on.
122193

123194
==== Changing the Status of a Pull Request
124195

125-
- PR status API
196+
One final example we'll look at since it's really useful if you're working with Pull Requests. Each commit can have one or more statuses associated with it and there is an API to add and query that status.
197+
198+
Most of the Continuous Integration and testing services make use of this API to test commits that are pushed and then report back if that commit has passed all the tests. You could also use this to check if the commit message is properly formatted, if the submitter followed all your contribution guidelines, if the commit was validly signed -- any number of things.
199+
200+
Let's say you set up a webhook on your repository that hits a small web service that checks for a `Signed-off-by` string in the commit message.
201+
202+
[source,ruby]
203+
----
204+
require 'httparty'
205+
require 'sinatra'
206+
require 'json'
207+
208+
post '/payload' do
209+
push = JSON.parse(request.body.read) # parse the JSON
210+
repo_name = push['repository']['full_name']
211+
212+
# look through each commit message
213+
push["commits"].each do |commit|
214+
215+
# look for a Signed-off-by string
216+
if /Signed-off-by/.match commit['message']
217+
state = 'success'
218+
description = 'Successfully signed off!'
219+
else
220+
state = 'failure'
221+
description = 'No signoff found.'
222+
end
223+
224+
# post status to GitHub
225+
sha = commit["id"]
226+
status_url = "https://api.github.com/repos/#{repo_name}/statuses/#{sha}"
227+
228+
status = {
229+
"state" => state,
230+
"description" => description,
231+
"target_url" => "http://example.com/how-to-signoff",
232+
"context" => "validate/signoff"
233+
}
234+
HTTParty.post(status_url,
235+
:body => status.to_json,
236+
:headers => {
237+
'Content-Type' => 'application/json',
238+
'User-Agent' => 'tonychacon/signoff',
239+
'Authorization' => "token #{ENV['TOKEN']}" }
240+
)
241+
end
242+
end
243+
----
244+
245+
Hopefully this is fairly simple to follow. In this web hook handler we look through each commit that was just pushed, we look for the string 'Signed-off-by' in the commit message and finally we POST via HTTP to the `/repos/<user>/<repo>/statuses/<commit_sha>` API endpoint with the status.
246+
247+
In this case you can send a state ('success', 'failure', 'error'), a description of what happened, a target URL the user can go to for more information and a ``context'' in case there are multiple statuses for a single commit. For example, a testing service may provide a status and a validation service like this may also provide a status -- the ``context'' field is how they're differentiated.
248+
249+
If someone opens a new Pull Request on GitHub and this hook is setup, you may see something like <<_commit_status>>.
250+
251+
[[_commit_status]]
252+
.Commit status via the API.
253+
image::images/scripting-07-status.png[Commit status]
126254

255+
You can now see a little green check mark next to the commit that has a ``Signed-off-by'' string in the message and a red cross through the one where the author forgot to sign off. You can also see that the Pull Request takes the status of the last commit on the branch and warns you if it is a failure. This is really useful if you're using this API for test results so you don't accidentally merge something where the last commit is failing tests.
127256

257+
==== Octokit
128258

129-
Though we've been doing everything through `curl` in these examples, several open-source libraries exist that make this API available in a more idiomatic way.
259+
Though we've been doing nearly everything through `curl` and simple HTTP requests in these examples, several open-source libraries exist that make this API available in a more idiomatic way.
130260
At the time of this writing, the supported languages include Go, Objective-C, Ruby, and .NET.
131261
Check out http://github.com/octokit[] for more information on these, as they handle much of the HTTP for you.
132262

263+
Hopefully these tools can help you customize and modify GitHub to work better for your specific workflows.
133264
For complete documentation on the entire API as well as guides for common tasks, check out https://developer.github.com[].

0 commit comments

Comments
 (0)