This gist describes a new GitHub API for importing issues. This API hasn't been finalized yet, but when it is -- it will be announced on the official API blog.
Overview:
- General notes
- Create a repository
- Try to start an issue import with incomplete data
- Start an issue import
- Check status of issue import
- Check status of multiple issues
- Import fails because issue has an invalid milestone, assignee, creator or label
- Import fails because of unexpected comment creation error
To access the Issue Import API, you'll need to include application/vnd.github.golden-comet-preview
in your request's Accept header. You'll also need to have admin permissions on the repository.
The maximum request size is 1MB.
Issues and comments created with this API do not trigger any notifications to mentioned users or users watching the repository into which issues are being imported. This is unlike the Issues API which does trigger notifications).
Like all other API requests, requests made to the Issue Import API are affected by regular API rate limits and abuse rate limits.
Issue imports started with this API are processed in the background asynchronously. When you start an import, you get back an import URL which you can use to check if the import completed, and whether it completed successfully or not. Because of this background processing, issue numbers are handed out to successfully imported issues once the processing is completed, and not when you start an import. As a result, if you use this API to submit two imports for issues A and B, and B is submitted after A, but before A's import completes, then it is possible that B will have a lower issue number than A. If you need to make sure that issues have specific numbers, then the recommended approach is that you start an import, wait for that import to complete and make sure it completed successfully, and only after that start a new import.
If you have any feedback or questions about the Issue Import API, please get in touch.
Create a repository using the web interface or the API.
Here is an example API request to create a repository:
curl -X POST -H "Authorization: token ${GITHUB_TOKEN}" \
-d '{"name":"foo","private":true}' \
https://api.github.com/user/repos
The Issue Import API attempts to provide actionable feedback when a request does not meet validation criteria.
curl -X POST -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.golden-comet-preview+json" \
-d '{"issue":{"title":"My money, mo issues"}}' \
https://api.github.com/repos/${GITHUB_USERNAME}/foo/import/issues
{
"message": "Validation Failed",
"errors": [
{
"resource": "Issue",
"code": "missing_field",
"field": "body"
}
],
"documentation_url": "https://developer.github.com/v3"
}
Just make a post request to the import issues API endpoint for the repository and include the issue and comments json as data. An issue only requires the following fields:
{
"issue": {
"title": "Imported from some other system",
"body": "..."
}
}
And an issue with a comment only needs the comment body added:
{
"issue": {
"title": "Imported from some other system",
"body": "..."
},
"comments": [
{
"body": "talk talk"
}
]
}
curl -X POST -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.golden-comet-preview+json" \
-d '{"issue":{"title":"Fix broken widgets","body":"- [ ] widget 1\n- [ ] widget 2","created_at":"2014-03-16T18:21:16Z"},"comments":[{"body":"Can we wrap this up soon?","created_at":"2014-03-16T17:15:42Z"}]}' \
https://api.github.com/repos/${GITHUB_USERNAME}/foo/import/issues
{
"id": 3,
"status": "pending",
"url": "https://api.github.com/repos/jonmagic/foo/import/issues/3",
"import_issues_url": "https://api.github.com/repos/jonmagic/foo/import/issues",
"repository_url": "https://api.github.com/repos/jonmagic/foo"
}
The complete json schema looks like this:
{
"issue": {
"title": "Imported from some other system",
"body": "...",
"created_at": "2014-01-01T12:34:58Z",
"closed_at": "2014-01-02T12:24:56Z",
"updated_at": "2014-01-03T11:34:53Z",
"assignee": "jonmagic",
"milestone": 1,
"closed": true,
"labels": [
"bug",
"low"
]
},
"comments": [
{
"created_at": "2014-01-02T12:34:56Z",
"body": "talk talk"
}
]
}
Note: The As of 2016-03-15 all newly created issues will be rendered with Markdown regardless of the created_at timestamp date.body
of an issue or comment will be parsed and rendered using Markdown if the created_at
value is set to a time after 2009-04-20T19:00:00Z, and using Textile if it's older. The body
may be at most 65535 characters long.
After making the API request to import an issue you can check the status of the import by making a get request to the url
value from the response in the previous post request.
curl -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.golden-comet-preview+json" \
https://api.github.com/repos/#{GITHUB_USERNAME}/foo/import/issues/3
{
"id": 3,
"status": "imported",
"url": "https://api.github.com/repos/jonmagic/foo/import/issues/3",
"import_issues_url": "https://api.github.com/repos/jonmagic/foo/import/issues",
"repository_url": "https://api.github.com/repos/jonmagic/foo",
"issue_url": "https://api.github.com/repos/jonmagic/foo/issues/1"
}
You can check the status of issues imported since a date or date and time.
curl -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.golden-comet-preview+json" \
https://api.github.com/repos/#{GITHUB_USERNAME}/foo/import/issues?since=2015-03-15
[
{
"id": 3,
"status": "imported",
"url": "https://api.github.com/repos/jonmagic/foo/import/issues/3",
"import_issues_url": "https://api.github.com/repos/jonmagic/foo/import/issues",
"repository_url": "https://api.github.com/repos/jonmagic/foo",
"issue_url": "https://api.github.com/repos/jonmagic/foo/issues/1"
}
]
What happens if you try to import an issue with an invalid attributes?
curl -X POST -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.golden-comet-preview+json" \
-d '{"issue":{"title":"Fix broken widgets","body":"...","milestone":5,
"assignee":"bobbyfoobar","labels":["bug","invalid,label"]}}' \
https://api.github.com/repos/${GITHUB_USERNAME}/foo/import/issues
{
"id": 7,
"status": "pending",
"url": "https://api.github.com/repos/jonmagic/foo/import/issues/7",
"import_issues_url": "https://api.github.com/repos/jonmagic/foo/import/issues",
"repository_url": "https://api.github.com/repos/jonmagic/foo"
}
curl -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.golden-comet-preview+json" \
https://api.github.com/repos/#{GITHUB_USERNAME}/foo/import/issues/7
{
"id": 7,
"status": "failed",
"url": "https://api.github.com/repos/jonmagic/foo/import/issues/7",
"import_issues_url": "https://api.github.com/repos/jonmagic/foo/import/issues",
"repository_url": "https://api.github.com/repos/jonmagic/foo",
"created_at": "2015-03-18T19:40:53-07:00",
"updated_at": "2015-03-18T19:40:58-07:00",
"errors": [
{
"location": "/issue/milestone",
"resource": "Issue",
"field": "milestone",
"value": "5",
"code": "invalid"
},
{
"location": "/issue/assignee",
"resource": "Issue",
"field": "assignee",
"value": "bobbyfoobar",
"code": "invalid"
},
{
"location": "/issue/labels[1]",
"resource": "Label",
"field": "name",
"value": "invalid,label",
"code": "invalid"
}
]
}
curl -X POST -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.golden-comet-preview+json" \
-d '{"issue":{"title":"foo","body":"1"},"comments":[{"body":"fail this comment somehow"}]}' \
https://api.github.com/repos/${GITHUB_USERNAME}/foo/import/issues
{
"id": 12,
"status": "pending",
"url": "https://api.github.com/repos/jonmagic/foo/import/issues/12",
"import_issues_url": "https://api.github.com/repos/jonmagic/foo/import/issues",
"repository_url": "https://api.github.com/repos/jonmagic/foo",
"created_at": "2015-03-18T21:45:58-07:00",
}
curl -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.golden-comet-preview+json" \
https://api.github.com/repos/#{GITHUB_USERNAME}/foo/import/issues/12
{
"id": 12,
"status": "failed",
"url": "https://api.github.com/repos/jonmagic/foo/import/issues/12",
"import_issues_url": "https://api.github.com/repos/jonmagic/foo/import/issues",
"repository_url": "https://api.github.com/repos/jonmagic/foo",
"created_at": "2015-03-18T21:45:58-07:00",
"updated_at": "2015-03-18T21:46:05-07:00",
"issue_url": "https://api.github.com/repos/jonmagic/foo/issues/7",
"errors": [
{
"location": "/comments[0]",
"resource": "IssueComment",
"field": null,
"value": null,
"code": "error"
}
]
}
Testing this with:
gives me:
But then
yields:
and
yields:
and sure enough: the issue is not created.