Skip to Content
SimulatorsGitHubIssues, events and the timeline

Simulators

Issues, events and the timeline

Issues are a REST surface of their own: list and create them, get and edit one by number (state closes and reopens it, with a state_reason), and lock and unlock its conversation. Its conversation comments list per subject and repository-wide, are created on a subject and are edited or deleted by comment id. Load the issue tracker scenario, open an issue, comment, close it and read its events:

H='Authorization: Bearer ghp_anything'
curl -s -X POST "$RYSTIC_URL/_rystic/scenario" -d '{"name":"github-pulls_issue_tracker"}' -o /dev/null
curl -s "$RYSTIC_URL/repos/tb-owner/tb-repo/issues?state=all" -H "$H" | jq -c '[.[] | {number, pr: has("pull_request"), state}]'
# -> [{"number":6,"pr":false,"state":"open"},{"number":3,"pr":true,"state":"open"},{"number":5,"pr":false,"state":"closed"},{"number":4,"pr":false,"state":"closed"},{"number":2,"pr":false,"state":"open"},{"number":1,"pr":false,"state":"open"}]
curl -s -X POST "$RYSTIC_URL/repos/tb-owner/tb-repo/issues" -H "$H" -d '{"title":"Retries drop the last error","labels":["bug"]}' | jq -c '{number, state}'
# -> {"number":7,"state":"open"}
curl -s -X POST "$RYSTIC_URL/repos/tb-owner/tb-repo/issues/7/comments" -H "$H" -d '{"body":"Reproduced **twice**"}' | jq -c '{id, body}'
# -> {"id":12100006,"body":"Reproduced **twice**"}
curl -s "$RYSTIC_URL/repos/tb-owner/tb-repo/issues/7/comments" -H "$H" -H 'Accept: application/vnd.github.html+json' | jq -c '.[0] | {body_html}'
# -> {"body_html":"<p>Reproduced <strong>twice</strong></p>\n"}
curl -s -X PATCH "$RYSTIC_URL/repos/tb-owner/tb-repo/issues/7" -H "$H" -d '{"state":"closed","state_reason":"completed"}' | jq -c '{state, state_reason}'
# -> {"state":"closed","state_reason":"completed"}
curl -s "$RYSTIC_URL/repos/tb-owner/tb-repo/issues/7/events" -H "$H" | jq -c '[.[].event]'
# -> ["labeled","closed"]
curl -s "$RYSTIC_URL/repos/tb-owner/tb-repo/issues/7/timeline" -H "$H" | jq -c '[.[].event]'
# -> ["commented","labeled","closed"]

One number sequence

A repository numbers its issues and its pull requests from the same counter, as GitHub does. In github-pulls_open_queue, which holds pull requests #41 to #44, the next thing opened, issue or pull request, is #45. A number addresses one or the other and never both, and GET .../issues/{n} on a pull request’s number returns that pull request rendered as an issue.

github-pulls_issue_tracker is the scenario to boot for issues: five issues around one pull request (#3), interleaved so the shared sequence is visible from the first read. Its conversation comments hang off both: two on #1, one on #2, one on #6 and one on the pull request. A pull request’s conversation comments live on the issues route that gh pr comment writes to, not on the diff-anchored .../pulls/{n}/comments.

Events and the timeline

GET .../issues/{n}/events lists a subject’s issue events oldest first: labeled, assigned, review requested, head ref force-pushed, merged, closed and the rest. A scenario’s events agree with its records: a closed issue logs its close, a merged pull request its merge and close, a locked subject its lock.

The writes below append the event GitHub logs, with its keys. Closing, reopening, renaming and merging count over REST or GraphQL. Locking and unlocking count over REST. Label, assignee and milestone changes count through the label and assignee routes, PATCH .../issues/{n}, or at creation.

WriteEventKeys
closing an issue or pull requestclosedstate_reason, and intent (null)
reopening onereopenedon an issue, state_reason: "reopened"
renaming onerenamedrename
locking onelockedlock_reason
unlocking oneunlocked
merging a pull requestmerged, then closed
readying a pull requestready_for_review
drafting a pull requestconvert_to_draft
adding or removing a labellabeled or unlabeledlabel {name, color}
adding or removing an assigneeassigned or unassignedassignee, assigner
adding or removing a milestonemilestoned or demilestonedmilestone {title}

Differs from GitHub: requesting a review or removing a request logs no event (review_requested, review_request_removed).

GET /repos/{owner}/{repo}/issues/events reads the repository’s whole feed, newest first. GET .../issues/events/{event_id} reads one of them.

Differs from GitHub: an event in the repository’s feed, or read by its id, carries no issue.

GET .../issues/{n}/timeline merges a subject’s events with these entries, ordered by time:

eventEntry
commenteda conversation comment
revieweda submitted review
line_commentedthe review comments of one review, grouped
committeda commit of a pull request

The committed entries include every commit reachable from the pull request’s head, through every parent, and exclude each commit reachable from its base. The events list and the timeline page with per_page and page.

Rendered bodies

Every route that returns a body honors GitHub’s body media types:

AcceptBody fields
application/vnd.github.html+jsonbody_html in place of body
application/vnd.github.text+jsonbody_text in place of body
application/vnd.github.full+jsonbody, body_text and body_html
application/vnd.github.raw+json, or no media typebody, the Markdown as stored

Reviews and review comments take the same suffixes under application/vnd.github-commitcomment.*.

Differs from GitHub: the HTML is CommonMark with GitHub’s tables, strikethrough, autolinks and task lists, not GitHub’s renderer. Mentions and issue references stay text.

Avatars

Every avatar_url names avatars.githubusercontent.com, which the simulator re-bases onto its own origin like api.github.com. /u/{id} (/in/{id} for an app) returns a PNG identicon drawn from the id: the same image for the same user every time, sized by ?s= up to 460. Nothing is fetched from GitHub.

Last updated on