gojira

package module
v0.25.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 23, 2025 License: MIT Imports: 15 Imported by: 0

README

GoJira

Build Status Lint Status Go Report Card Docs LOC License

This module contains code to access Jira, parsing both the JSON API via github.com/andygrunwald/go-jira in jirarest and code to parse a Jira XML file in jiraxml.

Various aggregate staticstics and reports are calculated/generated.

Use Cases

  1. Programmatically construct JQL
  2. Generate Markdown Reports from JQLs for addition to git repos or Confluence

URL Formats

Accessing a list of issues by JQL is avialable via the UI and API:

  • UI: https://{jira_host}/issues/?jql=
  • API: https://{jira_host}/rest/api/2/search?jql=
REST API Authentication: Basic Auth

The API auth can be provided by Basic Auth using an personsal API Token.

Note on Hours Per Day and Days Per Week

This module supports custom hoursPerDay and daysPerWeek settings per Jira.

This is described here and set in the UI via the screenshot below,

Ref: https://community.atlassian.com/t5/Jira-Software-questions/What-it-JIRA-counting-as-a-quot-day-quot-in-Time-Tracking/qaq-p/1703409

Also of note is that the hours per day can be set to a decimal value, such as 8.5, but the UI may not show it:

Ref: https://community.atlassian.com/t5/Jira-questions/change-quot-Working-hours-per-day-quot-by-a-decimal-value/qaq-p/583095

Additional Discussion on Jira XML

General Discussion

General discussion including using Jira XML to:

  1. export comments and issue link types
  2. create CSV for flexible reporting and import

Ref: https://community.atlassian.com/t5/Jira-questions/JIRA-Issue-XML-Export-What-is-it-good-for/qaq-p/603308

Global Config

Working Hours Per Day and Working Days Per Week are global values and cannot be set on a per-project basis.

Ref: https://community.atlassian.com/t5/Jira-Software-questions/Time-Tracking-Hours-Is-it-still-a-global-change/qaq-p/1337399

JQL Examples

Goal Example
Query by key key = ABC-123
Query by parent parent = ABC-123
Query by linked issue issue in linkedIssues (ABC-123)
Query by reporter reporter = "foo@bar.com"

https://community.atlassian.com/t5/Jira-questions/How-to-search-all-linked-issues-with-issues-from-specific/qaq-p/1027269

Backlog

Downloading the project backlog view appears to be challenging. Here is some info on attempts to do this.

Roughly:

project = <project_name> AND resolution = Unresolved AND status!=Closed AND (Sprint not in openSprints() OR Sprint is EMPTY) AND type not in (Epic, Sub-Task) ORDER BY Rank ASC

Agile Life Cycle Stages

Stage is a common way to understand the stages of development given that many companies can use different statuses and workflows.

Stage the following stages (from Asana) and will provide a grouping capability for implementation-specific workflows into these standard meta statuses for consistent and canonical understanding of the process.

Not all the stages need to be used, however, the stages that are used can be understood in a canonical way.

image courtesy of Asana

An alternate, but related agile methodology is avialable from eSparkBiz:

image courtesy of eSparkBiz

As well as from BISS:

image courtesy of BISS

This is described as "The 5 Stages of the Agile Software Development Lifecycle" by Mendix.

image courtesy of Mendix

Documentation

Index

Constants

