# Issues, events and the timeline

Issues and pull requests on one number sequence, their conversation comments, issue events, the merged timeline, rendered bodies and avatars.

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:

```bash
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.

| Write | Event | Keys |
|---|---|---|
| closing an issue or pull request | `closed` | `state_reason`, and `intent` (null) |
| reopening one | `reopened` | on an issue, `state_reason: "reopened"` |
| renaming one | `renamed` | `rename` |
| locking one | `locked` | `lock_reason` |
| unlocking one | `unlocked` | |
| merging a pull request | `merged`, then `closed` | |
| readying a pull request | `ready_for_review` | |
| drafting a pull request | `convert_to_draft` | |
| adding or removing a label | `labeled` or `unlabeled` | `label {name, color}` |
| adding or removing an assignee | `assigned` or `unassigned` | `assignee`, `assigner` |
| adding or removing a milestone | `milestoned` or `demilestoned` | `milestone {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:

| `event` | Entry |
|---|---|
| `commented` | a conversation comment |
| `reviewed` | a submitted review |
| `line_commented` | the review comments of one review, grouped |
| `committed` | a 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:

| `Accept` | Body fields |
|---|---|
| `application/vnd.github.html+json` | `body_html` in place of `body` |
| `application/vnd.github.text+json` | `body_text` in place of `body` |
| `application/vnd.github.full+json` | `body`, `body_text` and `body_html` |
| `application/vnd.github.raw+json`, or no media type | `body`, 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.

---

Source: https://www.rystic.ai/docs/simulators/github-pulls/features/issues-and-timeline · Markdown: https://www.rystic.ai/docs/simulators/github-pulls/features/issues-and-timeline.md
