Documentation
¶
Overview ¶
Package migrate exports a mirror into an issuetap fixture document — the seed a fresh standalone workspace loads one-shot (origin/issuetap.yaml, GDK-1264). Reads are mirror-only; the single origin round-trip is the attachment byte download, and the caller owns that client.
The document shapes mirror issuetap's internal/fixtures.Doc YAML contract (that package is internal, so the structs are declared here). Three rules came out of the GDK-1262 spike and must not regress:
- priorities emit in id order — issuetap assigns priority_rank by catalog position, so encounter order flips the ranking.
- links emit each issue's own mirror rows verbatim, both directions — the fixture load is single-sided (runtime AddIssueLink is what materializes both projections), so a pair exists on both ends only if both ends declare it.
- the status catalog includes every status id the changelog references, not just the ones issues currently sit in.
Index ¶
- Constants
- func Build(ctx context.Context, db *sql.DB, opt Options) (*Doc, *Stats, error)
- func InlineAttachments(ctx context.Context, doc *Doc, fetch Fetch, st *Stats)
- type Attachment
- type Comment
- type Doc
- type Fetch
- type History
- type HistoryItem
- type Issue
- type IssueType
- type Link
- type Options
- type Page
- type PageComment
- type Priority
- type Project
- type Space
- type Stats
- type Status
- type User
- type VerifyRow
Constants ¶
const MaxAttachmentBytes = 16 << 20
MaxAttachmentBytes caps one inlined file. The fixture is a YAML document read into memory; a file past this stays metadata-only and is reported.
Variables ¶
This section is empty.
Functions ¶
func Build ¶
Build reads the mirror and assembles the fixture document. db must be a mirror connection (read-only is fine); nothing is written.
func InlineAttachments ¶
InlineAttachments downloads each attachment's bytes and inlines them into the document — printable text/* as Text, anything else as std base64. A missing file (404) or an oversized one keeps its metadata row and is counted, never fatal: a partial archive that says what is missing beats no archive.
Types ¶
type Attachment ¶
type Attachment struct {
Filename string `json:"filename"`
MimeType string `json:"mimeType,omitempty"`
Text string `json:"text,omitempty"`
DataBase64 string `json:"dataBase64,omitempty"`
Author string `json:"author,omitempty"`
Created string `json:"created,omitempty"`
// ContentID is the origin content id for the byte download
// (external_id when set, else the store row id — the same rule as
// store.AttachmentOrigin). Never emitted.
ContentID string `json:"-"`
// Size is the mirror's byte count, used to skip oversized files
// before spending the download. Never emitted.
Size int64 `json:"-"`
// SourceURL is the mirror's stored origin content URL (non-Jira
// sources). Non-empty means the bytes do not live behind Jira's
// /attachment/content/{id} and this pass skips them. Never emitted.
SourceURL string `json:"-"`
}
type Doc ¶
type Doc struct {
Users []User `json:"users,omitempty"`
Projects []Project `json:"projects,omitempty"`
Statuses []Status `json:"statuses,omitempty"`
Priorities []Priority `json:"priorities,omitempty"`
IssueTypes []IssueType `json:"issueTypes,omitempty"`
Issues []Issue `json:"issues,omitempty"`
Spaces []Space `json:"spaces,omitempty"`
Pages []Page `json:"pages,omitempty"`
}
Doc is the fixture document. Key names follow issuetap's internal/fixtures.Doc (its json and yaml tags agree); only the parts a mirror can fill are declared. Emitted as JSON — see cmdMigrate for why the seed is never yaml.Marshal'd.
type Fetch ¶
Fetch downloads one attachment's bytes by content id. Implemented by the caller over the source origin client (Jira's and issuetap's /attachment/content/{id} are the same shape). A 404 returns status 404 with err nil.
type History ¶
type History struct {
At string `json:"at"`
Author string `json:"author,omitempty"`
Items []HistoryItem `json:"items"`
}
type HistoryItem ¶
type Issue ¶
type Issue struct {
Key string `json:"key"`
Summary string `json:"summary"`
Description string `json:"description,omitempty"`
Project string `json:"project,omitempty"`
Type string `json:"type,omitempty"` // id
Status string `json:"status,omitempty"` // id
Priority string `json:"priority,omitempty"`
Assignee string `json:"assignee,omitempty"`
Reporter string `json:"reporter,omitempty"`
Parent string `json:"parent,omitempty"`
Labels []string `json:"labels,omitempty"`
Components []string `json:"components,omitempty"`
FixVersions []string `json:"fixVersions,omitempty"`
Duedate string `json:"duedate,omitempty"`
Resolution string `json:"resolution,omitempty"`
Created string `json:"created,omitempty"`
Updated string `json:"updated,omitempty"`
Comments []Comment `json:"comments,omitempty"`
Attachments []Attachment `json:"attachments,omitempty"`
Links []Link `json:"links,omitempty"`
History []History `json:"history,omitempty"`
}
type Page ¶
type Page struct {
ID string `json:"id,omitempty"`
Title string `json:"title"`
Space string `json:"space"`
Version int `json:"version,omitempty"`
When string `json:"when,omitempty"`
Author string `json:"author,omitempty"`
Body string `json:"body,omitempty"`
Labels []string `json:"labels,omitempty"`
Parent string `json:"parent,omitempty"`
Comments []PageComment `json:"comments,omitempty"`
}
type PageComment ¶
type Stats ¶
type Stats struct {
Projects []string
Spaces []string
Issues int
Comments int
Attachments int
Links int
History int
Pages int
PageComments int
Users int
// Derived columns the target must reproduce from the migrated
// changelog (they are never stored in the fixture).
ReopenSum int
EpicKeys int
// Formatting nodes flattened to plain text by the fixture path
// (descriptions, comments and page bodies all load as adf.Doc(text)).
LossCodeBlock int
LossMedia int
LossTable int
// Dropped because the other end is outside the migrated set.
DroppedLinks int
DroppedParents []string
DroppedPageParents int
// Not migrated (the fixture has no slot, or out of scope).
DevLinks int
CustomIssues int
SprintIssues int
// Attachment byte pass.
AttachInlined int
AttachMissing int // origin answered 404 — metadata kept
AttachTooLarge int
AttachSkipURL int // stored origin URL (non-Jira source) — out of scope
AttachErrors []string
MissingUsers []string // referenced account ids absent from the users catalog
UnnamedStatuses []string // history-only status ids with no display name
}
Stats is the honest half of the export: what was counted, what was flattened, what was dropped and why. The verification report is built from it — silent loss and reported loss are different products.
type VerifyRow ¶
type VerifyRow struct {
Metric string `json:"metric"`
Source int `json:"source"`
Migrated int `json:"migrated"`
}
VerifyRow is one line of the migration report: a metric counted on the source mirror at export time against the same metric on the freshly filled target mirror.
func VerifyMirror ¶
VerifyMirror re-counts the exported axes on the target mirror. The derived rows (reopens, epic keys) matter most: they are never stored in the fixture, so equality proves the migrated changelog reproduces them.