View Source
const (
	// These are used by "GoJira" but not necessarily "Jira"
	FieldCreatedDate = "createddate"
	FieldDueDate     = "duedate"
	FieldFilter      = "filter"
	FieldIssue       = "issue" // issue keys
	FieldKey         = "key"
	FieldLabels      = "labels"
	FieldParent      = "parent"
	FieldProject     = "project" // project keys
	FieldProjectKey  = "projectkey"
	FieldResolution  = "resolution"
	FieldStatus      = "status"
	FieldSummary     = "summary"
	FieldType        = "type"
	FieldUpdated     = "updated"

	CalcCreatedAgeDays = "createdagedays"
	CalcCreatedMonth   = "createdmonth"
	AliasIssueKey      = "issuekey"

	FieldIssuePlural = "issues"

	// Statuses: https://support.atlassian.com/jira-cloud-administration/docs/what-are-issue-statuses-priorities-and-resolutions/
	StatusApproved    = "Approved" // Done
	StatusBuilding    = "Building"
	StatusClosed      = "Closed"
	StatusDone        = "Done"
	StatusInProgress  = "In Progress"
	StatusInReview    = "In Review"
	StatusOpen        = "Open"
	StatusRequested   = "Requested"
	StatusToDo        = "To Do"
	StatusUnderReview = "Under review"

	TypeIssue           = "Issue"
	TypeIssuePlural     = "Issues"
	TypeBug             = "Bug"
	TypeBugPlural       = "Bugs"
	TypeEpic            = "Epic"
	TypeEpicPlural      = "Epics"
	TypeSpike           = "Spike"
	TypeSpikePlural     = "Spikes"
	TypeStory           = "Story"
	TypeStoryPlural     = "Stories"
	TypeInitiative      = "Initiative"
	TypeInitiativePlura = "Initiatives"

	StagePlanning    = "Planning"
	StageDesign      = "Design"
	StageDevelopment = "Development"
	StageTesting     = "Testing"
	StageDeployment  = "Deployment"
	StageReview      = "Review"

	MetaStagePrefixReadyFor = "Ready for "
	MetaStagePrefixIn       = "In "

	OperatorGT  = ">"
	OperatorGTE = ">="
	OperatorLT  = "<"
	OperatorLTE = "<="
	OperatorAND = "AND"

	OperatorOR = "OR"

	MetaStageReadyForPlanning    = MetaStagePrefixReadyFor + StagePlanning
	MetaStageInPlanning          = MetaStagePrefixIn + StagePlanning
	MetaStageReadyForDesign      = MetaStagePrefixReadyFor + StageDesign
	MetaStageInDesign            = MetaStagePrefixIn + StageDesign
	MetaStageReadyForDevelopment = MetaStagePrefixReadyFor + StageDevelopment
	MetaStageInDevelopment       = MetaStagePrefixIn + StageDevelopment
	MetaStageReadyForTesting     = MetaStagePrefixReadyFor + StageTesting
	MetaStageInTesting           = MetaStagePrefixIn + StageTesting
	MetaStageReadyForDeployment  = MetaStagePrefixReadyFor + StageDeployment
	MetaStageInDeployment        = MetaStagePrefixIn + StageDeployment
	MetaStageReadyForReview      = MetaStagePrefixReadyFor + StageReview
	MetaStageInReview            = MetaStagePrefixIn + StageReview
	MetaStageDone                = StatusDone

	WorkingHoursPerDayDefault float32 = 8.0
	WorkingDaysPerWeekDefault float32 = 5.0

	JiraXMLGenerated = time.UnixDate // "Fri Jul 28 01:07:16 UTC 2023"

	JQLMaxResults = 100
	JQLMaxLength  = 6000 // https://jira.atlassian.com/browse/JRASERVER-41005
	JQLInSep      = ","

	JQLStatusCategoryNeDone = "statusCategory != Done"

	WebURLPathIssues = "issues/?"
)

Variables

View Source
var (
	ErrInvalidCustomFieldFormat = errors.New("invalid customfield format")
)

Functions

func CustomFieldKeyAnyToBrackets added in v0.17.0

func CustomFieldKeyAnyToBrackets(key string) (string, error)

func CustomFieldKeyCanonical added in v0.17.0

func CustomFieldKeyCanonical(key string) (string, error)

CustomFieldKeyCanonical converts a custom field string to `customfield_12345`.

func IsCustomFieldKey added in v0.17.0

func IsCustomFieldKey(key string) (string, bool)

func IsMetaStage added in v0.14.0

func IsMetaStage(status string) bool

func JQLStringsSimple added in v0.10.0

func JQLStringsSimple(field string, exclude bool, vals []string, jqlMaxLength int) []string

JQLStringsSimple provides a set of JQLs for a single field and values. The purpose of this function is to split very long lists of values so that each JQL is under a certain length limit.

func KeysContainProject added in v0.21.0

func KeysContainProject(keys []string, projectKey string) bool

func MetaStageOrder added in v0.14.0

func MetaStageOrder() []string

func ParseKeys added in v0.17.0

func ParseKeys(s string, unique, asc bool) []string

func StatusesInactive added in v0.10.0

func StatusesInactive() []string

