Skip to content

v0.28.0

Release Date: 2025-12-12

This release adds workflow automation through issue transitions, status category filtering, and batch operations for labels and custom fields.

Highlights

  • Issue Transitions API for workflow automation
  • Status Category Filtering and histograms
  • Batch Issue Operations for labels and patches
  • Enhanced JQL Builder with text search operators

New Features

Issue Transitions

Automate workflow transitions with the new transitions API.

import "github.com/grokify/gojira/rest"

// Get available transitions for an issue
transitions, err := client.IssueAPI.GetTransitions(ctx, "ISSUE-123")
if err != nil {
    log.Fatal(err)
}

// Print available transitions
for _, t := range transitions {
    fmt.Printf("ID: %s, Name: %s\n", t.ID, t.Name)
}

// Execute a transition by name
err = client.IssueAPI.DoTransitionWithNameAndPayload(ctx, "ISSUE-123", "Done", nil)

// Batch transitions
options := rest.TransitionOptionSet{
    Options: []rest.TransitionOption{
        {IssueKey: "ISSUE-1", TransitionName: "In Progress"},
        {IssueKey: "ISSUE-2", TransitionName: "Done"},
    },
}
results, err := client.IssueAPI.DoTransitions(ctx, options)

Status Category Filtering

Filter and analyze issues by Jira's built-in status categories (To Do, In Progress, Done).

// Filter by status category
doneIssues := issuesSet.FilterByStatusCategory("Done")
inProgressIssues := issuesSet.FilterByStatusCategory("In Progress")

// Histogram by status category
histogram := issuesSet.HistogramByStatusCategory()
for category, count := range histogram {
    fmt.Printf("%s: %d\n", category, count)
}

// Get statuses for specific categories
categories := gojira.StatusCategories{...}
statuses := categories.StatusesForCategories([]string{"Done", "In Progress"})

Batch Issue Operations

Update multiple issues efficiently.

// Batch patch issues
keys := []string{"ISSUE-1", "ISSUE-2", "ISSUE-3"}
reqBody := rest.IssuePatchRequestBody{
    Fields: map[string]rest.IssuePatchRequestBodyField{
        "priority": {Value: "High"},
    },
}
results, err := client.IssueAPI.IssuesPatch(ctx, keys, reqBody)

// Batch add label
results, err := client.IssueAPI.IssuesPatchAddLabel(ctx, keys, "reviewed")

Cache search results to a file for repeated queries.

issuesSet, err := client.IssueAPI.SearchIssuesSetWithFileCache(
    "project = FOO",
    "cache/foo-issues.json",
    24*time.Hour, // Cache TTL
)

New JQL builder fields for text searching.

jql := gojira.JQL{
    ProjectsIncl: [][]string{{"FOO"}},
    SummaryLike:  []string{"login", "auth"},     // summary ~ "login" AND summary ~ "auth"
    TextLike:     []string{"error"},              // text ~ "error"
    TextNotLike:  []string{"test"},               // text !~ "test"
}

Issue Resolution Time

Calculate time from creation to resolution.

im := rest.NewIssueMore(issue)
resolutionTime := im.ResolutionTime()
if resolutionTime > 0 {
    fmt.Printf("Resolved in: %s\n", resolutionTime)
}

Custom Field Histograms

Generate histograms by any custom field.

histogram, err := issuesSet.HistogramByCustomField("customfield_10001")
for value, count := range histogram {
    fmt.Printf("%s: %d\n", value, count)
}

API Changes

Added

Type Method/Field Description
Method IssueService.DoTransitions() Batch issue transitions
Method IssueService.DoTransitionWithNameAndPayload() Named transition with payload
Method IssueService.GetTransitions() Get available transitions
Method IssueService.IssuesPatch() Batch update issues
Method IssueService.IssuesPatchAddLabel() Batch add label
Method IssueService.SearchIssuesSetWithFileCache() Cached search
Method IssuesSet.FilterByStatusCategory() Filter by status category
Method IssuesSet.FilterByKeys() Filter by issue keys
Method IssuesSet.HistogramByStatus() Histogram by status
Method IssuesSet.HistogramByStatusCategory() Histogram by category
Method IssuesSet.HistogramByCustomField() Histogram by custom field
Method IssuesSet.KeysFilterLabelIncl() Keys with label
Method IssuesSet.KeysFilterSummaryNotLike() Keys without summary text
Method IssuesSet.Summaries() Get all summaries
Method IssueMore.Description() Get issue description
Method IssueMore.ResolutionTime() Time to resolution
Method IssuesSets.Histogram() Histogram across sets
Method IssuesSets.BarChartsText() Text bar charts
Method StatusCategories.StatusesForCategories() Statuses for categories
Method Transitions.Names() Get transition names
Field JQL.SummaryLike Summary text search
Field JQL.SummaryNotLike Summary exclusion
Field JQL.TextLike Full text search
Field JQL.TextNotLike Text exclusion
Type Transition{} Transition type
Type Transitions{} Transitions slice
Type TransitionOption{} Transition option
Type TransitionOptionSet{} Batch transitions

Changed

Change Description
IssueMore.Issue Now public for direct access
IssuesSet.Items Renamed attribute
IssueMore.LabelExists() Added matchToLowerTrimSpace parameter

Example: Workflow Automation

Complete example automating issue transitions based on labels:

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/grokify/gojira/rest"
)

func main() {
    client, err := rest.NewClientFromBasicAuth(
        "https://your-instance.atlassian.net",
        "your-email@example.com",
        "your-api-token",
        false,
    )
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    // Find issues with "ready-for-review" label
    issues, err := client.IssueAPI.SearchIssues(
        "project = FOO AND labels = ready-for-review AND status = 'In Progress'",
        true,
    )
    if err != nil {
        log.Fatal(err)
    }

    // Transition each to "In Review"
    for _, issue := range issues {
        err := client.IssueAPI.DoTransitionWithNameAndPayload(ctx, issue.Key, "In Review", nil)
        if err != nil {
            log.Printf("Failed to transition %s: %v", issue.Key, err)
            continue
        }
        fmt.Printf("Transitioned %s to In Review\n", issue.Key)
    }
}

Commits

Type Description Commit
Added IssueService.DoTransitions() 350db95
Added IssueService.DoTransitionWithNameAndPayload() 48b51bc
Added IssueService.GetTransitions() f066b2d
Added Transition{}, Transitions{} types 59e1796
Added IssuesSet.FilterByStatusCategory() 7640a46
Added IssuesSet.HistogramByStatus(), HistogramByStatusCategory() f7e0fdf
Added IssuesSet.HistogramByCustomField() af1d8ab
Added IssueService.IssuesPatch(), IssuesPatchAddLabel() 9944a42
Added IssueService.SearchIssuesSetWithFileCache() 38dd2f3
Added IssuesSet.FilterByKeys(), filter methods f6a59f9
Added IssueMore.Description() edf1a04
Added IssuesSet.Summaries() 6bcf571
Added IssueMore.ResolutionTime() adc5a25
Added JQL.SummaryLike, TextLike, etc. 7ba5f3a
Added StatusCategories.StatusesForCategories() 46ea60f
Added IssuesSets.Histogram(), BarChartsText() d77c98a
Changed Externalized IssueMore.Issue 8f21c6a
Changed Renamed IssuesSet.Items 72f52c2