diff --git a/src/pitpkg/cliconstants.nim b/src/pitpkg/cliconstants.nim index c9bcd64..5091230 100644 --- a/src/pitpkg/cliconstants.nim +++ b/src/pitpkg/cliconstants.nim @@ -181,6 +181,30 @@ Issue Properties: after 12 hours every 2 weeks, 10a544 + relations + + Used to store information about relationships between issues. PIT treats + all relations as bi-directional and will update related tickets as + necessary to maintain the integrity of the links. + + Relations are captured as . Multiple + relations can be separated by ",". The must be a unique + issue ID or ID prefix (in the case of multiple matching issues, the first + found will be used with no guarantee on ordering). Valid value pairs for + are: + + - child-of / parent-of + - related-to (default) + - blocks / blocked-by + - follows / precedes + - caused / caused-by + + Examples: + + relation: child-of fb3e63, blocked-by 2b71c1 + relation: 2b71c1, 8f2b4c, follows 184dc6 + relation: relates-to 2b71c1 + tags If present, expected to be a comma-delimited list of text tags. The -g diff --git a/src/pitpkg/private/libpit.nim b/src/pitpkg/private/libpit.nim index f86ad8c..5292566 100644 --- a/src/pitpkg/private/libpit.nim +++ b/src/pitpkg/private/libpit.nim @@ -11,6 +11,7 @@ type filepath*: string summary*, details*: string properties*: TableRef[string, string] + relations*: seq[Relation] tags*: seq[string] state*: IssueState @@ -40,6 +41,19 @@ type interval*: TimeInterval isFromCompletion*: bool + Relation* = tuple[rel: RelationType, id: UUID] + + RelationType* = enum + ParentOf = "parent-of", + ChildOf = "child-of", + RelatedTo = "related-to", + Blocks = "blocks", + BlockedBy = "blocked-by", + Follow = "follows", + FollowedBy = "followed-by", + Caused = "caused", + CausedBy = "caused-by" + const DONE_FOLDER_FORMAT* = "yyyy-MM" const ISO8601_MS = "yyyy-MM-dd'T'HH:mm:ss'.'fffzzz" @@ -173,6 +187,11 @@ proc parseDate*(d: string): DateTime = continue raise newException(ValueError, "Unable to parse input as a date: " & d & errMsg) +proc parseRelation*(relStr: string): Relation = + let parts = relStr.split({' '}) + if parts.len == 1: result = (RelatedTo, parseUUID(parts[0])) + else: result = (parseEnum[RelationType](parts[0]), parseUUID(parts[1])) + ## Parse and format issues proc fromStorageFormat*(id: string, issueTxt: string): Issue = type ParseState = enum ReadingSummary, ReadingProps, ReadingDetails @@ -180,6 +199,7 @@ proc fromStorageFormat*(id: string, issueTxt: string): Issue = result = Issue( id: parseUUID(id), properties: newTable[string,string](), + relations: @[], tags: @[]) var parseState = ReadingSummary @@ -203,14 +223,16 @@ proc fromStorageFormat*(id: string, issueTxt: string): Issue = parseState = ReadingDetails continue - let parts = line.split({':'}, 1) --> map(it.strip()) if parts.len != 2: raise newException(ValueError, "unable to parse property line: " & line) - # Take care of special properties: `tags` + # Take care of special properties: `tags` and `relations` if parts[0] == "tags": result.tags = parts[1].split({','}) --> map(it.strip()) + elif parts[0] == "relations": + result.relations = parts[1].split({','}) --> + map(parseRelation(it.strip)) else: result[parts[0]] = parts[1] of ReadingDetails: @@ -231,6 +253,11 @@ proc toStorageFormat*(issue: Issue, withComments = false): string = if issue.tags.len > 0: lines.add("tags: " & issue.tags.join(",")) + if issue.relations.len > 0: + lines.add("relations: " & + (issue.relations --> map(it.rel & " " & it.id)). + join(', ')) + if not isEmptyOrWhitespace(issue.details) or withComments: if withComments: lines.add("# Details go below the \"--------\"") lines.add("--------")