func TimeRemaining

func TimeRemaining(status string, timeOriginalEstimate, timeEstimate, timeSpent int) (timeRemainingOriginal, timeRemaining int)

TimeRemaining returns calculated timeRemainingOriginal and timeRemaiing and against the timeOriginalEstimate and timeEstimate respectively.

Types

type Config

type Config struct {
	ServerURL          string
	WorkingHoursPerDay float32
	WorkingDaysPerWeek float32
	StatusConfig       *StatusConfig
}

func NewConfigDefault

func NewConfigDefault() *Config

func (*Config) CapacityForDaysPeople

func (c *Config) CapacityForDaysPeople(days, people float32) time.Duration

func (*Config) SecondsToWorkingDays added in v0.24.1

func (c *Config) SecondsToWorkingDays(sec int) float32

func (*Config) SecondsToWorkingWeeks added in v0.24.1

func (c *Config) SecondsToWorkingWeeks(sec int) float32

func (*Config) WebURLIssues added in v0.24.1

func (c *Config) WebURLIssues(v url.Values) string

type CustomFieldID added in v0.17.0

type CustomFieldID int

func CustomFieldLabelToID added in v0.17.0

func CustomFieldLabelToID(key string) (CustomFieldID, error)

CustomFieldLabelToID converts a custom field string to `customfield_12345`.

func (CustomFieldID) StringBrackets added in v0.17.0

func (cfid CustomFieldID) StringBrackets() string

StringBrackets returns a string in the format of `cf[12345]`. This is used in JQL queries.

func (CustomFieldID) StringPrefix added in v0.17.0

func (cfid CustomFieldID) StringPrefix() string

StringPrefix returns a string in the format of `customfield_12345`. This is used in API responses.

type EstimateStats

type EstimateStats struct {
	WithEstimate    int
	WithoutEstimate int
}

type EstimateVsActual

type EstimateVsActual struct {
	ClosedCount             int
	ClosedCountWithEstimate int
	EstimateDays            float64
	ActualDays              float64
	EstimateRatio           float64
}

func (*EstimateVsActual) Inflate

func (eva *EstimateVsActual) Inflate()

type IssuesStats

type IssuesStats struct {
	WorkingHoursPerDay       float32
	WorkingDaysPerWeek       float32
	ItemCount                int
	ItemCountByStatus        map[string]int
	ItemCountByType          map[string]int
	EstimateStatsByType      map[string]EstimateStats
	TimeOriginalEstimate     time.Duration
	TimeOriginalEstimateDays float64
	AggregateTimeSpent       time.Duration
	AggregateTimeSpentDays   float64
	ClosedEstimateVsActual   EstimateVsActual
}

type JQL added in v0.10.0

type JQL struct {
	Meta            JQLMeta // Not part of JQL
	CreatedGT       *time.Time
	CreatedGTE      *time.Time
	CreatedLT       *time.Time
	CreatedLTE      *time.Time
	DueGT           *time.Time
	DueGTE          *time.Time
	DueLT           *time.Time
	DueLTE          *time.Time
	UpdatedGT       *time.Time
	UpdatedGTE      *time.Time
	UpdatedLT       *time.Time
	UpdatedLTE      *time.Time
	FiltersIncl     [][]string // outer level is `AND`, inner level is `IN`.
	FiltersExcl     [][]string
	IssuesIncl      [][]string
	IssuesExcl      [][]string
	KeysIncl        [][]string
	KeysExcl        [][]string
	LabelsIncl      [][]string
	LabelsExcl      [][]string
	ParentsIncl     [][]string
	ParentsExcl     [][]string
	ProjectsIncl    [][]string
	ProjectsExcl    [][]string
	ResolutionIncl  [][]string
	ResolutionExcl  [][]string
	StatusesIncl    [][]string
	StatusesExcl    [][]string
	TypesIncl       [][]string
	TypesExcl       [][]string
	CustomFieldIncl map[string][]string // slice is `IN`
	CustomFieldExcl map[string][]string
	AnyIncl         JQLAndOrStringer
	AnyExcl         JQLAndOrStringer
	Raw             []string
}

JQL is a JQL builder. It will create a JQL string using `JQL.String()` from the supplied infomration.

func (JQL) QueryString added in v0.23.0

