Importing issues from GitHub or GitLab
Bringing a repository's issues into a project, with their comments, labels, milestones and history, read from the host with a token you give.
Teams that track their work as GitHub or GitLab issues can bring a repository's issues into a project. Alba Ticket reads them from the host's API: the bodies, who opened them and who is assigned to them, their labels and milestone, every comment, and every time each was closed and reopened, which becomes the ticket's history. Pull and merge requests are left out; they are not issues.
The code host integration is a different thing: it links commits, branches and pull requests to tickets as work goes on. The import is a one-time move of the issues themselves.
What you need
- The repository:
owner/nameon GitHub, or the project's path on GitLab (group/project). - An access token that can read the repository's issues: on GitHub a fine-grained token with read access to issues and metadata, on GitLab a token with the
read_apiscope. A public repository on github.com or gitlab.com can be read without one, within the host's limits for anonymous requests. The token is stored encrypted and used for nothing else. - For a self-managed instance, its address (
https://gitlab.example.com); leave it empty for github.com or gitlab.com. - The project the issues go into, or a key and a name for a new one. The key is suggested from the repository's name.
Step 1: check the repository
Under Administration, GitHub and GitLab issues, give the repository, the token and the project, and check it. Alba Ticket asks the host for the repository, counts its open and closed issues and lists its labels and milestones, so you know the token works and what the import will do before it starts. Nothing is written.
Step 2: import
Dry run first, if you like, and then import. It goes in three stages:
- Repository: the project is found or created (with the repository's description and address), the repository's labels become the project's labels (
good first issuebecomesgood-first-issue), and its milestones become versions, released when the milestone is closed. - Tickets: one ticket per issue, page by page from the host. An issue keeps its number when the project has not used it. An open issue lands in the workflow's first status; a closed one in its first done status, with a resolution from the reason GitHub gives (completed, not planned, duplicate). A GitHub issue type, or a label such as
bug, picks the ticket type when the workspace has one of that name. The first assignee becomes the ticket's assignee; the others become watchers. Comments come across as comments, and every close and reopen as a transition in the history, by the person who did it and at the time they did. - Verification: compares the number of issues on the host with the tickets created, and the comments read with the comments imported.
People are placeholders named by their login, since the host does not give email addresses; someone who already has an account here with that username is matched instead. Placeholders are claimed on their first login or invitation, like people imported from Jira. An issue with no author belongs to whoever ran the import.
Bodies and comments are Markdown, as GitHub and GitLab write them. References like #12 and @login are kept as text; images and files attached on the host stay on the host, where the links point.
The import is idempotent: an issue already imported is left alone, so running it again brings in nothing twice, and a run that stops continues where it left off. Every issue keeps its full record from the host with the ticket, and a link back to it.
Limits and rate limits
The import reads one page of a hundred issues at a time, and each issue's comments and history in requests of their own, so a repository with ten thousand issues means some twenty thousand requests. GitHub allows five thousand an hour with a token; when the host says to wait, the import waits and carries on, so a large repository simply takes longer. A repository that fails part-way is reported with the issues that could not be read, and running the import again fetches only what is missing.