- $ curl foobar - .... -- -This isn't a `curl` tutorial though, I'm not sure every API call needs -to show how to access it with `curl`. +``` sh +$ rake generate_json_from_responses +``` -## Development +The generated files will end up in *json-dump/*. -Nanoc compiles the site into static files living in `./output`. It's -smart enough not to try to compile unchanged files: +### Terminal blocks - $ nanoc compile - Loading site data... - Compiling site... - identical [0.00s] output/css/960.css - identical [0.00s] output/css/pygments.css - identical [0.00s] output/css/reset.css - identical [0.00s] output/css/styles.css - identical [0.00s] output/css/uv_active4d.css - update [0.28s] output/index.html - update [1.31s] output/v3/gists/comments/index.html - update [1.92s] output/v3/gists/index.html - update [0.25s] output/v3/issues/comments/index.html - update [0.99s] output/v3/issues/labels/index.html - update [0.49s] output/v3/issues/milestones/index.html - update [0.50s] output/v3/issues/index.html - update [0.05s] output/v3/index.html +You can specify terminal blocks by using the `command-line` syntax highlighting. - Site compiled in 5.81s. + ``` command-line + $ curl foobar + ``` -You can setup whatever you want to view the files. If you have the adsf -gem, however (I hope so, it was in the Gemfile), you can start Webrick: +You can use certain characters, like `$` and `#`, to emphasize different parts +of commands. - $ nanoc view - $ open http://localhost:3000 + ``` command-line + # call foobar + $ curl foobar + .... + ``` -Compilation times got you down? Use `autocompile`! +For more information, see [the reference documentation](https://github.com/gjtorikian/extended-markdown-filter#command-line-highlighting). - $ nanoc autocompile +## Licenses -This starts a web server too, so there's no need to run `nanoc view`. -One thing: remember to add trailing slashes to all nanoc links! +The code to generate the site (everything excluding the assets, content, +and layouts directories) as well as the code samples on the site are +licensed under +[CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode). +CC0 waives all copyright restrictions but does not grant you any trademark +permissions. -## Deploy +Site content (everything in the assets, content, and layouts directories, +excluding files under open source licenses individually marked) is licensed +under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/). CC-BY-4.0 +gives you permission to use content for almost any purpose but does not grant +you any trademark permissions, so long as you note the license and give credit, +such as follows: - $ rake publish +> Content based on +> developer.github.com +> used under the +> CC-BY-4.0 +> license. -## TODO +This means you can use the code and content in this repository except for +GitHub trademarks in your own projects. -* Integrate through a simple hurl.it app for live API calls. -* Maybe add a nice TOC at the top of each page. -* Write a task for verifying JSON Resource examples against the actual - API. +When you contribute to this repository you are doing so under the above +licenses. diff --git a/Rakefile b/Rakefile index e936202c3a..066f1ab736 100644 --- a/Rakefile +++ b/Rakefile @@ -1,34 +1,111 @@ -require 'nanoc3/tasks' +require_relative 'lib/resources' +require 'tmpdir' -desc "Compile the site" -task :compile do - `nanoc compile` +Dir.glob('tasks/**/*.rake').each { |r| load r } + +task :default => [:test] + +desc 'Builds the site' +task :build do + if ENV['RACK_ENV'] == 'test' + begin + sh 'node_modules/gulp/bin/gulp.js build > build.txt' + rescue StandardError => e + puts 'uh oh' + $stderr.puts `cat build.txt` + raise e + end + else + sh 'node_modules/gulp/bin/gulp.js build' + end end -desc "Publish to http://developer.github.com" -task :publish => [:clean] do +desc "Test the output" +task :test => [:remove_tmp_dir, :remove_output_dir, :build] do + Rake::Task['spec'].invoke + Rake::Task['run_proofer'].invoke +end + +desc "Run Rspec" +task :spec do + require 'rspec/core/rake_task' + RSpec::Core::RakeTask.new(:rspec) + Rake::Task['rspec'].invoke +end + +desc "Run the HTML-Proofer" +task :run_proofer do + require 'html-proofer' + ignored_links = [%r{www.w3.org}, /api\.github\.com/, /import\.github\.com/] + # swap versionless Enterprise articles with versioned paths + url_swap = { + %r{help.github.com/enterprise/admin/} => "help.github.com/enterprise/#{config[:versions][0]}/admin/", + %r{help.github.com/enterprise/user/} => "help.github.com/enterprise/#{config[:versions][0]}/user/" + } + proofer_opts = { + :url_ignore => ignored_links, + :url_swap => url_swap, + :parallel => { :in_processes => 5 } + } + HTMLProofer.check_directory("./output", proofer_opts).run +end + +desc "Remove the tmp dir" +task :remove_tmp_dir do + FileUtils.rm_r('tmp') if File.exist?('tmp') +end + +desc "Remove the output dir" +task :remove_output_dir do FileUtils.rm_r('output') if File.exist?('output') +end - sh "nanoc compile" - - ENV['GIT_DIR'] = File.expand_path(`git rev-parse --git-dir`.chomp) - old_sha = `git rev-parse refs/remotes/origin/gh-pages`.chomp - Dir.chdir('output') do - ENV['GIT_INDEX_FILE'] = gif = '/tmp/dev.gh.i' - ENV['GIT_WORK_TREE'] = Dir.pwd - File.unlink(gif) if File.file?(gif) - `git add -A` - tsha = `git write-tree`.strip - puts "Created tree #{tsha}" - if old_sha.size == 40 - csha = `echo 'boom' | git commit-tree #{tsha} -p #{old_sha}`.strip - else - csha = `echo 'boom' | git commit-tree #{tsha}`.strip - end - puts "Created commit #{csha}" - puts `git show #{csha} --stat` - puts "Updating gh-pages from #{old_sha}" - `git update-ref refs/heads/gh-pages #{csha}` - `git push origin gh-pages` +# Prompt user for a commit message; default: P U B L I S H :emoji: +def commit_message(no_commit_msg = false) + publish_emojis = [':boom:', ':rocket:', ':metal:', ':bulb:', ':zap:', + ':sailboat:', ':gift:', ':ship:', ':shipit:', ':sparkles:', ':rainbow:'] + default_message = "P U B L I S H #{publish_emojis.sample}" + + unless no_commit_msg + print "Enter a commit message (default: '#{default_message}'): " + STDOUT.flush + mesg = STDIN.gets.chomp.strip end + + mesg = default_message if mesg.nil? || mesg == '' + mesg << "\nGenerated from #{ENV['BUILD_SHA']}" if ENV['BUILD_SHA'] + mesg.gsub(/'/, '') # Allow this to be handed off via -m '#{message}' +end + +namespace :assets do + task :precompile => [:build] do + sh 'mv output _site/' + end +end + +desc "Publish to http://developer.github.com" +task :publish, [:no_commit_msg] => [:remove_tmp_dir, :remove_output_dir, :build] do |t, args| + message = commit_message(args[:no_commit_msg]) + + Dir.mktmpdir do |tmp| + system "mv output/* #{tmp}" + system "cp .gitignore #{tmp}" + system 'git checkout gh-pages' + system "rsync -av #{tmp}/ ." + system 'git add .' + system "git commit -am #{message.shellescape}" + system 'git push origin gh-pages --force' + system 'git checkout master' + end +end + +desc "Generate JSON from the sample responses" +task :generate_json_from_responses do + Dir[File.join(File.dirname(__FILE__), 'lib', 'responses', '*.rb')].each { |file| load file } + FileUtils.mkdir_p(File.join(File.dirname(__FILE__), 'json-dump')) + GitHub::Resources::Responses.constants.each { |constant| + File.open('json-dump/' + constant.to_s + '.json', 'w') { |file| + file.write(JSON.pretty_generate(GitHub::Resources::Helpers.get_resource(constant))) + } + } end diff --git a/Rules b/Rules old mode 100644 new mode 100755 index 832aa5c592..c04b63886d --- a/Rules +++ b/Rules @@ -4,56 +4,88 @@ # # * The order of rules is important: for each item, only the first matching # rule is applied. -# -# * Item identifiers start and end with a slash (e.g. “/about/” for the file -# “content/about.html”). To select all children, grandchildren, … of an -# item, use the pattern “/about/*/”; “/about/*” will also select the parent, -# because “*” matches zero or more characters. -compile '/static/*' do +preprocess do + add_created_at_attribute + add_kind_attribute + create_individual_blog_pages + generate_redirects(config[:redirects]) + @items.each do |item| + ConrefFS.apply_attributes(@config, item, :default) + end end -compile '/CNAME/' do +passthrough '/CNAME' + +compile '/changes.atom' do + filter :erb end -compile '/feed/' do +compile '/integrations-directory/*' do + filter :'conref-fs-filter' filter :erb - filter :kramdown, :toc_levels => [2] + filter :html_pipeline, @config[:pipeline_config] + layout item[:layout] || '/integrations-directory.*' end -%w(v3 */).each do |version| - compile "/changes/#{version}" do - filter :erb - filter :kramdown, :toc_levels => [2] - filter :colorize_syntax, - :colorizers => {:javascript => :pygmentsrb} - layout 'changes' if version[0] == '*' - layout 'default' - end +compile '/v3{.*,/**/*}' do + filter :'conref-fs-filter' + filter :erb + filter :html_pipeline, @config[:pipeline_config] + layout(item[:layout] ? "/#{item[:layout]}.*" : '/api.*') +end + +compile "/changes/20*" do + filter :'conref-fs-filter' + filter :erb + filter :html_pipeline, @config[:pipeline_config] + layout '/changes.*' + layout(item[:layout] ? "/#{item[:layout]}.*" : '/blog.*') +end + +compile '/guides/**/*' do + filter :'conref-fs-filter' + filter :html_pipeline, @config[:pipeline_config] + filter :erb + layout(item[:layout] ? "/#{item[:layout]}.*" : '/guides.*') end -compile '*' do +compile '/webhooks/**/*' do + filter :'conref-fs-filter' filter :erb - filter :kramdown, :toc_levels => [2] - filter :colorize_syntax, - :colorizers => {:javascript => :pygmentsrb} - layout 'default' + filter :html_pipeline, @config[:pipeline_config] + layout(item[:layout] ? "/#{item[:layout]}.*" : '/webhooks.*') end -route '/static/*' do - item.identifier[7..-2] +compile '/search/search-index.json' do + filter :erb end -route '/CNAME/' do - '/CNAME' +compile '/**/*' do + filter :'conref-fs-filter' + filter :erb + filter :html_pipeline, @config[:pipeline_config] + layout(item[:layout] ? "/#{item[:layout]}.*" : '/default.*') end -route '/feed' do +route '/changes.atom' do '/changes.atom' end -route '*' do - item.identifier + 'index.html' +route '/search/search-index.json' do + item.identifier.to_s +end + +route '/**/index.*' do + item.identifier.without_ext + '.html' +end + +route '/404.html' do + '/404.html' +end + +route '/**/*' do + item.identifier.without_ext + '/index.html' end -layout '*', :erb +layout '/**/*', :erb diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 0000000000..cedb6140f4 Binary files /dev/null and b/assets/favicon.ico differ diff --git a/assets/images/add_github_autodeploy_service.png b/assets/images/add_github_autodeploy_service.png new file mode 100644 index 0000000000..0a09f51f54 Binary files /dev/null and b/assets/images/add_github_autodeploy_service.png differ diff --git a/assets/images/add_heroku_autodeploy_service.png b/assets/images/add_heroku_autodeploy_service.png new file mode 100644 index 0000000000..389b3942c6 Binary files /dev/null and b/assets/images/add_heroku_autodeploy_service.png differ diff --git a/assets/images/callout-earth-static.png b/assets/images/callout-earth-static.png new file mode 100644 index 0000000000..f20e9e6d30 Binary files /dev/null and b/assets/images/callout-earth-static.png differ diff --git a/assets/images/cancel.png b/assets/images/cancel.png new file mode 100644 index 0000000000..a4742556fa Binary files /dev/null and b/assets/images/cancel.png differ diff --git a/assets/images/cancel@2x.png b/assets/images/cancel@2x.png new file mode 100644 index 0000000000..ca95b36109 Binary files /dev/null and b/assets/images/cancel@2x.png differ diff --git a/assets/images/deploy-keys.png b/assets/images/deploy-keys.png new file mode 100644 index 0000000000..5208ba9997 Binary files /dev/null and b/assets/images/deploy-keys.png differ diff --git a/assets/images/electrocat.png b/assets/images/electrocat.png new file mode 100644 index 0000000000..7a27fde088 Binary files /dev/null and b/assets/images/electrocat.png differ diff --git a/assets/images/electrocat@2x.png b/assets/images/electrocat@2x.png new file mode 100644 index 0000000000..563905bf69 Binary files /dev/null and b/assets/images/electrocat@2x.png differ diff --git a/assets/images/expand-arrows.png b/assets/images/expand-arrows.png new file mode 100644 index 0000000000..3c7c1a839b Binary files /dev/null and b/assets/images/expand-arrows.png differ diff --git a/assets/images/expand-arrows@2x.png b/assets/images/expand-arrows@2x.png new file mode 100644 index 0000000000..25273491b7 Binary files /dev/null and b/assets/images/expand-arrows@2x.png differ diff --git a/assets/images/feed-icon.png b/assets/images/feed-icon.png new file mode 100755 index 0000000000..428988e69b Binary files /dev/null and b/assets/images/feed-icon.png differ diff --git a/assets/images/feed-icon@2x.png b/assets/images/feed-icon@2x.png new file mode 100644 index 0000000000..90749098a7 Binary files /dev/null and b/assets/images/feed-icon@2x.png differ diff --git a/assets/images/gdp-callout-static.png b/assets/images/gdp-callout-static.png new file mode 100644 index 0000000000..f20e9e6d30 Binary files /dev/null and b/assets/images/gdp-callout-static.png differ diff --git a/assets/images/gundamcat.png b/assets/images/gundamcat.png new file mode 100644 index 0000000000..512d0ae921 Binary files /dev/null and b/assets/images/gundamcat.png differ diff --git a/assets/images/gundamcat@2x.png b/assets/images/gundamcat@2x.png new file mode 100644 index 0000000000..bf8e8ad414 Binary files /dev/null and b/assets/images/gundamcat@2x.png differ diff --git a/assets/images/header-animation-short-loop.gif b/assets/images/header-animation-short-loop.gif new file mode 100644 index 0000000000..5238585ecd Binary files /dev/null and b/assets/images/header-animation-short-loop.gif differ diff --git a/assets/images/header-animation.gif b/assets/images/header-animation.gif new file mode 100644 index 0000000000..7b20d910d8 Binary files /dev/null and b/assets/images/header-animation.gif differ diff --git a/assets/images/header.png b/assets/images/header.png new file mode 100644 index 0000000000..6a0a4cc1f1 Binary files /dev/null and b/assets/images/header.png differ diff --git a/assets/images/header@2x.png b/assets/images/header@2x.png new file mode 100644 index 0000000000..266eeaf94c Binary files /dev/null and b/assets/images/header@2x.png differ diff --git a/assets/images/logo_developer.png b/assets/images/logo_developer.png new file mode 100644 index 0000000000..b93dc932a9 Binary files /dev/null and b/assets/images/logo_developer.png differ diff --git a/assets/images/logo_developer@2x.png b/assets/images/logo_developer@2x.png new file mode 100644 index 0000000000..8a42891292 Binary files /dev/null and b/assets/images/logo_developer@2x.png differ diff --git a/assets/images/mark@2x.png b/assets/images/mark@2x.png new file mode 100644 index 0000000000..ea6ff545a2 Binary files /dev/null and b/assets/images/mark@2x.png differ diff --git a/assets/images/oauth_prompt.png b/assets/images/oauth_prompt.png new file mode 100644 index 0000000000..387d022505 Binary files /dev/null and b/assets/images/oauth_prompt.png differ diff --git a/assets/images/pagination_sample.png b/assets/images/pagination_sample.png new file mode 100644 index 0000000000..de20437d35 Binary files /dev/null and b/assets/images/pagination_sample.png differ diff --git a/assets/images/payload_request_tab.png b/assets/images/payload_request_tab.png new file mode 100644 index 0000000000..2fddc6d189 Binary files /dev/null and b/assets/images/payload_request_tab.png differ diff --git a/assets/images/payload_response_tab.png b/assets/images/payload_response_tab.png new file mode 100644 index 0000000000..f2507841db Binary files /dev/null and b/assets/images/payload_response_tab.png differ diff --git a/assets/images/personal_token.png b/assets/images/personal_token.png new file mode 100644 index 0000000000..188873d592 Binary files /dev/null and b/assets/images/personal_token.png differ diff --git a/assets/images/posts/create-repo-init.png b/assets/images/posts/create-repo-init.png new file mode 100644 index 0000000000..8a47f73a32 Binary files /dev/null and b/assets/images/posts/create-repo-init.png differ diff --git a/assets/images/posts/default-branch.png b/assets/images/posts/default-branch.png new file mode 100644 index 0000000000..30712f2b68 Binary files /dev/null and b/assets/images/posts/default-branch.png differ diff --git a/assets/images/posts/submodule-links.png b/assets/images/posts/submodule-links.png new file mode 100644 index 0000000000..a1e6e8ce25 Binary files /dev/null and b/assets/images/posts/submodule-links.png differ diff --git a/assets/images/professorcat.png b/assets/images/professorcat.png new file mode 100644 index 0000000000..00739ad078 Binary files /dev/null and b/assets/images/professorcat.png differ diff --git a/assets/images/professorcat@2x.png b/assets/images/professorcat@2x.png new file mode 100644 index 0000000000..f8139c71fd Binary files /dev/null and b/assets/images/professorcat@2x.png differ diff --git a/assets/images/rocketship.png b/assets/images/rocketship.png new file mode 100644 index 0000000000..f6720a52a8 Binary files /dev/null and b/assets/images/rocketship.png differ diff --git a/assets/images/rocketship@2x.png b/assets/images/rocketship@2x.png new file mode 100644 index 0000000000..4055ede1b6 Binary files /dev/null and b/assets/images/rocketship@2x.png differ diff --git a/assets/images/search.png b/assets/images/search.png new file mode 100644 index 0000000000..9021936e33 Binary files /dev/null and b/assets/images/search.png differ diff --git a/assets/images/search@2x.png b/assets/images/search@2x.png new file mode 100644 index 0000000000..1c39a700cf Binary files /dev/null and b/assets/images/search@2x.png differ diff --git a/assets/images/status-icon-good.png b/assets/images/status-icon-good.png new file mode 100644 index 0000000000..6b216644c9 Binary files /dev/null and b/assets/images/status-icon-good.png differ diff --git a/assets/images/status-icon-good@2x.png b/assets/images/status-icon-good@2x.png new file mode 100644 index 0000000000..93f4cc8691 Binary files /dev/null and b/assets/images/status-icon-good@2x.png differ diff --git a/assets/images/status-icon-major.png b/assets/images/status-icon-major.png new file mode 100644 index 0000000000..67ee1fe8c2 Binary files /dev/null and b/assets/images/status-icon-major.png differ diff --git a/assets/images/status-icon-major@2x.png b/assets/images/status-icon-major@2x.png new file mode 100644 index 0000000000..a57070c61b Binary files /dev/null and b/assets/images/status-icon-major@2x.png differ diff --git a/assets/images/status-icon-minor.png b/assets/images/status-icon-minor.png new file mode 100644 index 0000000000..4372e3c5b0 Binary files /dev/null and b/assets/images/status-icon-minor.png differ diff --git a/assets/images/status-icon-minor@2x.png b/assets/images/status-icon-minor@2x.png new file mode 100644 index 0000000000..5b1bfa10b5 Binary files /dev/null and b/assets/images/status-icon-minor@2x.png differ diff --git a/assets/images/status-icon-unknown.png b/assets/images/status-icon-unknown.png new file mode 100644 index 0000000000..7df5bc94cd Binary files /dev/null and b/assets/images/status-icon-unknown.png differ diff --git a/assets/images/status-icon-unknown@2x.png b/assets/images/status-icon-unknown@2x.png new file mode 100644 index 0000000000..49a482876c Binary files /dev/null and b/assets/images/status-icon-unknown@2x.png differ diff --git a/assets/images/webhook_sample_url.png b/assets/images/webhook_sample_url.png new file mode 100644 index 0000000000..abf4083d6b Binary files /dev/null and b/assets/images/webhook_sample_url.png differ diff --git a/assets/images/webhook_secret_token.png b/assets/images/webhook_secret_token.png new file mode 100644 index 0000000000..6d2074b6ac Binary files /dev/null and b/assets/images/webhook_secret_token.png differ diff --git a/assets/images/webhooks_recent_deliveries.png b/assets/images/webhooks_recent_deliveries.png new file mode 100644 index 0000000000..3a742bfeae Binary files /dev/null and b/assets/images/webhooks_recent_deliveries.png differ diff --git a/assets/javascripts/dev_mode.js b/assets/javascripts/dev_mode.js new file mode 100644 index 0000000000..1996cb2614 --- /dev/null +++ b/assets/javascripts/dev_mode.js @@ -0,0 +1,9 @@ +// Init sidebar +$(function() { + $(window).keydown(function(e){ + // d + if (e.keyCode == 68) { + $("body.dev-mode").toggleClass('enterprise') + } + }); +}); diff --git a/assets/javascripts/documentation.js b/assets/javascripts/documentation.js new file mode 100644 index 0000000000..d006cd551e --- /dev/null +++ b/assets/javascripts/documentation.js @@ -0,0 +1,96 @@ +// Init sidebar +$(function() { + var activeItem, + helpList = $('#js-sidebar .js-topic'), + firstOccurance = true, + styleTOC = function() { + var pathRegEx = /\/\/[^\/]+([A-Za-z0-9-_./]+)/g, + docUrl = pathRegEx.exec(window.location.toString()) + if (docUrl){ + $('#js-sidebar .js-topic a').each(function(){ + if ($(this).parent('li').hasClass('disable')) + $(this).parent('li').removeClass('disable') + + var url = $(this).attr('href').toString() + var cleanDocUrl = docUrl[1] + if(url.indexOf(cleanDocUrl) >= 0 && url.length == cleanDocUrl.length){ + $(this).parent('li').addClass('disable') + var parentTopic = $(this).parentsUntil('div.sidebar-module > ul').last() + parentTopic.addClass('js-current') + parentTopic.find('.js-expand-btn').toggleClass('collapsed expanded') + } + }); + } + } + + // bind every href with a hash; take a look at v3/search/ for example + $('#js-sidebar .js-accordion-list .js-topic a[href*=#]').bind("click", function(e) { + if (window.location.toString().indexOf($(e.target).attr('href')) == -1) + setTimeout(styleTOC, 0); // trigger the window.location change, then stylize + }); + + // hide list items at startup + if($('body.api') && window.location){ + styleTOC(); + } + + $('#js-sidebar .js-topic').each(function(){ + if(($(this).find('.disable').length == 0 || firstOccurance == false) && + $(this).hasClass('js-current') != true){ + $(this).find('.js-guides').children().hide() + } else { + activeItem = $(this).index() + firstOccurance = false + } + }) + + // Toggle style list. Expanded items stay + // expanded when new items are clicked. + $('#js-sidebar .js-toggle-list .js-expand-btn').click(function(){ + var clickedTopic = $(this).parents('.js-topic'), + topicGuides = clickedTopic.find('.js-guides li') + $(this).toggleClass('collapsed expanded') + topicGuides.slideToggle(100) + return false + }) + + // Accordion style list. Expanded items + // collapse when new items are clicked. + $('#js-sidebar .js-accordion-list .js-topic h3 a').click(function(){ + var clickedTopic = $(this).parents('.js-topic'), + topicGuides = clickedTopic.find('.js-guides li') + + if(activeItem != clickedTopic.index()){ + if(helpList.eq(activeItem)){ + helpList.eq(activeItem).find('.js-guides li').slideToggle(100) + } + activeItem = clickedTopic.index() + topicGuides.slideToggle(100) + } else { + activeItem = undefined + topicGuides.slideToggle(100) + } + + return false + }) + + // Grab API status + $.getJSON('https://status.github.com/api/status.json?callback=?', function(data) { + if(data) { + var link = $("") + .attr("href", "https://status.github.com") + .addClass(data.status) + .attr("title", "API Status: " + data.status + ". Click for details.") + .text("API Status: " + data.status); + $('.api-status').html(link); + } + }); + + // Earth animation + if ($('.dev-program').length) { + setTimeout(function() { + $('.earth').fadeOut(); + $('.earth-short-loop').show(); + }, 19 * 1000); // Let first loop run through 19 seconds + } +}); diff --git a/assets/javascripts/images.js b/assets/javascripts/images.js new file mode 100644 index 0000000000..d335cfceb6 --- /dev/null +++ b/assets/javascripts/images.js @@ -0,0 +1,25 @@ +$(function() { + // copy Help's image show/hide functionality in OLs + var dismissFullImage; + + $('ol img').each(function(index, elem) { + return $(elem).parent().prepend(elem); + }); + + $(document).on('click', 'ol img', function(event) { + var $fullImg, $img; + dismissFullImage(); + $img = $(event.currentTarget).clone(); + $fullImg = $('
+```
+
+The script will check your server to see if an alternative image exists at `/images/my_image@2x.png`
+
+However, if you have:
+
+```html
+
+```
+
+The script will use `http://example.com/my_image@2x.png` as the high-resolution image. No checks to the server will be performed.
+
+## How to use
+
+### JavaScript
+
+The JavaScript helper script automatically replaces images on your page with high-resolution variants (if they exist). To use it, download the script and include it at the bottom of your page.
+
+1. Place the retina.js file on your server
+2. Include the script on your page (put it at the bottom of your template, before your closing \ tag)
+
+``` html
+
+```
+
+### LESS
+
+The LESS CSS mixin is a helper for applying high-resolution background images in your stylesheet. You provide it with an image path and the dimensions of the original-resolution image. The mixin creates a media query specifically for Retina displays, changes the background image for the selector elements to use the high-resolution (@2x) variant and applies a background-size of the original image in order to maintain proper dimensions. To use it, download the mixin, import or include it in your LESS stylesheet, and apply it to elements of your choice.
+
+*Syntax:*
+
+``` less
+.at2x(@path, [optional] @width: auto, [optional] @height: auto);
+```
+
+*Steps:*
+
+1. Add the .at2x() mixin from retina.less to your LESS stylesheet (or reference it in an @import statement)
+2. In your stylesheet, call the .at2x() mixin anywhere instead of using background-image
+
+This:
+
+``` less
+.logo {
+ .at2x('/images/my_image.png', 200px, 100px);
+}
+```
+
+Will compile to:
+
+``` less
+.logo {
+ background-image: url('/images/my_image.png');
+}
+
+@media all and (-webkit-min-device-pixel-ratio: 1.5) {
+ .logo {
+ background-image: url('/images/my_image@2x.png');
+ background-size: 200px 100px;
+ }
+}
+```
+
+### Ruby on Rails 3.x
+
+...or any framework that embeds some digest/hash to the asset URLs based on the contents, e.g. `/images/image-{hash1}.jpg`.
+
+The problem with this is that the high-resolution version would have a different hash, and would not conform the usual pattern, i.e. `/images/image@2x-{hash2}.jpg`. So automatic detection would fail because retina.js would check the existence of `/images/image-{hash1}@2x.jpg`.
+
+There's no way for retina.js to know beforehand what the high-resolution image's hash would be without some sort of help from the server side. So in this case, the suggested method is to supply the high-resolution URLs using the `data-at2x` attributes as previously described in the How It Works section.
+
+In Rails, one way to automate this is using a helper, e.g.:
+
+```ruby
+# in app/helpers/some_helper.rb or app/helpers/application_helper.rb
+def image_tag_with_at2x(name_at_1x, options={})
+ name_at_2x = name_at_1x.gsub(%r{\.\w+$}, '@2x\0')
+ image_tag(name_at_1x, options.merge("data-at2x" => asset_path(name_at_2x)))
+end
+```
+
+And then in your views (templates), instead of using image_tag, you would use image_tag_with_at2x, e.g. for ERB:
+
+```erb
+<%= image_tag_with_at2x "logo.png" %>
+```
+
+It would generate something like:
+
+```html
+
+```
+
+## How to test
+
+We use [mocha](http://visionmedia.github.com/mocha/) for unit testing with [should](https://github.com/visionmedia/should.js) assertions. Install mocha and should by running `npm install`.
+
+To run the test suite:
+
+``` bash
+$ npm test
+```
+
+Use [http-server](https://github.com/nodeapps/http-server) for node.js to test it. To install, run `npm install -g http-server`.
+
+If you've updated `retina.js` be sure to copy it from `src/retina.js` to `test/functional/public/retina.js`.
+
+To start the server, run:
+
+``` bash
+$ cd test/functional && http-server
+```
+
+Then navigate your browser to [http://localhost:8080](http://localhost:8080)
+
+After that, open up `test/functional/public/index.html` in your editor, and try commenting out the line that spoofs retina support, and reloading it.
diff --git a/assets/vendor/retinajs/package.json b/assets/vendor/retinajs/package.json
new file mode 100644
index 0000000000..f35dc1796f
--- /dev/null
+++ b/assets/vendor/retinajs/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "retina.js",
+ "version": "1.1.0",
+ "devDependencies": {
+ "mocha": "*",
+ "should": "*",
+ "less": "*"
+ },
+ "main": "./src/retina",
+ "scripts": {
+ "test": "mocha"
+ }
+}
diff --git a/assets/vendor/retinajs/src/retina.js b/assets/vendor/retinajs/src/retina.js
new file mode 100644
index 0000000000..c948b7f4f0
--- /dev/null
+++ b/assets/vendor/retinajs/src/retina.js
@@ -0,0 +1,143 @@
+(function() {
+
+ var root = (typeof exports == 'undefined' ? window : exports);
+
+ var config = {
+ // Ensure Content-Type is an image before trying to load @2x image
+ // https://github.com/imulus/retinajs/pull/45)
+ check_mime_type: true
+ };
+
+
+
+ root.Retina = Retina;
+
+ function Retina() {}
+
+ Retina.configure = function(options) {
+ if (options == null) options = {};
+ for (var prop in options) config[prop] = options[prop];
+ };
+
+ Retina.init = function(context) {
+ if (context == null) context = root;
+
+ var existing_onload = context.onload || new Function;
+
+ context.onload = function() {
+ var images = document.getElementsByTagName("img"), retinaImages = [], i, image;
+ for (i = 0; i < images.length; i++) {
+ image = images[i];
+ retinaImages.push(new RetinaImage(image));
+ }
+ existing_onload();
+ }
+ };
+
+ Retina.isRetina = function(){
+ var mediaQuery = "(-webkit-min-device-pixel-ratio: 1.5),\
+ (min--moz-device-pixel-ratio: 1.5),\
+ (-o-min-device-pixel-ratio: 3/2),\
+ (min-resolution: 1.5dppx)";
+
+ if (root.devicePixelRatio > 1)
+ return true;
+
+ if (root.matchMedia && root.matchMedia(mediaQuery).matches)
+ return true;
+
+ return false;
+ };
+
+
+ root.RetinaImagePath = RetinaImagePath;
+
+ function RetinaImagePath(path, at_2x_path) {
+ this.path = path;
+ if (typeof at_2x_path !== "undefined" && at_2x_path !== null) {
+ this.at_2x_path = at_2x_path;
+ this.perform_check = false;
+ } else {
+ this.at_2x_path = path.replace(/\.\w+$/, function(match) { return "@2x" + match; });
+ this.perform_check = true;
+ }
+ }
+
+ RetinaImagePath.confirmed_paths = [];
+
+ RetinaImagePath.prototype.is_external = function() {
+ return !!(this.path.match(/^https?\:/i) && !this.path.match('//' + document.domain) )
+ }
+
+ RetinaImagePath.prototype.check_2x_variant = function(callback) {
+ var http, that = this;
+ if (this.is_external()) {
+ return callback(false);
+ } else if (!this.perform_check && typeof this.at_2x_path !== "undefined" && this.at_2x_path !== null) {
+ return callback(true);
+ } else if (this.at_2x_path in RetinaImagePath.confirmed_paths) {
+ return callback(true);
+ } else {
+ http = new XMLHttpRequest;
+ http.open('HEAD', this.at_2x_path);
+ http.onreadystatechange = function() {
+ if (http.readyState != 4) {
+ return callback(false);
+ }
+
+ if (http.status >= 200 && http.status <= 399) {
+ if (config.check_mime_type) {
+ var type = http.getResponseHeader('Content-Type');
+ if (type == null || !type.match(/^image/i)) {
+ return callback(false);
+ }
+ }
+
+ RetinaImagePath.confirmed_paths.push(that.at_2x_path);
+ return callback(true);
+ } else {
+ return callback(false);
+ }
+ }
+ http.send();
+ }
+ }
+
+
+
+ function RetinaImage(el) {
+ this.el = el;
+ this.path = new RetinaImagePath(this.el.getAttribute('src'), this.el.getAttribute('data-at2x'));
+ var that = this;
+ this.path.check_2x_variant(function(hasVariant) {
+ if (hasVariant) that.swap();
+ });
+ }
+
+ root.RetinaImage = RetinaImage;
+
+ RetinaImage.prototype.swap = function(path) {
+ if (typeof path == 'undefined') path = this.path.at_2x_path;
+
+ var that = this;
+ function load() {
+ if (! that.el.complete) {
+ setTimeout(load, 5);
+ } else {
+ that.el.setAttribute('width', that.el.offsetWidth);
+ that.el.setAttribute('height', that.el.offsetHeight);
+ that.el.setAttribute('src', path);
+ }
+ }
+ load();
+ }
+
+
+
+
+ if (Retina.isRetina()) {
+ Retina.init(root);
+ }
+
+})();
+
diff --git a/assets/vendor/retinajs/src/retina.less b/assets/vendor/retinajs/src/retina.less
new file mode 100644
index 0000000000..3b96a416cd
--- /dev/null
+++ b/assets/vendor/retinajs/src/retina.less
@@ -0,0 +1,14 @@
+// retina.less
+// A helper mixin for applying high-resolution background images (http://www.retinajs.com)
+
+@highdpi: ~"(-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-resolution: 1.5dppx)";
+
+.at2x(@path, @w: auto, @h: auto) {
+ background-image: url(@path);
+ @at2x_path: ~`@{path}.replace(/\.\w+$/, function(match) { return "@2x" + match; })`;
+
+ @media @highdpi {
+ background-image: url("@{at2x_path}");
+ background-size: @w @h;
+ }
+}
diff --git a/assets/vendor/retinajs/test/fixtures/desired_output.css b/assets/vendor/retinajs/test/fixtures/desired_output.css
new file mode 100644
index 0000000000..493c281363
--- /dev/null
+++ b/assets/vendor/retinajs/test/fixtures/desired_output.css
@@ -0,0 +1,18 @@
+body {
+ background-image: url('/path/to/image.png');
+}
+@media (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-resolution: 1.5dppx) {
+ body {
+ background-image: url("/path/to/image@2x.png");
+ background-size: 200px 100px;
+ }
+}
+header {
+ background-image: url("/path/to/header.png");
+}
+@media (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-resolution: 1.5dppx) {
+ header {
+ background-image: url("/path/to/header@2x.png");
+ background-size: 600px 50px;
+ }
+}
diff --git a/assets/vendor/retinajs/test/fixtures/image.js b/assets/vendor/retinajs/test/fixtures/image.js
new file mode 100644
index 0000000000..976b56be8f
--- /dev/null
+++ b/assets/vendor/retinajs/test/fixtures/image.js
@@ -0,0 +1,19 @@
+function Image() {
+ this.complete = true;
+ this.attributes = {
+ src : "/images/some_image.png",
+ offsetWidth : 500,
+ offsetHeight : 400
+ };
+}
+
+Image.prototype.setAttribute = function(name, value) {
+ this.attributes[name] = value;
+}
+
+Image.prototype.getAttribute = function(name) {
+ return this.attributes[name];
+}
+
+var root = (exports || window);
+root.Image = Image;
diff --git a/assets/vendor/retinajs/test/fixtures/test.less b/assets/vendor/retinajs/test/fixtures/test.less
new file mode 100644
index 0000000000..47e13f7533
--- /dev/null
+++ b/assets/vendor/retinajs/test/fixtures/test.less
@@ -0,0 +1,10 @@
+@import 'src/retina';
+
+// Single quoted
+body {
+ .at2x('/path/to/image.png', 200px, 100px);
+}
+// Double quoted
+header {
+ .at2x("/path/to/header.png", 600px, 50px);
+}
diff --git a/assets/vendor/retinajs/test/fixtures/xml_http_request.js b/assets/vendor/retinajs/test/fixtures/xml_http_request.js
new file mode 100644
index 0000000000..7c26b1cab7
--- /dev/null
+++ b/assets/vendor/retinajs/test/fixtures/xml_http_request.js
@@ -0,0 +1,24 @@
+function XMLHttpRequest() {
+ this.status = XMLHttpRequest.status;
+ this.contentType = XMLHttpRequest.contentType;
+ this.readyState = 4;
+ this.onreadystatechange = function() {}
+}
+
+XMLHttpRequest.status = 200;
+XMLHttpRequest.contentType = 'image/png';
+
+XMLHttpRequest.prototype.open = function() {
+ return true;
+}
+
+XMLHttpRequest.prototype.send = function() {
+ this.onreadystatechange();
+}
+
+XMLHttpRequest.prototype.getResponseHeader = function(contentType) {
+ return this.contentType;
+}
+
+var root = (exports || window);
+root.XMLHttpRequest = XMLHttpRequest;
diff --git a/assets/vendor/retinajs/test/functional/public/google.png b/assets/vendor/retinajs/test/functional/public/google.png
new file mode 100644
index 0000000000..533d2b2737
Binary files /dev/null and b/assets/vendor/retinajs/test/functional/public/google.png differ
diff --git a/assets/vendor/retinajs/test/functional/public/google@1x.png b/assets/vendor/retinajs/test/functional/public/google@1x.png
new file mode 100644
index 0000000000..533d2b2737
Binary files /dev/null and b/assets/vendor/retinajs/test/functional/public/google@1x.png differ
diff --git a/assets/vendor/retinajs/test/functional/public/google@2x.png b/assets/vendor/retinajs/test/functional/public/google@2x.png
new file mode 100644
index 0000000000..99b37d55bf
Binary files /dev/null and b/assets/vendor/retinajs/test/functional/public/google@2x.png differ
diff --git a/assets/vendor/retinajs/test/functional/public/index.html b/assets/vendor/retinajs/test/functional/public/index.html
new file mode 100644
index 0000000000..8dc85f57fd
--- /dev/null
+++ b/assets/vendor/retinajs/test/functional/public/index.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/vendor/retinajs/test/functional/public/ipad_hero.jpeg b/assets/vendor/retinajs/test/functional/public/ipad_hero.jpeg
new file mode 100644
index 0000000000..40943cb679
Binary files /dev/null and b/assets/vendor/retinajs/test/functional/public/ipad_hero.jpeg differ
diff --git a/assets/vendor/retinajs/test/functional/public/ipad_hero@1x.jpeg b/assets/vendor/retinajs/test/functional/public/ipad_hero@1x.jpeg
new file mode 100644
index 0000000000..40943cb679
Binary files /dev/null and b/assets/vendor/retinajs/test/functional/public/ipad_hero@1x.jpeg differ
diff --git a/assets/vendor/retinajs/test/functional/public/ipad_hero@2x.jpeg b/assets/vendor/retinajs/test/functional/public/ipad_hero@2x.jpeg
new file mode 100644
index 0000000000..da7a1709d4
Binary files /dev/null and b/assets/vendor/retinajs/test/functional/public/ipad_hero@2x.jpeg differ
diff --git a/assets/vendor/retinajs/test/mocha.opts b/assets/vendor/retinajs/test/mocha.opts
new file mode 100644
index 0000000000..24d45f5902
--- /dev/null
+++ b/assets/vendor/retinajs/test/mocha.opts
@@ -0,0 +1,3 @@
+--require should
+--slow 20
+--growl
diff --git a/assets/vendor/retinajs/test/retina.test.js b/assets/vendor/retinajs/test/retina.test.js
new file mode 100644
index 0000000000..6dc3ad4934
--- /dev/null
+++ b/assets/vendor/retinajs/test/retina.test.js
@@ -0,0 +1,36 @@
+// Create a document object because we don't have one
+// in our Node test environment
+delete global.document;
+global.document = {};
+
+var Retina = require('../').Retina;
+
+describe('Retina', function() {
+
+ before(function(){
+ // stub out the getElementsByTagName method
+ global.document = {
+ getElementsByTagName : function(){
+ return [];
+ }
+ }
+ });
+
+ describe('init', function(){
+ it('stashes the existing onload and executes it later', function(){
+ var existingOnloadExecutions = 0;
+ var window = {
+ matchMedia : function() {
+ return { matches: false }
+ },
+ onload : function() {
+ existingOnloadExecutions++;
+ }
+ };
+ Retina.init(window);
+ window.onload();
+ existingOnloadExecutions.should.equal(1);
+ });
+ });
+
+});
diff --git a/assets/vendor/retinajs/test/retina_image_path.test.js b/assets/vendor/retinajs/test/retina_image_path.test.js
new file mode 100644
index 0000000000..439d711b4a
--- /dev/null
+++ b/assets/vendor/retinajs/test/retina_image_path.test.js
@@ -0,0 +1,195 @@
+// Create a document object because we don't have one
+// in our Node test environment
+delete global.document;
+global.document = {};
+global.Image = require('./fixtures/image').Image;
+global.XMLHttpRequest = require('./fixtures/xml_http_request').XMLHttpRequest;
+
+global.exports = {
+ devicePixelRatio : 0.9,
+ matchMedia : function() {
+ return {
+ matches : false
+ }
+ }
+}
+
+var Retina = require('../').Retina;
+var RetinaImage = require('../').RetinaImage;
+var RetinaImagePath = require('../').RetinaImagePath;
+
+describe('RetinaImagePath', function() {
+ var path = null;
+
+ before(function(){
+ global.document = {domain: null};
+ });
+
+ describe('@at_2x_path', function(){
+ it('adds "@2x" before the extension', function(){
+ path = new RetinaImagePath("/path/to/image.png");
+ path.at_2x_path.should.equal("/path/to/image@2x.png");
+ });
+
+ it('uses data-@2x when supplied', function(){
+ path = new RetinaImagePath("/path/to/image-hash1.png", "/path/to/image@2x-hash2.png");
+ path.at_2x_path.should.equal("/path/to/image@2x-hash2.png");
+ });
+ });
+
+ describe('#is_external()', function() {
+ it('should return true when image path references a remote domain with www', function() {
+ document.domain = "www.apple.com";
+ path = new RetinaImagePath("http://www.google.com/images/some_image.png");
+ path.is_external().should.equal(true);
+ });
+
+ it('should return true when image path references a remote domain without www', function() {
+ document.domain = "www.apple.com";
+ path = new RetinaImagePath("http://google.com/images/some_image.png");
+ path.is_external().should.equal(true);
+ });
+
+ it('should return true when image path references a remote domain with https', function() {
+ document.domain = "www.apple.com";
+ path = new RetinaImagePath("https://google.com/images/some_image.png");
+ path.is_external().should.equal(true);
+ });
+
+ it('should return true when image path is a remote domain with www and domain is localhost', function() {
+ document.domain = "localhost";
+ path = new RetinaImagePath("http://www.google.com/images/some_image.png");
+ path.is_external().should.equal(true);
+ });
+
+ it('should return true when image path is a remote domain without www and domain is localhost', function() {
+ document.domain = "localhost"
+ path = new RetinaImagePath("http://google.com/images/some_image.png")
+ path.is_external().should.equal(true);
+ });
+
+ it('should return true when image path has www and domain does not', function() {
+ document.domain = "apple.com";
+ path = new RetinaImagePath("http://www.apple.com/images/some_image.png");
+ path.is_external().should.equal(true);
+ });
+
+ it('should return true when image path does not have www and domain does', function() {
+ document.domain = "www.apple.com";
+ path = new RetinaImagePath("http://apple.com/images/some_image.png");
+ path.is_external().should.equal(true);
+ });
+
+ it('should return false when image path is relative with www', function() {
+ document.domain = "www.apple.com";
+ path = new RetinaImagePath("/images/some_image.png");
+ path.is_external().should.equal(false);
+ });
+
+ it('should return false when image path is relative without www', function() {
+ document.domain = "apple.com";
+ path = new RetinaImagePath("/images/some_image.png");
+ path.is_external().should.equal(false);
+ });
+
+ it('should return false when image path is relative to localhost', function() {
+ document.domain = "localhost";
+ path = new RetinaImagePath("/images/some_image.png");
+ path.is_external().should.equal(false);
+ });
+
+ it('should return false when image path has same domain as current site with www', function() {
+ document.domain = "www.apple.com";
+ path = new RetinaImagePath("http://www.apple.com/images/some_image.png");
+ path.is_external().should.equal(false);
+ });
+ });
+
+ describe('#check_2x_variant()', function() {
+ it('should callback with false when #is_external() is true', function(done) {
+ document.domain = "www.apple.com";
+ path = new RetinaImagePath("http://google.com/images/some_image.png");
+ path.check_2x_variant(function(hasVariant) {
+ hasVariant.should.equal(false);
+ done();
+ });
+ });
+
+ it('should callback with true when at2x is supplied', function(done) {
+ path = new RetinaImagePath("/images/some_image.png", "/images/some_image@100x.png");
+ path.check_2x_variant(function(hasVariant) {
+ hasVariant.should.equal(true);
+ done();
+ });
+ });
+
+ it('should callback with false when remote at2x image does not exist', function(done) {
+ XMLHttpRequest.status = 404; // simulate a failing request
+ XMLHttpRequest.contentType = 'image/png'; // simulate a proper content type
+ path = new RetinaImagePath("/images/some_image.png");
+ path.check_2x_variant(function(hasVariant) {
+ hasVariant.should.equal(false);
+ done();
+ });
+ });
+
+ it('should callback with false when content-type is not an image type', function(done) {
+ XMLHttpRequest.status = 200; // simulate a an image request that comes back OK
+ XMLHttpRequest.contentType = 'text/html'; // but is actually an improperly coded 404 page
+ path = new RetinaImagePath("/images/some_image.png");
+ path.check_2x_variant(function(hasVariant) {
+ hasVariant.should.equal(false);
+ done();
+ });
+ });
+
+ it('should callback with true when content-type is wrong, but check_mime_type is false', function(done) {
+ XMLHttpRequest.status = 200; // simulate a proper request
+ XMLHttpRequest.contentType = 'text/html'; // but with an incorrect content type
+
+ Retina.configure({
+ check_mime_type: false // but ignore it
+ });
+
+ path = new RetinaImagePath("/images/some_image.png");
+ path.check_2x_variant(function(hasVariant) {
+ hasVariant.should.equal(true);
+
+ Retina.configure({
+ check_mime_type: true
+ });
+
+ done();
+ });
+ });
+
+ it('should callback with true when remote at2x image exists', function(done) {
+ XMLHttpRequest.status = 200; // simulate a proper request
+ XMLHttpRequest.contentType = 'image/png'; // simulate a proper content type
+ path = new RetinaImagePath("/images/some_image.png");
+ path.check_2x_variant(function(hasVariant) {
+ hasVariant.should.equal(true);
+ done();
+ });
+ });
+
+ it('should add path to cache when at2x image exists', function(done) {
+ XMLHttpRequest.status = 200; // simulate a proper request
+ XMLHttpRequest.contentType = 'image/png'; // simulate a proper content type
+ path = new RetinaImagePath("/images/some_image.png");
+ path.check_2x_variant(function(hasVariant) {
+ RetinaImagePath.confirmed_paths.should.include(path.at_2x_path);
+ done();
+ });
+ });
+
+ it('should return true when the at2x image path has already been checked and confirmed', function(done) {
+ RetinaImagePath.confirmed_paths = ['/images/some_image@2x.png']
+ path = new RetinaImagePath("/images/some_image.png")
+ path.check_2x_variant(function(hasVariant) {
+ hasVariant.should.equal(true);
+ done();
+ });
+ });
+ });
+});
diff --git a/assets/vendor/retinajs/test/retina_less.test.js b/assets/vendor/retinajs/test/retina_less.test.js
new file mode 100644
index 0000000000..7268ab14e4
--- /dev/null
+++ b/assets/vendor/retinajs/test/retina_less.test.js
@@ -0,0 +1,17 @@
+var fs = require('fs');
+var less = require('less');
+
+describe('retina.less', function() {
+
+ describe('.at2x()', function(){
+ it('compiles correctly', function(done){
+ var desired_output = fs.readFileSync('test/fixtures/desired_output.css', 'utf8');
+ var input = fs.readFileSync('test/fixtures/test.less', 'utf8');
+ less.render(input, function (e, actual_output) {
+ actual_output.should.equal(desired_output);
+ done();
+ });
+ });
+ });
+
+});
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000000..d2ddf6b081
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,8 @@
+{
+ "name": "developer.github.com",
+ "dependencies": {
+ "lunr.js": "0.6.0",
+ "octicons": "3.0.1",
+ "retinajs": "1.1.0"
+ }
+}
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000000..6763c19b6b
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,5 @@
+# This file is auto-generated by Jekyll Auth
+# It tells Heroku how to launch our site
+
+require "jekyll-auth"
+run JekyllAuth.site
diff --git a/config.yaml b/config.yaml
deleted file mode 100644
index b2a6c6213a..0000000000
--- a/config.yaml
+++ /dev/null
@@ -1,56 +0,0 @@
-# A list of file extensions that nanoc will consider to be textual rather than
-# binary. If an item with an extension not in this list is found, the file
-# will be considered as binary.
-text_extensions: [ 'css', 'erb', 'haml', 'htm', 'html', 'js', 'less', 'markdown', 'md', 'php', 'rb', 'sass', 'scss', 'txt', 'xhtml', 'xml', 'atom' ]
-
-# The path to the directory where all generated files will be written to. This
-# can be an absolute path starting with a slash, but it can also be path
-# relative to the site directory.
-output_dir: output
-
-# A list of index filenames, i.e. names of files that will be served by a web
-# server when a directory is requested. Usually, index files are named
-# “index.hml”, but depending on the web server, this may be something else,
-# such as “default.htm”. This list is used by nanoc to generate pretty URLs.
-index_filenames: [ 'index.html' ]
-
-# Whether or not to generate a diff of the compiled content when compiling a
-# site. The diff will contain the differences between the compiled content
-# before and after the last site compilation.
-enable_output_diff: false
-
-# The data sources where nanoc loads its data from. This is an array of
-# hashes; each array element represents a single data source. By default,
-# there is only a single data source that reads data from the “content/” and
-# “layout/” directories in the site directory.
-data_sources:
- -
- # The type is the identifier of the data source. By default, this will be
- # `filesystem_unified`.
- type: filesystem_unified
-
- # The path where items should be mounted (comparable to mount points in
- # Unix-like systems). This is “/” by default, meaning that items will have
- # “/” prefixed to their identifiers. If the items root were “/en/”
- # instead, an item at content/about.html would have an identifier of
- # “/en/about/” instead of just “/about/”.
- items_root: /
-
- # The path where layouts should be mounted. The layouts root behaves the
- # same as the items root, but applies to layouts rather than items.
- layouts_root: /
-
- -
- type: static
- items_root: /static
-
-# For the atom feed.
-base_url: http://developer.github.com
-
-# Array of [version, released_at] Array tuples.
-api_versions:
- -
- - beta
- - 2011-4-27
- -
- - v3
diff --git a/content/404.html b/content/404.html
new file mode 100644
index 0000000000..77bc3992f1
--- /dev/null
+++ b/content/404.html
@@ -0,0 +1,7 @@
+---
+title: GitHub Help • Article not found!
+exclude_from_search: true
+---
++ API v3 will continue to officially support the functionality described in + Phase 1 above. This functionality will remain intact for the lifetime of + API v3. +
++ API v3 will not include Phases 2 and 3 (below). Those phases will + likely be part of the next major version of the API. (We have not announced + a timeline for the next major version of the API.) +
+/watchers API Endpoint/user/starred to get a user's starred repositories, not
+/user/watched.application/vnd.github.v3+json
+# Accesses a user's watched repositories. +curl https://api.github.com/user/watched \ + -H "Accept: application/vnd.github.v3+json" ++
/subscribers API Endpoint.
-curl -i -u pengwynn \
- -d '{"name": "create-repo-test", "auto_init": true}' \
- https://api.github.com/user/repos
-
+``` command-line
+$ curl -i -u pengwynn \
+$ -d '{"name": "create-repo-test", "auto_init": true}' \
+$ https://api.github.com/user/repos
+```
The resulting repository will have a README stub and an initial commit.
-
+
### .gitignore templates
@@ -29,13 +27,12 @@
the basename of any template in the [GitHub gitignore templates
project](https://github.com/github/gitignore).
-
-curl -i -u pengwynn \
- -d '{"name": "create-repo-test", "auto_init": true, \
- "gitignore_template": "Haskell"}' \
- https://api.github.com/user/repos
-
-
+``` command-line
+$ curl -i -u pengwynn \
+$ -d '{"name": "create-repo-test", "auto_init": true, \
+$ "gitignore_template": "Haskell"}' \
+$ https://api.github.com/user/repos
+```
As the [docs point out](/v3/repos/#create), the `gitignore_template` parameter
is ignored if `auto_init` is not present and `true`.
@@ -47,4 +44,3 @@
[twitter]: https://twitter.com/githubapi
[email]: mailto:support@github.com
[c]: https://github.com/c
-
diff --git a/content/changes/2012-10-14-rate-limit-changes.html b/content/changes/2012-10-14-rate-limit-changes.html
index b33e2cf9bc..60aa94f4fa 100644
--- a/content/changes/2012-10-14-rate-limit-changes.html
+++ b/content/changes/2012-10-14-rate-limit-changes.html
@@ -1,7 +1,5 @@
---
-kind: change
title: Rate limit changes for unauthenticated requests
-created_at: 2012-10-14
author_name: pengwynn
---
@@ -11,7 +9,7 @@
[authenticate](http://developer.github.com/v3/#authentication) via Basic Auth
or OAuth. Unauthenticated requests will be limited to 60 per hour unless you
[include your OAuth client and
-secret](http://developer.github.com/v3/#unauthenticated-rate-limited-requests).
+secret](http://developer.github.com/v3/#increasing-the-unauthenticated-rate-limit-for-oauth-applications).
We'll soon require all requests to include a valid [User Agent
header](http://en.wikipedia.org/wiki/User_agent). Setting a
diff --git a/content/changes/2012-10-17-org-members-redirection.md b/content/changes/2012-10-17-org-members-redirection.md
index 1bb651ba07..ace24c0173 100644
--- a/content/changes/2012-10-17-org-members-redirection.md
+++ b/content/changes/2012-10-17-org-members-redirection.md
@@ -1,13 +1,11 @@
---
-kind: change
title: Organization Members Resource Changes
-created_at: 2012-10-17
author_name: pezra
---
Requesting the [member list](/v3/orgs/members/index.html#members-list) of an
organization of which you are not a member now redirects to the [public members
-list](v3/orgs/members/index.html#public-members-list). Similarly, requests to
+list](/v3/orgs/members/index.html#public-members-list). Similarly, requests to
[membership check](/v3/orgs/members/index.html#check-membership) resources of
an organization of which you are not a member are redirected to the equivalent
[public membership check](/v3/orgs/members/index.html#check-public-membership).
diff --git a/content/changes/2012-10-24-set-default-branch.html b/content/changes/2012-10-24-set-default-branch.html
index 05bb456161..ac9800b41b 100644
--- a/content/changes/2012-10-24-set-default-branch.html
+++ b/content/changes/2012-10-24-set-default-branch.html
@@ -1,21 +1,19 @@
---
-kind: change
title: Set the default branch for a repository
-created_at: 2012-10-24
author_name: pengwynn
---
You can set the default branch for a repository to something other than 'master' from the GitHub repository admin screen:
-
+
Now, you can update this setting via the API. We've added a `default_branch` parameter to the [Edit Repository method][edit-repo]:
-
-curl -u pengwynn \
- -d '{"name": "octokit", "default_branch":"development"}' \
- https://api.github.com/repos/pengwynn/octokit
-
+``` command-line
+$ curl -u pengwynn \
+$ -d '{"name": "octokit", "default_branch":"development"}' \
+$ https://api.github.com/repos/octokit/octokit.rb
+```
If you provide a branch name that hasn't been pushed to GitHub, we'll gracefully fall back to `'master'` or the first branch.
diff --git a/content/changes/2012-10-26-notifications-api.md b/content/changes/2012-10-26-notifications-api.md
index 6d1e6bd3e4..db08698377 100644
--- a/content/changes/2012-10-26-notifications-api.md
+++ b/content/changes/2012-10-26-notifications-api.md
@@ -1,7 +1,5 @@
---
-kind: change
title: Notifications API
-created_at: 2012-10-26
author_name: technoweenie
---
@@ -17,56 +15,54 @@ view and mark notifications as read.
The core notifications functionality is under the `/notifications` endpoint.
You can look for unread notifications:
-+``` command-line $ curl https://api.github.com/notifications -+``` You can filter these notifications to a single Repository: -
+``` command-line $ curl https://api.github.com/repos/technoweenie/faraday/notifications -+``` You can mark them as read: -
+``` command-line
# all notifications
$ curl https://api.github.com/notifications \
- -X PUT -d '{"read": true}'
+$ -X PUT -d '{"read": true}'
# notifications for a single repository
$ curl https://api.github.com/repos/technoweenie/faraday/notifications \
- -X PUT -d '{"read": true}'
-
+$ -X PUT -d '{"read": true}'
+```
You can also modify subscriptions for a Repository or a single thread.
-+``` command-line # subscription details for the thread (either an Issue or Commit) $ curl https://api.github.com/notifications/threads/1/subscription # subscription details for a whole Repository. $ curl https://api.github.com/repos/technoweenie/faraday/subscription -+``` ## Polling The Notifications API is optimized for polling by the last modified time: -
+``` command-line # Add authentication to your requests $ curl -I https://api.github.com/notifications -HTTP/1.1 200 OK -Last-Modified: Thu, 25 Oct 2012 15:16:27 GMT -X-Poll-Interval: 60 +> HTTP/1.1 200 OK +> Last-Modified: Thu, 25 Oct 2012 15:16:27 GMT +> X-Poll-Interval: 60 # Pass the Last-Modified header exactly $ curl -I https://api.github.com/notifications - -H "If-Modified-Since: Thu, 25 Oct 2012 15:16:27 GMT" -HTTP/1.1 304 Not Modified -X-Poll-Interval: 60 -+$ -H "If-Modified-Since: Thu, 25 Oct 2012 15:16:27 GMT" +> HTTP/1.1 304 Not Modified +> X-Poll-Interval: 60 +``` You can read about the API details in depth in the [Notifications documentation][api]. - - diff --git a/content/changes/2012-10-31-gist-comment-uris.md b/content/changes/2012-10-31-gist-comment-uris.md index 09c112586c..a6f3d9e4f4 100644 --- a/content/changes/2012-10-31-gist-comment-uris.md +++ b/content/changes/2012-10-31-gist-comment-uris.md @@ -1,7 +1,5 @@ --- -kind: change title: Gist comment URIs -created_at: 2012-10-31 author_name: pezra --- diff --git a/content/changes/2012-11-27-forking-to-organizations.html b/content/changes/2012-11-27-forking-to-organizations.html index 7e4530985a..90282f045a 100644 --- a/content/changes/2012-11-27-forking-to-organizations.html +++ b/content/changes/2012-11-27-forking-to-organizations.html @@ -1,29 +1,32 @@ --- -kind: change title: Forking to Organizations -created_at: 2012-11-27 author_name: technoweenie --- We made a slight change to the way you fork a repository. By default, you can fork my repository through an HTTP POST to the repository's fork resource. - $ curl -X POST https://api.github.com/repos/technoweenie/faraday/forks +``` command-line +$ curl -X POST https://api.github.com/repos/technoweenie/faraday/forks +``` This repository forks to your personal account. However, there are cases when you want to fork to one of your organizations instead. The previous method required a `?org` query parameter: - $ curl -X POST /repos/technoweenie/faraday/forks?org=mycompany +``` command-line +$ curl -X POST /repos/technoweenie/faraday/forks?org=mycompany +``` Query parameters on POST requests are unusual in APIs, and definitely inconsistent with the rest of the GitHub API. You should be able to post a JSON body like every other POST endpoint. Now, you can! Only, now we're calling the field `organization`. - $ curl /repos/technoweenie/faraday/forks?org=mycompany \ - -d '{"organization": "mycompany"}' +``` command-line +$ curl /repos/technoweenie/faraday/forks?org=mycompany \ +$ -d '{"organization": "mycompany"}' +``` Don't worry, we are committed to maintaining the legacy behavior until the next major change of the GitHub API. - diff --git a/content/changes/2012-11-29-gitignore-templates.html b/content/changes/2012-11-29-gitignore-templates.html index 931e12b060..d88d39b88f 100644 --- a/content/changes/2012-11-29-gitignore-templates.html +++ b/content/changes/2012-11-29-gitignore-templates.html @@ -1,58 +1,60 @@ --- -kind: change title: Gitignore Templates API -created_at: 2012-11-29 author_name: pengwynn --- We recently [made it easy][init-post] to initialize a repository when you create it [via the API][repo-create]. One of the options you can pass when creating a repository is `gitignore_template`. This value is the name of one of the -templates from the the public [GitHub .gitignore repository][templates-repo]. +templates from the public [GitHub .gitignore repository][templates-repo]. The [Gitignore Templates API][new-api] makes it easy to list those templates: - curl https://api.github.com/gitignore/templates +``` command-line +$ curl https://api.github.com/gitignore/templates - HTTP/1.1 200 OK +> HTTP/1.1 200 OK - [ - "Actionscript", - "Android", - "AppceleratorTitanium", - "Autotools", - "Bancha", - "C", - "C++", - ... +> [ +> "Actionscript", +> "Android", +> "AppceleratorTitanium", +> "Autotools", +> "Bancha", +> "C", +> "C++", +> ... +``` If you'd like to view the source, you can also fetch a single template. - curl -H 'Accept: application/vnd.github.raw' \ - https://api.github.com/gitignore/templates/Objective-C - - HTTP/1.1 200 OK - - # Xcode - .DS_Store - build/ - *.pbxuser - !default.pbxuser - *.mode1v3 - !default.mode1v3 - *.mode2v3 - !default.mode2v3 - *.perspectivev3 - !default.perspectivev3 - *.xcworkspace - !default.xcworkspace - xcuserdata - profile - *.moved-aside - DerivedData - .idea/ - -[init-post]: /changes/2012-9-28-auto-init-for-repositories/ +``` command-line +$ curl -H 'Accept: application/vnd.github.raw' \ +$ https://api.github.com/gitignore/templates/Objective-C + +> HTTP/1.1 200 OK + +# Xcode +> .DS_Store +> build/ +> *.pbxuser +> !default.pbxuser +> *.mode1v3 +> !default.mode1v3 +> *.mode2v3 +> !default.mode2v3 +> *.perspectivev3 +> !default.perspectivev3 +> *.xcworkspace +> !default.xcworkspace +> xcuserdata +> profile +> *.moved-aside +> DerivedData +> .idea/ +``` + +[init-post]: /changes/2012-09-28-auto-init-for-repositories/ [repo-create]: /v3/repos/#create [templates-repo]: https://github.com/github/gitignore [new-api]: /v3/gitignore/ diff --git a/content/changes/2012-12-04-List-comments-for-repo.html b/content/changes/2012-12-04-List-comments-for-repo.html new file mode 100644 index 0000000000..7511737cdc --- /dev/null +++ b/content/changes/2012-12-04-List-comments-for-repo.html @@ -0,0 +1,24 @@ +--- +title: Per-repository Review and Issue Comment listing +author_name: pengwynn +--- + +You've always been able to grab all the commit comments for an entire +repository via the API, but to get Issue comments and Pull Request Review +Comments, you could only fetch the comments for a single Issue or Pull Request. + +Today, we're introducing two new methods to grab all Issue Comments and Review +Comments for a repository. + +``` command-line +# Grab all Issue Comments +> curl https://api.github.com/repos/mathiasbynens/dotfiles/issues/comments + +# Grab all Review Comments +> curl https://api.github.com/repos/mathiasbynens/dotfiles/pulls/comments +``` + +Check out the docs for sorting and filtering options: + +* [Issue comments](/v3/issues/comments/#list-comments-in-a-repository) +* [Review comments](/v3/pulls/comments/#list-comments-in-a-repository) diff --git a/content/changes/2012-12-06-create-authorization-for-app.html b/content/changes/2012-12-06-create-authorization-for-app.html new file mode 100644 index 0000000000..a1de9eb1b0 --- /dev/null +++ b/content/changes/2012-12-06-create-authorization-for-app.html @@ -0,0 +1,36 @@ +--- +title: Create an OAuth authorization for an app +author_name: pengwynn +--- + +The [Authorizations API][oauth-api] is an easy way to create an OAuth +authorization using Basic Auth. Just POST your desired scopes and optional +note and you get a token back: + +``` command-line +$ curl -u pengwynn -d '{"scopes": ["user", "gist"]}' \ +$ https://api.github.com/authorizations +``` + +This call creates a token for the authenticated user tied to a special "API" +OAuth application. + +We now support creating tokens for _your own OAuth application_ by passing your +twenty character `client_id` and forty character `client_secret` as found in +the settings page for your OAuth application. + + +``` command-line +$ curl -u pengwynn -d '{ \ +$ "scopes": ["user", "gist"], \ +$ "client_id": "abcdeabcdeabcdeabcdeabcde" \ +$ "client_secret": "abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde" \ +$ }' \ ' +$ https://api.github.com/authorizations +``` + +No more implementing the [web flow][web-flow] just to get a token tied to your +app's rate limit. + +[oauth-api]: /v3/oauth_authorizations/#oauth-authorizations-api +[web-flow]: /v3/oauth/#web-application-flow diff --git a/content/changes/2012-12-08-finding-source-and-fork-repos-for-organizations.html b/content/changes/2012-12-08-finding-source-and-fork-repos-for-organizations.html new file mode 100644 index 0000000000..bd9f91bedf --- /dev/null +++ b/content/changes/2012-12-08-finding-source-and-fork-repos-for-organizations.html @@ -0,0 +1,22 @@ +--- +title: Finding sources and fork repositories for organizations +author_name: rick +--- + +We've made a couple of changes today to the Organization repositories +listing to bring it a bit closer to the functionality of the GitHub.com +Organization repositories tab. We now let you retrieve repositories +which are forks of another repository, as well as those repositories which +are sources (not forks). + +``` command-line +# Grab all fork Repositories for an Organization +$ curl "https://api.github.com/orgs/:org/repos?type=forks" + +# Grab all source Repositories for an Organization +$ curl "https://api.github.com/orgs/:org/repos?type=sources" +``` + +Check out the docs for sorting and filtering options: + +* [Organization Repositories](/v3/repos/#list-organization-repositories) diff --git a/content/changes/2012-12-09-organization-repositories-results-now-paginate.html b/content/changes/2012-12-09-organization-repositories-results-now-paginate.html new file mode 100644 index 0000000000..530d13e2ef --- /dev/null +++ b/content/changes/2012-12-09-organization-repositories-results-now-paginate.html @@ -0,0 +1,17 @@ +--- +title: Pagination for Organization Repository lists now paginates properly +author_name: rick +--- + + + +Improvements continue to the Organizations Repository listing endpoint. +Today we're improving pagination so that it works as documented. Now +you can expect `Link` headers to navigate through the results space, +regardless of what you send in the `type` parameter. + +The docs for Organization Repositories queries are still here: + +* [Organization Repositories](/v3/repos/#list-organization-repositories) + +**EDIT:** `Link` headers are our preferred navigation technique. \ No newline at end of file diff --git a/content/changes/2012-12-10-Diff-and-patch-media-types.html b/content/changes/2012-12-10-Diff-and-patch-media-types.html new file mode 100644 index 0000000000..96eb82a02a --- /dev/null +++ b/content/changes/2012-12-10-Diff-and-patch-media-types.html @@ -0,0 +1,33 @@ +--- +title: Diff and patch media types +author_name: pengwynn +--- + +Starting today, you can get `.diff` and `.patch` content directly from the API for the following resources: + +* [Commits][commits-get] +* [Commit comparisons][commits-compare] +* [Pull request][pulls] + +Simply use the same resource URL and send either `application/vnd.github.diff` or `application/vnd.github.patch` in the `Accept` header: + +``` command-line +$ curl -H "Accept: application/vnd.github.diff" $ https://api.github.com/repos/pengwynn/dotfiles/commits/aee60a4cd56fb4c6a50e60f17096fc40c0d4d72c + +> diff --git a/tmux/tmux.conf.symlink b/tmux/tmux.conf.symlink +> index 1f599cb..abaf625 100755 +> --- a/tmux/tmux.conf.symlink +> +++ b/tmux/tmux.conf.symlink +> @@ -111,6 +111,7 @@ set-option -g base-index 1 +> ## enable mouse +> set-option -g mouse-select-pane on +> set-option -g mouse-select-window on +> +set-option -g mouse-resize-pane on +> set-window-option -g mode-keys vi +> set-window-option -g mode-mouse on +> # set-window-option -g monitor-activity off +``` + +[commits-get]: /v3/repos/commits/#get-a-single-commit +[commits-compare]: /v3/repos/commits/#compare-two-commits +[pulls]: /v3/pulls/#get-a-single-pull-request diff --git a/content/changes/2013-01-08-new-user-scopes.html b/content/changes/2013-01-08-new-user-scopes.html new file mode 100644 index 0000000000..ecd48a14db --- /dev/null +++ b/content/changes/2013-01-08-new-user-scopes.html @@ -0,0 +1,20 @@ +--- +title: New User scopes +author_name: technoweenie +--- + +We've added a [few new user scopes][scopes] for 3rd party applications that want very +specific user functionality. The `user:email` scope gives apps read-only access +to a user's private email addresses. The `user:follow` scope lets a user +follow and unfollow other users. + +This should help keep applications from requiring the `user` scope, which +can be potentially dangerous. + +We also added a read-only endpoint to get a user's public SSH keys. + + GET https://api.github.com/users/technoweenie/keys + +[scopes]: http://developer.github.com/v3/oauth/#scopes +[keys]: http://developer.github.com/v3/users/keys/#list-public-keys-for-a-user + diff --git a/content/changes/2013-01-31-user-agent-will-soon-be-mandatory.html b/content/changes/2013-01-31-user-agent-will-soon-be-mandatory.html new file mode 100644 index 0000000000..3c06f81381 --- /dev/null +++ b/content/changes/2013-01-31-user-agent-will-soon-be-mandatory.html @@ -0,0 +1,19 @@ +--- +title: User Agent mandatory from March 4th 2013 +author_name: agh +--- + +Following on from our [previous post](http://developer.github.com/changes/2012-10-14-rate-limit-changes/) +about requiring requests to include a valid [User Agent header](http://en.wikipedia.org/wiki/User_agent) +we will soon be changing our API servers to return HTTP 403 +to any clients not providing a valid User Agent header. + +We will be making this change on Monday, March 4th 2013. + +Setting this helps us identify requests from you, and get in touch with people who are using +the API in a way which causes disruption to GitHub. Most HTTP libraries and tools like cURL +already provide a valid header for you, and allow you to customize it, so this will not require +many of our users to make any changes whatsoever. + +If you have any questions or feedback, please drop us a line at +[support@github.com](mailto:support@github.com?subject=User Agent Requirement). diff --git a/content/changes/2013-02-05-changes-to-services.html b/content/changes/2013-02-05-changes-to-services.html new file mode 100644 index 0000000000..4ff6d6e8cd --- /dev/null +++ b/content/changes/2013-02-05-changes-to-services.html @@ -0,0 +1,32 @@ +--- +title: Upcoming Changes to GitHub Services +author_name: technoweenie +--- + +We are finishing up a new GitHub Services backend, dubbed "Hookshot", to +increase the speed and reliability of our delivered payloads. We are doing +what we can to make this a seamless transition for everyone. However, there +are a few notable changes. + +* There is a new [Meta API endpoint](http://developer.github.com/v3/meta/) +listing the current public IPs that hooks originate from. + +* We're removing the AMQP service from GitHub. It hasn't worked in quite some +time, and the code it uses doesn't work in our background workers. + +* We're also instituting a new guideline to improve the reliability and +maintainability of services in the future. As of today, all new services must +accept an unmodified payload over HTTP. Any service that does not will be +rejected. To see an example of an acceptable service, check out [Code Climate][codeclimate]. +Notice their service simply accepts HTTP POST from GitHub unmodified. For an +example of a service that won't be accepted after today, check out [Campfire][cf]. It +uses other Ruby gems and contains custom logic to transform the GitHub payload +to Campfire messages. Existing hooks will keep working (don't worry 37signals, we +:heart: Campfire). + +We're making these changes because we want to focus on the reliability of the +core Services backend for everyone. Maintaining custom logic and libraries for +over 100 services is taking too much of this focus away. + +[codeclimate]: https://github.com/github/github-services/blob/fbc0db24b8b7685b2058462181d928a5f2a0a448/lib/services/codeclimate.rb +[cf]: https://github.com/github/github-services/blob/fbc0db24b8b7685b2058462181d928a5f2a0a448/lib/services/campfire.rb diff --git a/content/changes/2013-02-13-hookshot-issues.html b/content/changes/2013-02-13-hookshot-issues.html new file mode 100644 index 0000000000..7e69bc2ada --- /dev/null +++ b/content/changes/2013-02-13-hookshot-issues.html @@ -0,0 +1,17 @@ +--- +title: Some Hookshot Issues +author_name: technoweenie +--- + +We turned Hookshot (our new GitHub Services backend) on yesterday. Things have +been pretty smooth, with one issue: Hooks going to other EC2 nodes come from +the private IP addresses of our nodes in the 10.*.*.* range. + +If your web hook servers are on EC2 and are missing hooks from GitHub due to +an IP restriction, we recommend the following: + +1. Remove the IP white list. +2. Fall back to HTTPS and Basic Auth to restrict pushes to authorized senders only. + +We're currently working on solving this problem. Hit up [support@github.com](mailto:support@github.com) +if you have any questions. diff --git a/content/changes/2013-02-13-hookshot-load-balancer.html b/content/changes/2013-02-13-hookshot-load-balancer.html new file mode 100644 index 0000000000..fd6b3114cd --- /dev/null +++ b/content/changes/2013-02-13-hookshot-load-balancer.html @@ -0,0 +1,11 @@ +--- +title: Hookshot Load balancer +author_name: technoweenie +--- + +We had an issue with the Hookshot load balancer this morning, causing the +majority of hooks to flow to a single node only. This lead to massive queue +times. While fixing this, we're putting the old Services backend in use. + +This means the old IPs are back in use. Use this [Help guide](https://help.github.com/articles/what-ip-addresses-does-github-use-that-i-should-whitelist) +if you already removed them from your firewall. diff --git a/content/changes/2013-02-14-sortable-stars.html b/content/changes/2013-02-14-sortable-stars.html new file mode 100644 index 0000000000..d7b253b919 --- /dev/null +++ b/content/changes/2013-02-14-sortable-stars.html @@ -0,0 +1,17 @@ +--- +title: Sortable Stars in Repository Starring API +author_name: pengwynn +--- + +As we [announced on the GitHub blog][post], Stars now support sorting. The +Repository Starring API now supports [two new parameters][params] when listing +Stars: `sort` and `direction`. + +``` command-line +$ curl https://api.github.com/users/defunkt/starred?sort=created&direction=asc +``` + +Enjoy. + +[post]: https://github.com/blog/1410-sortable-stars +[params]: /v3/activity/starring/#list-repositories-being-starred diff --git a/content/changes/2013-03-01-new-hookshot-coming.html b/content/changes/2013-03-01-new-hookshot-coming.html new file mode 100644 index 0000000000..c109a40653 --- /dev/null +++ b/content/changes/2013-03-01-new-hookshot-coming.html @@ -0,0 +1,22 @@ +--- +title: New Hookshot Changes +author_name: technoweenie +--- + +We are experimenting with changes to the "Hookshot" backend that powers service +hooks. There were some significant networking changes with the new cluster, +so there are some new IP whitelist rules for hooks: + +* 204.232.175.64/27 +* 192.30.252.0/22 + +These are in CIDR notation. They represent a significant range of GitHub +addresses, meaning this should be the last IP change for a while. Once this +cluster is activated and we shut the other cluster down, we will be removing +the other entries. + +We are currently testing the new backend with all repositories in the GitHub +organization only, and expect to start testing it with user data next week. + +This also means we should be able to start accepting [GitHub Services pull +requests](https://github.com/github/github-services/pulls) very soon :) diff --git a/content/changes/2013-04-24-user-agent-required.html b/content/changes/2013-04-24-user-agent-required.html new file mode 100644 index 0000000000..b1fae21ff0 --- /dev/null +++ b/content/changes/2013-04-24-user-agent-required.html @@ -0,0 +1,14 @@ +--- +title: User Agent now mandatory +author_name: pengwynn +--- + +After an almost six week grace period, we're now enforcing the [User Agent +header][1] for all API requests. Most HTTP libraries (including cURL) +set this header by default. If you're experiencing an increase in `403` +responses, be sure and check your code. + +[1]: /v3/#user-agent-required + +If you have any questions or feedback, please drop us a line at +[support@github.com](mailto:support@github.com?subject=User Agent Requirement). diff --git a/content/changes/2013-04-25-deprecating-merge-commit-sha.html b/content/changes/2013-04-25-deprecating-merge-commit-sha.html new file mode 100644 index 0000000000..8bff84e414 --- /dev/null +++ b/content/changes/2013-04-25-deprecating-merge-commit-sha.html @@ -0,0 +1,21 @@ +--- +title: Deprecating a Confusing Attribute in the Pull Request API +author_name: jasonrudolph +--- + +When you get the details for a Pull Request from the API, the +[response](/v3/pulls/#get-a-single-pull-request) provides everything there is to +know about that Pull Request. In addition to the useful information provided in +the API response, the JSON also includes the `merge_commit_sha` attribute. This +attribute is a frequent source of misunderstanding, and we aim to remove the +confusion. + +To help current API consumers, we've [documented the +attribute](/v3/pulls/#get-a-single-pull-request) for improved understanding. + +To protect future API consumers from this confusion, we have +[deprecated](/v3/versions/#v3-deprecations) the `merge_commit_sha` attribute, and we will +remove it in the next major version of the API. + +As always, if you have any questions or feedback, please drop us a line at +[support@github.com](mailto:support@github.com?subject=Deprecating merge_commit_sha). diff --git a/content/changes/2013-04-30-improved-submodule-support-in-repository-contents-api.md b/content/changes/2013-04-30-improved-submodule-support-in-repository-contents-api.md new file mode 100644 index 0000000000..8b7598e783 --- /dev/null +++ b/content/changes/2013-04-30-improved-submodule-support-in-repository-contents-api.md @@ -0,0 +1,37 @@ +--- +title: Improved Support for Submodules in the Repository Contents API +author_name: jasonrudolph +--- + +When you view a repository with a submodule on github.com, you get useful links and information for the submodule. + +[][screenshot] + +Today we're making that data available in the [Repository Contents API][docs]. + +``` command-line +$ curl https://api.github.com/repos/jquery/jquery/contents/test/qunit + +> { +> "name": "qunit", +> "path": "test/qunit", +> "type": "submodule", +> "submodule_git_url": "git://github.com/jquery/qunit.git", +> "sha": "6ca3721222109997540bd6d9ccd396902e0ad2f9", +> "size": 0, +> "url": "https://api.github.com/repos/jquery/jquery/contents/test/qunit?ref=master", +> "git_url": "https://api.github.com/repos/jquery/qunit/git/trees/6ca3721222109997540bd6d9ccd396902e0ad2f9", +> "html_url": "https://github.com/jquery/qunit/tree/6ca3721222109997540bd6d9ccd396902e0ad2f9", +> "_links": { +> "self": "https://api.github.com/repos/jquery/jquery/contents/test/qunit?ref=master", +> "git": "https://api.github.com/repos/jquery/qunit/git/trees/6ca3721222109997540bd6d9ccd396902e0ad2f9", +> "html": "https://github.com/jquery/qunit/tree/6ca3721222109997540bd6d9ccd396902e0ad2f9" +> } +> } +``` + +If you have any questions or feedback, please drop us a line at +[support@github.com](mailto:support@github.com?subject=Submodules in Repository Contents API). + +[docs]: /v3/repos/contents/#get-contents +[screenshot]: /assets/images/posts/submodule-links.png diff --git a/content/changes/2013-04-30-statuses-for-branches-and-tags.md b/content/changes/2013-04-30-statuses-for-branches-and-tags.md new file mode 100644 index 0000000000..b42aafdb81 --- /dev/null +++ b/content/changes/2013-04-30-statuses-for-branches-and-tags.md @@ -0,0 +1,17 @@ +--- +title: Commit Statuses Now Available for Branches and Tags +author_name: foca +--- + +Last week we announced [support for build statuses in the branches page][blog]. +Now we are extending this to the API. The [API endpoint for commit statuses][doc] +has been extended to allow branch and tag names, as well as commit SHAs. + +``` command-line +curl https://api.github.com/repos/rails/rails/statuses/3-2-stable +``` + +Enjoy. + +[blog]: https://github.com/blog/1484-check-the-status-of-your-branches +[doc]: http://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref diff --git a/content/changes/2013-05-06-create-update-delete-individual-files.md b/content/changes/2013-05-06-create-update-delete-individual-files.md new file mode 100644 index 0000000000..f9baff52ca --- /dev/null +++ b/content/changes/2013-05-06-create-update-delete-individual-files.md @@ -0,0 +1,21 @@ +--- +title: Create, update, and delete individual files +author_name: ymendel +--- + +We're following in the footsteps of GitHub.com's ability to [edit][web_edit] and +[create][web_create] files in your web browser. Starting today, the +[Repository Contents API][docs] will let you easily [create][], [update][], and even +[delete][] individual files. + +Happy editing! + + +[web_edit]: https://github.com/blog/143-inline-file-editing +[web_create]: https://github.com/blog/1327-creating-files-on-github + +[docs]: /v3/repos/contents/ +[create]: /v3/repos/contents/#create-a-file +[update]: /v3/repos/contents/#update-a-file +[delete]: /v3/repos/contents/#delete-a-file + diff --git a/content/changes/2013-05-06-repository-stats.md b/content/changes/2013-05-06-repository-stats.md new file mode 100644 index 0000000000..3ff4b37d97 --- /dev/null +++ b/content/changes/2013-05-06-repository-stats.md @@ -0,0 +1,18 @@ +--- +title: Repository Statistics +author_name: Caged +--- + +Today we're happy to open our [Repository Statistics API](/v3/repos/statistics) to everyone. We're using +repository statistics to power [our graphs](https://github.com/github/linguist/graphs), +but we can't wait to see what others can do with this information. + +Starting today, these resources are available to you: + +* **[Contributors](/v3/repos/statistics/#contributors)** +* **[Commit Activity](/v3/repos/statistics/#commit-activity)** +* **[Code Frequency](/v3/repos/statistics/#code-frequency)** +* **[Participation](/v3/repos/statistics/#participation)** +* **[Punch Card](/v3/repos/statistics/#punch-card)** + +Enjoy! diff --git a/content/changes/2013-07-01-feeds-api.md b/content/changes/2013-07-01-feeds-api.md new file mode 100644 index 0000000000..e15115c5bf --- /dev/null +++ b/content/changes/2013-07-01-feeds-api.md @@ -0,0 +1,52 @@ +--- +title: Feeds API +author_name: pengwynn +--- + +Today we're releasing a new [Feeds API][], an easy way to list all the Atom +resources available to the authenticated user. + +``` command-line +$ curl -u defunkt https://api.github.com/feeds + +> { +> "timeline_url": "https://github.com/timeline", +> "user_url": "https://github.com/{user}", +> "current_user_public_url": "https://github.com/defunkt", +> "current_user_url": "https://github.com/defunkt.private?token=abc123", +> "current_user_actor_url": "https://github.com/defunkt.private.actor?token=abc123", +> "current_user_organization_url": "https://github.com/organizations/{org}/defunkt.private.atom?token=abc123", +> "_links": { +> "timeline": { +> "href": "https://github.com/timeline", +> "type": "application/atom+xml" +> }, +> "user": { +> "href": "https://github.com/{user}", +> "type": "application/atom+xml" +> }, +> "current_user_public": { +> "href": "https://github.com/defunkt", +> "type": "application/atom+xml" +> }, +> "current_user": { +> "href": "https://github.com/defunkt.private?token=abc123", +> "type": "application/atom+xml" +> }, +> "current_user_actor": { +> "href": "https://github.com/defunkt.private.actor?token=abc123", +> "type": "application/atom+xml" +> }, +> "current_user_organization": { +> "href": "https://github.com/organizations/{org}/defunkt.private.atom?token=abc123", +> "type": "application/atom+xml" +> } +> } +> } +``` + +If you have any questions or feedback, [please drop us a line][contact]. + +[Feeds API]: /v3/activity/feeds/ +[contact]: https://github.com/contact?form[subject]=Feeds%20API + diff --git a/content/changes/2013-07-02-rate-limit-reset.md b/content/changes/2013-07-02-rate-limit-reset.md new file mode 100644 index 0000000000..5106f7412b --- /dev/null +++ b/content/changes/2013-07-02-rate-limit-reset.md @@ -0,0 +1,43 @@ +--- +title: When Does My Rate Limit Reset? +author_name: jasonrudolph +--- + +Have you ever wondered when your [rate limit][rate-limit-docs] will reset back to its maximum value? +That information is now available in the new `X-RateLimit-Reset` response header. + +``` command-line +$ curl -I https://api.github.com/orgs/octokit + +> HTTP/1.1 200 OK +> Status: 200 OK +> X-RateLimit-Limit: 60 +> X-RateLimit-Remaining: 42 +> X-RateLimit-Reset: 1372700873 +> ... +``` + +The `X-RateLimit-Reset` header provides a [Unix UTC timestamp][unix-time], letting you know the exact time that your fresh new rate limit kicks in. + +The reset timestamp is also available as part of the `/rate_limit` resource. + +``` command-line +$ curl https://api.github.com/rate_limit + +> { +> "rate": { +> "limit": 60, +> "remaining": 42, +> "reset": 1372700873 +> } +> } +``` + +For more information on rate limits, be sure to check out the [docs][rate-limit-docs]. + +If you have any questions or feedback, please [drop us a line][contact]. + + +[contact]: https://github.com/contact?form[subject]=X-RateLimit-Reset +[rate-limit-docs]: /v3/#rate-limiting +[unix-time]: http://en.wikipedia.org/wiki/Unix_time diff --git a/content/changes/2013-07-19-preview-the-new-search-api.md b/content/changes/2013-07-19-preview-the-new-search-api.md new file mode 100644 index 0000000000..370a1440c2 --- /dev/null +++ b/content/changes/2013-07-19-preview-the-new-search-api.md @@ -0,0 +1,67 @@ +--- +title: Preview the New Search API +author_name: jasonrudolph +--- + +Today we're excited to announce a [brand new Search API][docs]. Whether you're +searching for [code][code-docs], [repositories][repo-docs], +[issues][issue-docs], or [users][user-docs], all the query abilities of +github.com are now available via the API as well. + +Maybe you want to find [popular Tetris implementations written in Assembly][tetris-repos]. +We've got you covered. +Or perhaps you're looking for [new gems that are using Octokit.rb][octokit-gemspecs]. +No problem. +The possibilities are endless. + +## Highlights + +On github.com, we enjoy the context provided by code snippets and highlights in +search results. + +[][example-web-search] + +We want API consumers to have access to that information as well. So, API +requests can opt to receive those +[text fragments in the response][text-matches]. Each fragment is accompanied by +numeric offsets identifying the exact location of each matching search term. + +## Preview period + +We're making this new API available today for developers to +preview. We think developers are going to love it, but we want +to get your feedback before we declare the Search API "final" and +"unchangeable." We expect the preview period to last for roughly 60 days. + +As we discover opportunities to improve this new API during the preview period, +we may ship changes that break clients using the preview version of the API. We +want to iterate quickly. To do so, we will announce any changes here (on the +developer blog), but we will not provide any advance notice. + +At the end of preview period, the Search API will become an official component +of GitHub API v3. At that point, the new Search API will be stable and suitable +for production use. + +## What about the old search API? + +The [legacy search API][legacy-search] is still available. Many existing clients +depend on it, and it is not changing in any way. While the new API offers much +more functionality, the legacy search endpoints remain an official part of +GitHub API v3. + +## Take it for a spin + +We hope you'll kick the tires and [send us your feedback][contact]. Happy +
+ Well, hello there! +
++ We're going to now talk to the GitHub API. Ready? + Click here to begin! +
++ If that link doesn't work, remember to provide your own Client ID! +
+ + +``` + +(If you're unfamiliar with how Sinatra works, we recommend [reading the Sinatra guide][Sinatra guide].) + +Also, notice that the URL uses the `scope` query parameter to define the +[scopes][oauth scopes] requested by the application. For our application, we're +requesting `user:email` scope for reading private email addresses. + +Navigate your browser to `http://localhost:4567`. After clicking on the link, you +should be taken to {{ site.data.variables.product.product_name }}, and presented with a dialog that looks something like this: + + +If you trust yourself, click **Authorize App**. Wuh-oh! Sinatra spits out a +`404` error. What gives?! + +Well, remember when we specified a Callback URL to be `callback`? We didn't provide +a route for it, so {{ site.data.variables.product.product_name }} doesn't know where to drop the user after they authorize +the app. Let's fix that now! + +### Providing a callback + +In _server.rb_, add a route to specify what the callback should do: + +``` ruby +get '/callback' do + # get temporary GitHub code... + session_code = request.env['rack.request.query_hash']['code'] + + # ... and POST it back to GitHub + result = RestClient.post('https://github.com/login/oauth/access_token', + {:client_id => CLIENT_ID, + :client_secret => CLIENT_SECRET, + :code => session_code}, + :accept => :json) + + # extract the token and granted scopes + access_token = JSON.parse(result)['access_token'] +end +``` + +After a successful app authentication, {{ site.data.variables.product.product_name }} provides a temporary `code` value. +You'll need to `POST` this code back to {{ site.data.variables.product.product_name }} in exchange for an `access_token`. +To simplify our GET and POST HTTP requests, we're using the [rest-client][REST Client]. +Note that you'll probably never access the API through REST. For a more serious +application, you should probably use [a library written in the language of your choice][libraries]. + +### Checking granted scopes + +In the future, users will be able to [edit the scopes you requested][edit scopes post], +and your application might be granted less access than you originally asked for. +So, before making any requests with the token, you should check the scopes that +were granted for the token by the user. + +The scopes that were granted are returned as a part of the response from +exchanging a token. + +``` ruby +get '/callback' do + # ... + # Get the access_token using the code sample above + # ... + + # check if we were granted user:email scope + scopes = JSON.parse(result)['scope'].split(',') + has_user_email_scope = scopes.include? 'user:email' +end +``` + +In our application, we're using `scopes.include?` to check if we were granted +the `user:email` scope needed for fetching the authenticated user's private +email addresses. Had the application asked for other scopes, we would have +checked for those as well. + +Also, since there's a hierarchical relationship between scopes, you should +check that you were granted the lowest level of required scopes. For example, +if the application had asked for `user` scope, it might have been granted only +`user:email` scope. In that case, the application wouldn't have been granted +what it asked for, but the granted scopes would have still been sufficient. + +Checking for scopes only before making requests is not enough since it's possible +that users will change the scopes in between your check and the actual request. +In case that happens, API calls you expected to succeed might fail with a `404` +or `401` status, or return a different subset of information. + +To help you gracefully handle these situations, all API responses for requests +made with valid tokens also contain an [`X-OAuth-Scopes` header][oauth scopes]. +This header contains the list of scopes of the token that was used to make the +request. In addition to that, the Authorization API provides an endpoint to +[check a token for validity][check token valid]. +Use this information to detect changes in token scopes, and inform your users of +changes in available application functionality. + +### Making authenticated requests + +At last, with this access token, you'll be able to make authenticated requests as +the logged in user: + +``` ruby +# fetch user information +auth_result = JSON.parse(RestClient.get('https://api.github.com/user', + {:params => {:access_token => access_token}})) + +# if the user authorized it, fetch private emails +if has_user_email_scope + auth_result['private_emails'] = + JSON.parse(RestClient.get('https://api.github.com/user/emails', + {:params => {:access_token => access_token}})) +end + +erb :basic, :locals => auth_result +``` + +We can do whatever we want with our results. In this case, we'll just dump them straight into _basic.erb_: + +``` erb +Hello, <%= login %>!
++ <% if !email.nil? && !email.empty? %> It looks like your public email address is <%= email %>. + <% else %> It looks like you don't have a public email. That's cool. + <% end %> +
++ <% if defined? private_emails %> + With your permission, we were also able to dig up your private email addresses: + <%= private_emails.map{ |private_email_address| private_email_address["email"] }.join(', ') %> + <% else %> + Also, you're a bit secretive about your private email addresses. + <% end %> +
+``` + +## Implementing "persistent" authentication + +It'd be a pretty bad model if we required users to log into the app every single +time they needed to access the web page. For example, try navigating directly to +`http://localhost:4567/basic`. You'll get an error. + +What if we could circumvent the entire +"click here" process, and just _remember_ that, as long as the user's logged into +{{ site.data.variables.product.product_name }}, they should be able to access this application? Hold on to your hat, +because _that's exactly what we're going to do_. + +Our little server above is rather simple. In order to wedge in some intelligent +authentication, we're going to switch over to using sessions for storing tokens. +This will make authentication transparent to the user. + +Also, since we're persisting scopes within the session, we'll need to +handle cases when the user updates the scopes after we checked them, or revokes +the token. To do that, we'll use a `rescue` block and check that the first API +call succeeded, which verifies that the token is still valid. After that, we'll +check the `X-OAuth-Scopes` response header to verify that the user hasn't revoked +the `user:email` scope. + +Create a file called _advanced_server.rb_, and paste these lines into it: + +``` ruby +require 'sinatra' +require 'rest_client' +require 'json' + +# !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!! +# Instead, set and test environment variables, like below +# if ENV['GITHUB_CLIENT_ID'] && ENV['GITHUB_CLIENT_SECRET'] +# CLIENT_ID = ENV['GITHUB_CLIENT_ID'] +# CLIENT_SECRET = ENV['GITHUB_CLIENT_SECRET'] +# end + +CLIENT_ID = ENV['GH_BASIC_CLIENT_ID'] +CLIENT_SECRET = ENV['GH_BASIC_SECRET_ID'] + +use Rack::Session::Pool, :cookie_only => false + +def authenticated? + session[:access_token] +end + +def authenticate! + erb :index, :locals => {:client_id => CLIENT_ID} +end + +get '/' do + if !authenticated? + authenticate! + else + access_token = session[:access_token] + scopes = [] + + begin + auth_result = RestClient.get('https://api.github.com/user', + {:params => {:access_token => access_token}, + :accept => :json}) + rescue => e + # request didn't succeed because the token was revoked so we + # invalidate the token stored in the session and render the + # index page so that the user can start the OAuth flow again + + session[:access_token] = nil + return authenticate! + end + + # the request succeeded, so we check the list of current scopes + if auth_result.headers.include? :x_oauth_scopes + scopes = auth_result.headers[:x_oauth_scopes].split(', ') + end + + auth_result = JSON.parse(auth_result) + + if scopes.include? 'user:email' + auth_result['private_emails'] = + JSON.parse(RestClient.get('https://api.github.com/user/emails', + {:params => {:access_token => access_token}, + :accept => :json})) + end + + erb :advanced, :locals => auth_result + end +end + +get '/callback' do + session_code = request.env['rack.request.query_hash']['code'] + + result = RestClient.post('https://github.com/login/oauth/access_token', + {:client_id => CLIENT_ID, + :client_secret => CLIENT_SECRET, + :code => session_code}, + :accept => :json) + + session[:access_token] = JSON.parse(result)['access_token'] + + redirect '/' +end +``` + +Much of the code should look familiar. For example, we're still using `RestClient.get` +to call out to the {{ site.data.variables.product.product_name }} API, and we're still passing our results to be rendered +in an ERB template (this time, it's called `advanced.erb`). + +Also, we now have the `authenticated?` method which checks if the user is already +authenticated. If not, the `authenticate!` method is called, which performs the +OAuth flow and updates the session with the granted token and scopes. + +Next, create a file in _views_ called _advanced.erb_, and paste this markup into it: + +``` erb + + + + +Well, well, well, <%= login %>!
++ <% if !email.empty? %> It looks like your public email address is <%= email %>. + <% else %> It looks like you don't have a public email. That's cool. + <% end %> +
++ <% if defined? private_emails %> + With your permission, we were also able to dig up your private email addresses: + <%= private_emails.map{ |private_email_address| private_email_address["email"] }.join(', ') %> + <% else %> + Also, you're a bit secretive about your private email addresses. + <% end %> +
+ + +``` + +From the command line, call `ruby advanced_server.rb`, which starts up your +server on port `4567` -- the same port we used when we had a simple Sinatra app. +When you navigate to `http://localhost:4567`, the app calls `authenticate!` +which redirects you to `/callback`. `/callback` then sends us back to `/`, +and since we've been authenticated, renders _advanced.erb_. + +We could completely simplify this roundtrip routing by simply changing our callback +URL in {{ site.data.variables.product.product_name }} to `/`. But, since both _server.rb_ and _advanced.rb_ are relying on +the same callback URL, we've got to do a little bit of wonkiness to make it work. + +Also, if we had never authorized this application to access our {{ site.data.variables.product.product_name }} data, +we would've seen the same confirmation dialog from earlier pop-up and warn us. + +If you'd like, you can play around with [yet another Sinatra-GitHub auth example][sinatra auth github test] +available as a separate project. + +[webflow]: /v3/oauth/#web-application-flow +[Sinatra]: http://www.sinatrarb.com/ +[about env vars]: http://en.wikipedia.org/wiki/Environment_variable#Getting_and_setting_environment_variables +[Sinatra guide]: https://github.com/sinatra/sinatra-book/blob/master/book/Introduction.markdown#hello-world-application +[REST Client]: https://github.com/archiloque/rest-client +[libraries]: /libraries/ +[sinatra auth github test]: https://github.com/atmos/sinatra-auth-github-test +[oauth scopes]: /v3/oauth/#scopes +[edit scopes post]: /changes/2013-10-04-oauth-changes-coming/ +[check token valid]: /v3/oauth_authorizations/#check-an-authorization +[platform samples]: https://github.com/github/platform-samples/tree/master/api/ruby/basics-of-authentication +[new oauth app]: https://github.com/settings/applications/new +[app settings]: https://github.com/settings/developers diff --git a/content/guides/best-practices-for-integrators.md b/content/guides/best-practices-for-integrators.md new file mode 100644 index 0000000000..f0cd17c9b4 --- /dev/null +++ b/content/guides/best-practices-for-integrators.md @@ -0,0 +1,162 @@ +--- +title: Best practices for integrators +--- + +# Best practices for integrators + +Interested in integrating with the GitHub platform? [You're in good company](https://github.com/integrations). This guide will help you build an app that provides the best experience for your users *and* ensure that it's reliably interacting with the API. + +{:toc} + +## Secure payloads delivered from GitHub + +It's very important that you secure [the payloads sent from GitHub][event-types]. Although no personal information (like passwords) is ever transmitted in a payload, leaking *any* information is not good. Some information that might be sensitive include committer email address or the names of private repositories. + +There are three steps you can take to secure receipt of payloads delivered by GitHub: + +1. Ensure that your receiving server is on an HTTPS connection. By default, GitHub will verify SSL certificates when delivering payloads. +2. You can whitelist [the IP address we use when delivering hooks](https://help.github.com/articles/what-ip-addresses-does-github-use-that-i-should-whitelist) to your server. To ensure that you're always checking the right IP address, you can [use the `/meta` endpoint](/v3/meta/#meta) to find the address we use. +3. Provide [a secret token](/webhooks/securing/) to ensure payloads are definitely coming from GitHub. By enforcing a secret token, you're ensuring that any data received by your server is absolutely coming from GitHub. Ideally, you should provide a different secret token *per user* of your service. That way, if one token is compromised, no other user would be affected. + +## Favor asynchronous work over synchronous + +GitHub expects that integrations respond within thirty seconds of receiving the webhook payload. If your service takes longer than that to complete, then GitHub terminates the connection and the payload is lost. + +Since it's impossible to predict how fast your service will complete, you should do all of "the real work" in a background job. [Resque](https://github.com/resque/resque/) (for Ruby), [RQ](http://python-rq.org/) (for Python), or [RabbitMQ](http://www.rabbitmq.com/) (for Java) are examples of libraries that can handle queuing and processing of background jobs. + +Note that even with a background job running, GitHub still expects your server to respond within thirty seconds. Your server simply needs to acknowledge that it received the payload by sending some sort of response. It's critical that your service to performs any validations on a payload as soon as possible, so that you can accurately report whether your server will continue with the request or not. + +## Use appropriate HTTP status codes when responding to GitHub + +Every webhook has its own "Recent Deliveries" section, which lists whether a deployment was successful or not. + + + +You should make use of proper HTTP status codes in order to inform users. You can use codes like `201` or `202` to acknowledge receipt of payload that won't be processed (for example, a payload delivered by a branch that's not the default). Reserve the `500` error code for catastrophic failures. + +## Provide as much information as possible to the user + +Users can dig into the server responses you send back to GitHub. Ensure that your messages are clear and informative. + + + +## Follow any redirects that the API sends you + +GitHub is explicit in telling you when a resource has moved by providing a redirect status code. You should follow these redirections. Every redirect response sets the `Location` header with the new URI to go to. If you receive a redirect, it's best to update your code to follow the new URI, in case you're requesting a deprecated path that we might remove. + +We've provided [a list of HTTP status codes](/v3/#http-redirects) to watch out for when designing your app to follow redirects. + +## Don't manually parse URLs + +Often, API responses contain data in the form of URLs. For example, when requesting a repository, we'll send a key called `clone_url` with a URL you can use to clone the repository. + +For the stability of your app, you shouldn't try to parse this data or try to guess and construct the format of future URLs. Your app is liable to break if we decide to change the URL. + +For example, when working with paginated results, it's often tempting to construct URLs that append `?page=Check this sweet data out:
+ + + + + +``` + +Phew! Again, don't worry about what most of this code is doing. The relevant part +here is a line way at the top--`var data = <%= languages %>;`--which indicates +that we're passing our previously created `languages` array into ERB for manipulation. + +As the "D3 for Mortals" guide suggests, this isn't necessarily the best use of +D3. But it does serve to illustrate how you can use the library, along with Octokit, +to make some really amazing things. + +## Combining different API calls + +Now it's time for a confession: the `language` attribute within repositories +only identifies the "primary" language defined. That means that if you have +a repository that combines several languages, the one with the most bytes of code +is considered to be the primary language. + +Let's combine a few API calls to get a _true_ representation of which language +has the greatest number of bytes written across all our code. A [treemap][D3 treemap] +should be a great way to visualize the sizes of our coding languages used, rather +than simply the count. We'll need to construct an array of objects that looks +something like this: + +``` json +[ { "name": "language1", "size": 100}, + { "name": "language2", "size": 23} + ... +] +``` + +Since we already have a list of repositories above, let's inspect each one, and +call [the language listing API method][language API]: + +``` ruby +repos.each do |repo| + repo_name = repo.name + repo_langs = octokit_client.languages("#{github_user.login}/#{repo_name}") +end +``` + +From there, we'll cumulatively add each language found to a "master list": + +``` ruby +repo_langs.each do |lang, count| + if !language_obj[lang] + language_obj[lang] = count + else + language_obj[lang] += count + end +end +``` + +After that, we'll format the contents into a structure that D3 understands: + +``` ruby +language_obj.each do |lang, count| + language_byte_count.push :name => "#{lang} (#{count})", :count => count +end + +# some mandatory formatting for D3 +language_bytes = [ :name => "language_bytes", :elements => language_byte_count] +``` + +(For more information on D3 tree map magic, check out [this simple tutorial][language API].) + +To wrap up, we pass this JSON information over to the same ERB template: + +``` ruby +erb :lang_freq, :locals => { :languages => languages.to_json, :language_byte_count => language_bytes.to_json} +``` + +Like before, here's a bunch of JavaScript that you can drop +directly into your template: + +``` html + + +``` + +Et voila! Beautiful rectangles containing your repo languages, with relative +proportions that are easy to see at a glance. You might need to +tweak the height and width of your treemap, passed as the first two +arguments to `drawTreemap` above, to get all the information to show up properly. + + +[D3.js]: http://d3js.org/ +[basics-of-authentication]: ../basics-of-authentication/ +[sinatra auth github]: https://github.com/atmos/sinatra_auth_github +[Octokit]: https://github.com/octokit/octokit.rb +[D3 mortals]: http://www.recursion.org/d3-for-mere-mortals/ +[D3 treemap]: http://bl.ocks.org/mbostock/4063582 +[language API]: https://developer.github.com/v3/repos/#list-languages +[simple tree map]: http://2kittymafiasoftware.blogspot.com/2011/09/simple-treemap-visualization-with-d3.html +[platform samples]: https://github.com/github/platform-samples/tree/master/api/ruby/rendering-data-as-graphs +[new oauth application]: https://github.com/settings/applications/new diff --git a/content/guides/traversing-with-pagination.md b/content/guides/traversing-with-pagination.md new file mode 100644 index 0000000000..ff4d11cf0b --- /dev/null +++ b/content/guides/traversing-with-pagination.md @@ -0,0 +1,259 @@ +--- +title: Traversing with Pagination +--- + +# Traversing with Pagination + +{:toc} + +The {{ site.data.variables.product.product_name }} API provides a vast wealth of information for developers to consume. +Most of the time, you might even find that you're asking for _too much_ information, +and in order to keep our servers happy, the API will automatically [paginate the requested items][pagination]. + +In this guide, we'll make some calls to the {{ site.data.variables.product.product_name }} Search API, and iterate over +the results using pagination. You can find the complete source code for this project +in the [platform-samples][platform samples] repository. + +## Basics of Pagination + +To start with, it's important to know a few facts about receiving paginated items: + +1. Different API calls respond with different defaults. For example, a call to +[list GitHub's public repositories](https://developer.github.com/v3/repos/#list-all-public-repositories) +provides paginated items in sets of 30, whereas a call to the GitHub Search API +provides items in sets of 100 +2. You can specify how many items to receive (up to a maximum of 100); but, +3. For technical reasons, not every endpoint behaves the same. For example, +[events](https://developer.github.com/v3/activity/events/) won't let you set a maximum for items to receive. +Be sure to read the documentation on how to handle paginated results for specific endpoints. + +Information about pagination is provided in [the Link header](http://tools.ietf.org/html/rfc5988) +of an API call. For example, let's make a curl request to the search API, to find +out how many times Mozilla projects use the phrase `addClass`: + +``` command-line +$ curl -I "{{ site.data.variables.product.api_url_pre }}/search/code?q=addClass+user:mozilla" +``` + +The `-I` parameter indicates that we only care about the headers, not the actual +content. In examining the result, you'll notice some information in the Link header +that looks like this: + + Link:Get started with one of our guides, or jump straight into the API documentation.
+ Browse the documentation +
+The best way to integrate with GitHub. Learn more.
+New to the GitHub API? With these guides you’ll be up and running in a snap.
+We’ve got you covered. Use the GitHub API in your favorite language.
+Are you stuck? Already tried our troubleshooting guide? Talk to a supportocat.
+Use the official Octokit library, or choose between any of the available third party libraries.
+
+Building an application that integrates with GitHub? Register for our Developer Program! The possibilities are endless, and you enjoy the kudos.
+ Register now +
+
+ Be the first to know about API changes and try out new features before they launch.
+Build your own tools that seamlessly integrate with the place you push code every day.
+Obtain developer licenses to build and test your application against GitHub Enterprise.
+Awesome! We'd love to have you be part of the program. Here’s how you can spread the word:
+Membership is open to individual developers and companies who have:
+-$ curl -i https://api.github.com/users/octocat/orgs - -HTTP/1.1 200 OK -Server: nginx -Date: Fri, 12 Oct 2012 23:33:14 GMT -Content-Type: application/json; charset=utf-8 -Connection: keep-alive -Status: 200 OK -ETag: "a00049ba79152d03380c34652f2cb612" -X-RateLimit-Limit: 5000 -X-GitHub-Media-Type: github.beta -X-RateLimit-Remaining: 4987 -Content-Length: 5 -Cache-Control: max-age=0, private, must-revalidate -X-Content-Type-Options: nosniff - -[] -+``` command-line +$ curl -i {{ site.data.variables.product.api_url_pre }}/users/octocat/orgs + +> HTTP/1.1 200 OK +> Server: nginx +> Date: Fri, 12 Oct 2012 23:33:14 GMT +> Content-Type: application/json; charset=utf-8 +> Connection: keep-alive +> Status: 200 OK +> ETag: "a00049ba79152d03380c34652f2cb612" +> X-GitHub-Media-Type: github.v3 +{% if page.version == 'dotcom' %} +> X-RateLimit-Limit: 5000 +> X-RateLimit-Remaining: 4987 +> X-RateLimit-Reset: 1350085394 +{% endif %} +> Content-Length: 5 +> Cache-Control: max-age=0, private, must-revalidate +> X-Content-Type-Options: nosniff +``` Blank fields are included as `null` instead of being omitted. @@ -43,28 +48,78 @@ All timestamps are returned in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ +### Summary Representations + +When you fetch a list of resources, the response includes a _subset_ of the +attributes for that resource. This is the "summary" representation of the +resource. (Some attributes are computationally expensive for the API to provide. +For performance reasons, the summary representation excludes those attributes. +To obtain those attributes, fetch the "detailed" representation.) + +**Example**: When you get a list of repositories, you get the summary +representation of each repository. Here, we fetch the list of repositories owned +by the [octokit](https://github.com/octokit) organization: + + GET /orgs/octokit/repos + +### Detailed Representations + +When you fetch an individual resource, the response typically includes _all_ +attributes for that resource. This is the "detailed" representation of the +resource. (Note that authorization sometimes influences the amount of detail +included in the representation.) + +**Example**: When you get an individual repository, you get the detailed +representation of the repository. Here, we fetch the +[octokit/octokit.rb](https://github.com/octokit/octokit.rb) repository: + + GET /repos/octokit/octokit.rb + +The documentation provides an example response for each API method. The example +response illustrates all attributes that are returned by that method. + ## Parameters Many API methods take optional parameters. For GET requests, any parameters not specified as a segment in the path can be passed as an HTTP query string parameter: -
-$ curl -i "https://api.github.com/repos/mojombo/jekyll/issues?state=closed" -+``` command-line +$ curl -i "{{ site.data.variables.product.api_url_pre }}/repos/vmg/redcarpet/issues?state=closed" +``` -In this example, the 'mojombo' and 'jekyll' values are provided for the `:owner` +In this example, the 'vmg' and 'redcarpet' values are provided for the `:owner` and `:repo` parameters in the path while `:state` is passed in the query string. -For POST requests, parameters not included in the URL should be encoded as JSON -with a Content-Type of 'application/x-www-form-urlencoded': +For POST, PATCH, PUT, and DELETE requests, parameters not included in the URL should be encoded as JSON +with a Content-Type of 'application/json': + +``` command-line +$ curl -i -u username -d '{"scopes":["public_repo"]}' {{ site.data.variables.product.api_url_pre }}/authorizations +``` + +## Root Endpoint + +You can issue a `GET` request to the root endpoint to get all the endpoint categories that the API supports: + +``` command-line +$ curl {{ site.data.variables.product.api_url_pre }} +``` + +{% if page.version != 'dotcom' %} + +{{#tip}} -
-$ curl -i -u username -d '{"scopes":["public_repo"]}' https://api.github.com/authorizations
-
+**Tip:** For GitHub Enterprise, [as with all other endpoints](https://developer.github.com/v3/enterprise/#endpoint-urls), you'll need to pass in your GitHub Enterprise endpoint as the hostname, *as well as your username and password*:
+``` command-line
+$ curl https://hostname/api/v3/ -u username:password
+```
+{{/tip}}
+
+{% endif %}
## Client Errors
@@ -84,7 +139,7 @@ receive request bodies:
HTTP/1.1 400 Bad Request
Content-Length: 40
- {"message":"Body should be a JSON Hash"}
+ {"message":"Body should be a JSON object"}
3. Sending invalid fields will result in a `422 Unprocessable Entity`
response.
@@ -108,32 +163,28 @@ can tell what the problem is. There's also an error code to let you
know what is wrong with the field. These are the possible validation error
codes:
-missing
-: This means a resource does not exist.
-
-missing\_field
-: This means a required field on a resource has not been set.
-
-invalid
-: This means the formatting of a field is invalid. The documentation
-for that resource should be able to give you more specific information.
-already\_exists
-: This means another resource has the same value as this field. This
-can happen in resources that must have some unique key (such as Label
-names).
+Error Name | Description
+-----------|-----------|
+`missing` | This means a resource does not exist.
+`missing_field` | This means a required field on a resource has not been set.
+`invalid` | This means the formatting of a field is invalid. The documentation for that resource should be able to give you more specific information.
+`already_exists` | This means another resource has the same value as this field. This can happen in resources that must have some unique key (such as Label names).
-If resources have custom validation errors, they will be documented with the resource.
+Resources may also send custom validation errors (where `code` is `custom`). Custom errors will always have a `message` field describing the error, and most errors will also include a `documentation_url` field pointing to some content that might help you resolve the error.
## HTTP Redirects
-API v3 uses HTTP redirection where appropriate. Clients should assume that any request may result in a redirection. Receiving an HTTP redirection is *not* an error and clients should follow that redirect. Redirect responses will have a `Location` header field which contains the URI of the resource to which the client should repeat the requests.
+API v3 uses HTTP redirection where appropriate. Clients should assume that any
+request may result in a redirection. Receiving an HTTP redirection is *not* an
+error and clients should follow that redirect. Redirect responses will have a
+`Location` header field which contains the URI of the resource to which the
+client should repeat the requests.
-301
-: Permanent redirection. The URI you used to make the request has be superseded by the one specified in the `Location` header field. This and all future requests to this resource should be directed the new URI.
-
-302, 307
-: Temporary redirection. The request should be repeated verbatim to the URI specified in the `Location` header field but clients should continue to use the original URI for future requests.
+Status Code | Description
+-----------|-----------|
+`301` | Permanent redirection. The URI you used to make the request has been superseded by the one specified in the `Location` header field. This and all future requests to this resource should be directed to the new URI.
+`302`, `307` | Temporary redirection. The request should be repeated verbatim to the URI specified in the `Location` header field but clients should continue to use the original URI for future requests.
Other redirection status codes may be used in accordance with the HTTP 1.1 spec.
@@ -142,68 +193,86 @@ Other redirection status codes may be used in accordance with the HTTP 1.1 spec.
Where possible, API v3 strives to use appropriate HTTP verbs for each
action.
-HEAD
-: Can be issued against any resource to get just the HTTP header info.
-
-GET
-: Used for retrieving resources.
-
-POST
-: Used for creating resources, or performing custom actions (such as
-merging a pull request).
-
-PATCH
-: Used for updating resources with partial JSON data. For instance, an
-Issue resource has `title` and `body` attributes. A PATCH request may
-accept one or more of the attributes to update the resource. PATCH is a
-relatively new and uncommon HTTP verb, so resource endpoints also accept
-POST requests.
-
-PUT
-: Used for replacing resources or collections. For PUT requests
-with no `body` attribute, be sure to set the `Content-Length` header to zero.
-
-DELETE
-: Used for deleting resources.
+Verb | Description
+-----|-----------
+`HEAD` | Can be issued against any resource to get just the HTTP header info.
+`GET` | Used for retrieving resources.
+`POST` | Used for creating resources.
+`PATCH` | Used for updating resources with partial JSON data. For instance, an Issue resource has `title` and `body` attributes. A PATCH request may accept one or more of the attributes to update the resource. PATCH is a relatively new and uncommon HTTP verb, so resource endpoints also accept `POST` requests.
+`PUT` | Used for replacing resources or collections. For `PUT` requests with no `body` attribute, be sure to set the `Content-Length` header to zero.
+`DELETE` |Used for deleting resources.
## Authentication
-There are three ways to authenticate through GitHub API v3. Requests that
-require authentication will return 404, instead of 403, in some places. This
-is to prevent the accidental leakage of private repositories to unauthorized
-users.
+There are three ways to authenticate through {{ site.data.variables.product.product_name }} API v3. Requests that
+require authentication will return `404 Not Found`, instead of
+`403 Forbidden`, in some places. This is to prevent the accidental leakage
+of private repositories to unauthorized users.
### Basic Authentication
--$ curl -u "username" https://api.github.com -+``` command-line +$ curl -u "username" {{ site.data.variables.product.api_url_pre }} +``` ### OAuth2 Token (sent in a header) -
-$ curl -H "Authorization: token OAUTH-TOKEN" https://api.github.com -+``` command-line +$ curl -H "Authorization: token OAUTH-TOKEN" {{ site.data.variables.product.api_url_pre }} +``` ### OAuth2 Token (sent as a parameter) -
-$ curl https://api.github.com/?access_token=OAUTH-TOKEN -+``` command-line +$ curl {{ site.data.variables.product.api_url_pre }}/?access_token=OAUTH-TOKEN +``` Read [more about OAuth2](/v3/oauth/). Note that OAuth2 tokens can be [acquired -programmatically](/v3/oauth/#create-a-new-authorization), for applications that +programmatically](/v3/oauth_authorizations/#create-a-new-authorization), for applications that are not websites. ### OAuth2 Key/Secret -
-$ curl https://api.github.com/users/whatever?client_id=xxxx&client_secret=yyyy -+``` command-line +$ curl '{{ site.data.variables.product.api_url_pre }}/users/whatever?client_id=xxxx&client_secret=yyyy' +``` This should only be used in server to server scenarios. Don't leak your -OAuth application's client secret to your users. Read [more about -unauthenticated rate limiting](#unauthenticated-rate-limited-requests). +OAuth application's client secret to your users. + +{% if page.version == 'dotcom' %} + +Read [more about unauthenticated rate limiting](#increasing-the-unauthenticated-rate-limit-for-oauth-applications). + +{% endif %} + +### Failed login limit + +Authenticating with invalid credentials will return `401 Unauthorized`: + +``` command-line +$ curl -i {{ site.data.variables.product.api_url_pre }} -u foo:bar +> HTTP/1.1 401 Unauthorized + +> { +> "message": "Bad credentials", +> "documentation_url": "https://developer.github.com/v3" +> } +``` + +After detecting several requests with invalid credentials within a short period, +the API will temporarily reject all authentication attempts for that user +(including ones with valid credentials) with `403 Forbidden`: + +``` command-line +$ curl -i {{ site.data.variables.product.api_url_pre }} -u valid_username:valid_password +> HTTP/1.1 403 Forbidden + +> { +> "message": "Maximum number of login attempts exceeded. Please try again later.", +> "documentation_url": "https://developer.github.com/v3" +> } +``` ## Hypermedia @@ -213,7 +282,7 @@ don't need to construct URLs on their own. It is highly recommended that API clients use these. Doing so will make future upgrades of the API easier for developers. All URLs are expected to be proper [RFC 6570][rfc] URI templates. -You can then expand these templates using something like the [`uri_template`][uri] +You can then expand these templates using something like the [uri_template][uri] gem: >> tmpl = URITemplate.new('/notifications{?since,all,participating}') @@ -235,14 +304,21 @@ Requests that return multiple items will be paginated to 30 items by default. You can specify further pages with the `?page` parameter. For some resources, you can also set a custom page size up to 100 with the `?per_page` parameter. Note that for technical reasons not all endpoints respect the `?per_page` parameter, -see [events](http://developer.github.com/v3/activity/events/) for example. +see [events](https://developer.github.com/v3/activity/events/) for example. + +``` command-line +$ curl '{{ site.data.variables.product.api_url_pre }}/user/repos?page=2&per_page=100' +``` + +Note that page numbering is 1-based and that omitting the `?page` +parameter will return the first page. + +For more information on pagination, check out our guide on [Traversing with Pagination][pagination-guide]. -
-$ curl https://api.github.com/user/repos?page=2&per_page=100 -+### Link Header The pagination info is included in [the Link -header](http://www.w3.org/Protocols/9707-link-header.html). It is important to +header](http://tools.ietf.org/html/rfc5988). It is important to follow these Link header values instead of constructing your own URLs. In some instances, such as in the [Commits API](/v3/repos/commits/), pagination is based on @@ -253,175 +329,299 @@ SHA1 and not on page number. _Linebreak is included for readability._ +This `Link` response header contains one or more [Hypermedia](/v3/#hypermedia) link relations, some of which may require expansion as [URI templates](http://tools.ietf.org/html/rfc6570). + The possible `rel` values are: -`next` -: Shows the URL of the immediate next page of results. +Name | Description +-----------|-----------| +`next` |The link relation for the immediate next page of results. +`last` |The link relation for the last page of results. +`first` |The link relation for the first page of results. +`prev` |The link relation for the immediate previous page of results. -`last` -: Shows the URL of the last page of results. +{% if page.version == 'dotcom' %} -`first` -: Shows the URL of the first page of results. +## Rate Limiting -`prev` -: Shows the URL of the immediate previous page of results. +For requests using Basic Authentication or OAuth, you can make up to 5,000 +requests per hour. For unauthenticated requests, the rate limit allows you to +make up to 60 requests per hour. Unauthenticated requests are associated with your IP address, +and not the user making requests. Note that [the Search API has custom rate limit +rules](/v3/search/#rate-limit). + +You can check the returned HTTP headers of any API request to see your current +rate limit status: + +``` command-line +$ curl -i {{ site.data.variables.product.api_url_pre }}/users/whatever +> HTTP/1.1 200 OK +> Date: Mon, 01 Jul 2013 17:27:06 GMT +> Status: 200 OK +> X-RateLimit-Limit: 60 +> X-RateLimit-Remaining: 56 +> X-RateLimit-Reset: 1372700873 +``` + +The headers tell you everything you need to know about your current rate limit status: + +Header Name | Description +-----------|-----------| +`X-RateLimit-Limit` | The maximum number of requests that the consumer is permitted to make per hour. +`X-RateLimit-Remaining` | The number of requests remaining in the current rate limit window. +`X-RateLimit-Reset` | The time at which the current rate limit window resets in [UTC epoch seconds](http://en.wikipedia.org/wiki/Unix_time). + +If you need the time in a different format, any modern programming language can get the job done. For example, if you open up the console on your web browser, you can easily get the reset time as a JavaScript Date object. + +``` javascript +new Date(1372700873 * 1000) +// => Mon Jul 01 2013 13:47:53 GMT-0400 (EDT) +``` + +Once you go over the rate limit you will receive an error response: + +``` command-line +> HTTP/1.1 403 Forbidden +> Date: Tue, 20 Aug 2013 14:50:41 GMT +> Status: 403 Forbidden +> X-RateLimit-Limit: 60 +> X-RateLimit-Remaining: 0 +> X-RateLimit-Reset: 1377013266 + +> { +> "message": "API rate limit exceeded for xxx.xxx.xxx.xxx. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)", +> "documentation_url": "https://developer.github.com/v3/#rate-limiting" +> } +``` + +You can also [check your rate limit status](/v3/rate_limit) without incurring an +API hit. +
-$ curl -i https://api.github.com/users/whatever
+``` command-line
+$ curl -i '{{ site.data.variables.product.api_url_pre }}/users/whatever?client_id=xxxx&client_secret=yyyy'
+> HTTP/1.1 200 OK
+> Date: Mon, 01 Jul 2013 17:27:06 GMT
+> Status: 200 OK
+> X-RateLimit-Limit: 5000
+> X-RateLimit-Remaining: 4966
+> X-RateLimit-Reset: 1372700873
+```
-HTTP/1.1 200 OK
-Status: 200 OK
-X-RateLimit-Limit: 5000
-X-RateLimit-Remaining: 4966
-
+This method should only be used for server-to-server calls. You should never
+share your client secret with anyone or include it in client-side browser code.
-You can also check your rate limit status without incurring an API hit.
+### Staying within the rate limit
- GET /rate_limit
+If you are using Basic Authentication or OAuth, and you are exceeding
+your rate limit, you can likely fix the issue by caching API responses
+and using [conditional requests](#conditional-requests).
-### Rate limit
+If you're using conditional requests and still exceeding your rate
+limit, please [contact us][support] to request a
+higher rate limit for your OAuth application.
-<%= headers 200 %>
-<%= json :rate => {:remaining => 4999, :limit => 5000} %>
+### Abuse Rate Limits
--$ curl -i https://api.github.com/users/whatever?client_id=xxxxxxxxxxxxxx&client_secret=yyyyyyyyyyyyyyyyyyyyy +``` command-line +> HTTP/1.1 403 Forbidden +> Content-Type: application/json; charset=utf-8 +> Connection: close -HTTP/1.1 200 OK -Status: 200 OK -X-RateLimit-Limit: 12500 -X-RateLimit-Remaining: 11966 -+> { +> "message": "You have triggered an abuse detection mechanism and have been temporarily blocked from content creation. Please retry your request again later.", +> "documentation_url": "https://developer.github.com/v3#abuse-rate-limits" +> } +``` -This method should only be used for server-to-server calls. You should never -share your client secret with anyone or include it in client-side browser code. +{% endif %} + +## User Agent Required + +All API requests MUST include a valid `User-Agent` header. Requests with no `User-Agent` +header will be rejected. We request that you use your {{ site.data.variables.product.product_name }} username, or the name of your +application, for the `User-Agent` header value. This allows us to contact you if there are problems. + +Here's an example: -Please [contact us](https://github.com/contact) to request a higher rate limit -for your OAuth application. +``` command-line +User-Agent: Awesome-Octocat-App +``` + +If you provide an invalid `User-Agent` header, you will receive a `403 Forbidden` response: + +``` command-line +$ curl -iH 'User-Agent: ' {{ site.data.variables.product.api_url_pre }}/meta +> HTTP/1.0 403 Forbidden +> Connection: close +> Content-Type: text/html + +> Request forbidden by administrative rules. +> Please make sure your request has a User-Agent header. +> Check https://developer.github.com for other possible causes. +``` ## Conditional requests -Most responses return `Last-Modified` and `Etag` headers. You can use the values +Most responses return an `ETag` header. Many responses also return a `Last-Modified` header. You can use the values of these headers to make subsequent requests to those resources using the -`If-Modified-Since` and `If-None-Match` headers, respectively. If the resource -has not changed, the server will return a `304 Not Modified`. Also note: making -a conditional request and receiving a 304 response does not count against your -[Rate Limit](#rate-limiting), so we encourage you to use it whenever possible. - -
-$ curl -i https://api.github.com/user -HTTP/1.1 200 OK -Cache-Control: private, max-age=60 -ETag: "644b5b0155e6404a9cc4bd9d8b1ae730" -Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT -Status: 200 OK -Vary: Accept, Authorization, Cookie -X-RateLimit-Limit: 5000 -X-RateLimit-Remaining: 4996 - -$ curl -i https://api.github.com/user -H "If-Modified-Since: Thu, 05 Jul 2012 15:31:30 GMT" -HTTP/1.1 304 Not Modified -Cache-Control: private, max-age=60 -Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT -Status: 304 Not Modified -Vary: Accept, Authorization, Cookie -X-RateLimit-Limit: 5000 -X-RateLimit-Remaining: 4996 - -$ curl -i https://api.github.com/user -H 'If-None-Match: "644b5b0155e6404a9cc4bd9d8b1ae730"' -HTTP/1.1 304 Not Modified -Cache-Control: private, max-age=60 -ETag: "644b5b0155e6404a9cc4bd9d8b1ae730" -Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT -Status: 304 Not Modified -Vary: Accept, Authorization, Cookie -X-RateLimit-Limit: 5000 -X-RateLimit-Remaining: 4996 -+`If-None-Match` and `If-Modified-Since` headers, respectively. If the resource +has not changed, the server will return a `304 Not Modified`. + +{% if page.version == 'dotcom' %} + +{{#tip}} + +**Note**: Making a conditional request and receiving a 304 response does not +count against your [Rate Limit](#rate-limiting), so we encourage you to use it +whenever possible. + +{{/tip}} + +{% endif %} + +``` command-line +$ curl -i {{ site.data.variables.product.api_url_pre }}/user +> HTTP/1.1 200 OK +> Cache-Control: private, max-age=60 +> ETag: "644b5b0155e6404a9cc4bd9d8b1ae730" +> Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT +> Status: 200 OK +> Vary: Accept, Authorization, Cookie +{% if page.version == 'dotcom' %} +> X-RateLimit-Limit: 5000 +> X-RateLimit-Remaining: 4996 +> X-RateLimit-Reset: 1372700873 +{% endif %} + +$ curl -i {{ site.data.variables.product.api_url_pre }}/user -H 'If-None-Match: "644b5b0155e6404a9cc4bd9d8b1ae730"' +> HTTP/1.1 304 Not Modified +> Cache-Control: private, max-age=60 +> ETag: "644b5b0155e6404a9cc4bd9d8b1ae730" +> Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT +> Status: 304 Not Modified +> Vary: Accept, Authorization, Cookie +{% if page.version == 'dotcom' %} +> X-RateLimit-Limit: 5000 +> X-RateLimit-Remaining: 4996 +> X-RateLimit-Reset: 1372700873 +{% endif %} + +$ curl -i {{ site.data.variables.product.api_url_pre }}/user -H "If-Modified-Since: Thu, 05 Jul 2012 15:31:30 GMT" +> HTTP/1.1 304 Not Modified +> Cache-Control: private, max-age=60 +> Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT +> Status: 304 Not Modified +> Vary: Accept, Authorization, Cookie +{% if page.version == 'dotcom' %} +> X-RateLimit-Limit: 5000 +> X-RateLimit-Remaining: 4996 +> X-RateLimit-Reset: 1372700873 +{% endif %} +``` ## Cross Origin Resource Sharing -The API supports Cross Origin Resource Sharing (CORS) for AJAX requests. -you can read the [CORS W3C working draft](http://www.w3.org/TR/cors), or +The API supports Cross Origin Resource Sharing (CORS) for AJAX requests from +any origin. +You can read the [CORS W3C Recommendation](http://www.w3.org/TR/cors/), or [this intro](http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity) from the HTML 5 Security Guide. Here's a sample request sent from a browser hitting -`http://some-site.com`: - - $ curl -i https://api.github.com -H "Origin: http://some-site.com" - HTTP/1.1 302 Found - -Any domain that is registered as an OAuth Application is accepted. -Here's a sample request for a browser hitting [Calendar About Nothing](http://calendaraboutnothing.com/): +`http://example.com`: - $ curl -i https://api.github.com -H "Origin: http://calendaraboutnothing.com" - HTTP/1.1 302 Found - Access-Control-Allow-Origin: http://calendaraboutnothing.com - Access-Control-Expose-Headers: Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-OAuth-Scopes, X-Accepted-OAuth-Scopes - Access-Control-Allow-Credentials: true +``` command-line +$ curl -i {{ site.data.variables.product.api_url_pre }} -H "Origin: http://example.com" +HTTP/1.1 302 Found +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, {% if page.version == 'dotcom' %}X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset,{% endif %} X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval +Access-Control-Allow-Credentials: true +``` This is what the CORS preflight request looks like: - $ curl -i https://api.github.com -H "Origin: http://calendaraboutnothing.com" -X OPTIONS - HTTP/1.1 204 No Content - Access-Control-Allow-Origin: http://calendaraboutnothing.com - Access-Control-Allow-Headers: Authorization, X-Requested-With - Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE - Access-Control-Expose-Headers: Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-OAuth-Scopes, X-Accepted-OAuth-Scopes - Access-Control-Max-Age: 86400 - Access-Control-Allow-Credentials: true +``` command-line +$ curl -i {{ site.data.variables.product.api_url_pre }} -H "Origin: http://example.com" -X OPTIONS +HTTP/1.1 204 No Content +Access-Control-Allow-Origin: * +Access-Control-Allow-Headers: Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-GitHub-OTP, X-Requested-With +Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE +Access-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, {% if page.version == 'dotcom' %}X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset,{% endif %} X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval +Access-Control-Max-Age: 86400 +Access-Control-Allow-Credentials: true +``` ## JSON-P Callbacks You can send a `?callback` parameter to any GET call to have the results wrapped in a JSON function. This is typically used when browsers want -to embed GitHub content in web pages by getting around cross domain +to embed {{ site.data.variables.product.product_name }} content in web pages by getting around cross domain issues. The response includes the same data output as the regular API, plus the relevant HTTP Header information. -
+``` command-line
$ curl https://api.github.com?callback=foo
-foo({
- "meta": {
- "status": 200,
- "X-RateLimit-Limit": "5000",
- "X-RateLimit-Remaining": "4966",
- "Link": [ // pagination headers and other links
- ["https://api.github.com?page=2", {"rel": "next"}]
- ]
- },
- "data": {
- // the data
- }
-})
-
-
-You can write a javascript handler to process the callback like this:
-
-function foo(response) {
- var meta = response.meta
- var data = response.data
- console.log(meta)
- console.log(data)
-}
+> /**/foo({
+> "meta": {
+> "status": 200,
+{% if page.version == 'dotcom' %}
+> "X-RateLimit-Limit": "5000",
+> "X-RateLimit-Remaining": "4966",
+> "X-RateLimit-Reset": "1372700873",
+{% endif %}
+> "Link": [ // pagination headers and other links
+> ["https://api.github.com?page=2", {"rel": "next"}]
+> ]
+> },
+> "data": {
+> // the data
+> }
+> })
+```
+
+You can write a JavaScript handler to process the callback. Here's a minimal example you can try out:
+
+
+
+
+
+
+
+ Open up your browser's console.
+ + All of the headers are the same String value as the HTTP Headers with one notable exception: Link. Link headers are pre-parsed for you and come @@ -437,4 +637,47 @@ A link that looks like this: ["url1", {:rel => "next"}], ["url2", {:rel => "foo", :bar => "baz"}]] %> +## Timezones + +Some requests allow for specifying timestamps or generate timestamps with time +zone information. We apply the following rules, in order of priority, to +determine timezone information for API calls. + +#### Explicitly provide an ISO 8601 timestamp with timezone information + +For API calls that allow for a timestamp to be specified, we use that exact +timestamp. An example of this is the [Commits API](/v3/git/commits). + +These timestamps look something like `2014-02-27T15:05:06+01:00`. Also see +[this example](https://developer.github.com/v3/git/commits/#example-input) for +how these timestamps can be specified. + +#### Using the `Time-Zone` header + +It is possible to supply a `Time-Zone` header which defines a timezone according +to the [list of names from the Olson database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). + +``` command-line +$ curl -H "Time-Zone: Europe/Amsterdam" -X POST {{ site.data.variables.product.api_url_pre }}/repos/github/linguist/contents/new_file.md +``` + +This means that we generate a timestamp for the moment your API call is made in +the timezone this header defines. For example, the [Contents API](/v3/repos/contents/) +generates a git commit for each addition or change and uses the current time +as the timestamp. This header will determine the timezone used for generating +that current timestamp. + +#### Using the last known timezone for the user + +If no `Time-Zone` header is specified and you make an authenticated call to the +API, we use the last known timezone for the authenticated user. The last known +timezone is updated whenever you browse the {{ site.data.variables.product.product_name }} website. + +#### UTC + +If the steps above don't result in any information, we use UTC as the timezone +to create the git commit. +[support]: https://github.com/contact?form[subject]=APIv3 +[abuse-support]: https://github.com/contact?form[subject]=API+Abuse+Rate+Limits +[pagination-guide]: /guides/traversing-with-pagination diff --git a/content/v3/activity.md b/content/v3/activity.md index a1fccf0f60..cdac1ca8a7 100644 --- a/content/v3/activity.md +++ b/content/v3/activity.md @@ -1,28 +1,39 @@ --- -title: Activity | GitHub API +title: Activity --- +# Activity -Serving up the 'social' in Social Coding™, the Activity APIs provide access to +Serving up the 'social' in Social Coding, the Activity APIs provide access to notifications, subscriptions, and timelines. -## Notifications +## [Events][] -Notifications of new comments are delivered to users. The Notifications API -lets you view these notifications, and mark them as read. +The [Events API][Events] is a read-only interface to all the [event +types][types] that power the various activity streams on {{ site.data.variables.product.product_name }}. -## Starring +## [Feeds][] -Repository Starring is a feature that lets users bookmark repositories. Stars +List of [Atom feeds][Feeds] available for the authenticated user. + +## [Notifications][] + +Notifications of new comments are delivered to users. [The Notifications +API][Notifications] lets you view these notifications and mark them as read. + +## [Starring][] + +[Repository Starring][Starring] is a feature that lets users bookmark repositories. Stars are shown next to repositories to show an approximate level of interest. Stars have no effect on notifications or the activity feed. -## Watching +## [Watching][] -Watching a Repository registers the user to receive notificactions on new +[Watching a Repository][Watching] registers the user to receive notifications on new discussions, as well as events in the user's activity feed. -## Events - -This is a read-only API of the events that power the various activity streams -on GitHub. - +[Events]: /v3/activity/events/ +[types]: /v3/activity/events/types/ +[Feeds]: /v3/activity/feeds/ +[Notifications]: /v3/activity/notifications/ +[Starring]: /v3/activity/starring/ +[Watching]: /v3/activity/watching/ diff --git a/content/v3/activity/events.md b/content/v3/activity/events.md index f9436ea722..5541291631 100644 --- a/content/v3/activity/events.md +++ b/content/v3/activity/events.md @@ -1,13 +1,12 @@ --- -title: Events | GitHub API +title: Events --- # Events -This is a read-only API to the GitHub events. These events power the +This is a read-only API to the {{ site.data.variables.product.product_name }} events. These events power the various activity streams on the site. -* TOC {:toc} Events are optimized for polling with the "ETag" header. If no new events have @@ -16,24 +15,30 @@ rate limit will be untouched. There is also an "X-Poll-Interval" header that specifies how often (in seconds) you are allowed to poll. In times of high server load, the time may increase. Please obey the header. - $ curl -I https://api.github.com/users/tater/events - HTTP/1.1 200 OK - X-Poll-Interval: 60 - ETag: "a18c3bded88eb5dbb5c849a489412bf3" +``` command-line +$ curl -I {{ site.data.variables.product.api_url_pre }}/users/tater/events +> HTTP/1.1 200 OK +> X-Poll-Interval: 60 +> ETag: "a18c3bded88eb5dbb5c849a489412bf3" - # The quotes around the ETag value are important - $ curl -I https://api.github.com/users/tater/events \ - -H 'If-None-Match: "a18c3bded88eb5dbb5c849a489412bf3"' - HTTP/1.1 304 Not Modified - X-Poll-Interval: 60 +# The quotes around the ETag value are important +$ curl -I {{ site.data.variables.product.api_url_pre }}/users/tater/events \ +$ -H 'If-None-Match: "a18c3bded88eb5dbb5c849a489412bf3"' +> HTTP/1.1 304 Not Modified +> X-Poll-Interval: 60 +``` Events support [pagination](/v3/#pagination), however the `per_page` option is unsupported. The fixed page size is 30 items. Fetching up to ten pages is supported, for a total of 300 events. +Only events created within the past 90 days will be included in timelines. Events +older than 90 days will not be included (even if the total number of events +in the timeline is less than 300). + All Events have the same response format: -<%= headers 200, :pagination => true %> +<%= headers 200, :pagination => default_pagination_rels %> <%= json(:event) { |h| [h] } %> ## List public events @@ -46,6 +51,9 @@ All Events have the same response format: ## List issue events for a repository +Repository issue events have a different format than other events, +as documented in the [Issue Events API](https://developer.github.com/v3/issues/events/). + GET /repos/:owner/:repo/issues/events ## List public events for a network of repositories @@ -62,27 +70,26 @@ These are events that you've received by watching repos and following users. If you are authenticated as the given user, you will see private events. Otherwise, you'll only see public events. - GET /users/:user/received_events + GET /users/:username/received_events ## List public events that a user has received - GET /users/:user/received_events/public + GET /users/:username/received_events/public ## List events performed by a user If you are authenticated as the given user, you will see your private events. Otherwise, you'll only see public events. - GET /users/:user/events + GET /users/:username/events ## List public events performed by a user - GET /users/:user/events/public + GET /users/:username/events/public ## List events for an organization This is the user's organization dashboard. You must be authenticated as the user to view this. - GET /users/:user/events/orgs/:org - + GET /users/:username/events/orgs/:org diff --git a/content/v3/activity/events/types.md b/content/v3/activity/events/types.md index fab4f8b09c..9504e2de89 100644 --- a/content/v3/activity/events/types.md +++ b/content/v3/activity/events/types.md @@ -1,255 +1,558 @@ --- -title: Event types | GitHub API +title: Event Types & Payloads --- -# Event Types +# Event Types & Payloads Each event has a similar JSON schema, but a unique `payload` object that is -determined by its event type. [Repository hook](/v3/repos/hooks/) names relate to event types, and will have the exact same payload. The only exception to this is the `push` hook, which has a larger, more detailed payload. +determined by its event type. -This describes just the payload of an event. A full event will also -show the user that performed the event (actor), the repository, and the -organization (if applicable). +Event names are used by [repository webhooks](/v3/repos/hooks/) to specify +which events the webhook should receive. The included payloads below are from webhook deliveries but +match events returned by the [Events API](/v3/activity/events/) (except where noted). The Events API uses the CamelCased name (e.g. `CommitCommentEvent`) in the `type` field of an event object and does not include the `repository` or `sender` fields in the event payload object. -Note that some of these events may not be rendered in timelines. -They're only created for various internal and repository hooks. -* TOC +**Note:** Some of these events may not be rendered in timelines, they're only +created for various internal and webhook purposes. + {:toc} ## CommitCommentEvent -Hook name: `commit_comment` +Triggered when a [commit comment](/v3/repos/comments/#list-commit-comments-for-a-repository) is created. + +### Events API payload + +Key | Type | Description +----|------|------------- +`comment`|`object` | The [comment](/v3/repos/comments/#list-commit-comments-for-a-repository) itself. + +### Webhook event name -comment -: **object** - The [comment](/v3/repos/comments/#list-commit-comments-for-a-repository) itself. +`commit_comment` + +### Webhook payload example + +<%= webhook_payload "commit_comment" %> ## CreateEvent Represents a created repository, branch, or tag. -Hook name: `create` +Note: webhooks will not receive this event for created repositories. Additionally, webhooks will not receive this event for tags if more than three tags are pushed at once. + +### Events API payload + +Key | Type | Description +----|------|------------- +`ref_type`|`string` | The object that was created. Can be one of "repository", "branch", or "tag" +`ref`|`string` | The git ref (or `null` if only a repository was created). +`master_branch`|`string` | The name of the repository's default branch (usually `master`). +`description`|`string` | The repository's current description. -ref\_type -: **string** - The object that was created: "repository", "branch", or -"tag" +### Webhook event name -ref -: **string** - The git ref (or `null` if only a repository was created). +`create` -master\_branch -: **string** - The name of the repository's master branch. +### Webhook payload example -description -: **string** - The repository's current description. +<%= webhook_payload "create" %> ## DeleteEvent -Represents a deleted branch or tag. +Represents a [deleted branch or tag](/v3/git/refs/#delete-a-reference). + +Note: webhooks will not receive this event for tags if more than three tags are deleted at once. + +### Events API payload + +Key | Type | Description +----|------|------------- +`ref_type`|`string` | The object that was deleted. Can be "branch" or "tag". +`ref`|`string` | The full git ref. + +### Webhook event name + +`delete` + +### Webhook payload example + +<%= webhook_payload "delete" %> + +## DeploymentEvent + +Represents a [deployment](/v3/repos/deployments/#list-deployments). + +Events of this type are not visible in timelines. These events are only used to trigger hooks. + +### Events API payload + +Key | Type | Description +----|------|------------- +`deployment` |`object` | The [deployment](/v3/repos/deployments/#list-deployments). +`deployment`[`"sha"`] |`string` | The commit SHA for which this deployment was created. +`deployment`[`"payload"`] |`string` | The optional extra information for this deployment. +`deployment`[`"environment"`] |`string` | The optional environment to deploy to. Default: `"production"` +`deployment`[`"description"`] |`string` | The optional human-readable description added to the deployment. +`repository` |`object` | The [repository](/v3/repos/) for this deployment. + +### Webhook event name + +`deployment` + +### Webhook payload example + +<%= webhook_payload "deployment" %> + +## DeploymentStatusEvent + +Represents a [deployment status](/v3/repos/deployments/#list-deployment-statuses). + +Events of this type are not visible in timelines. These events are only used to trigger hooks. + +### Events API payload + +Key | Type | Description +----|------|------------- +`deployment_status` |`object` | The [deployment status](/v3/repos/deployments/#list-deployment-statuses). +`deployment_status["state"]` |`string` | The new state. Can be `pending`, `success`, `failure`, or `error`. +`deployment_status["target_url"]` |`string` | The optional link added to the status. +`deployment_status["description"]`|`string` | The optional human-readable description added to the status. +`deployment` |`object` | The [deployment](/v3/repos/deployments/#list-deployments) that this status is associated with. +`repository` |`object` | The [repository](/v3/repos/) for this deployment. + +### Webhook event name -Hook name: `delete` +`deployment_status` -ref\_type -: **string** - The object that was deleted: "branch" or "tag". +### Webhook payload example -ref -: **string** - The full git ref. +<%= webhook_payload "deployment_status" %> ## DownloadEvent -Hook name: `download` +Triggered when a new [download](/v3/repos/downloads/) is created. -download -: **object** - The [download](/v3/repos/downloads/) that was just -created. +Events of this type are **no longer created**, but it's possible that they exist in timelines of some users. + +### Events API payload + +Key | Type | Description +----|------|------------- +`download`|`object` | The [download](/v3/repos/downloads/) that was just created. + +### Webhook event name + +`download` ## FollowEvent -Hook name: `follow` +Triggered when a user [follows another user](/v3/users/followers/#follow-a-user). + +Events of this type are **no longer created**, but it's possible that they exist in timelines of some users. + +### Events API payload + +Key | Type | Description +----|------|------------- +`target`|`object` | The [user](/v3/users) that was just followed. + +### Webhook event name -target -: **object** - The [user](/v3/users) that was just followed. +`follow` ## ForkEvent -Hook name: `fork` +Triggered when a user [forks a repository](/v3/repos/forks/#create-a-fork). -forkee -: **object** - The created [repository](/v3/repos/). +### Events API payload + +Key | Type | Description +----|------|------------- +`forkee`|`object` | The created [repository](/v3/repos/). + +### Webhook event name + +`fork` + +### Webhook payload example + +<%= webhook_payload "fork" %> ## ForkApplyEvent Triggered when a patch is applied in the Fork Queue. -Hook name: `fork_apply` +Events of this type are **no longer created**, but it's possible that they exist in timelines of some users. + +### Events API payload -head -: **string** - The branch name the patch is applied to. +Key | Type | Description +----|------|------------- +`head`|`string` | The branch name the patch is applied to. +`before`|`string` | SHA of the repository state before the patch. +`after`|`string` | SHA of the repository state after the patch. -before -: **string** - SHA of the repo state before the patch. +### Webhook event name -after -: **string** - SHA of the repo state after the patch. +`fork_apply` ## GistEvent -Hook name: `gist` +Triggered when a [Gist](/v3/gists/) is created or updated. + +Events of this type are **no longer created**, but it's possible that they exist in timelines of some users. -action -: **string** - The action that was performed: "create" or "update" +### Events API payload -gist -: **object** - The [gist](/v3/gists/) itself. +Key | Type | Description +----|------|------------- +`action`|`string` | The action that was performed. Can be "create" or "update" +`gist`|`object` | The [gist](/v3/gists/) itself. + +### Webhook event name + +`gist` ## GollumEvent -Hook name: `gollum` +Triggered when a Wiki page is created or updated. -pages -: **array** - The pages that were updated. +### Events API payload -pages[][page_name] -: **string** - The name of the page. +Key | Type | Description +----|------|------------- +`pages`|`array` | The pages that were updated. +`pages[][page_name]`|`string` | The name of the page. +`pages[][title]`|`string` | The current page title. +`pages[][action]`|`string` | The action that was performed on the page. Can be "created" or "edited". +`pages[][sha]`|`string` | The latest commit SHA of the page. +`pages[][html_url]`|`string` | Points to the HTML wiki page. -pages[][title] -: **string** - The current page title. +### Webhook event name -pages[][action] -: **string** - The action that was performed on the page. +`gollum` -pages[][sha] -: **string** - The latest commit SHA of the page. +### Webhook payload example -pages[][html_url] -: **string** - Points to the HTML wiki page. +<%= webhook_payload "gollum" %> ## IssueCommentEvent -Hook name: `issue_comment` +{% if page.version == 'dotcom' or page.version > 2.6 %} +Triggered when an [issue comment](/v3/issues/comments/) is created, edited, or deleted. +{% else %} +Triggered when an [issue is commented on](/v3/issues/comments/). +{% endif %} + +### Events API payload + +Key | Type | Description +----|------|------------- +`action`|`string` | The action that was performed on the comment. {% if page.version == 'dotcom' or page.version > 2.6 %}Can be one of "created", "edited", or "deleted". +`changes`|`object` | The changes to the comment if the action was "edited". +`changes[body][from]` |`string` | The previous version of the body if the action was "edited".{% else %}Currently, can only be "created".{% endif %} +`issue`|`object` | The [issue](/v3/issues/) the comment belongs to. +`comment`|`object` | The [comment](/v3/issues/comments/) itself. -action -: **string** - The action that was performed on the comment. +### Webhook event name -issue -: **object** - The [issue](/v3/issues/) the comment belongs to. +`issue_comment` -comment -: **object** - The [comment](/v3/issues/comments/) itself. +### Webhook payload example + +<%= webhook_payload "issue_comment" %> ## IssuesEvent -Hook name: `issues` +Triggered when an [issue](/v3/issues) is assigned, unassigned, labeled, unlabeled, opened, {% if page.version == 'dotcom' or page.version > 2.6 %}edited, {% endif %}closed, or reopened. + +### Events API payload + +Key | Type | Description +----|------|------------- +`action`|`string` | The action that was performed. Can be one of "assigned", "unassigned", "labeled", "unlabeled", "opened", {% if page.version == 'dotcom' or page.version > 2.6 %}"edited", {% endif %}"closed", or "reopened". +`issue`|`object` | The [issue](/v3/issues) itself.{% if page.version == 'dotcom' or page.version > 2.6 %} +`changes`|`object`| The changes to the issue if the action was "edited". +`changes[title][from]`|`string` | The previous version of the title if the action was "edited". +`changes[body][from]`|`string` | The previous version of the body if the action was "edited".{% endif %} +`assignee`|`object` | The optional user who was assigned or unassigned from the issue. +`label`|`object` | The optional label that was added or removed from the issue. + +### Webhook event name -action -: **string** - The action that was performed: "opened", "closed", or -"reopened". +`issues` -issue -: **object** - The [issue](/v3/issues) itself. +### Webhook payload example + +<%= webhook_payload "issues" %> ## MemberEvent -Triggered when a user is added as a collaborator to a repository. +Triggered when a user is [added as a collaborator](/v3/repos/collaborators/#add-user-as-a-collaborator) to a repository. + +### Events API payload + +Key | Type | Description +----|------|------------- +`member`|`object` | The [user](/v3/users/) that was added. +`action`|`string` | The action that was performed. Currently, can only be "added". + +### Webhook event name + +`member` + +### Webhook payload example + +<%= webhook_payload "member" %> -Hook name: `member` +## MembershipEvent -member -: **object** - The [user](/v3/users/) that was added. +Triggered when a user is added or removed from a team. -action -: **string** - The action that was performed: "added". +Events of this type are not visible in timelines. These events are only used to trigger hooks. + +### Events API payload + +Key | Type | Description +----|------|------------- +`action` |`string` | The action that was performed. Can be "added" or "removed". +`scope` |`string` | The scope of the membership. Currently, can only be "team". +`member` |`object` | The [user](/v3/users/) that was added or removed. +`team` |`object` | The [team](/v3/orgs/teams/) for the membership. + +### Webhook event name + +`membership` + +### Webhook payload example + +<%= webhook_payload "membership" %> + +## PageBuildEvent + +Represents an attempted build of a GitHub Pages site, whether successful or not. + +Triggered on push to a GitHub Pages enabled branch (`gh-pages` for project pages, `master` for user and organization pages). + +Events of this type are not visible in timelines. These events are only used to trigger hooks. + +### Events API payload + +Key | Type | Description +----|------|------------ +`build` | `object` | The [page build](https://developer.github.com/v3/repos/pages/#list-pages-builds) itself. + +### Webhook event name + +`page_build` + +### Webhook payload example + +<%= webhook_payload "page_build" %> ## PublicEvent -This is triggered when a private repo is open sourced. Without a doubt: the -best GitHub event. +Triggered when a private repository is [open sourced](/v3/repos/#edit). Without a doubt: the best {{ site.data.variables.product.product_name }} event. + +### Events API payload + +### Webhook event name + +`public` -Hook name: `public` +### Webhook payload example -(empty payload) +<%= webhook_payload "public" %> ## PullRequestEvent -Hook name: `pull_request` +Triggered when a [pull request](/v3/pulls) is assigned, unassigned, labeled, unlabeled, opened, {% if page.version == 'dotcom' or page.version > 2.6 %}edited, {% endif %}closed, reopened, or synchronized. -action -: **string** - The action that was performed: "opened", "closed", -"synchronize", or "reopened". +### Events API payload -number -: **integer** - The pull request number. +Key | Type | Description +----|------|------------- +`action`|`string` | The action that was performed. Can be one of "assigned", "unassigned", "labeled", "unlabeled", "opened", {% if page.version == 'dotcom' or page.version > 2.6 %}"edited", {% endif %}"closed", or "reopened", or "synchronize". If the action is "closed" and the `merged` key is `false`, the pull request was closed with unmerged commits. If the action is "closed" and the `merged` key is `true`, the pull request was merged. +`number`|`integer` | The pull request number.{% if page.version == 'dotcom' or page.version > 2.6 %} +`changes`|`object`| The changes to the comment if the action was "edited". +`changes[title][from]`|`string` | The previous version of the title if the action was "edited". +`changes[body][from]`|`string` | The previous version of the body if the action was "edited".{% endif %} +`pull_request`|`object` | The [pull request](/v3/pulls) itself. -pull\_request -: **object** - The [pull request](/v3/pulls) itself. +### Webhook event name + +`pull_request` + +### Webhook payload example + +<%= webhook_payload "pull_request" %> ## PullRequestReviewCommentEvent -Hook name: `pull_request_review_comment` +{% if page.version == 'dotcom' or page.version > 2.6 %} +Triggered when a [comment on a Pull Request's unified diff](/v3/pulls/comments) is created, edited, or deleted (in the Files Changed tab). +{% else %} +Triggered when a [Pull Request's unified diff is commented on](/v3/pulls/comments) (in the Files Changed tab). +{% endif %} + +### Events API payload -comment -: **object** - The [comment](/v3/repos/commits/#list-commit-comments-for-a-repository) itself. +Key | Type | Description +----|------|------------- +`action`|`string` | The action that was performed on the comment. {% if page.version == 'dotcom' or page.version > 2.6 %}Can be one of "created", "edited", or "deleted". +`changes`|`object`| The changes to the comment if the action was "edited". +`changes[body][from]`|`string` | The previous version of the body if the action was "edited".{% else %}Currently, can only be "created".{% endif %} +`pull_request`|`object` | The [pull request](/v3/pulls/) the comment belongs to. +`comment`|`object` | The [comment](/v3/pulls/comments) itself. + +### Webhook event name + +`pull_request_review_comment` + +### Webhook payload example + +<%= webhook_payload "pull_request_review_comment" %> ## PushEvent -Hook name: `push` +Triggered when a repository branch is pushed to. In addition to branch pushes, webhook [`push` events](/webhooks/#events) are also triggered when repository tags are pushed. + +{{#tip}} + +The Events API `PushEvent` payload is described in the table below. The example payload below that is from a webhook delivery and will differ from the Events API `PushEvent` payload. + +{{/tip}} -head -: **string** - The SHA of the HEAD commit on the repository. +### Events API payload -ref -: **string** - The full Git ref that was pushed. Example: -"refs/heads/master" +Key | Type | Description +----|------|------------- +`ref`|`string` | The full Git ref that was pushed. Example: `"refs/heads/master"`. +`head`|`string` | The SHA of the most recent commit on `ref` after the push. +`before`|`string` | The SHA of the most recent commit on `ref` before the push. +`size`|`integer` | The number of commits in the push. +`distinct_size`|`integer` | The number of distinct commits in the push. +`commits`|`array` | An array of commit objects describing the pushed commits. (The array includes a maximum of 20 commits. If necessary, you can use the [Commits API](/v3/repos/commits/) to fetch additional commits. This limit is applied to timeline events only and isn't applied to webhook deliveries.) +`commits[][sha]`|`string` | The SHA of the commit. +`commits[][message]`|`string` | The commit message. +`commits[][author]`|`object` | The git author of the commit. +`commits[][author][name]`|`string` | The git author's name. +`commits[][author][email]`|`string` | The git author's email address. +`commits[][url]`|`url` | Points to the commit API resource. +`commits[][distinct]`|`boolean` | Whether this commit is distinct from any that have been pushed before. -size -: **integer** - The number of commits in the push. +### Webhook event name -commits -: **array** - The list of pushed commits. +`push` -commits[][sha] -: **string** - The SHA of the commit. +### Webhook payload example -commits[][message] -: **string** - The commit message. +<%= webhook_payload "push" %> -commits[][author] -: **object** - The git author of the commit. +## ReleaseEvent -commits[][author][name] -: **string** - The git author's name. +Triggered when a [release](/v3/repos/releases/#get-a-single-release) is published. -commits[][author][email] -: **string** - The git author's email address. +### Events API payload -commits[][url] -: **url** - Points to the commit API resource. +Key | Type | Description +----|------|------------- +`action`|`string` | The action that was performed. Currently, can only be "published". +`release`|`object` | The [release](/v3/repos/releases/#get-a-single-release) itself. -commits[][distinct] -: **boolean** - Whether this commit is distinct from any that have been pushed -before. +### Webhook event name + +`release` + +### Webhook payload example + +<%= webhook_payload "release" %> + +## RepositoryEvent + +Triggered when a repository is created{% if page.version == 'dotcom' or page.version > 2.6 %}, deleted, made public, or made private{% endif %}. + +Events of this type are not visible in timelines. These events are only used to trigger {% if page.version != 'dotcom' and page.version <= 2.6 %}organization {% endif %}hooks. + +### Events API payload + +Key | Type | Description +----|------|------------- +`action` |`string` | The action that was performed. {% if page.version == 'dotcom' or page.version > 2.6 %}This can be one of "created", "deleted", "publicized", or "privatized".{% else %}Currently, can only be "created".{% endif %} +`repository`|`object` | The [repository](/v3/repos/) itself. + +### Webhook event name + +`repository` + +### Webhook payload example + +<%= webhook_payload "repository" %> + +## StatusEvent + +Triggered when the status of a Git commit changes. + +Events of this type are not visible in timelines. These events are only used to trigger hooks. + +### Events API payload + +Key | Type | Description +----|------|------------- +`sha`|`string` | The Commit SHA. +`state`|`string` | The new state. Can be `pending`, `success`, `failure`, or `error`. +`description`|`string` | The optional human-readable description added to the status. +`target_url`|`string` | The optional link added to the status. +`branches`|`array` | An array of branch objects containing the status' SHA. Each branch contains the given SHA, but the SHA may or may not be the head of the branch. The array includes a maximum of 10 branches. + +### Webhook event name + +`status` + +### Webhook payload example + +<%= webhook_payload "status" %> ## TeamAddEvent -Hook name: `team_add` +Triggered when a [repository is added to a team](/v3/orgs/teams/#add-or-update-team-repository). + +Events of this type are not visible in timelines. These events are only used to trigger hooks. -team -: **object** - The [team](/v3/orgs/teams/) that was modified. Note: -older events may not include this in the payload. +### Events API payload -user -: **object** - The [user](/v3/users/) that was added to this team. +Key | Type | Description +----|------|------------- +`team`|`object` | The [team](/v3/orgs/teams/) that was modified. Note: older events may not include this in the payload. +`repository`|`object` | The [repository](/v3/repos/) that was added to this team. -repo -: **object** - The [repository](/v3/repos/) that was added to this team. +### Webhook event name + +`team_add` + +### Webhook payload example + +<%= webhook_payload "team_add" %> ## WatchEvent -The event's actor is the watcher, and the event's repo is the watched -repository. +The WatchEvent is related to [starring a repository](/v3/activity/starring/#star-a-repository), not [watching](/v3/activity/watching/). +See [this API blog post](/changes/2012-09-05-watcher-api/) for an explanation. + +The event’s actor is the [user](/v3/users/) who starred a repository, and the +event’s repository is the [repository](/v3/repos/) that was starred. + +### Events API payload + +Key | Type | Description +----|------|------------- +`action`|`string` | The action that was performed. Currently, can only be `started`. + +### Webhook event name -Hook name: `watch` +`watch` -action -: **string** - The action that was performed. +### Webhook payload example +<%= webhook_payload "watch" %> diff --git a/content/v3/activity/feeds.md b/content/v3/activity/feeds.md new file mode 100644 index 0000000000..11c583fa9b --- /dev/null +++ b/content/v3/activity/feeds.md @@ -0,0 +1,34 @@ +--- +title: Feeds +--- + +# Feeds + +{:toc} + +## List Feeds + +{{ site.data.variables.product.product_name }} provides several timeline resources in [Atom][] format. The Feeds API +lists all the feeds available to the authenticated user: + +* **Timeline**: The {{ site.data.variables.product.product_name }} global public timeline +* **User**: The public timeline for any user, using [URI template][] +* **Current user public**: The public timeline for the authenticated user +* **Current user**: The private timeline for the authenticated user +* **Current user actor**: The private timeline for activity created by the authenticated user +* **Current user organizations**: The private timeline for the organizations the authenticated user is a member of. + +**Note**: Private feeds are only returned when [authenticating via Basic +Auth][authenticating] since current feed URIs use the older, non revocable auth +tokens. + + GET /feeds + +### Response + +<%= headers 200 %> +<%= json :feeds %> + +[Atom]: http://en.wikipedia.org/wiki/Atom_(standard) +[authenticating]: /v3/#basic-authentication +[URI template]: https://developer.github.com/v3/#hypermedia diff --git a/content/v3/activity/notifications.md b/content/v3/activity/notifications.md index dde6f5d85b..b09ec649a7 100644 --- a/content/v3/activity/notifications.md +++ b/content/v3/activity/notifications.md @@ -1,21 +1,19 @@ --- -title: Notifications | GitHub API +title: Notifications --- -# Notifications API +# Notifications -* TOC {:toc} -GitHub Notifications are powered by [watched repositories](/v3/repos/watching/). -Users receive notifications for discussions in repositories they watch +Users receive notifications for conversations in repositories they watch including: * Issues and their comments * Pull Requests and their comments * Comments on any commits -Notifications are also sent for discussions in unwatched repositories when the +Notifications are also sent for conversations in unwatched repositories when the user is involved including: * **@mentions** @@ -23,8 +21,8 @@ user is involved including: * Commits the user authors or commits * Any discussion in which the user actively participates -All Notification API calls require the "notifications" or -"repo API scopes. Doing this will give read-only access to +All Notification API calls require the `notifications` or +`repo` API scopes. Doing this will give read-only access to some Issue/Commit content. You will still need the "repo" scope to access Issues and Commits from their respective endpoints. @@ -37,17 +35,45 @@ leaving your current rate limit untouched. There is an "X-Poll-Interval" header that specifies how often (in seconds) you are allowed to poll. In times of high server load, the time may increase. Please obey the header. - # Add authentication to your requests - $ curl -I https://api.github.com/notifications - HTTP/1.1 200 OK - Last-Modified: Thu, 25 Oct 2012 15:16:27 GMT - X-Poll-Interval: 60 - - # Pass the Last-Modified header exactly - $ curl -I https://api.github.com/notifications - -H "If-Modified-Since: Thu, 25 Oct 2012 15:16:27 GMT" - HTTP/1.1 304 Not Modified - X-Poll-Interval: 60 +``` command-line +# Add authentication to your requests +$ curl -I {{ site.data.variables.product.api_url_pre }}/notifications +HTTP/1.1 200 OK +Last-Modified: Thu, 25 Oct 2012 15:16:27 GMT +X-Poll-Interval: 60 + +# Pass the Last-Modified header exactly +$ curl -I {{ site.data.variables.product.api_url_pre }}/notifications +$ -H "If-Modified-Since: Thu, 25 Oct 2012 15:16:27 GMT" +> HTTP/1.1 304 Not Modified +> X-Poll-Interval: 60 +``` + +## Notification Reasons + +When retrieving responses from the Notifications API, each payload has a key titled +`reason`. These correspond to events that trigger a notification. + +Here's a list of potential `reason`s for receiving a notification: + +Reason Name | Description +------------|------------ +`subscribed` | The notification arrived because you're watching the repository +`manual` | The notification arrived because you've specifically decided to subscribe to the thread (via an Issue or Pull Request) +`author` | The notification arrived because you've created the thread +`comment` | The notification arrived because you've commented on the thread +`mention` | The notification arrived because you were specifically **@mentioned** in the content +`team_mention` | The notification arrived because you were on a team that was mentioned (like @org/team) +`state_change` | The notification arrived because you changed the thread state (like closing an Issue or merging a Pull Request) +`assign` | The notification arrived because you were assigned to the Issue + +Note that the `reason` is modified on a per-thread basis, and can change, if the +`reason` on a later notification is different. + +For example, if you are the author of an issue, subsequent notifications on that +issue will have a `reason` of `author`. If you're then **@mentioned** on the same +issue, the notifications you fetch thereafter will have a `reason` of `mention`. +The `reason` remains as `mention`, regardless of whether you're ever mentioned again. ## List your notifications @@ -57,21 +83,20 @@ List all notifications for the current user, grouped by repository. ### Parameters -all -: _Optional_ **boolean** `true` to show notifications marked as read. - -participating -: _Optional_ **boolean** `true` to show only notifications in which the user is -directly participating or mentioned. - -since -: _Optional_ **time** filters out any notifications updated before the given -time. The time should be passed in as UTC in the ISO 8601 format: -`YYYY-MM-DDTHH:MM:SSZ`. Example: "2012-10-09T23:39:01Z". +Name | Type | Description +-----|------|-------------- +`all`|`boolean` | If `true`, show notifications marked as read. Default: `false` +`participating`|`boolean` | If `true`, only shows notifications in which the user is directly participating or mentioned. Default: `false` +`since`|`string` | Only show notifications updated after the given time. This is a timestamp in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`. Default: `Time.now` +`before`|`string` | Only show notifications updated before the given time. This is a timestamp in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`. ### Response +{% if page.version == 'dotcom' or page.version > 2.5 %} +<%= headers 200, :pagination => default_pagination_rels %> +{% else %} <%= headers 200 %> +{% endif %} <%= json(:thread) { |h| [h] } %> ## List your notifications in a repository @@ -82,42 +107,35 @@ List all notifications for the current user. ### Parameters -all -: _Optional_ **boolean** `true` to show notifications marked as read. - -participating -: _Optional_ **boolean** `true` to show only notifications in which the user is -directly participating or mentioned. - -since -: _Optional_ **time** filters out any notifications updated before the given -time. The time should be passed in as UTC in the ISO 8601 format: -`YYYY-MM-DDTHH:MM:SSZ`. Example: "2012-10-09T23:39:01Z". +Name | Type | Description +-----|------|-------------- +`all`|`boolean` | If `true`, show notifications marked as read. Default: `false` +`participating`|`boolean` | If `true`, only shows notifications in which the user is directly participating or mentioned. Default: `false` +`since`|`string` | Only show notifications updated after the given time. This is a timestamp in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`. Default: `Time.now` +`before`|`string` | Only show notifications updated before the given time. This is a timestamp in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`. ### Response +{% if page.version == 'dotcom' or page.version > 2.5 %} +<%= headers 200, :pagination => default_pagination_rels %> +{% else %} <%= headers 200 %> +{% endif %} <%= json(:thread) { |h| [h] } %> ## Mark as read Marking a notification as "read" removes it from the [default view -on GitHub.com](https://github.com/notifications). +on {{ site.data.variables.product.product_name }}](https://github.com/notifications). PUT /notifications -### Input - -unread -: **Boolean** Changes the unread status of the threads. +### Parameters -read -: **Boolean** Inverse of "unread". +Name | Type | Description +-----|------|-------------- +`last_read_at`|`string` | Describes the last point that notifications were checked. Anything updated since this time will not be updated. This is a timestamp in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`. Default: `Time.now` -last_read_at -: _Optional_ **Time** Describes the last point that notifications were checked. Anything -updated since this time will not be updated. Default: Now. Expected in ISO -8601 format: `YYYY-MM-DDTHH:MM:SSZ`. Example: "2012-10-09T23:39:01Z". ### Response @@ -126,22 +144,16 @@ updated since this time will not be updated. Default: Now. Expected in ISO ## Mark notifications as read in a repository Marking all notifications in a repository as "read" removes them -from the [default view on GitHub.com](https://github.com/notifications). +from the [default view on {{ site.data.variables.product.product_name }}](https://github.com/notifications). PUT /repos/:owner/:repo/notifications -### Input - -unread -: **Boolean** Changes the unread status of the threads. +### Parameters -read -: **Boolean** Inverse of "unread". +Name | Type | Description +-----|------|-------------- +`last_read_at`|`string` | Describes the last point that notifications were checked. Anything updated since this time will not be updated. This is a timestamp in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`. Default: `Time.now` -last_read_at -: _Optional_ **Time** Describes the last point that notifications were checked. Anything -updated since this time will not be updated. Default: Now. Expected in ISO -8601 format: `YYYY-MM-DDTHH:MM:SSZ`. Example: "2012-10-09T23:39:01Z". ### Response @@ -160,14 +172,6 @@ updated since this time will not be updated. Default: Now. Expected in ISO PATCH /notifications/threads/:id -### Input - -unread -: **Boolean** Changes the unread status of the threads. - -read -: **Boolean** Inverse of "unread". - ### Response <%= headers 205 %> @@ -177,7 +181,13 @@ read This checks to see if the current user is subscribed to a thread. You can also [get a Repository subscription](/v3/activity/watching/#get-a-repository-subscription). - GET /notifications/threads/1/subscription +{{#tip}} + +Note that subscriptions are only generated if a user is participating in a conversation--for example, they've replied to the thread, were **@mention**ed, or manually subscribe to a thread. + +{{/tip}} + + GET /notifications/threads/:id/subscription ### Response @@ -186,22 +196,17 @@ This checks to see if the current user is subscribed to a thread. You can also ## Set a Thread Subscription -This lets you subscribe to a thread, or ignore it. Subscribing to a thread -is unnecessary if the user is already subscribed to the repository. Ignoring -a thread will mute all future notifications (until you comment or get -@mentioned). +This lets you subscribe or unsubscribe from a conversation. Unsubscribing from a conversation mutes all future notifications (until you comment or get **@mention**ed once more). - PUT /notifications/threads/1/subscription + PUT /notifications/threads/:id/subscription -### Input +### Parameters -subscribed -: **boolean** Determines if notifications should be received from this -thread. +Name | Type | Description +-----|------|-------------- +`subscribed`|`boolean`| Determines if notifications should be received from this thread +`ignored`|`boolean`| Determines if all notifications should be blocked from this thread -ignored -: **boolean** Deterimines if all notifications should be blocked from this -thread. ### Response @@ -210,9 +215,8 @@ thread. ## Delete a Thread Subscription - DELETE /notifications/threads/1/subscription + DELETE /notifications/threads/:id/subscription ### Response <%= headers 204 %> - diff --git a/content/v3/activity/settings.md b/content/v3/activity/settings.md deleted file mode 100644 index e5f63d625b..0000000000 --- a/content/v3/activity/settings.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Notification Settings | GitHub API ---- - -# Notification Settings API - -This API is not implemented. This documentation is a placeholder for when it -is ready for public consumption. - -## View Settings - - GET /notifications/settings - -## Update Settings - -Update the notification settings for the authenticated user. - - PATCH /notifications/settings - -### Parameters - -participating.email -: _Optional_ **boolean** `true` to receive participating notificationsn via -email. - -participating.web -: _Optional_ **boolean** `true` to receive participating notificationsn via -web. - -watching.email -: _Optional_ **boolean** `true` to receive watching notificationsn via -email. - -watching.web -: _Optional_ **boolean** `true` to receive watching notificationsn via -web. - -<%= json \ - :participating => {:email => true, :web => false}, - :watching => {:email => true, :web => false} %> - -## Get notification email settings - - GET /notifications/emails - -## Get the global email settings - - GET /notifications/global/emails - -## Get notification email settings for an organization - - GET /notifications/organization/:org/emails - -## Update email settings - - PATCH /notifications/emails - -## Update global email settings - - PUT /notifications/global/emails - -### Parameters - -email -: _Required_ **string** Email address to which to send notifications to the -authenticated user for discussions related to projects for this organization. - -## Update Organization email settings - -Update the notification settings for the authenticated user. - - PUT /notifications/organization/:org/emails - -### Parameters - -email -: _Required_ **string** Email address to which to send notifications to the -authenticated user for discussions related to projects for this organization. - diff --git a/content/v3/activity/starring.md b/content/v3/activity/starring.md index 38cb24c383..b32b1a7c0b 100644 --- a/content/v3/activity/starring.md +++ b/content/v3/activity/starring.md @@ -1,72 +1,85 @@ --- -title: Repository Starring | GitHub API +title: Starring --- -# Repository Starring API +# Starring -* TOC {:toc} Repository Starring is a feature that lets users bookmark repositories. Stars are shown next to repositories to show an approximate level of interest. Stars have no effect on notifications or the activity feed. For that, see [Repository -Watching](/v3/repos/watching). +Watching](/v3/activity/watching). -We recently [changed the way watching -works](https://github.com/blog/1204-notifications-stars) on GitHub. Many 3rd -party applications may be using the "watcher" endpoints for accessing these. -Starting today, you can start changing these to the new "star" endpoints. See -below. Check the [Watcher API Change post](/changes/2012-9-5-watcher-api/) for -more. +### Starring vs. Watching +In August 2012, we [changed the way watching +works](https://github.com/blog/1204-notifications-stars) on {{ site.data.variables.product.product_name }}. Many API +client applications may be using the original "watcher" endpoints for accessing +this data. You can now start using the "star" endpoints instead (described +below). Check out the [Watcher API Change post](/changes/2012-09-05-watcher-api/) +for more details. ## List Stargazers GET /repos/:owner/:repo/stargazers - # Legacy, using github.beta media type. - GET /repos/:owner/:repo/watchers - ### Response -<%= headers 200, :pagination => true %> +<%= headers 200, :pagination => default_pagination_rels %> <%= json(:user) { |h| [h] } %> +### Alternative response with star creation timestamps + +You can also find out _when_ stars were created by passing the following custom [media type](/v3/media/) via the `Accept` header: + + Accept: application/vnd.github.v3.star+json + +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:stargazer_with_timestamps) { |hash| [hash] } %> + ## List repositories being starred List repositories being starred by a user. - GET /users/:user/starred - - # Legacy, using github.beta media type. - GET /users/:user/watched + GET /users/:username/starred -List repositories being watched by the authenticated user. +List repositories being starred by the authenticated user. GET /user/starred - # Legacy, using github.beta media type. - GET /user/watched +### Parameters + +Name | Type | Description +-----|------|-------------- +`sort`|`string` | One of `created` (when the repository was starred) or `updated` (when it was last pushed to). Default: `created` +`direction`|`string` | One of `asc` (ascending) or `desc` (descending). Default: `desc` ### Response -<%= headers 200, :pagination => true %> +<%= headers 200, :pagination => default_pagination_rels %> <%= json(:repo) { |h| [h] } %> +### Alternative response with star creation timestamps + +You can also find out _when_ stars were created by passing the following custom [media type](/v3/media/) via the `Accept` header: + + Accept: application/vnd.github.v3.star+json + +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:starred_repo) { |hash| [hash] } %> + ## Check if you are starring a repository Requires for the user to be authenticated. GET /user/starred/:owner/:repo - # Legacy, using github.beta media type. - GET /user/watched/:owner/:repo - -### Response if this repository is watched by you +### Response if this repository is starred by you <%= headers 204 %> -### Response if this repository is not watched by you +### Response if this repository is not starred by you <%= headers 404 %> @@ -76,8 +89,7 @@ Requires for the user to be authenticated. PUT /user/starred/:owner/:repo - # Legacy, using github.beta media type. - PUT /user/watched/:owner/:repo +<%= fetch_content(:put_content_length) %> ### Response @@ -89,9 +101,6 @@ Requires for the user to be authenticated. DELETE /user/starred/:owner/:repo - # Legacy, using github.beta media type. - DELETE /user/watched/:owner/:repo - ### Response <%= headers 204 %> diff --git a/content/v3/activity/watching.md b/content/v3/activity/watching.md index ccd6891a66..40b39b87bd 100644 --- a/content/v3/activity/watching.md +++ b/content/v3/activity/watching.md @@ -1,21 +1,26 @@ --- -title: Repository Watching | GitHub API +title: Watching --- -# Repository Watching API +# Watching -* TOC {:toc} -Watching a Repository registers the user to receive notificactions on new +Watching a Repository registers the user to receive notifications on new discussions, as well as events in the user's activity feed. See [Repository -Starring](/v3/repos/starring) for simple repository bookmarks. +Starring](/v3/activity/starring) for simple repository bookmarks. -We recently [changed the way watching -works](https://github.com/blog/1204-notifications-stars) on GitHub. Until 3rd -party applications stop using the "watcher" endpoints for the current Starring -API, the Watching API will use the below "subscription" endpoints. Check the -[Watcher API Change post](/changes/2012-9-5-watcher-api/) for more. +### Watching vs. Starring + +In August 2012, we [changed the way watching +works](https://github.com/blog/1204-notifications-stars) on GitHub. At the time +of that change, many API clients were already using the existing "watcher" +endpoints to access starring data. To avoid breaking those applications, the +legacy "watcher" endpoints continue to provide starring data. + +To provide access to watching data, the v3 Watcher API uses the "subscription" +endpoints described below. Check out the [Watcher API Change +post](/changes/2012-09-05-watcher-api/) for more details. ## List watchers @@ -23,14 +28,14 @@ API, the Watching API will use the below "subscription" endpoints. Check the ### Response -<%= headers 200, :pagination => true %> +<%= headers 200, :pagination => default_pagination_rels %> <%= json(:user) { |h| [h] } %> ## List repositories being watched List repositories being watched by a user. - GET /users/:user/subscriptions + GET /users/:username/subscriptions List repositories being watched by the authenticated user. @@ -38,31 +43,38 @@ List repositories being watched by the authenticated user. ### Response -<%= headers 200, :pagination => true %> +<%= headers 200, :pagination => default_pagination_rels %> <%= json(:repo) { |h| [h] } %> ## Get a Repository Subscription GET /repos/:owner/:repo/subscription -### Response +### Response if you are subscribed to the repository <%= headers 200 %> <%= json :repo_subscription %> +### Response if you are not subscribed to the repository + +<%= headers 404 %> + ## Set a Repository Subscription PUT /repos/:owner/:repo/subscription -### Input +### Parameters + +Name | Type | Description +-----|------|-------------- +`subscribed`|`boolean`| Determines if notifications should be received from this repository. +`ignored`|`boolean`| Determines if all notifications should be blocked from this repository. -subscribed -: **boolean** Determines if notifications should be received from this -repository. +{{#tip}} -ignored -: **boolean** Deterimines if all notifications should be blocked from this -repository. +If you would like to watch a repository, set `subscribed` to `true`. If you would like to ignore notifications made within a repository, set `ignored` to `true`. If you would like to stop watching a repository, [delete the repository's subscription](#delete-a-repository-subscription) completely. + +{{/tip}} ### Response @@ -71,6 +83,12 @@ repository. ## Delete a Repository Subscription +{{#tip}} + +This endpoint should only be used to stop watching a repository. To control whether or not you wish to receive notifications from a repository, [set the repository's subscription manually](#set-a-repository-subscription). + +{{/tip}} + DELETE /repos/:owner/:repo/subscription ### Response @@ -93,10 +111,12 @@ Requires for the user to be authenticated. ## Watch a repository (LEGACY) -Requires for the user to be authenticated. +Requires the user to be authenticated. PUT /user/subscriptions/:owner/:repo +<%= fetch_content(:put_content_length) %> + ### Response <%= headers 204 %> diff --git a/content/v3/auth.md b/content/v3/auth.md new file mode 100644 index 0000000000..ca387bfaa0 --- /dev/null +++ b/content/v3/auth.md @@ -0,0 +1,72 @@ +--- +title: Other Authentication Methods +--- + +# Other Authentication Methods + +{:toc} + +While the API provides multiple methods for authentication, we strongly +recommend using [OAuth](/v3/oauth/) for production applications. The other +methods provided are intended to be used for scripts or testing (i.e., cases +where full OAuth would be overkill). Third party applications that rely on +{{ site.data.variables.product.product_name }} for authentication should not ask for or collect {{ site.data.variables.product.product_name }} credentials. +Instead, they should use the [OAuth web flow](/v3/oauth). + +## Basic Authentication + +The API supports Basic Authentication as defined in +[RFC2617](http://www.ietf.org/rfc/rfc2617.txt) with a few slight differences. +The main difference is that the RFC requires unauthenticated requests to be +answered with `401 Unauthorized` responses. In many places, this would disclose +the existence of user data. Instead, the {{ site.data.variables.product.product_name }} API responds with `404 Not Found`. +This may cause problems for HTTP libraries that assume a `401 Unauthorized` +response. The solution is to manually craft the `Authorization` header. + +### Via Username and Password + +To use Basic Authentication with the {{ site.data.variables.product.product_name }} API, simply send the username and +password associated with the account. + +For example, if you're accessing the API via [cURL][curl], the following command +would authenticate you if you replace `null object.
+
+{{/tip}}
+
+
### Response
<%= headers 200 %>
<%= json :full_gist %>
+
+## List gist commits
+
+ GET /gists/:id/commits
+
+### Response
+
+<%= headers 200, :pagination => { :next => 'https://api.github.com/resource?page=2' } %>
+<%= json(:gist_history) %>
+
## Star a gist
PUT /gists/:id/star
+<%= fetch_content(:put_content_length) %>
+
### Response
<%= headers 204 %>
@@ -158,13 +211,28 @@ including the filename with a null hash.
## Fork a gist
- POST /gists/:id/fork
+ POST /gists/:id/forks
+
+{{#tip}}
+
+**Note**: This was previously `/gists/:id/fork`.
+
+{{/tip}}
### Response
-<%= headers 201, :Location => "https://api.github.com/gists/2" %>
+<%= headers 201, :Location => get_resource(:gist)['url'] %>
<%= json(:gist) %>
+## List gist forks
+
+ GET /gists/:id/forks
+
+### Response
+
+<%= headers 200, :pagination => default_pagination_rels %>
+<%= json(:gist_forks) %>
+
## Delete a gist
DELETE /gists/:id
@@ -174,3 +242,11 @@ including the filename with a null hash.
<%= headers 204 %>
[1]: /v3/oauth/#scopes
+
+## Custom media types
+
+The following media types are supported when fetching gist contents. You can read more about the
+use of media types in the API [here](/v3/media/).
+
+ application/vnd.github.VERSION.raw
+ application/vnd.github.VERSION.base64
diff --git a/content/v3/gists/comments.md b/content/v3/gists/comments.md
index 985b6e8e5b..91249c09f6 100644
--- a/content/v3/gists/comments.md
+++ b/content/v3/gists/comments.md
@@ -1,14 +1,13 @@
---
-title: Gist Comments | GitHub API
+title: Gist Comments
---
-# Gist Comments API
+# Comments
-* TOC
{:toc}
-Gist Comments leverage [these](#custom-mime-types) custom mime types.
-You can read more about the use of mime types in the API
+Gist Comments use [these custom media types](#custom-media-types).
+You can read more about the use of media types in the API
[here](/v3/media/).
## List comments on a gist
@@ -17,7 +16,7 @@ You can read more about the use of mime types in the API
### Response
-<%= headers 200 %>
+<%= headers 200, :pagination => default_pagination_rels %>
<%= json(:gist_comment) { |h| [h] } %>
## Get a single comment
@@ -33,17 +32,18 @@ You can read more about the use of mime types in the API
POST /gists/:gist_id/comments
-### Input
+### Parameters
+
+Name | Type | Description
+-----|------|--------------
+`body`|`string` | **Required**. The comment text.
-body
-: _Required_ **string**
<%= json :body => 'Just commenting for the sake of commenting' %>
### Response
-<%= headers 201,
- :Location => "https://api.github.com/gists/comments/1" %>
+<%= headers 201, :Location => get_resource(:gist_comment)['url'] %>
<%= json :gist_comment %>
## Edit a comment
@@ -52,8 +52,10 @@ body
### Input
-body
-: _Required_ **string**
+Name | Type | Description
+-----|------|--------------
+`body`|`string` | **Required**. The comment text.
+
<%= json :body => 'Just commenting for the sake of commenting' %>
@@ -70,10 +72,10 @@ body
<%= headers 204 %>
-## Custom Mime Types
+## Custom media types
-These are the supported mime types for gist comments. You can read more about the
-use of mime types in the API [here](/v3/media/).
+These are the supported media types for gist comments. You can read more about the
+use of media types in the API [here](/v3/media/).
application/vnd.github.VERSION.raw+json
application/vnd.github.VERSION.text+json
diff --git a/content/v3/git.md b/content/v3/git.md
index 08098b754c..a7ec1bd618 100644
--- a/content/v3/git.md
+++ b/content/v3/git.md
@@ -1,11 +1,11 @@
---
-title: Git | GitHub API
+title: Git Data
---
-# Git DB API
+# Git Data
The Git Database API gives you access to read and write raw Git objects
-to your Git database on GitHub and to list and update your references
+to your Git database on {{ site.data.variables.product.product_name }} and to list and update your references
(branch heads and tags).
This basically allows you to reimplement a lot of Git functionality over
@@ -13,14 +13,14 @@ our API - by creating raw objects directly into the database and updating
branch references you could technically do just about anything that Git
can do without having Git installed.
-Git DB API functions will return a 409 if the git repo for a Repository is empty
+Git DB API functions will return a `409 Conflict` if the git repository for a Repository is empty
or unavailable. This typically means it is being created still. [Contact
-Support](https://github.com/contact) if this response status persists.
+Support](https://github.com/contact?form[subject]=Commits API) if this response status persists.

For more information on the Git object database, please read the
-Git Internals chapter of
+[Git Internals](http://git-scm.com/book/en/v1/Git-Internals) chapter of
the Pro Git book.
As an example, if you wanted to commit a change to a file in your
diff --git a/content/v3/git/blobs.md b/content/v3/git/blobs.md
index ad4b1d4753..df84b5c41f 100644
--- a/content/v3/git/blobs.md
+++ b/content/v3/git/blobs.md
@@ -1,24 +1,22 @@
---
-title: Git Blobs | GitHub API
+title: Git Blobs
---
-# Blobs API
+# Blobs
-* TOC
{:toc}
-Since blobs can be any arbitrary binary data, the input and responses
-for the blob API takes an encoding parameter that can be either `utf-8`
-or `base64`. If your data cannot be losslessly sent as a UTF-8 string,
-you can base64 encode it.
-
-Blobs leverage [these](#custom-mime-types) custom mime types. You can
-read more about the use of mime types in the API [here](/v3/media/).
+Blobs leverage [these custom media types](#custom-media-types). You can
+read more about the use of media types in the API [here](/v3/media/).
## Get a Blob
GET /repos/:owner/:repo/git/blobs/:sha
+The `content` in the response will always be Base64 encoded.
+
+*Note*: This API supports blobs up to 100 megabytes in size.
+
### Response
<%= headers 200 %>
@@ -28,20 +26,26 @@ read more about the use of mime types in the API [here](/v3/media/).
POST /repos/:owner/:repo/git/blobs
-### Input
+### Parameters
+
+Name | Type | Description
+-----|------|-------------
+`content`|`string` | **Required**. The new blob's content.
+`encoding`|`string` | The encoding used for `content`. Currently, `"utf-8"` and `"base64"` are supported. Default: `"utf-8"`.
+
+### Example Input
<%= json :content => "Content of the blob", :encoding => "utf-8" %>
### Response
-<%= headers 201,
- :Location => "https://api.github.com/git/:owner/:repo/blob/:sha" %>
-<%= json :sha => "3a0f86fb8db8eea7ccbb9a95f325ddbedfb25e15" %>
+<%= headers 201, :Location => get_resource(:blob_after_create)['url'] %>
+<%= json :blob_after_create %>
-## Custom Mime Types
+## Custom media types
-These are the supported mime types for blobs. You can read more about the
-use of mime types in the API [here](/v3/media/).
+These are the supported media types for blobs. You can read more about the
+use of media types in the API [here](/v3/media/).
application/json
application/vnd.github.VERSION.raw
diff --git a/content/v3/git/commits.md b/content/v3/git/commits.md
index 31aeefe408..69a0da52fe 100644
--- a/content/v3/git/commits.md
+++ b/content/v3/git/commits.md
@@ -1,10 +1,9 @@
---
-title: Git Commits | GitHub API
+title: Git Commits
---
-# Commits API
+# Commits
-* TOC
{:toc}
## Get a Commit
@@ -22,42 +21,30 @@ title: Git Commits | GitHub API
### Parameters
-message
-: _String_ of the commit message
+Name | Type | Description
+-----|------|--------------
+`message`|`string` | **Required**. The commit message
+`tree`|`string` | **Required**. The SHA of the tree object this commit points to
+`parents`|`array` of `string`s| **Required**. The SHAs of the commits that were the parents of this commit. If omitted or empty, the commit will be written as a root commit. For a single parent, an array of one SHA should be provided; for a merge commit, an array of more than one should be provided.
-tree
-: _String_ of the SHA of the tree object this commit points to
-
-parents
-: _Array_ of the SHAs of the commits that were the parents of this
-commit. If omitted or empty, the commit will be written as a root
-commit. For a single parent, an array of one SHA should be provided,
-for a merge commit, an array of more than one should be provided.
### Optional Parameters
+You can provide an additional `committer` parameter, which is an object containing
+information about the committer. Or, you can provide an `author` parameter, which
+is an object containing information about the author.
+
The `committer` section is optional and will be filled with the `author`
data if omitted. If the `author` section is omitted, it will be filled
in with the authenticated user's information and the current date.
+Both the `author` and `committer` parameters have the same keys:
-author.name
-: _String_ of the name of the author of the commit
-
-author.email
-: _String_ of the email of the author of the commit
-
-author.date
-: _Timestamp_ of when this commit was authored
-
-committer.name
-: _String_ of the name of the committer of the commit
-
-committer.email
-: _String_ of the email of the committer of the commit
-
-committer.date
-: _Timestamp_ of when this commit was committed
+Name | Type | Description
+-----|------|-------------
+`name`|`string` | The name of the author (or committer) of the commit
+`email`|`string` | The email of the author (or committer) of the commit
+`date`|`string` | Indicates when this commit was authored (or committed). This is a timestamp in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`.
### Example Input
@@ -70,7 +57,61 @@ committer.date
### Response
-<%= headers 201,
- :Location => "https://api.github.com/git/:owner/:repo/commit/:sha" %>
+<%= headers 201, :Location => get_resource(:new_commit)['url'] %>
<%= json :new_commit %>
+{% if page.version == 'dotcom' %}
+
+## Commit signature verification
+
+{{#tip}}
+
+Commit response objects including signature verification data are currently available for developers to preview.
+During the preview period, the object formats may change without advance notice.
+Please see the [blog post](/changes/2016-04-04-git-signing-api-preview) for full details.
+
+To receive signature verification data in commit objects you must provide a custom [media type](/v3/media) in the `Accept` header:
+
+ application/vnd.github.cryptographer-preview
+
+{{/tip}}
+
+ GET /repos/:owner/:repo/git/commits/:sha
+
+### Response
+
+<%= headers 200 %>
+<%= json(:signed_git_commit) %>
+
+### The `verification` object
+
+The response will include a `verification` field whose value is an object describing the result of verifying the commit's signature. The following fields are included in the `verification` object:
+
+Name | Type | Description
+-----|------|--------------
+`verified`|`boolean` | Does GitHub consider the signature in this commit to be verified?
+`reason`|`string` | The reason for `verified` value. Possible values and their meanings are enumerated in the table below.
+`signature`|`string` | The signature that was extracted from the commit.
+`payload`|`string` | The value that was signed.
+
+#### The `reason` field
+
+The following are possible `reason`s that may be included in the `verification` object:
+
+Value | Description
+------|------------
+`expired_key` | The key that made the signature is expired.
+`not_signing_key` | The "signing" flag is not among the usage flags in the GPG key that made the signature.
+`gpgverify_error` | There was an error communicating with the signature-verification service.
+`gpgverify_unavailable` | The signature-verification service is currently unavailable.
+`unsigned` | The object does not include a signature.
+`unknown_signature_type` | A non-PGP signature was found in the commit.
+`no_user` | No user was associated with the `committer` email address in the commit.
+`unverified_email` | The `committer` email address in the commit was associated with a user, but the email address is not verified on her/his account.
+`bad_email` | The `committer` email address in the commit is not included in the identities of the PGP key that made the signature.
+`unknown_key` | The key that made the signature has not been registered with any user's account.
+`malformed_signature` | There was an error parsing the signature.
+`invalid` | The signature could not be cryptographically verified using the key whose key-id was found in the signature.
+`valid` | None of the above errors applied, so the signature is considered to be verified.
+
+{% endif %}
diff --git a/content/v3/git/import.md b/content/v3/git/import.md
deleted file mode 100644
index a96d53173c..0000000000
--- a/content/v3/git/import.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: Git Import | GitHub API
----
-
-# Import API
-
-`git fast-import` input parser
-
-Would this be cool?
-
-See the [Pro Git book](http://git-scm.com/book/ch8-2.html#a_custom_importer) or the
-[fast-import man page](http://www.kernel.org/pub/software/scm/git/docs/git-fast-import.html)
-for more information about the fast-import syntax.
-
-It would be awesome if there was some way to open up a streaming
-listener and just stream this data to it in order to:
-
-* import directly into github from the fast-export scripts that exist
- for multiple VCS systems
-
-* be able to easily import multiple objects - for instance a series of
- commits without having to make multiple git calls
-
-even without streaming capability, this might be pretty interesting
-functionality.
-
diff --git a/content/v3/git/refs.md b/content/v3/git/refs.md
index 03538c134a..ef4a444d92 100644
--- a/content/v3/git/refs.md
+++ b/content/v3/git/refs.md
@@ -1,10 +1,9 @@
---
-title: Git Refs | GitHub API
+title: Git Refs
---
-# References API
+# References
-* TOC
{:toc}
## Get a Reference
@@ -15,11 +14,26 @@ The `ref` in the URL must be formatted as `heads/branch`, not just `branch`. For
GET /repos/:owner/:repo/git/refs/heads/skunkworkz/featureA
-### Response
-
<%= headers 200 %>
<%= json :ref %>
+If the `ref` doesn't exist in the repository, but existing refs start with `ref`
+they will be returned as an array. For example, a call to get the data for a
+branch named `feature`, which doesn't exist, would return head refs
+including `featureA` and `featureB` which do.
+
+ GET /repos/:owner/:repo/git/refs/heads/feature
+
+<%= headers 200 %>
+<%= json :refs_matching %>
+
+If the `ref` doesn't match an existing ref or any prefixes a 404 will be returned.
+
+ GET /repos/:owner/:repo/git/refs/heads/feature-branch-that-no-longer-exists
+
+<%= headers 404 %>
+<%= json :refs_not_found %>
+
## Get all References
GET /repos/:owner/:repo/git/refs
@@ -36,7 +50,7 @@ references, you can call:
For a full refs listing, you'll get something that looks like:
-<%= headers 200 %>
+<%= headers 200, :pagination => default_pagination_rels %>
<%= json :refs %>
@@ -46,21 +60,20 @@ For a full refs listing, you'll get something that looks like:
### Parameters
-ref
-: _String_ of the name of the fully qualified reference (ie: `refs/heads/master`).
- If it doesn't start with 'refs' and have at least two slashes, it will be rejected.
+Name | Type | Description
+-----|------|--------------
+`ref`|`type`| **Required**. The name of the fully qualified reference (ie: `refs/heads/master`). If it doesn't start with 'refs' and have at least two slashes, it will be rejected.
+`sha`|`type`| **Required**. The SHA1 value to set this reference to
-sha
-: _String_ of the SHA1 value to set this reference to
### Input
-<%= json "ref"=>"refs/heads/master",\
- "sha"=>"827efc6d56897b048c772eb4087f854f46256132" %>
+<%= json "ref"=>"refs/heads/featureA",\
+ "sha"=>"aa218f56b14c9653891f9e74264a383fa43fefbd" %>
### Response
-<%= headers 201 %>
+<%= headers 201, :Location => get_resource(:ref)['url'] %>
<%= json :ref %>
## Update a Reference
@@ -69,13 +82,11 @@ sha
### Parameters
-sha
-: _String_ of the SHA1 value to set this reference to
+Name | Type | Description
+-----|------|--------------
+`sha`|`type`| **Required**. The SHA1 value to set this reference to
+`force`|`boolean`| Indicates whether to force the update or to make sure the update is a fast-forward update. Leaving this out or setting it to `false` will make sure you're not overwriting work. Default: `false`
-force
-: _Boolean_ indicating whether to force the update or to make sure the
-update is a fast-forward update. The default is `false`, so leaving this
-out or setting it to `false` will make sure you're not overwriting work.
### Input
@@ -84,8 +95,7 @@ out or setting it to `false` will make sure you're not overwriting work.
### Response
-<%= headers 200, \
- :Location => "https://api.github.com/git/:owner/:repo/commit/:sha" %>
+<%= headers 200 %>
<%= json :ref %>
## Delete a Reference
@@ -103,4 +113,3 @@ Example: Deleting a tag:
### Response
<%= headers 204 %>
-
diff --git a/content/v3/git/tags.md b/content/v3/git/tags.md
index 648f6c25e3..b0605da270 100644
--- a/content/v3/git/tags.md
+++ b/content/v3/git/tags.md
@@ -1,10 +1,9 @@
---
-title: Git Tags | GitHub API
+title: Git Tags
---
-# Tags API
+# Tags
-* TOC
{:toc}
This tags API only deals with tag objects - so only annotated tags, not
@@ -23,40 +22,100 @@ lightweight tags.
Note that creating a tag object does not create the reference that
makes a tag in Git. If you want to create an annotated tag in Git,
-you have to do this call to create the tag object, and then create
-the `refs/tags/[tag]` reference. If you want to create a lightweight
-tag, you simply have to create the reference - this call would be
-unnecessary.
+you have to do this call to create the tag object, and then
+[create](/v3/git/refs/#create-a-reference) the `refs/tags/[tag]` reference.
+If you want to create a lightweight tag, you only have to
+[create](/v3/git/refs/#create-a-reference) the tag reference - this call
+would be unnecessary.
POST /repos/:owner/:repo/git/tags
### Parameters
-tag
-: _String_ of the tag
+Name | Type | Description
+-----|------|--------------
+`tag`|`string`| The tag
+`message`|`string`| The tag message
+`object`|`string`| The SHA of the git object this is tagging
+`type`|`string`| The type of the object we're tagging. Normally this is a `commit` but it can also be a `tree` or a `blob`.
+`tagger`|`object`| An object with information about the individual creating the tag.
-message
-: _String_ of the tag message
+The `tagger` object contains the following keys:
-object
-: _String_ of the SHA of the git object this is tagging
+Name | Type | Description
+-----|------|--------------
+`name`|`string`| The name of the author of the tag
+`email`|`string`| The email of the author of the tag
+`date`|`string`| When this object was tagged. This is a timestamp in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`.
-type
-: _String_ of the type of the object we're tagging. Normally this is a
-`commit` but it can also be a `tree` or a `blob`.
-tagger.name
-: _String_ of the name of the author of the tag
+### Example Input
-tagger.email
-: _String_ of the email of the author of the tag
-
-tagger.date
-: _Timestamp_ of when this object was tagged
+<%= json "tag"=> "v0.0.1", \
+ "message" => "initial version\n", \
+ "object" => "c3d0be41ecbe669545ee3e94d31ed9a4bc91ee3c", \
+ "type" => "commit", \
+ "tagger"=> \
+ {"name" => "Scott Chacon", "email" => "schacon@gmail.com", \
+ "date" => "2011-06-17T14:53:35-07:00"} %>
### Response
-<%= headers 201,
- :Location => "https://api.github.com/repos/:owner/:repo/git/tags/:sha" %>
+<%= headers 201, :Location => get_resource(:gittag)['url'] %>
<%= json :gittag %>
+{% if page.version == 'dotcom' %}
+
+## Tag signature verification
+
+{{#tip}}
+
+Tag response objects including signature verification data are currently available for developers to preview.
+During the preview period, the object formats may change without advance notice.
+Please see the [blog post](/changes/2016-04-04-git-signing-api-preview) for full details.
+
+To receive signature verification data in tag objects you must provide a custom [media type](/v3/media) in the `Accept` header:
+
+ application/vnd.github.cryptographer-preview
+
+{{/tip}}
+
+ GET /repos/:owner/:repo/git/tags/:sha
+
+### Response
+
+<%= headers 200 %>
+<%= json(:signed_gittag) %>
+
+### The `verification` object
+
+The response will include a `verification` field whose value is an object describing the result of verifying the tag's signature. The following fields are included in the `verification` object:
+
+Name | Type | Description
+-----|------|--------------
+`verified`|`boolean` | Does GitHub consider the signature in this tag to be verified?
+`reason`|`string` | The reason for `verified` value. Possible values and their meanings are enumerated in the table below.
+`signature`|`string` | The signature that was extracted from the tag.
+`payload`|`string` | The value that was signed.
+
+#### The `reason` field
+
+The following are possible `reason`s that may be included in the `verification` object:
+
+Value | Description
+------|------------
+`expired_key` | The key that made the signature is expired.
+`not_signing_key` | The "signing" flag is not among the usage flags in the GPG key that made the signature.
+`gpgverify_error` | There was an error communicating with the signature-verification service.
+`gpgverify_unavailable` | The signature-verification service is currently unavailable.
+`unsigned` | The object does not include a signature.
+`unkown_signature_type` | A non-PGP signature was found in the tag.
+`no_user` | No user was associated with the `tagger` email address in the tag.
+`unverified_email` | The `tagger` email address in the tag was associated with a user, but the email address is not verified on her/his account.
+`bad_email` | The `tagger` email address in the tag is not included in the identities of the PGP key that made the signature.
+`unknown_key` | The key that made the signature has not been registered with any user's account.
+`malformed_signature` | There was an error parsing the signature.
+`invalid` | The signature could not be cryptographically verified using the key whose key-id was found in the signature.
+`valid` | None of the above errors applied, so the signature is considered to be verified.
+
+{% endif %}
diff --git a/content/v3/git/trees.md b/content/v3/git/trees.md
index ae879a8e6e..485e622ada 100644
--- a/content/v3/git/trees.md
+++ b/content/v3/git/trees.md
@@ -1,10 +1,9 @@
---
-title: Git Trees | GitHub API
+title: Git Trees
---
-# Trees API
+# Trees
-* TOC
{:toc}
## Get a Tree
@@ -13,6 +12,12 @@ title: Git Trees | GitHub API
### Response
+{{#tip}}
+
+If `truncated` is `true`, the number of items in the `tree` array exceeded our maximum limit. If you need to fetch more items, you can clone the repository and iterate over the Git data locally.
+
+{{/tip}}
+
<%= headers 200 %>
<%= json :tree %>
@@ -22,6 +27,12 @@ title: Git Trees | GitHub API
### Response
+{{#tip}}
+
+If `truncated` is `true`, the number of items in the `tree` array exceeded our maximum limit. If you need to fetch more items, use the non-recursive method of fetching trees, and fetch one sub-tree at a time.
+
+{{/tip}}
+
<%= headers 200 %>
<%= json :tree_extra %>
@@ -36,38 +47,33 @@ a new tree out.
### Parameters
-base_tree
-: optional _String_ of the SHA1 of the tree you want to update with new data
-
-tree
-: _Array_ of _Hash_ objects (of `path`, `mode`, `type` and `sha`) specifying a tree structure
-
-tree.path
-: _String_ of the file referenced in the tree
+Name | Type | Description
+-----|------|--------------
+`tree`|`array` of `object`s | **Required**. Objects (of `path`, `mode`, `type`, and `sha`) specifying a tree structure
+`base_tree`| `string` | The SHA1 of the tree you want to update with new data. If you don't set this, the commit will be created on top of everything; however, it will only contain your change, the rest of your files will show up as deleted.
-tree.mode
-: _String_ of the file mode - one of `100644` for file (blob), `100755` for executable (blob), `040000` for subdirectory (tree), `160000` for submodule (commit) or `120000` for a blob that specifies the path of a symlink
+The `tree` parameter takes the following keys:
-tree.type
-: _String_ of `blob`, `tree`, `commit`
+Name | Type | Description
+-----|------|--------------
+`path`|`string`| The file referenced in the tree
+`mode`|`string`| The file mode; one of `100644` for file (blob), `100755` for executable (blob), `040000` for subdirectory (tree), `160000` for submodule (commit), or `120000` for a blob that specifies the path of a symlink
+`type`| `string`| Either `blob`, `tree`, or `commit`
+`sha`|`string`| The SHA1 checksum ID of the object in the tree
+`content`|`string` | The content you want this file to have. {{ site.data.variables.product.product_name }} will write this blob out and use that SHA for this entry. Use either this, or `tree.sha`.
-tree.sha
-: _String_ of SHA1 checksum ID of the object in the tree
-
-tree.content
-: _String_ of content you want this file to have - GitHub will write this blob out and use that SHA for this entry. Use either this or `tree.sha`
### Input
-<%= json "tree"=> \
- [{"path"=>"file.rb", \
- "mode"=>"100644", \
- "type"=>"blob", \
- "sha"=>"44b4fc6d56897b048c772eb4087f854f46256132"}] %>
+<%= json \
+ "base_tree" => "9fb037999f264ba9a7fc6274d15fa3ae2ab98312", \
+ "tree"=> \
+ [{"path"=>"file.rb", \
+ "mode"=>"100644", \
+ "type"=>"blob", \
+ "sha"=>"44b4fc6d56897b048c772eb4087f854f46256132"}] %>
### Response
-<%= headers 201,
- :Location => "https://api.github.com/repos/:owner/:repo/git/trees/:sha" %>
+<%= headers 201, :Location => get_resource(:tree_new)['url'] %>
<%= json :tree_new %>
-
diff --git a/content/v3/gitignore.md b/content/v3/gitignore.md
index ee9067c09f..66fc12632d 100644
--- a/content/v3/gitignore.md
+++ b/content/v3/gitignore.md
@@ -1,15 +1,14 @@
---
-title: Gitignore templates | GitHub API
+title: Gitignore
---
-# Gitignore Templates API
+# Gitignore
-* TOC
{:toc}
-When you create a new GitHub repository via the API, you can specify a
+When you create a new {{ site.data.variables.product.product_name }} repository via the API, you can specify a
[.gitignore template][what-is] to apply to the repository upon creation. The
-.gitignore Templates API lists and fetches templates from the [GitHub .gitignore repository][templates-repo].
+.gitignore Templates API lists and fetches templates from the [{{ site.data.variables.product.product_name }} .gitignore repository][templates-repo].
## Listing available templates
diff --git a/content/v3/issues.md b/content/v3/issues.md
index c918ecd0dd..59e7f99a29 100644
--- a/content/v3/issues.md
+++ b/content/v3/issues.md
@@ -1,196 +1,281 @@
---
-title: Issues | GitHub API
+title: Issues
---
-# Issues API
+# Issues
-* TOC
{:toc}
-Issues leverage [these](#custom-mime-types) custom mime types. You can
-read more about the use of mime types in the API [here](/v3/media/).
+Issues use [these custom media types](#custom-media-types). You can
+read more about the use of media types in the API [here](/v3/media/).
## List issues
-List all issues across all the authenticated user's visible repositories
+<%= fetch_content(:prs_as_issues) %>
+
+List all issues **assigned** to the authenticated user across all visible repositories
including owned repositories, member repositories, and organization
repositories:
GET /issues
-List all issues across owned and member repositories for the authenticated user:
+{{#tip}}
+
+You can use the `filter` query parameter to fetch issues that are not necessarily assigned to you. See the table below for more information.
+
+{{/tip}}
+
+List all issues across owned and member repositories assigned to the authenticated user:
GET /user/issues
-List all issues for a given organization for the authenticated user:
+List all issues for a given organization assigned to the authenticated user:
GET /orgs/:org/issues
### Parameters
-filter
-: * `assigned`: Issues assigned to you (default)
- * `created`: Issues created by you
- * `mentioned`: Issues mentioning you
- * `subscribed`: Issues you're subscribed to updates for
- * `all`: All issues the authenticated user can see, regardless of particpation or creation
+Name | Type | Description
+-----|------|--------------
+`filter`|`string`| Indicates which sorts of issues to return. Can be one of:
+ Important: The default version of the API may change in the
+ future. If you're building an application and care about the stability of
+ the API, be sure to request a specific version in the Accept
+ header as shown in the examples below.
+
+https://s3.amazonaws.com/github-cloud/migration/79/67?response-content-disposition=filename%3D0b989ba4-242f-11e5-81e1.tar.gz&response-content-type=application/x-gzip
+
+
+## Delete a migration archive
+
+Deletes a previous migration archive. Migration archives are automatically deleted after seven days.
+
+ DELETE /orgs/:org/migrations/:id/archive
+
+### Response
+
+<%= headers 204 %>
+
+## Unlock a repository
+
+Unlocks a repository that was locked for migration. You should unlock each migrated repository and [delete them](/v3/repos/#delete-a-repository) when the migration is complete and you no longer need the source data.
+
+ DELETE /orgs/:org/migrations/:id/repos/:repo_name/lock
+
+### Response
+
+<%= headers 204 %>
diff --git a/content/v3/migration/source_imports.md b/content/v3/migration/source_imports.md
new file mode 100644
index 0000000000..044cc0079e
--- /dev/null
+++ b/content/v3/migration/source_imports.md
@@ -0,0 +1,321 @@
+---
+title: Source Imports | GitHub API
+---
+
+# Source Imports
+
+{:toc}
+
+{% if page.version != 'dotcom' %}
+
+{{#warning}}
+
+This API is not currently available on GitHub Enterprise.
+
+{{/warning}}
+
+{% endif %}
+
+{{#tip}}
+
+ The source import APIs are currently in public preview. During this period, the APIs may change in a backwards-incompatible way. To access the API during the preview period, you must provide a custom [media type](/v3/media) in the `Accept` header:
+
+ application/vnd.github.barred-rock-preview
+
+{{/tip}}
+
+The Source Import API lets you start an import from a Git, Subversion, Mercurial, or Team Foundation Server source repository. This is the same functionality as [the GitHub Importer](https://help.github.com/articles/importing-from-other-version-control-systems-to-github/).
+
+A typical source import would [start the import](#start-an-import) and then (optionally) [update the authors](#map-a-commit-author) and/or [set the preference](#set-git-lfs-preference) for using Git LFS if large files exist in the import. A more detailed example can be seen in this diagram:
+
+```
++---------+ +--------+ +---------------------+
+| Tooling | | GitHub | | Original Repository |
++---------+ +--------+ +---------------------+
+ | | |
+ | Start import | |
+ |----------------------------->| |
+ | | |
+ | | Download source data |
+ | |--------------------------------------------->|
+ | | Begin streaming data |
+ | |<---------------------------------------------|
+ | | |
+ | Get import progress | |
+ |----------------------------->| |
+ | "status": "importing" | |
+ |<-----------------------------| |
+ | | |
+ | Get commit authors | |
+ |----------------------------->| |
+ | | |
+ | Map a commit author | |
+ |----------------------------->| |
+ | | |
+ | | |
+ | | Finish streaming data |
+ | |<---------------------------------------------|
+ | | |
+ | | Rewrite commits with mapped authors |
+ | |------+ |
+ | | | |
+ | |<-----+ |
+ | | |
+ | | Update repository on GitHub |
+ | |------+ |
+ | | | |
+ | |<-----+ |
+ | | |
+ | Map a commit author | |
+ |----------------------------->| |
+ | | Rewrite commits with mapped authors |
+ | |------+ |
+ | | | |
+ | |<-----+ |
+ | | |
+ | | Update repository on GitHub |
+ | |------+ |
+ | | | |
+ | |<-----+ |
+ | | |
+ | Get large files | |
+ |----------------------------->| |
+ | | |
+ | opt_in to Git LFS | |
+ |----------------------------->| |
+ | | Rewrite commits for large files |
+ | |------+ |
+ | | | |
+ | |<-----+ |
+ | | |
+ | | Update repository on GitHub |
+ | |------+ |
+ | | | |
+ | |<-----+ |
+ | | |
+ | Get import progress | |
+ |----------------------------->| |
+ | "status": "complete" | |
+ |<-----------------------------| |
+ | | |
+ | | |
+```
+
+## Start an import
+
+Start a source import to a GitHub repository using GitHub Importer.
+
+ PUT /repos/:owner/:repo/import
+
+### Parameters
+
+Name | Type | Description
+-----|------|--------------
+`vcs_url`|`url`|**Required** The URL of the originating repository.
+`vcs`|`string`|The originating VCS type. Can be one of `subversion`, `git`, `mercurial`, or `tfvc`. Please be aware that without this parameter, the import job will take additional time to detect the VCS type before beginning the import. This detection step will be reflected in the response.
+`vcs_username`|`string`|If authentication is required, the username to provide to `vcs_url`.
+`vcs_password`|`string`|If authentication is required, the password to provide to `vcs_url`.
+`tfvc_project`|`string`|For a tfvc import, the name of the project that is being imported.
+
+#### Example
+
+<%= json \
+ :vcs => "subversion",
+ :vcs_url => "http://svn.mycompany.com/svn/myproject",
+ :vcs_username => "octocat",
+ :vcs_password => "secret"
+%>
+
+### Response
+
+<%= headers 201, :Location => "https://api.github.com/repos/spraints/socm/import" %>
+<%= json :source_import %>
+
+## Get import progress
+
+View the progress of an import.
+
+ GET /repos/:owner/:repo/import
+
+### Response
+
+<%= headers 200 %>
+<%= json :source_import_complete %>
+
+### Import `status`
+
+This section includes details about the possible values of the `status` field of the Import Progress response.
+
+An import that does not have errors will progress through these steps:
+
+* `detecting` - the "detection" step of the import is in progress because the request did not include a `vcs` parameter. The import is identifying the type of source control present at the URL.
+* `importing` - the "raw" step of the import is in progress. This is where commit data is fetched from the original repository. The import progress response will include `commit_count` (the total number of raw commits that will be imported) and `percent` (0 - 100, the current progress through the import).
+* `mapping` - the "rewrite" step of the import is in progress. This is where SVN branches are converted to Git branches, and where author updates are applied. The import progress response does not include progress information.
+* `pushing` - the "push" step of the import is in progress. This is where the importer updates the repository on GitHub. The import progress response will include `push_percent`, which is the percent value reported by `git push` when it is "Writing objects".
+* `complete` - the import is complete, and the repository is ready on GitHub.
+
+If there are problems, you will see one of these in the `status` field:
+
+* `auth_failed` - the import requires authentication in order to connect to the original repository. To update authentication for the import, please see the [Update Existing Import](#update-existing-import) section.
+* `error` - the import encountered an error. The import progress response will include the `failed_step` and an error message. [Contact support](https://github.com/contact?form%5Bsubject%5D=Source+Import+API+error) for more information.
+* `detection_needs_auth` - the importer requires authentication for the originating repository to continue detection. To update authentication for the import, please see the [Update Existing Import](#update-existing-import) section.
+* `detection_found_nothing` - the importer didn't recognize any source control at the URL. To resolve, [Cancel the import](#cancel-an-import) and [retry](#start-an-import) with the correct URL.
+* `detection_found_multiple` - the importer found several projects or repositories at the provided URL. When this is the case, the Import Progress response will also include a `project_choices` field with the possible project choices as values. To update project choice, please see the [Update Existing Import](#update-existing-import) section.
+
+### The `project_choices` field
+
+When multiple projects are found at the provided URL, the response hash will include a `project_choices` field, the value of which is an array of hashes each representing a project choice. The exact key/value pairs of the project hashes will differ depending on the version control type.
+
+<%= json :source_import_project_choices %>
+
+### Git LFS related fields
+
+This section includes details about Git LFS related fields that may be present in the Import Progress response.
+
+* `use_lfs` - describes whether the import has been opted in or out of using Git LFS. The value can be `opt_in`, `opt_out`, or `undecided` if no action has been taken.
+* `has_large_files` - the boolean value describing whether files larger than 100MB were found during the `importing` step.
+* `large_files_size` - the total size in gigabytes of files larger than 100MB found in the originating repository.
+* `large_files_count` - the total number of files larger than 100MB found in the originating repository. To see a list of these files, make a "Get Large Files" request.
+
+## Update existing import
+
+An import can be updated with credentials or a project choice by passing in the appropriate parameters in this API request. If no parameters are provided, the import will be restarted.
+
+ PATCH /repos/:owner/:repo/import
+
+### Parameters for updating authentication
+
+Name | Type | Description
+-----|------|--------------
+`vcs_username`|`string`|The username to provide to the originating repository.
+`vcs_password`|`string`|The password to provide to the originating repository.
+
+### Example
+
+<%= json \
+ :vcs_username => "octocat",
+ :vcs_password => "secret"
+%>
+
+### Response
+
+<%= headers 200 %>
+<%= json :source_import_update_auth %>
+
+### Parameters for updating project choice
+
+Some servers (e.g. TFS servers) can have several projects at a single URL. In those cases the import progress will have the status `detection_found_multiple` and the Import Progress response will include a `project_choices` array. You can select the project to import by providing one of the objects in the `project_choices` array in the update request.
+
+The following example demonstrates the workflow for updating an import with "project1" as the project choice. Given a `project_choices` array like such:
+
+<%= json :source_import_project_choices %>
+
+### Example
+
+<%= json\
+ "vcs": "tfvc",
+ "tfvc_project": "project1",
+ "human_name": "project1 (tfs)"
+%>
+
+### Response
+
+<%= headers 200 %>
+<%= json :source_import_update_project_choice %>
+
+### Parameters for restarting import
+
+To restart an import, no parameters are provided in the update request.
+
+### Response
+
+<%= headers 200, :Location => "https://api.github.com/repos/spraints/socm/import" %>
+<%= json :source_import %>
+
+## Get commit authors
+
+Each type of source control system represents authors in a different way. For example, a Git commit author has a display name and an email address, but a Subversion commit author just has a username. The GitHub Importer will make the author information valid, but the author might not be correct. For example, it will change the bare Subversion username `hubot` into something like `hubot
+ The token attribute is deprecated in all
+ of the following OAuth Authorizations API responses:
+
token is still returned for "create" token is still returned for "create"
+ To reduce the impact of removing the token value,
+ the OAuth Authorizations API now includes a new request attribute
+ (fingerprint), three new response attributes
+ (token_last_eight, hashed_token, and
+ fingerprint), and
+ one new endpoint.
+
+ To reduce the impact of removing the token value,
+ the OAuth Authorizations API now includes a new request attribute
+ (fingerprint) and three new response attributes
+ (token_last_eight, hashed_token, and
+ fingerprint).
+
+ This functionality became the default for all requests on April 20, 2015. Please see the blog post for full details. +
++814412cfbd631109df337e16c807207e78c0d24e +## Compare two commits GET /repos/:owner/:repo/compare/:base...:head +Both `:base` and `:head` must be branch names in `:repo`. To compare branches across other repositories in the same network as `:repo`, use the format `
-curl -L https://api.github.com/repos/pengwynn/octokit/tarball > octokit.tar.gz +``` command-line +$curl -L https://api.github.com/repos/octokit/octokit.rb/tarball > octokit.tar.gz + +> % Total % Received % Xferd Average Speed Time Time Time Current +> Dload Upload Total Spent Left Speed +> 100 206k 100 206k 0 0 146k 0 0:00:01 0:00:01 --:--:-- 790k +``` + +## Custom media types + +[READMEs](#get-the-readme), [files](#get-contents), and [symlinks](#get-contents) support the following custom media types: + + application/vnd.github.VERSION.raw + application/vnd.github.VERSION.html + +Use the `.raw` media type to retrieve the contents of the file. + +For markup files such as Markdown or AsciiDoc, you can retrieve the rendered HTML using the `.html` media type. Markup languages are rendered to HTML using our open-source [Markup library](https://github.com/github/markup). + +[All objects](#get-contents) support the following custom media type: + + application/vnd.github.VERSION.object + +Use the `object` media type parameter to retrieve the contents in a consistent object format regardless of the content type. For example, instead of an array of objects +for a directory, the response will be an object with an `entries` attribute containing the array of objects. - % Total % Received % Xferd Average Speed Time Time Time Current - Dload Upload Total Spent Left Speed -100 206k 100 206k 0 0 146k 0 0:00:01 0:00:01 --:--:-- 790k -+You can read more about the use of media types in the API [here](/v3/media/). diff --git a/content/v3/repos/deployments.md b/content/v3/repos/deployments.md new file mode 100644 index 0000000000..34e2574621 --- /dev/null +++ b/content/v3/repos/deployments.md @@ -0,0 +1,277 @@ +--- +title: Deployments +--- + +# Deployments + +{:toc} + +Deployments are a request for a specific ref (branch, SHA, tag) to be deployed. +GitHub then dispatches deployment events that external services can listen for +and act on. This enables developers and organizations to build loosely-coupled +tooling around deployments, without having to worry about implementation +details of delivering different types of applications (e.g., web, native). + +Deployment Statuses allow external services to mark deployments with a +'success', 'failure', 'error', or 'pending' state, which can then be consumed +by any system listening for `deployment_status` events. + +Deployment Statuses can also include an optional `description` and `target_url`, and +we highly recommend providing them as they make deployment statuses much more +useful. The `target_url` would be the full URL to the deployment output, and +the `description` would be the high level summary of what happened with the +deployment. + +Deployments and Deployment Statuses both have associated +[repository events](/v3/activity/events/types/#deploymentevent) when +they're created. This allows webhooks and 3rd party integrations to respond to +deployment requests as well as update the status of a deployment as progress is +made. + +Below is a simple sequence diagram for how these interactions would work. + +``` ++---------+ +--------+ +-----------+ +-------------+ +| Tooling | | GitHub | | 3rd Party | | Your Server | ++---------+ +--------+ +-----------+ +-------------+ + | | | | + | Create Deployment | | | + |--------------------->| | | + | | | | + | Deployment Created | | | + |<---------------------| | | + | | | | + | | Deployment Event | | + | |---------------------->| | + | | | SSH+Deploys | + | | |-------------------->| + | | | | + | | Deployment Status | | + | |<----------------------| | + | | | | + | | | Deploy Completed | + | | |<--------------------| + | | | | + | | Deployment Status | | + | |<----------------------| | + | | | | +``` + +Keep in mind that GitHub is never actually accessing your servers. It's up to +your 3rd party integration to interact with deployment events. This allows for +[GitHub integrations](https://github.com/integrations) as +well as running your own systems depending on your use case. Multiple systems +can listen for deployment events, and it's up to each of those systems to +decide whether or not they're responsible for pushing the code out to your +servers, building native code, etc. + +Note that the `repo_deployment` [OAuth scope](/v3/oauth/#scopes) grants +targeted access to Deployments and Deployment Statuses **without** +granting access to repository code, while the `repo` scope grants permission to code +as well. + +## List Deployments + +Simple filtering of deployments is available via query parameters: + + GET /repos/:owner/:repo/deployments + +Name | Type | Description +-----|------|-------------- +`sha`|`string` | The SHA that was recorded at creation time. Default: `none` +`ref`|`string` | The name of the ref. This can be a branch, tag, or SHA. Default: `none` +`task`|`string` | The name of the task for the deployment. e.g. `deploy` or `deploy:migrations`. Default: `none` +`environment`|`string` | The name of the environment that was deployed to. e.g. `staging` or `production`. Default: `none` + +### Response + +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:deployment) { |h| [h] } %> + +## Create a Deployment + +Deployments offer a few configurable parameters with sane defaults. + +The `ref` parameter can be any named branch, tag, or SHA. At GitHub we often +deploy branches and verify them before we merge a pull request. + +The `environment` parameter allows deployments to be issued to different +runtime environments. Teams often have multiple environments for verifying +their applications, like 'production', 'staging', and 'qa'. This allows for +easy tracking of which environments had deployments requested. The default +environment is 'production'. + +The `auto_merge` parameter is used to ensure that the requested ref is not +behind the repository's default branch. If the ref *is* behind the default +branch for the repository, we will attempt to merge it for you. If the merge +succeeds, the API will return a successful merge commit. If merge conflicts +prevent the merge from succeeding, the API will return a failure response. + +By default, [commit statuses](/v3/repos/statuses) for every submitted context +must be in a 'success' state. The `required_contexts` parameter allows you to +specify a subset of contexts that must be "success", or to specify contexts +that have not yet been submitted. You are not required to use commit statuses +to deploy. If you do not require any contexts or create any commit statuses, +the deployment will always succeed. + +The `payload` parameter is available for any extra information that a +deployment system might need. It is a JSON text field that will be passed on +when a deployment event is dispatched. + +The `task` parameter is used by the deployment system to allow different +execution paths. In the web world this might be 'deploy:migrations' to run +schema changes on the system. In the compiled world this could be a flag to +compile an application with debugging enabled. + +Users with `repo` or `repo_deployment` scopes can create a deployment for a given ref: + + POST /repos/:owner/:repo/deployments + +### Parameters + +Name | Type | Description +-----|------|-------------- +`ref`|`string`| **Required**. The ref to deploy. This can be a branch, tag, or SHA. +`task`|`string`| Optional parameter to specify a task to execute, e.g. `deploy` or `deploy:migrations`. Default: `deploy` +`auto_merge`|`boolean`| Optional parameter to merge the default branch into the requested ref if it is behind the default branch. Default: `true` +`required_contexts`|`Array`| Optional array of status contexts verified against commit status checks. If this parameter is omitted from the parameters then all unique contexts will be verified before a deployment is created. To bypass checking entirely pass an empty array. Defaults to all unique contexts. +`payload`|`string` | Optional JSON payload with extra information about the deployment. Default: `""` +`environment`|`string` | Optional name for the target deployment environment (e.g., production, staging, qa). Default: `"production"` +`description`|`string` | Optional short description. Default: `""` +{% if page.version == 'dotcom' || page.version > 2.6 %} `transient_environment` | `boolean` | Optionally specifies if the given environment is specific to the deployment and will no longer exist at some point in the future. Default: `false` **This parameter requires a custom media type to be specified. Please see more in the alert below.**{% endif %} +{% if page.version == 'dotcom' || page.version > 2.6 %} `production_environment` | `boolean` | Optionally specifies if the given environment is one that end-users directly interact with. Default: `true` when `environment` is `"production"` and `false` otherwise. **This parameter requires a custom media type to be specified. Please see more in the alert below.**{% endif %} + +{% if page.version == 'dotcom' || page.version > 2.6 %} +{{#tip}} + +The new `transient_environment` and `production_environment` parameters are currently available for developers to preview. During the preview period, the API may change without advance notice. Please see the [blog post][blog-post] for full details. + +To access the API during the preview period, you must provide a custom [media type](/v3/media) in the `Accept` header: + +``` +application/vnd.github.ant-man-preview+json +``` + +{{/tip}} + +{% endif %} + +#### Simple Example + +A simple example putting the user and room into the payload to notify back to +chat networks. + +<%= json \ + :ref => "topic-branch", + :payload => "{\"user\":\"atmos\",\"room_id\":123456}", + :description => "Deploying my sweet branch" +%> + +### Successful response + +<%= headers 201, :Location => get_resource(:deployment)['url'] %> +<%= json :deployment %> + +#### Advanced Example + +A more advanced example specifying required commit statuses and bypassing auto-merging. + +<%= json \ + :ref => "topic-branch", + :auto_merge => false, + :payload => "{\"user\":\"atmos\",\"room_id\":123456}", + :description => "Deploying my sweet branch", + :required_contexts => ["ci/janky", "security/brakeman"] +%> + +### Successful response + +<%= headers 201, :Location => get_resource(:deployment)['url'] %> +<%= json :deployment %> + +### Merge conflict response + +This error happens when the `auto_merge` option is enabled and when the default branch (in this case `master`), can't be merged into the branch that's being deployed (in this case `topic-branch`), due to merge conflicts. + +<%= headers 409 %> +<%= json({ :message => "Conflict merging master into topic-branch" }) %> + +### Failed commit status checks + +This error happens when the `required_contexts` parameter indicates that one or more contexts need to have a `success` status for the commit to be deployed, but one or more of the required contexts do not have a state of `success`. + +<%= headers 409 %> +<%= json({ :message => "Conflict: Commit status checks failed for topic-branch." }) %> + +## Update a Deployment + +Once a deployment is created, it cannot be updated. Information relating to the +success or failure of a deployment is handled through Deployment Statuses. + +# Deployment Statuses + +## List Deployment Statuses + +Users with pull access can view deployment statuses for a deployment: + + GET /repos/:owner/:repo/deployments/:id/statuses + +### Parameters + +Name | Type | Description +-----|------|-------------- +`id` |`integer`| **Required**. The Deployment ID to list the statuses from. + + +### Response + +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:deployment_status) { |h| h.delete("deployment"); [h] } %> + +## Create a Deployment Status + +Users with push access can create deployment statuses for a given deployment: + + POST /repos/:owner/:repo/deployments/:id/statuses + +### Parameters + +Name | Type | Description +-----|------|-------------- +`state`|`string` | **Required**. The state of the status. Can be one of `pending`, `success`, `error`, {% if page.version == 'dotcom' || page.version > 2.6 %} `inactive`, {% endif %}or `failure` **The `inactive` state requires a custom media type to be specified. Please see more in the alert below.**. +`target_url`|`string` | The target URL to associate with this status. This URL should contain output to keep the user updated while the task is running or serve as historical information for what happened in the deployment. Default: `""` +{% if page.version == 'dotcom' || page.version > 2.6 %}`log_url`|`string` | This is functionally equivalent to `target_url`. We will continue accept `target_url` to support legacy uses, but we recommend modifying this to the new name to avoid confusion. Default: `""` **This parameter requires a custom media type to be specified. Please see more in the alert below.**{% endif %} +`description`|`string` | A short description of the status. Maximum length of 140 characters. Default: `""` +{% if page.version == 'dotcom' || page.version > 2.6 %}`environment_url`|`string`| Optionally set the URL for accessing your environment. Default: `""` **This parameter requires a custom media type to be specified. Please see more in the alert below.**{% endif %} +{% if page.version == 'dotcom' || page.version > 2.6 %}`auto_inactive`|`boolean`| Optional parameter to add a new `inactive` status to all non-transient, non-production environment deployments with the same repository and environment name as the created status's deployment. Default: `true` **This parameter requires a custom media type to be specified. Please see more in the alert below.**{% endif %} + +{% if page.version == 'dotcom' || page.version > 2.6 %} + +{{#tip}} + +The new `inactive` state, rename of the `target_url` parameter to `log_url` and new `environment_url` and `auto_inactive` parameters are currently available for developers to preview. During the preview period, the API may change without advance notice. Please see the [blog post][blog-post] for full details. + +To access the API during the preview period, you must provide a custom [media type](/v3/media) in the `Accept` header: + +``` +application/vnd.github.ant-man-preview+json +``` + +{{/tip}} + +{% endif %} + +#### Example + +<%= json \ + :state => "success", + :target_url => "https://example.com/deployment/42/output", + :description => "Deployment finished successfully." +%> + +### Response + +<%= headers 201, :Location => get_resource(:deployment_status)['url'] %> +<%= json :deployment_status %> + +[blog-post]: /changes/2016-04-06-deployment-and-deployment-status-enhancements diff --git a/content/v3/repos/downloads.md b/content/v3/repos/downloads.md index 62c1d47162..c5f027a106 100644 --- a/content/v3/repos/downloads.md +++ b/content/v3/repos/downloads.md @@ -1,12 +1,21 @@ --- -title: Repo Downloads | GitHub API +title: Downloads --- -# Repo Downloads API +# Downloads -* TOC {:toc} +### Downloads API is Deprecated + +{{#warning}} + +The Downloads API (described below) was deprecated on December 11, 2012. It will be removed at a future date. + +We recommend using Releases instead. + +{{/warning}} + The downloads API is for package downloads only. If you want to get source tarballs you should use [this](/v3/repos/contents/#get-archive-link) instead. @@ -17,7 +26,7 @@ instead. ### Response -<%= headers 200 %> +<%= headers 200, :pagination => default_pagination_rels %> <%= json(:download) { |h| [h] } %> ## Get a single download @@ -29,96 +38,6 @@ instead. <%= headers 200 %> <%= json :download %> -## Create a new download (Part 1: Create the resource) - -Creating a new download is a two step process. You must first create a -new download resource. - - POST /repos/:owner/:repo/downloads - -### Input - -name -: _Required_ **string** - -size -: _Required_ **number** - Size of file in bytes. - -description -: _Optional_ **string** - -content\_type -: _Optional_ **string** - -<%= json \ - :name => "new_file.jpg", - :size => 114034, - :description => "Latest release", - :content_type => "text/plain" -%> - -### Response - -<%= headers 201, :Location => "https://api.github.com/user/repo/downloads/1" %> -<%= json :create_download %> - -## Create a new download (Part 2: Upload file to s3) - -Now that you have created the download resource, you can use the -information in the response to upload your file to s3. This can be done -with a `POST` to the `s3_url` you got in the create response. Here is a -brief example using curl: - - curl \ - -F "key=downloads/octocat/Hello-World/new_file.jpg" \ - -F "acl=public-read" \ - -F "success_action_status=201" \ - -F "Filename=new_file.jpg" \ - -F "AWSAccessKeyId=1ABCDEF..." \ - -F "Policy=ewogIC..." \ - -F "Signature=mwnF..." \ - -F "Content-Type=image/jpeg" \ - -F "file=@new_file.jpg" \ - https://github.s3.amazonaws.com/ - -NOTES - -The order in which you pass these fields matters! Follow the order shown -above exactly. All parameters shown are required and if you excluded or -modify them your upload will fail because the values are hashed and signed -by the policy. - -key -: Value of `path` field in the response. - -acl -: Value of `acl` field in the response. - -success_action_status -: 201, or whatever you want to get back. - -Filename -: Value of `name` field in the response. - -AWSAccessKeyId -: Value of `accesskeyid` field in the response. - -Policy -: Value of `policy` field in the response. - -Signature -: Value of `signature` field in the response. - -Content-Type -: Value of `mime_type` field in the response. - -file -: Local file. Example assumes the file existing in the directory where -you are running the curl command. Yes, the `@` matters. - -More information about using the REST API to interact with s3 can -be found [here](http://docs.amazonwebservices.com/AmazonS3/latest/API/). - ## Delete a download DELETE /repos/:owner/:repo/downloads/:id diff --git a/content/v3/repos/forks.md b/content/v3/repos/forks.md index c1e8365538..27c1c98f89 100644 --- a/content/v3/repos/forks.md +++ b/content/v3/repos/forks.md @@ -1,10 +1,9 @@ --- -title: Repo Forks | GitHub API +title: Forks --- -# Repo Forks API +# Forks -* TOC {:toc} ## List forks @@ -13,13 +12,15 @@ title: Repo Forks | GitHub API ### Parameters -sort -: `newest`, `oldest`, `watchers`, default: `newest`. +Name | Type | Description +-----|------|------------- +`sort`|`string` | The sort order. Can be either `newest`, `oldest`, or `stargazers`. Default: `newest` + ### Response -<%= headers 200 %> -<%= json(:repo) { |h| [h] } %> +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:repo) { |h| h['fork'] = true; [h] } %> ## Create a fork @@ -27,20 +28,18 @@ Create a fork for the authenticated user. POST /repos/:owner/:repo/forks -One can either use the `organization` parameter or POST a JSON document with -the field `organization` - ### Parameters -organization -: _Optional_ **String** - Organization login. The repository will be -forked into this organization. +Name | Type | Description +-----|------|------------- +`organization`|`string` | Optional parameter to specify the organization name if forking into an organization. + ### Response Forking a Repository happens asynchronously. Therefore, you may have to wait a short period before accessing the git objects. If this takes longer than -5 minutes, be sure to [contact Support](https://github.com/contact). +5 minutes, be sure to [contact Support](https://github.com/contact?form[subject]=APIv3). <%= headers 202 %> -<%= json :repo %> +<%= json(:repo) { |h| h['fork'] = true; h } %> diff --git a/content/v3/repos/hooks.md b/content/v3/repos/hooks.md index 600e8c99e4..2208924598 100644 --- a/content/v3/repos/hooks.md +++ b/content/v3/repos/hooks.md @@ -1,52 +1,24 @@ --- -title: Repo Hooks | GitHub API +title: Repository Webhooks --- -# Repo Hooks API +# Webhooks -* TOC {:toc} -The Repository Hooks API manages the post-receive web and service hooks -for a repository. There are two main APIs to manage these hooks: a JSON -HTTP API, and [PubSubHubbub](#pubsubhubbub). - -Active hooks can be configured to trigger for one or more events. -The default event is `push`. The available events are: - -* `push` - Any git push to a Repository. -* `issues` - Any time an Issue is opened or closed. -* `issue_comment` - Any time an Issue is commented on. -* `commit_comment` - Any time a Commit is commented on. -* `pull_request` - Any time a Pull Request is opened, closed, or - synchronized (updated due to a new push in the branch that the pull -request is tracking). -* `gollum` - Any time a Wiki page is updated. -* `watch` - Any time a User watches the Repository. -* `download` - Any time a Download is added to the Repository. -* `fork` - Any time a Repository is forked. -* `fork_apply` - Any time a patch is applied to the Repository from the - Fork Queue. -* `member` - Any time a User is added as a collaborator to a - non-Organization Repository. -* `public` - Any time a Repository changes from private to public. -* `status` - Any time a Repository has a status update from the API - -The payloads for all of the hooks mirror [the payloads for the Event -types](/v3/activity/events/types/), with the exception of [the original `push` -event](http://help.github.com/post-receive-hooks/). - -For a Hook to go through, the Hook needs to be configured to trigger for -an event, and the Service has to listen to it. The Services are all -part of the open source [github-services](https://github.com/github/github-services) project. Most of the Services only listen for `push` events. However, the generic [Web Service](https://github.com/github/github-services/blob/master/services/web.rb) listens for all events. Other services like the [IRC Service](https://github.com/github/github-services/blob/master/services/irc.rb) may only listen for `push`, `issues`, and `pull_request` events. - -## List +The Repository Webhooks API allows repository admins to manage the post-receive +hooks for a repository. Webhooks can be managed using the JSON HTTP API, +or the [PubSubHubbub API](#pubsubhubbub). + +If you would like to set up a single webhook to receive events from all of your organization's repositories, check out our [API documentation for Organization Webhooks][org-hooks]. + +## List hooks GET /repos/:owner/:repo/hooks ### Response -<%= headers 200, :pagination => true %> +<%= headers 200, :pagination => default_pagination_rels %> <%= json(:hook) { |h| [h] } %> ## Get single hook @@ -62,109 +34,64 @@ part of the open source [github-services](https://github.com/github/github-servi POST /repos/:owner/:repo/hooks -### Input +**Note**: Repository service hooks (like email or Campfire) can have at most one configured at a time. Creating hooks for a service that already has one configured will [update the existing hook](#edit-a-hook). -`name` -: _Required_ **string** - The name of the service that is being called. -See [/hooks](https://api.github.com/hooks) for the possible names. +Repositories can have multiple webhooks installed. Each webhook should have a unique `config`. Multiple webhooks can share the same `config` as long as those webhooks do not have any `events` that overlap. -`config` -: _Required_ **hash** - A Hash containing key/value pairs to provide -settings for this hook. These settings vary between the services and -are defined in the -[github-services](https://github.com/github/github-services) repo. -Booleans are stored internally as "1" for true, and "0" for false. Any -JSON true/false values will be converted automatically. +### Parameters -`events` -: _Optional_ **array** - Determines what events the hook is triggered -for. Default: `["push"]`. +Name | Type | Description +-----|------|-------------- +`name`|`string` | **Required**. Use `web` for a webhook or use the name of a valid service. (See /hooks for the list of valid service names.) +`config`|`object` | **Required**. Key/value pairs to provide settings for this hook. These settings vary between hooks and some are defined in the [github-services](https://github.com/github/github-services) repository. Booleans are stored internally as "1" for true, and "0" for false. Any JSON `true`/`false` values will be converted automatically. +`events`|`array` | Determines what events the hook is triggered for. Default: `["push"]` +`active`|`boolean` | Determines whether the hook is actually triggered on pushes. -`active` -: _Optional_ **boolean** - Determines whether the hook is actually -triggered on pushes. +#### Example -Example: The ["web" service hook](https://github.com/github/github-services/blob/master/services/web.rb#L4-11) -takes these fields: +To create [a webhook](/webhooks), the following fields are required by the `config`: -* `url` -* `content_type` -* `secret` +* `url`: A required string defining the URL to which the payloads will be delivered. +* `content_type`: An optional string defining the media type used to serialize the payloads. Supported values include `json` and `form`. The default is `form`. +* `secret`: An optional string that's passed with the HTTP requests as an `X-Hub-Signature` header. The value of this header is computed as the HMAC hex digest of the body, using the `secret` as the key. +* `insecure_ssl`: An optional string that determines whether the SSL certificate of the host for `url` will be verified when delivering payloads. Supported values include `"0"` (verification is performed) and `"1"` (verification is not performed). The default is `"0"`. -Here's how you can setup a hook that posts raw JSON (instead of the default -legacy format): +Here's how you can create a hook that posts payloads in JSON format: <%= json \ :name => "web", :active => true, :events => ['push', 'pull_request'], :config => { - :url => 'http://something.com/webhook', + :url => 'http://example.com/webhook', :content_type => 'json'} %> ### Response -<%= headers 201, - :Location => 'https://api.github.com/repos/user/repo/hooks/1' %> +<%= headers 201, :Location => get_resource(:hook)['url'] %> <%= json :hook %> ## Edit a hook PATCH /repos/:owner/:repo/hooks/:id -### Input - -`name` -: _Required_ **string** - The name of the service that is being called. -See [/hooks](https://api.github.com/hooks) for the possible names. - -`config` -: _Required_ **hash** - A Hash containing key/value pairs to provide -settings for this hook. Modifying this will replace the entire config -object. These settings vary between the services and -are defined in the -[github-services](https://github.com/github/github-services) repo. -Booleans are stored internally as "1" for true, and "0" for false. Any -JSON true/false values will be converted automatically. - - - -You can change a hook to send straight JSON by - -`events` -: _Optional_ **array** - Determines what events the hook is triggered -for. This replaces the entire array of events. Default: `["push"]`. - -`add_events` -: _Optional_ **array** - Determines a list of events to be added to the -list of events that the Hook triggers for. - -`remove_events` -: _Optional_ **array** - Determines a list of events to be removed from the -list of events that the Hook triggers for. - -`active` -: _Optional_ **boolean** - Determines whether the hook is actually -triggered on pushes. +### Parameters -Example: The ["web" service hook](https://github.com/github/github-services/blob/master/services/web.rb#L4-11) -takes these fields: +Name | Type | Description +-----|------|-------------- +`config`|`object` | Key/value pairs to provide settings for this hook. Modifying this will replace the entire config object. These settings vary between hooks and some are defined in the [github-services](https://github.com/github/github-services) repository. Booleans are stored internally as "1" for true, and "0" for false. Any JSON `true`/`false` values will be converted automatically. +`events`|`array` | Determines what events the hook is triggered for. This replaces the entire array of events. Default: `["push"]` +`add_events`|`array` | Determines a list of events to be added to the list of events that the Hook triggers for. +`remove_events`|`array` | Determines a list of events to be removed from the list of events that the Hook triggers for. +`active`|`boolean` | Determines whether the hook is actually triggered on pushes. -* `url` -* `content_type` -* `secret` -Here's how you can setup a hook that posts raw JSON (instead of the default -legacy format): +#### Example <%= json \ - :name => "web", :active => true, - :add_events => ['pull_request'], - :config => { - :url => "http://requestb.in", - :content_type => "json"} + :add_events => ['pull_request'] %> ### Response @@ -172,12 +99,26 @@ legacy format): <%= headers 200 %> <%= json :hook %> -## Test a hook +## Test a `push` hook This will trigger the hook with the latest push to the current -repository. +repository if the hook is subscribed to `push` events. If the +hook is not subscribed to `push` events, the server will respond +with 204 but no test POST will be generated. + + POST /repos/:owner/:repo/hooks/:id/tests - POST /repos/:owner/:repo/hooks/:id/test +**Note**: Previously `/repos/:owner/:repo/hooks/:id/test` + +### Response + +<%= headers 204 %> + +## Ping a hook + +This will trigger a [ping event][ping-event-url] to be sent to the hook. + + POST /repos/:owner/:repo/hooks/:id/pings ### Response @@ -191,15 +132,35 @@ repository. <%= headers 204 %> +## Receiving Webhooks + +In order for {{ site.data.variables.product.product_name }} to send webhook payloads, your server needs to be accessible from the Internet. We also highly suggest using SSL so that we can send encrypted payloads over HTTPS. + +### Webhook Headers + +GitHub will send along several HTTP headers to differentiate between event types and payload identifiers. + +Name | Description +-----|-----------| +`X-GitHub-Event` | The [event type](/v3/activity/events/types/) that was triggered. +`X-GitHub-Delivery` | A [guid][guid] to identify the payload and event being sent. +`X-Hub-Signature` | The value of this header is computed as the HMAC hex digest of the body, using the `secret` config option as the key. + ## PubSubHubbub -GitHub can also serve as a [PubSubHubbub][pubsub] hub for all repositories. PSHB is a simple publish/subscribe protocol that lets servers register to receive updates when a topic is updated. The updates are sent with an HTTP POST request to a callback URL. Topic URLs for a GitHub repository's pushes are in this format: +GitHub can also serve as a [PubSubHubbub][pubsub] hub for all repositories. +PSHB is a simple publish/subscribe protocol +that lets servers register to receive updates when a topic is updated. +The updates are sent with an HTTP POST request to a callback URL. +Topic URLs for a GitHub repository's pushes are in this format: https://github.com/:owner/:repo/events/:event -The event can be any Event string that is listed at the top of this +The event can be any [event][events-url] string that is listed at the top of this document. +### Response format + The default format is what [existing post-receive hooks should expect][post-receive]: A JSON body sent as the `payload` parameter in a POST. You can also specify to receive the raw JSON body with either an @@ -208,6 +169,8 @@ POST. You can also specify to receive the raw JSON body with either an Accept: application/json https://github.com/:owner/:repo/events/push.json +### Callback URLs + Callback URLs can use either the `http://` protocol, or `github://`. `github://` callbacks specify a GitHub service. @@ -217,38 +180,38 @@ Callback URLs can use either the `http://` protocol, or `github://`. # Send updates to Campfire github://campfire?subdomain=github&room=Commits&token=abc123 -The GitHub PubSubHubbub endpoint is: https://api.github.com/hub. -(GitHub Enterprise users should use http://yourhost/api/v3/hub as the +### Subscribing + +The GitHub PubSubHubbub endpoint is: `https://api.github.com/hub`. +(GitHub Enterprise users should use `http://yourhost/api/v3/hub` as the PubSubHubbub endpoint, but not change the `hub.topic` URI format.) A successful request with curl looks like: - curl -u "user" -i \ - https://api.github.com/hub \ - -F "hub.mode=subscribe" \ - -F "hub.topic=https://github.com/:owner/:repo/events/push" \ - -F "hub.callback=http://postbin.org/123" +``` command-line +curl -u "user" -i \ + https://api.github.com/hub \ + -F "hub.mode=subscribe" \ + -F "hub.topic=https://github.com/:owner/:repo/events/push" \ + -F "hub.callback=http://postbin.org/123" +``` PubSubHubbub requests can be sent multiple times. If the hook already exists, it will be modified according to the request. -### Parameters - -`hub.mode` -: _Required_ **string** - Either `subscribe` or `unsubscribe`. +#### Parameters -`hub.topic` -: _Required_ **string** - The URI of the GitHub repository to subscribe -to. The path must be in the format of `/:owner/:repo/events/:event`. +Name | Type | Description +-----|------|-------------- +``hub.mode``|`string` | **Required**. Either `subscribe` or `unsubscribe`. +``hub.topic``|`string` |**Required**. The URI of the GitHub repository to subscribe to. The path must be in the format of `/:owner/:repo/events/:event`. +``hub.callback``|`string` | The URI to receive the updates to the topic. +``hub.secret``|`string` | A shared secret key that generates a SHA1 HMAC of the outgoing body content. You can verify a push came from GitHub by comparing the raw request body with the contents of the `X-Hub-Signature` header. You can see [the PubSubHubbub documentation][pshb-secret] for more details. -`hub.callback` -: _Required_ **string** - The URI to receive the updates to the topic. -`hub.secret` -: _Optional_ **string** - A shared secret key that generates a SHA1 HMAC -of the payload content. You can verify a push came from GitHub by -comparing the received body with the contents of the `X-Hub-Signature` -header. - -[pubsub]: http://code.google.com/p/pubsubhubbub/ +[guid]: http://en.wikipedia.org/wiki/Globally_unique_identifier +[pubsub]: https://github.com/pubsubhubbub/PubSubHubbub [post-receive]: http://help.github.com/post-receive-hooks/ - +[pshb-secret]: https://pubsubhubbub.github.io/PubSubHubbub/pubsubhubbub-core-0.4.html#authednotify +[events-url]: /webhooks/#events +[ping-event-url]: /webhooks/#ping-event +[org-hooks]: /v3/orgs/hooks/ diff --git a/content/v3/repos/invitations.md b/content/v3/repos/invitations.md new file mode 100644 index 0000000000..50469923aa --- /dev/null +++ b/content/v3/repos/invitations.md @@ -0,0 +1,98 @@ +--- +title: Repository Invitations +--- + +# Repository Invitations + +{{#tip}} + +We're currently offering a preview of the Repository Invitations API. + +To access the API during the preview period, you must provide a custom [media type](/v3/media) in the `Accept` header: + +``` +application/vnd.github.swamp-thing-preview+json +``` + +{{/tip}} + +{:toc} + + + +## Invite a user to a repository + +Use the API endpoint for adding a collaborator [here](/v3/repos/collaborators). + + + +## List invitations for a repository + + GET /repositories/:repo_id/invitations + +When authenticating as a user with admin rights to a repository, this endpoint will list all currently open repository invitations. + +### Response + +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:repository_invitation) { |h| [h] } %> + + + +## Delete a repository invitation + + DELETE /repositories/:repo_id/invitations/:invitation_id + +### Response + +<%= headers 204 %> + + + +## Update a repository invitation + + PATCH /repositories/:repo_id/invitations/:invitation_id + +### Input + +Name | Type | Description +-----|------|-------------- +`permissions`|`string` | The permissions that the associated user will have on the repository. Valid values are `read`, `write`, and `admin`. + +### Response + +<%= headers 200 %> +<%= json(:repository_invitation) %> + + + +## List a user's repository invitations + + GET /user/repository_invitations + +When authenticating as a user, this endpoint will list all currently open repository invitations for that user. + +### Response + +<%= headers 200 %> +<%= json(:repository_invitation) { |h| [h] } %> + + + +## Accept a repository invitation + + PATCH /user/repository_invitations/:invitation_id + +### Response + +<%= headers 204 %> + + + +## Decline a repository invitation + + DELETE /user/repository_invitations/:invitation_id + +### Response + +<%= headers 204 %> diff --git a/content/v3/repos/keys.md b/content/v3/repos/keys.md index 464de222d5..db2fdcc7cc 100644 --- a/content/v3/repos/keys.md +++ b/content/v3/repos/keys.md @@ -1,57 +1,68 @@ --- -title: Repo Deploy Keys | GitHub API +title: Deploy Keys --- -# Repo Deploy Keys API +# Deploy Keys -* TOC {:toc} -## List + + +## List deploy keys GET /repos/:owner/:repo/keys ### Response -<%= headers 200 %> -<%= json(:public_key) { |h| [h] } %> +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:deploy_key) { |h| [h] } %> + + -## Get +## Get a deploy key GET /repos/:owner/:repo/keys/:id ### Response <%= headers 200 %> -<%= json :public_key %> +<%= json :deploy_key %> -## Create + + +## Add a new deploy key POST /repos/:owner/:repo/keys -### Input +### Parameters -<%= json :title => "octocat@octomac", :key => "ssh-rsa AAA..." %> +Name | Type | Description +-----|------|------------- +`title`|`string`|A name for the key. +`key`|`string`|The contents of the key. +`read_only`|`boolean`|If `true`, the key will only be able to read repository contents. Otherwise, the key will be able to read and write. -### Response +#### Example -<%= headers 201, :Location => "https://api.github.com/user/repo/keys/1" %> -<%= json :public_key %> +Here's how you can create a read-only deploy key: -## Edit +<%= json :title => "octocat@octomac", :key => "ssh-rsa AAA...", :read_only => true %> - PATCH /repos/:owner/:repo/keys/:id +### Response -### Input +<%= headers 201, :Location => get_resource(:deploy_key)['url'] %> +<%= json :deploy_key %> -<%= json :title => "octocat@octomac", :key => "ssh-rsa AAA..." %> + -### Response +## Edit a deploy key -<%= headers 200 %> -<%= json :public_key %> +Deploy keys are immutable. If you need to update a key, [remove the +key](#remove-a-deploy-key) and [create a new one](#add-a-new-deploy-key) instead. + + -## Delete +## Remove a deploy key DELETE /repos/:owner/:repo/keys/:id diff --git a/content/v3/repos/merging.md b/content/v3/repos/merging.md index ab51266df1..ed5285c212 100644 --- a/content/v3/repos/merging.md +++ b/content/v3/repos/merging.md @@ -1,15 +1,14 @@ --- -title: Repo Merging | GitHub API +title: Merging --- -# Repo Merging API +# Merging -* TOC {:toc} The Repo Merging API supports merging branches in a repository. This accomplishes essentially the same thing as merging one branch into another in a local repository -and then pushing to GitHub. The benefit is that the merge is done on the server side +and then pushing to {{ site.data.variables.product.product_name }}. The benefit is that the merge is done on the server side and a local repository is not needed. This makes it more appropriate for automation and other tools where maintaining local repositories would be cumbersome and inefficient. @@ -21,15 +20,12 @@ The authenticated user will be the author of any merges done through this endpoi ### Input -base -: _Required_ **string** - The name of the base branch that the head will be merged into. +Name | Type | Description +-----|------|-------------- +`base`|`string` | **Required**. The name of the base branch that the head will be merged into. +`head`|`string` | **Required**. The head to merge. This can be a branch name or a commit SHA1. +`commit_message`|`string` | Commit message to use for the merge commit. If omitted, a default message will be used. -head -: _Required_ **string** - The head to merge. This can be a branch name or a commit SHA1. - -commit_message -: _Optional_ **string** - Commit message to use for the merge commit. -If omitted, a default message will be used. <%= json \ :base => "master", @@ -51,8 +47,12 @@ If omitted, a default message will be used. <%= headers 409 %> <%= json({ :message => "Merge Conflict" }) %> -### Missing base or head response +### Missing base response <%= headers 404 %> <%= json(:message => "Base does not exist") %> + +### Missing head response + +<%= headers 404 %> <%= json(:message => "Head does not exist") %> diff --git a/content/v3/repos/pages.md b/content/v3/repos/pages.md new file mode 100644 index 0000000000..78f8c5ba94 --- /dev/null +++ b/content/v3/repos/pages.md @@ -0,0 +1,91 @@ +--- +title: Pages +--- + +# Pages + +{:toc} + +The GitHub Pages API retrieves information about your GitHub Pages configuration, and +the statuses of your builds. Information about the site and the builds can only be +accessed by authenticated owners, even though the websites are public. + +In JSON responses, `status` can be one of: + +* `null`, which means the site has yet to be built +* `queued`, which means the build has been requested but not yet begun +* `building`, which means the build is in progress +* `built`, which means the site has been built +* `errored`, which indicates an error occurred during the build + +## Get information about a Pages site + + GET /repos/:owner/:repo/pages + +{% if page.version == 'dotcom' or page.version > 2.7 %} + +{{#tip}} + + + + Additional functionality of the GitHub Pages API is currently available for developers to preview. + During the preview period, the API may change without advance notice. + + To access the additional functionality during the preview period, you must provide a custom [media type](/v3/media) in the `Accept` header: + + application/vnd.github.mister-fantastic-preview+json + + When the [preview flag](#preview-period) is passed, the response will contain an additional field, `html_url`, which will contain the absolute URL (with scheme) to the rendered site (e.g., `https://username.github.io`, or `http://example.com`). + +{{/tip}} + +{% endif %} + +### Response + +<%= headers 200 %> +<%= json(:pages) %> + +{% if page.version == 'dotcom' or page.version > 2.7 %} + +## Request a page build + + POST /repos/:owner/:repo/pages/builds + +{{#tip}} + + + + This endpoint is currently available for developers to preview. + During the preview period, the API may change without advance notice. + + To access this endpoint during the preview period, you must provide a custom [media type](/v3/media) in the `Accept` header: + + application/vnd.github.mister-fantastic-preview+json + +{{/tip}} + +You can request that your site be built from the latest revision on the default branch. This has the same effect as pushing a commit to your default branch, but does not require an additional commit. Manually triggering page builds can be helpful when diagnosing build warnings and failures. + +Build requests are limited to one concurrent build per repository and one concurrent build per requester. If you request a build while another is still in progress, the second request will be queued until the first completes. + +### Response + +<%= headers 200 %> +<%= json(:pages_request_build) %> + +{% endif %} + +## List Pages builds + + GET /repos/:owner/:repo/pages/builds + +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:pages_build) { |h| [h] } %> + +## List latest Pages build + + GET /repos/:owner/:repo/pages/builds/latest + +<%= headers 200 %> +<%= json(:pages_build) %> diff --git a/content/v3/repos/pre_receive_hooks.md b/content/v3/repos/pre_receive_hooks.md new file mode 100644 index 0000000000..2eef1d9459 --- /dev/null +++ b/content/v3/repos/pre_receive_hooks.md @@ -0,0 +1,88 @@ +--- +title: Repository Pre-receive Hooks +--- + +# Repository Pre-receive Hooks (Enterprise) + +{{#tip}} + + + + APIs for managing pre-receive hooks are currently available for developers to preview. + During the preview period, the APIs may change without advance notice. + + To access the API you must provide a custom [media type](/v3/media) in the `Accept` header: + + application/vnd.github.eye-scream-preview + +{{/tip}} + + +{:toc} + +The Repository Pre-receive Hooks API allows you to view and modify +enforcement of the pre-receive hooks that are available to a repository. + +Prefix all the endpoints for this API with the following URL: + +``` command-line +http(s)://hostname/api/v3 +``` + +## Object attributes + +| Name | Type | Description | +|---------------------|----------|-----------------------------------------------------------| +| `name` | `string` | The name of the hook. | +| `enforcement` | `string` | The state of enforcement for the hook on this repository. | +| `configuration_url` | `string` | URL for the endpoint where enforcement is set. | + +Possible values for *enforcement* are `enabled`, `disabled` and`testing`. `disabled` indicates the pre-receive hook will not run. `enabled` indicates it will run and reject +any pushes that result in a non-zero status. `testing` means the script will run but will not cause any pushes to be rejected. + +`configuration_url` may be a link to this repository, it's organization +owner or global configuration. Authorization to access the endpoint at +`configuration_url` is determined at the owner or site admin level. + +## List pre-receive hooks + +List all pre-receive hooks that are enabled or testing for this +repository as well as any disabled hooks that are allowed to be enabled +at the repository level. Pre-receive hooks that are disabled at a higher +level and are not configurable will not be listed. + + GET /repos/:owner/:repo/pre-receive-hooks + +<%= headers 200, :pagination => default_pagination_rels %> +<%= json :pre_receive_hooks_repo %> + +## Get a single pre-receive hook + + GET /repos/:owner/:repo/pre-receive-hooks/:id + +<%= headers 200 %> <%= json :pre_receive_hook_repo %> + +## Update pre-receive hook enforcement + +For pre-receive hooks which are allowed to be configured at the repo level, you can set `enforcement` + + PATCH /repos/:owner/:repo/pre-receive-hooks/:id + +<%= json :enforcement => "enabled" %> + +### Response + +<%= headers 200 %><%= json :pre_receive_hook_repo_update %> + +## Remove enforcement overrides for a pre-receive hook + +Deletes any overridden enforcement on this repository for the specified +hook. + + DELETE /repos/:owner/:repo/pre-receive-hooks/:id + +### Response + +Responds with effective values inherited from owner and/or global level. + +<%= headers 200 %> <%= json :pre_receive_hook_repo %> diff --git a/content/v3/repos/releases.md b/content/v3/repos/releases.md new file mode 100644 index 0000000000..73a2e10891 --- /dev/null +++ b/content/v3/repos/releases.md @@ -0,0 +1,242 @@ +--- +title: Releases +--- + +# Releases + +{:toc} + +## List releases for a repository + +{{#tip}} + +This returns a list of releases, which does not include regular +Git tags that have not been associated with a release. +To get a list of Git tags, use the [Repository Tags API][repo tags api]. + +{{/tip}} + +Information about published releases are available to everyone. +Only users with push access will receive listings for draft releases. + + GET /repos/:owner/:repo/releases + +### Response + +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:release) { |h| [h] } %> + +## Get a single release + + GET /repos/:owner/:repo/releases/:id + +### Response + +{{#tip}} + + + +**Note:** This returns an `upload_url` key corresponding to the endpoint for uploading release assets. This key is a [hypermedia resource](https://developer.github.com/v3/#hypermedia). + +{{/tip}} + +<%= headers 200 %> +<%= json :release %> + +## Get the latest release + +View the latest published full release for the repository. Draft releases and prereleases are not returned by this endpoint. + + GET /repos/:owner/:repo/releases/latest + +### Response + +<%= headers 200 %> +<%= json :release %> + +## Get a release by tag name + +Get a published release with the specified tag. + + GET /repos/:owner/:repo/releases/tags/:tag + +### Response + +<%= headers 200 %> +<%= json :release %> + + +## Create a release + +Users with push access to the repository can create a release. + + POST /repos/:owner/:repo/releases + +### Input + +Name | Type | Description +-----|------|-------------- +`tag_name`|`string` | **Required**. The name of the tag. +`target_commitish`|`string` | Specifies the commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Unused if the Git tag already exists. Default: the repository's default branch (usually `master`). +`name`|`string` | The name of the release. +`body`|`string` | Text describing the contents of the tag. +`draft`|`boolean` | `true` to create a draft (unpublished) release, `false` to create a published one. Default: `false` +`prerelease`|`boolean` | `true` to identify the release as a prerelease. `false` to identify the release as a full release. Default: `false` + +#### Example + +<%= json \ + :tag_name => "v1.0.0", + :target_commitish => "master", + :name => "v1.0.0", + :body => "Description of the release", + :draft => false, + :prerelease => false +%> + +### Response + +<%= headers 201, :Location => get_resource(:created_release)['url'] %> +<%= json(:created_release) %> + +## Edit a release + +Users with push access to the repository can edit a release. + + PATCH /repos/:owner/:repo/releases/:id + +### Input + +Name | Type | Description +-----|------|-------------- +`tag_name`|`string` | The name of the tag. +`target_commitish`|`string` | Specifies the commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Unused if the Git tag already exists. Default: the repository's default branch (usually `master`). +`name`|`string` | The name of the release. +`body`|`string` | Text describing the contents of the tag. +`draft`|`boolean` | `true` makes the release a draft, and `false` publishes the release. +`prerelease`|`boolean` | `true` to identify the release as a prerelease, `false` to identify the release as a full release. + +#### Example + +<%= json \ + :tag_name => "v1.0.0", + :target_commitish => "master", + :name => "v1.0.0", + :body => "Description of the release", + :draft => false, + :prerelease => false +%> + +### Response + +<%= headers 200 %> +<%= json :release %> + +## Delete a release + +Users with push access to the repository can delete a release. + + DELETE /repos/:owner/:repo/releases/:id + +### Response + +<%= headers 204 %> + +## List assets for a release + + GET /repos/:owner/:repo/releases/:id/assets + +### Response + +<%= headers 200, :pagination => default_pagination_rels %> +<%= json(:release_asset) { |h| [h] } %> + +## Upload a release asset + +This endpoint makes use of [a Hypermedia relation](/v3/#hypermedia) to determine which URL to access. +This endpoint is provided by a URI template in [the release's API response](#get-a-single-release). +{% if page.version == 'dotcom' %}You need to use an HTTP client which supports +SNI to make calls to this endpoint.{% endif %} + +The asset data is expected in its raw binary form, rather than JSON. +Everything else about the endpoint is the same as the rest of the API. For example, you'll still need to pass your authentication to be able to upload an asset. + + POST https://
master branch.language:go is not valid, while amazing language:go is.