func (j JQL) QueryString() string

func (JQL) String added in v0.10.0

func (j JQL) String() string

type JQLAndOrStringer added in v0.23.0

type JQLAndOrStringer [][]fmt.Stringer

func (JQLAndOrStringer) Fields added in v0.24.0

func (j JQLAndOrStringer) Fields(not bool) []string

func (JQLAndOrStringer) String added in v0.23.0

func (j JQLAndOrStringer) String(not bool) string

JQLOrAndStringer combines `fmt.Stringer` slice of slice to create a JQL. Outer slide is "AND", Inner slice is "OR".

type JQLMeta added in v0.23.0

type JQLMeta struct {
	Name            string
	Key             string
	Description     string
	FilterID        int
	QueryTime       time.Time
	QueryTotalCount int
	Directions      []string
}

type JQLs added in v0.17.0

type JQLs []JQL

func (JQLs) JoinString added in v0.17.0

func (jqls JQLs) JoinString(keyword string) string

func (JQLs) ReportMarkdownLines added in v0.23.0

func (jqls JQLs) ReportMarkdownLines(opts *JQLsReportMarkdownOpts) ([]string, error)

ReportMarkdownLines provides Markdownlines for a set of JQLs. The `JQLsReportMarkdownOpts.AddCount` option adds a static count to the report. This is useful when the report isn't auto-updating, such as on a code repo. The `JQLsReportMarkdownOpts.AddExplicitURL` option adds a URL which can be pasted into Confluence. This will be interpreted to load a dynamic table in the Confluence page. This is not needed for git repo pages.

type JQLsReportMarkdownOpts added in v0.23.0

type JQLsReportMarkdownOpts struct {
	IssuesWebURL   string // should end with `issues/?`, query string `jql=...` will be appended.
	HeaderPrefix   string
	TimeLocation   *time.Location
	TimeZone       string
	AddCount       bool
	AddExplicitURL bool
}

func (JQLsReportMarkdownOpts) GetTimeLocation added in v0.24.0

func (opts JQLsReportMarkdownOpts) GetTimeLocation() (*time.Location, error)

type ProjectMeta added in v0.11.0

type ProjectMeta struct {
	Key      string
	TeamSize float32
}

type ProjectsMeta added in v0.11.0

type ProjectsMeta struct {
	Projects map[string]ProjectMeta
}

func NewProjectsMeta added in v0.11.0

func NewProjectsMeta() ProjectsMeta

func (*ProjectsMeta) AddMap added in v0.11.0

func (pm *ProjectsMeta) AddMap(info map[string]float32)

func (*ProjectsMeta) CapacitySimple added in v0.12.0

func (pm *ProjectsMeta) CapacitySimple(itemsPerWeekPerFTE, weekCount float32) float32

func (*ProjectsMeta) FTEs added in v0.12.0

func (pm *ProjectsMeta) FTEs() float32

type StageConfig added in v0.16.0

type StageConfig struct {
	StageNamePlanning            string
	StageNameDesign              string
	StageNameDevelopment         string
	StageNameTesting             string
	StageNameDeployment          string
	StageNameReview              string
	StageNameDone                string
	MetaStageInPlanning          string // Override auto-build
	MetaStageReadyForPlanning    string
	MetaStageInDesign            string
	MetaStageReadyForDesign      string
	MetaStageInDevelopment       string
	MetaStageReadyForDevelopment string
	MetaStageReadyForTesting     string
	MetaStageInTesting           string
	MetaStageReadyForDeployment  string
	MetaStageInDeployment        string
	MetaStageReadyForReview      string
	MetaStageInReview            string
	MetaStageDone                string
	MetaStagePrefixIn            string
	MetaStagePrefixReadyFor      string
}

func DefaultStageSet added in v0.16.0

func DefaultStageSet() *StageConfig

func NewStageConfigEmpty added in v0.16.0

func NewStageConfigEmpty() *StageConfig

func (*StageConfig) DoneName added in v0.16.0

func (ss *StageConfig) DoneName() string

func (*StageConfig) Exists added in v0.16.0

func (ss *StageConfig) Exists(stageName string) bool

func (*StageConfig) InDeploymentName added in v0.16.0

func (ss *StageConfig) InDeploymentName() string

