Menu ▾ ▴

#542 Mirror GitHub issues and pull requests into timelines (#538)

open
nobody
None
5 hours ago
6 hours ago
Anonymous
No

Originally created by: athanclark

The first work-item source for [#538]: GitHub issues and pull requests mirrored into timelines, read-only. This is stacked on [#541] → [#540] → [#539] (ongoing durations); I'll retarget it as those merge.

The mapping

On GitHub On the timeline
An issue or PR is opened A duration from its creation, ongoing
Closed or merged The duration ends then; reopened makes it ongoing again
Edited, labelled, milestoned Its title, notes and tags follow
Assigned or unassigned A moment, tagged assigned or unassigned and assignee:<login>
A PR saying "closes [#12]" A link to issue 12, when both are on the timeline
An issue is deleted Its duration is removed (webhook only)
  • Tags: github, repository:…, issue or pull request, state:…, assignee:…, label:…, milestone:…. Separating by assignee: tags gives the per-person Gantt view the issue asked about, with no new view.
  • IDs: they come from the source (gh:<owner>:<repo>:<n>), so a redelivered webhook and a re-run import update the same entities rather than adding copies.

Pieces

  • server/github-source.mjs: the mapping, signature checks and routing rules (owner/name or owner/* → timeline, then a default), with no I/O.
  • server/github-receiver.mjs (npm run github), the webhook receiver:
  • it checks X-Hub-Signature-256 (401 otherwise), answers 202 at once and coalesces changes per timeline;
  • it saves links apart, so a link to an issue the timeline doesn't hold is let go;
  • it retries 409, 429, 5xx and unreachable errors, and drains its queue on SIGTERM.
  • server/import-github.mjs (och-import-github), the backfill:
  • it reads issues and pull requests (/issues?state=all) and assignments (/issues/events), following Link pages;
  • options: --since, --no-events, --dry-run, a route file or --timeline;
  • it waits for a rate limit that resets within 15 minutes, and sends the token only to the GitHub API's origin (GitHub Enterprise through GITHUB_API_URL).
  • TimelineWriter.send can now delete durations and add links.
  • Gregorian check: both tools check that their timelines have the Gregorian display before writing.

docs/github.md (also added to the help area) covers setup, the mapping, limits, and which personal data is copied: logins of assignees, titles and the start of each item's text. Comments and email addresses are not copied.

Tests

  • Unit: 13 new tests in test/github-source.test.mjs, run against fake GitHub and OpenChronology APIs. They cover:
  • the mapping, IDs, "closes" parsing, signatures and routes;
  • receiver coalescing, retries, refused links, and HTTP end to end;
  • importer paging, since, links, the token and User-Agent, and the CLI's arguments and dry run.
  • Real GitHub: a dry run against this repository since 1 November read 125 items (12 open) and 51 links in 13 requests.
  • npm test: passes apart from contents.test.mjs, which fails locally with git ENOBUFS.

Not in this PR

  • Server packages: deb, rpm, Homebrew, Nix, AUR and the Docker Compose service. The log tools ship in all of them; this one runs from a checkout or npm for now.
  • More sources: Microsoft Planner and kanban boards, using the same mapping.

🤖 Generated with Claude Code

https://claude.ai/code/session_011fFY8eruEi1xAkkMBni13B

Related

Tickets: #12
Tickets: #538
Tickets: #539
Tickets: #540
Tickets: #541
Tickets: #543

Discussion

  • Anonymous

    Anonymous - 6 hours ago

    Originally posted by: athanclark

    Tags now follow GitHub's reference style (requested in review): github/<owner>/<name>#<number> on the item's duration and on its assignment moments, github/<owner>/<name> for the repository, github/<login> for people, and assigned on items that have assignees (assignment moments carry assigned or unassigned). They replace repository: and assignee:. See docs/github.md.

    🤖 Generated with Claude Code

     
  • Anonymous

    Anonymous - 6 hours ago

    Originally posted by: athanclark

    Added event moments, as discussed. Labels, milestones, closed/reopened/merged (by whom), renames, review requests and reviews, draft/ready, mentions (with a link), sub-issues and duplicates, project board moves, and lock/pin/transfer each become a moment tagged with the item's tag, the event, its subject (label:…, review:…, status:…) and github/<login>. The importer now reads each item's timeline. The receiver also takes Pull request reviews, Issue comments (mentions only, never the text), Sub-issues and Projects v2 items (resolved through GraphQL with GITHUB_TOKEN). Each kind can be switched off with events in the routes, or --events. A dry run on this repository since 6 November found 70 closes, 81 mentions, 31 merges, 4 labels and 1 rename in 84 requests.

    Board moves have a caveat: GitHub's timelines have mostly stopped recording Projects status changes since September 2026 (https://github.com/orgs/community/discussions/209484), so history comes reliably from the receiver from now on.

    Releases, milestones as durations and time-in-column durations are next.

    🤖 Generated with Claude Code

     

Log in to post a comment.