octokit 2.0.0.rc4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CONTRIBUTING.md CHANGED
@@ -1,4 +1,7 @@
1
1
  ## Submitting a Pull Request
2
+
3
+ 0. Check out Hacking on Octokit in the README guide for
4
+ bootstrapping the project for local development.
2
5
  1. [Fork the repository.][fork]
3
6
  2. [Create a topic branch.][branch]
4
7
  3. Add specs for your unimplemented feature or bug fix.
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011-2013 Wynn Netherland, Adam Stacoviak, Erik Michaels-Ober
1
+ Copyright (c) 2009-2013 Wynn Netherland, Adam Stacoviak, Erik Michaels-Ober
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,100 +1,426 @@
1
1
  # Octokit
2
2
 
3
- Simple Ruby wrapper for the GitHub API.
3
+ Ruby toolkit for the GitHub API.
4
4
 
5
- ## Installation
5
+ ![Logo][logo]
6
+ [logo]: http://cl.ly/image/3Y013H0A2z3z/gundam-ruby.png
7
+
8
+ Octokit 2.0 is out, check the [Upgrade Guide](#upgrading-guide) before
9
+ upgrading from 1.x.
10
+
11
+ ## Philosophy
12
+
13
+ API wrappers [should reflect the idioms of the language in which they were
14
+ written][wrappers]. Octokit.rb wraps the [GitHub API][github-api] in a flat API
15
+ client that follows Ruby conventions and requires little knowledge of REST.
16
+ Most methods have positional arguments for required input and an options hash
17
+ for optional parameters, headers, or other options:
18
+
19
+ ```ruby
20
+ # Fetch a README with Accept header for HTML format
21
+ Octokit.readme 'al3x/sovereign', :accept => 'application/vnd.github.html'
22
+ ```
23
+
24
+
25
+ [wrappers]: http://wynnnetherland.com/journal/what-makes-a-good-api-wrapper
26
+ [github-api]: http://developer.github.com
27
+
28
+ ## Quick start
29
+
30
+ Install via Rubygems
6
31
 
7
32
  gem install octokit
8
33
 
9
- ## Documentation
34
+ ... or add to your Gemfile
10
35
 
11
- [http://rdoc.info/gems/octokit][documentation]
36
+ gem "octokit", "~> 2.0"
12
37
 
13
- [documentation]: http://rdoc.info/gems/octokit
38
+ ### Making requests
14
39
 
15
- ### Examples
40
+ API methods are available as module methods (consuming module-level
41
+ configuration) or as client instance methods.
42
+
43
+ ```ruby
44
+ # Provide authentication credentials
45
+ Octokit.configure do |c|
46
+ c.login 'defunkt'
47
+ c.password 'c0d3b4ssssss!'
48
+ end
16
49
 
17
- #### Show a user
50
+ # Fetch the current user
51
+ Octokit.user
52
+ ```
53
+ or
18
54
 
19
55
  ```ruby
20
- Octokit.user "sferik"
21
- => #<Hashie::Mash avatar_url="https://secure.gravatar.com/avatar/1f74b13f1e5c6c69cb5d7fbaabb1e2cb?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" bio="" blog="http://twitter.com/sferik" company="" created_at="2008-05-14T20:36:12Z" email="sferik@gmail.com" events_url="https://api.github.com/users/sferik/events{/privacy}" followers=662 followers_url="https://api.github.com/users/sferik/followers" following=102 following_url="https://api.github.com/users/sferik/following{/other_user}" gists_url="https://api.github.com/users/sferik/gists{/gist_id}" gravatar_id="1f74b13f1e5c6c69cb5d7fbaabb1e2cb" hireable=false html_url="https://github.com/sferik" id=10308 location="San Francisco, CA" login="sferik" name="Erik Michaels-Ober" organizations_url="https://api.github.com/users/sferik/orgs" public_gists=59 public_repos=83 received_events_url="https://api.github.com/users/sferik/received_events" repos_url="https://api.github.com/users/sferik/repos" starred_url="https://api.github.com/users/sferik/starred{/owner}{/repo}" subscriptions_url="https://api.github.com/users/sferik/subscriptions" type="User" updated_at="2013-05-31T16:01:08Z" url="https://api.github.com/users/sferik">
56
+ # Provide authentication credentials
57
+ client = Octokit::Client.new :login => 'defunkt', :password => 'c0d3b4ssssss!'
58
+ # Fetch the current user
59
+ client.user
22
60
  ```
23
61
 
24
- #### Repositories
62
+ ### Consuming resources
25
63
 
26
- For convenience, methods that require a repository argument may be passed in
27
- any of the following forms:
64
+ Most methods return a `Resource` object which provides dot notation and `[]`
65
+ access for fields returned in the API response.
28
66
 
29
67
  ```ruby
30
- Octokit.repo "octokit/octokit.rb"
68
+ # Fetch a user
69
+ user = Octokit.user 'jbarnette'
70
+ puts user.name
71
+ # => "John Barnette"
72
+ puts user.fields
73
+ # => <Set: {:login, :id, :gravatar_id, :type, :name, :company, :blog, :location, :email, :hireable, :bio, :public_repos, :followers, :following, :created_at, :updated_at, :public_gists}>
74
+ puts user[:company]
75
+ # => "GitHub"
76
+ user.rels[:gists].href
77
+ # => "https://api.github.com/users/jbarnette/gists"
78
+ ```
31
79
 
32
- Octokit.repo {:username => "octokit", :name => "octokit.rb"}
80
+ **Note:** URL fields are culled into a separate `.rels` collection for easier
81
+ [Hypermedia](#hypermedia-agent) support.
33
82
 
34
- Octokit.repo {:username => "octokit", :repo => "octokit.rb"}
83
+ ### Accessing HTTP responses
35
84
 
36
- Octokit.repo Repository.new('octokit/octokit.rb')
85
+ While most methods return a `Resource` object or a Boolean, sometimes you may
86
+ need access to the raw HTTP response headers. You can access the last HTTP
87
+ response with `Client#last_response`:
88
+
89
+ ```ruby
90
+ user = Octokit.user 'andrewpthorp'
91
+ response = Octokit.last_response
92
+ etag = response.headers[:etag]
37
93
  ```
38
94
 
39
- #### List the commits for a repository
95
+ ## Authentication
40
96
 
41
- ```ruby
42
- Octokit.commits("octokit/octokit.rb")
97
+ Octokit supports the various [authentication methods supported by the GitHub
98
+ API][auth]:
99
+
100
+ ### Basic Authentication
43
101
 
44
- Octokit.list_commits("octokit/octokit.rb")
102
+ Using your GitHub username and password is the easiest way to get started
103
+ making authenticated requests:
45
104
 
46
- => [#<Hashie::Mash author=#<Hashie::Mash avatar_url="https://secure.gravatar.com/avatar/7e19cd5486b5d6dc1ef90e671ba52ae0?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" gravatar_id="7e19cd5486b5d6dc1ef90e671ba52ae0" id=865 login="pengwynn" url="https://api.github.com/users/pengwynn"> commit=#<Hashie::Mash author=#<Hashie::Mash date="2012-10-31T15:17:51Z" email="wynn@github.com" name="Wynn Netherland"> comment_count=0 committer=#<Hashie::Mash date="2012-10-31T15:17:51Z" email="wynn@github.com" name="Wynn Netherland"> message="Fix bug with archive_link for private repo" tree=#<Hashie::Mash sha="49bf2a476aa819f29b0fc1a8805f7567f010006d" url="https://api.github.com/repos/octokit/octokit.rb/git/trees/49bf2a476aa819f29b0fc1a8805f7567f010006d"> url="https://api.github.com/repos/octokit/octokit.rb/git/commits/8db3df37fad3a021eb8036b007c718149836cb32"> committer=#<Hashie::Mash avatar_url="https://secure.gravatar.com/avatar/7e19cd5486b5d6dc1ef90e671ba52ae0?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" gravatar_id="7e19cd5486b5d6dc1ef90e671ba52ae0" id=865 login="pengwynn" url="https://api.github.com/users/pengwynn"> parents=[#<Hashie::Mash sha="7a67f4b47791cb77de33e491df87cef06012c79f" url="https://api.github.com/repos/octokit/octokit.rb/commits/7a67f4b47791cb77de33e491df87cef06012c79f">] sha="8db3df37fad3a021eb8036b007c718149836cb32" url="https://api.github.com/repos/octokit/octokit.rb/commits/8db3df37fad3a021eb8036b007c718149836cb32">, ... , ...]
105
+ ```ruby
106
+ client = Octokit::Client.new \
107
+ :login => 'defunkt',
108
+ :password => 'c0d3b4ssssss!'
109
+
110
+ user = client.user
111
+ user.login
112
+ # => "defunkt"
47
113
  ```
114
+ While Basic Authentication makes it easy to get started quickly, OAuth access
115
+ tokens are the preferred way to authenticate on behalf of users.
116
+
117
+ ### OAuth access tokens
118
+
119
+ [OAuth access tokens][oauth] provide two main benefits over using your username
120
+ and password:
48
121
 
49
- #### Authenticated Requests
50
- For methods that require authentication, you'll need to setup a client with
51
- your login and password.
122
+ * **Revokable access**. Access tokens can be revoked, removing access for just
123
+ that token without having to change your password everywhere.
124
+ * **Limited access**. Access tokens have [access scopes][] which allow for more
125
+ granular access to API resources. For instance, you can grant a third party
126
+ access to your gists but not your private repositories.
127
+
128
+ To use an access token with the Octokit client, just pass it in lieu of your
129
+ username and password:
52
130
 
53
131
  ```ruby
54
- client = Octokit::Client.new(:login => "me", :password => "sekret")
55
- client.follow("sferik")
132
+ client = Octokit::Client.new :access_token => "<your 40 char token>"
133
+
134
+ user = client.user
135
+ user.login
136
+ # => "defunkt"
56
137
  ```
57
138
 
58
- Alternately, you can authenticate with a [GitHub OAuth2 token][oauth].
139
+ You can use `.create_authorization` to create a token using Basic Authorization
140
+ that you can use for subsequent calls.
59
141
 
60
- [oauth]: http://developer.github.com/v3/oauth
142
+ ### Using a .netrc file
143
+
144
+ Octokit supports reading credentials from a netrc file (defaulting to
145
+ `~/.netrc`). Given these lines in your netrc:
146
+
147
+ ```
148
+ machine api.github.com
149
+ login defunkt
150
+ password c0d3b4ssssss!
151
+ ```
152
+ You can now create a client with those credentials:
61
153
 
62
154
  ```ruby
63
- client = Octokit::Client.new(:login => "me", :oauth_token => "oauth2token")
64
- client.follow("sferik")
155
+ client = Octokit::Client.new :netrc => true
156
+ client.login
157
+ # => "defunkt"
158
+ ```
159
+ But _I want to use OAuth_ you say. Since the GitHub API supports using an OAuth
160
+ token as a Basic password, you totally can:
161
+
162
+ ```
163
+ machine api.github.com
164
+ login defunkt
165
+ password <your 40 char token>
65
166
  ```
66
167
 
67
- #### Requesting a specific media type
168
+ **Note:** Support for netrc requires adding the [netrc gem][] to your Gemfile
169
+ or `.gemspec`.
68
170
 
69
- You can pass an `:accept` option value to request a particular [media
70
- type][media-types].
171
+ ### Application authentication
71
172
 
72
- [media-types]: http://developer.github.com/v3/media/
173
+ Octokit also supports application-only authentication [using OAuth application client
174
+ credentials][app-creds]. Using application credentials will result in making
175
+ anonymous API calls on behalf of an application in order to take advantage of
176
+ the higher rate limit.
73
177
 
74
178
  ```ruby
75
- Octokit.contents 'octokit/octokit.rb', :path => 'README.md', :accept => 'application/vnd.github.html'
179
+ client = Octokit::Client.new \
180
+ :client_id => "<your 20 char id>",
181
+ :client_secret => "<your 40 char secret>"
182
+
183
+ user = client.users 'defunkt'
76
184
  ```
77
185
 
78
- ### Using with GitHub Enterprise
79
186
 
80
- To use with [GitHub Enterprise](https://enterprise.github.com/), you'll need to
81
- set the API and web endpoints before instantiating a client.
187
+
188
+ [auth]: http://developer.github.com/v3/#authentication
189
+ [oauth]: http://developer.github.com/v3/oauth/
190
+ [access scopes]: http://developer.github.com/v3/oauth/#scopes
191
+ [app-creds]: http://developer.github.com/v3/#unauthenticated-rate-limited-requests
192
+
193
+
194
+ ## Configuration and defaults
195
+
196
+ While `Octokit::Client` accepts a range of options when creating a new client
197
+ instance, Octokit's configuration API allows you to set your configuration
198
+ options at the module level. This is particularly handy if you're creating a
199
+ number of client instances based on some shared defaults.
200
+
201
+ ### Configuring module defaults
202
+
203
+ Every writable attribute in {Octokit::Configurable} can be set one at a time:
204
+
205
+ ```ruby
206
+ Octokit.api_endpoint = 'http://api.github.dev'
207
+ Octokit.web_endpoint = 'http://github.dev'
208
+ ```
209
+
210
+ or in batch:
82
211
 
83
212
  ```ruby
84
213
  Octokit.configure do |c|
85
- c.api_endpoint = 'https://github.company.com/api/v3'
86
- c.web_endpoint = 'https://github.company.com/'
214
+ c.api_endpoint = 'http://api.github.dev'
215
+ c.web_endpoint = 'http://github.dev'
87
216
  end
217
+ ```
218
+
219
+ ### Using ENV variables
220
+
221
+ Default configuration values are specified in {Octokit::Default}. Many
222
+ attributes will look for a default value from the ENV before returning
223
+ Octokit's default.
88
224
 
89
- @client = Octokit::Client.new(:login => 'USERNAME', :password => 'PASSWORD')
225
+ ```ruby
226
+ # Given $OCTOKIT_API_ENDPOINT is "http://api.github.dev"
227
+ Octokit.api_endpoint
228
+
229
+ # => "http://api.github.dev"
90
230
  ```
91
231
 
232
+ ## Hypermedia agent
233
+
234
+ Starting in version 2.0, Octokit is [hypermedia][]-enabled. Under the hood,
235
+ {Octokit::Client} uses [Sawyer][], a hypermedia client built on [Faraday][].
236
+
237
+ ### Hypermedia in Octokit
238
+
239
+ Resources returned by Octokit methods contain not only data but hypermedia
240
+ link relations:
241
+
242
+ ```ruby
243
+ user = Octokit.user 'technoweenie'
244
+
245
+ # Get the repos rel, returned from the API
246
+ # as repos_url in the resource
247
+ user.rels[:repos].href
248
+ # => "https://api.github.com/users/technoweenie/repos"
249
+
250
+ repos = user.rels[:repos].get.data
251
+ repos.last.name
252
+ # => "faraday-zeromq"
253
+ ```
254
+
255
+ When processing API responses, all `*_url` attributes are culled in to the link
256
+ relations collection. Any `url` attribute becomes `.rels[:self]`.
257
+
258
+ ### URI templates
259
+
260
+ You might notice many link relations have variable placeholders. Octokit
261
+ supports [URI Templates][uri-templates] for parameterized URI expansion:
262
+
263
+ ```ruby
264
+ repo = Octokit.repo 'pengwynn/pingwynn'
265
+ rel = repo.rels[:issues]
266
+ # => #<Sawyer::Relation: issues: get https://api.github.com/repos/pengwynn/pingwynn/issues{/number}>
267
+
268
+ # Get a page of issues
269
+ repo.rels[:issues].get.data
270
+
271
+ # Get issue #2
272
+ repo.rels[:issues].get(:uri => {:number => 2}).data
273
+ ```
274
+
275
+ ### The Full Hypermedia Experience™
276
+
277
+ If you want to use Octokit as a pure hypermedia API client, you can start at
278
+ the API root and and follow link relations from there:
279
+
280
+ ```ruby
281
+ root = Octokit.root
282
+ root.rels[:repository].get :uri => {:owner => "octokit", :repo => "octokit.rb" }
283
+ ```
284
+
285
+ Octokit 3.0 aims to be hypermedia-driven, removing the internal URL
286
+ construction currently used throughout the client.
287
+
288
+ [hypermedia]: http://en.wikipedia.org/wiki/Hypermedia
289
+ [Sawyer]: https://github.com/lostisland/sawyer
290
+ [Faraday]: https://github.com/lostisland/faraday
291
+ [uri-templates]: http://tools.ietf.org/html/rfc6570
292
+
293
+ ## Upgrading guide
294
+
295
+ Version 2.0 includes a completely rewritten `Client` factory that now memoizes
296
+ client instances based on unique configuration options. Breaking changes also
297
+ include:
298
+
299
+ * `:oauth_token` is now `:access_token`
300
+ * `Hashie::Mash` has been removed. Responses now return a `Sawyer::Resource`
301
+ object. This new type behaves mostly like a Ruby `Hash`, but does not fully
302
+ support the `Hashie::Mash` API.
303
+ * Two new client error types are raised where appropriate:
304
+ `Octokit::TooManyRequests` and `Octokit::TooManyLoginAttempts`
305
+ * The `search_*` methods from v1.x are now found at `legacy_search_*`
306
+ * Support for netrc requires including the [netrc gem][] in your Gemfile or
307
+ gemspec.
308
+
309
+ [netrc gem]: https://rubygems.org/gems/netrc
310
+
311
+
312
+ ## Advanced usage
313
+
314
+ Since Octokit employs [Faraday][faraday] under the hood, some behavior can be
315
+ extended via middleware.
316
+
317
+ ### Debugging
318
+
319
+ Often, it helps to know what Octokit is doing under the hood. Faraday makes it
320
+ easy to peek into the underlying HTTP traffic:
321
+
322
+ ```ruby
323
+ stack = Faraday::Builder.new do |builder|
324
+ builder.response :logger
325
+ builder.use Octokit::Response::RaiseError
326
+ builder.adapter Faraday.default_adapter
327
+ end
328
+ Octokit.middleware = stack
329
+ Octokit.user 'pengwynn'
330
+ ```
331
+ ```
332
+ I, [2013-08-22T15:54:38.583300 #88227] INFO -- : get https://api.github.com/users/pengwynn
333
+ D, [2013-08-22T15:54:38.583401 #88227] DEBUG -- request: Accept: "application/vnd.github.beta+json"
334
+ User-Agent: "Octokit Ruby Gem 2.0.0.rc4"
335
+ I, [2013-08-22T15:54:38.843313 #88227] INFO -- Status: 200
336
+ D, [2013-08-22T15:54:38.843459 #88227] DEBUG -- response: server: "GitHub.com"
337
+ date: "Thu, 22 Aug 2013 20:54:40 GMT"
338
+ content-type: "application/json; charset=utf-8"
339
+ transfer-encoding: "chunked"
340
+ connection: "close"
341
+ status: "200 OK"
342
+ x-ratelimit-limit: "60"
343
+ x-ratelimit-remaining: "39"
344
+ x-ratelimit-reset: "1377205443"
345
+ ...
346
+ ```
347
+
348
+ See the [Faraday README][faraday] for more middleware magic.
349
+
350
+ ### Caching
351
+
352
+ If you want to boost performance, stretch your API rate limit, or avoid paying
353
+ the hypermedia tax, you can use [Faraday Http Cache][cache].
354
+
355
+ Add the gem to your Gemfile
356
+
357
+ gem 'faraday-http-cache'
358
+
359
+ Next, construct your own Faraday middleware:
360
+
361
+ ```ruby
362
+ stack = Faraday::Builder.new do |builder|
363
+ builder.use Faraday::HttpCache
364
+ builder.use Octokit::Response::RaiseError
365
+ builder.adapter Faraday.default_adapter
366
+ end
367
+ Octokit.middleware = stack
368
+ ```
369
+
370
+ Once configured, the middleware will store responses in cache based on ETag
371
+ fingerprint and serve those back up for future `304` responses for the same
372
+ resource. See the [project README][cache] for advanced usage.
373
+
374
+
375
+ [cache]: https://github.com/plataformatec/faraday-http-cache
376
+ [faraday]: https://github.com/lostisland/faraday
377
+
378
+ ## Hacking on Octokit.rb
379
+
380
+ If you want to hack on Octokit locally, we try to make [bootstrapping the
381
+ project][bootstrapping] as painless as possible. Just clone and run:
382
+
383
+ script/bootstrap
384
+
385
+ This will install project dependencies and get you up and running. If you want
386
+ to run a Ruby console to poke on Octokit, you can crank one up with:
387
+
388
+ script/console
389
+
390
+ Using the scripts in `./scripts` instead of `bundle exec rspec`, `bundle
391
+ console`, etc. ensures your dependencies are up-to-date.
392
+
393
+ ### Running and writing new tests
394
+
395
+ Octokit uses [VCR][] for recording and playing back API fixtures during test
396
+ runs. These fixtures are part of the Git project in the `spec/cassettes`
397
+ folder. For the most part, tests use an authenticated client, using a token
398
+ stored in `ENV['OCTOKIT_TEST_GITHUB_TOKEN']`. If you're not recording new
399
+ cassettes, you don't need to have this set. If you do need to record new
400
+ cassettes, this token can be any GitHub API token because the test suite strips
401
+ the actual token from the cassette output before storing to disk.
402
+
403
+ Since we periodically refresh our cassettes, please keep some points in mind
404
+ when writing new specs.
405
+
406
+ * **Specs should be idempotent**. The HTTP calls made during a spec should be
407
+ able to be run over and over. This means deleting a known resource prior to
408
+ creating it if the name has to be unique.
409
+ * **Specs should be able to be run in random order.** If a spec depends on
410
+ another resource as a fixture, make sure that's created in the scope of the
411
+ spec and not depend on a previous spec to create the data needed.
412
+ * **Do not depend on authenticated user info.** Instead of asserting
413
+ actual values in resources, try to assert the existence of a key or that a
414
+ response is an Array. We're testing the client, not the API.
415
+
416
+ [bootstrapping]: http://wynnnetherland.com/linked/2013012801/bootstrapping-consistency
417
+ [VCR]: https://github.com/vcr/vcr
418
+
92
419
  ## Supported Ruby Versions
93
420
 
94
421
  This library aims to support and is [tested against][travis] the following Ruby
95
422
  implementations:
96
423
 
97
- * Ruby 1.8.7
98
424
  * Ruby 1.9.2
99
425
  * Ruby 1.9.3
100
426
  * Ruby 2.0.0
@@ -125,40 +451,11 @@ introduced with new major versions. As a result of this policy, you can (and
125
451
  should) specify a dependency on this gem using the [Pessimistic Version
126
452
  Constraint][pvc] with two digits of precision. For example:
127
453
 
128
- spec.add_dependency 'octokit', '~> 1.0'
454
+ spec.add_dependency 'octokit', '~> 2.0'
129
455
 
130
456
  [semver]: http://semver.org/
131
457
  [pvc]: http://docs.rubygems.org/read/chapter/16#page74
132
458
 
133
- ### JSON dependency
134
-
135
- Since JSON is included in 1.9 now, we no longer include it as a hard
136
- dependency. Please require it explicitly if you're running Ruby 1.8
137
-
138
- gem 'json', '~> 1.7'
139
-
140
- ## Contributors
141
-
142
- Octokit was initially created by Wynn Netherland and [Adam
143
- Stacoviak](http://twitter.com/adamstac) but has
144
- turned into a true community effort. Special thanks to the following
145
- contributors:
146
-
147
- * [Erik Michaels-Ober](http://github.com/sferik)
148
- * [Clint Shryock](http://github.com/ctshryock)
149
- * [Joey Wendt](http://github.com/joeyw)
150
-
151
-
152
- ## Inspiration
153
-
154
- Octokit was inspired by [Octopi][] and aims to be a lightweight,
155
- less-ActiveResourcey alternative.
156
-
157
- [octopi]: https://github.com/fcoury/octopi
158
-
159
- ## Copyright
160
-
161
- Copyright (c) 2011-2013 Wynn Netherland, Adam Stacoviak, Erik Michaels-Ober.
162
- See [LICENSE][] for details.
459
+ ## License
163
460
 
164
- [license]: LICENSE.md
461
+ {include:file:LICENSE.md}