func (*StageConfig) InDesignName added in v0.16.0

func (ss *StageConfig) InDesignName() string

func (*StageConfig) InDevelopmentName added in v0.16.0

func (ss *StageConfig) InDevelopmentName() string

func (*StageConfig) InPlanningName added in v0.16.0

func (ss *StageConfig) InPlanningName() string

func (*StageConfig) InReviewName added in v0.16.0

func (ss *StageConfig) InReviewName() string

func (*StageConfig) InTestingName added in v0.16.0

func (ss *StageConfig) InTestingName() string

func (*StageConfig) Map added in v0.16.0

func (ss *StageConfig) Map() map[string]int

func (*StageConfig) Order added in v0.16.0

func (ss *StageConfig) Order() []string

func (*StageConfig) ReadyForDeploymentName added in v0.16.0

func (ss *StageConfig) ReadyForDeploymentName() string

func (*StageConfig) ReadyForDesignName added in v0.16.0

func (ss *StageConfig) ReadyForDesignName() string

func (*StageConfig) ReadyForDevlopmentName added in v0.16.0

func (ss *StageConfig) ReadyForDevlopmentName() string

func (*StageConfig) ReadyForReviewName added in v0.16.0

func (ss *StageConfig) ReadyForReviewName() string

func (*StageConfig) ReadyForTestingName added in v0.16.0

func (ss *StageConfig) ReadyForTestingName() string

func (*StageConfig) ReadyforPlanningName added in v0.16.0

func (ss *StageConfig) ReadyforPlanningName() string

func (*StageConfig) TrimSpaceNames added in v0.16.0

func (ss *StageConfig) TrimSpaceNames()

type StatusConfig added in v0.16.0

type StatusConfig struct {
	Map         map[string]string
	StageConfig StageConfig
}

func NewStatusConfig added in v0.16.0

func NewStatusConfig(stageConfig StageConfig) StatusConfig

func (*StatusConfig) Add added in v0.16.0

func (ss *StatusConfig) Add(status, metaStage string) error

func (*StatusConfig) AddMapSlice added in v0.16.0

func (ss *StatusConfig) AddMapSlice(m map[string][]string) error

AddMapSlice should be a map where the keys are meta statuses and the values are slices of Jira statuses.

func (*StatusConfig) MapMetaStageToStatuses added in v0.16.0

func (ss *StatusConfig) MapMetaStageToStatuses() map[string][]string

func (*StatusConfig) MetaStage added in v0.16.0

func (ss *StatusConfig) MetaStage(status string) string

MetaStage returns the metastatus for a status. If there is no metastatus, an empty string is returned.

func (*StatusConfig) StatusesDone added in v0.16.0

func (ss *StatusConfig) StatusesDone() []string

func (*StatusConfig) StatusesForMetaStage added in v0.16.0

func (ss *StatusConfig) StatusesForMetaStage(metaStatus string) []string

func (*StatusConfig) StatusesInDevelopment added in v0.16.0

func (ss *StatusConfig) StatusesInDevelopment() []string

func (*StatusConfig) StatusesInDevelopmentAndDone added in v0.16.0

func (ss *StatusConfig) StatusesInDevelopmentAndDone() []string

func (*StatusConfig) StatusesReadyForPlanning added in v0.16.0

func (ss *StatusConfig) StatusesReadyForPlanning() []string

type TimeStats

type TimeStats struct {
	TimeUnit                      string
	WorkingHoursPerDay            float32
	WorkingDaysPerWeek            float32
	ItemCount                     int
	TimeSpent                     float32
	TimeEstimate                  float32
	TimeOriginalEstimate          float32
	AggregateTimeOriginalEstimate float32
	AggregateTimeSpent            float32
	AggregateTimeEstimate         float32
	TimeRemaining                 float32
	TimeRemainingOriginal         float32
}

func (TimeStats) SecondsToDays

func (ts TimeStats) SecondsToDays() (TimeStats, error)

type TimeStatsSet

type TimeStatsSet struct {
	Map map[string]TimeStats
}

type TimeStatsSets

type TimeStatsSets struct {
	Map map[string]TimeStatsSet
}

func (*TimeStatsSets) AddIssue

func (tss *TimeStatsSets) AddIssue(iss jira.Issue)

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL