Skip to main content

jira

info

This promotion step is only available in Kargo on the Akuity Platform, versions v1.6 and above.

The jira promotion step provides comprehensive integration with Jira, allowing you to create, update, delete, and search for issues, manage comments, and track promotion workflows. This is particularly useful for maintaining traceability between your promotion processes and project management activities.

This promotion step supports various operations including issue management, comment handling, and status tracking, making it a powerful tool for promotion workflows that require coordination with project management systems.

Credentials Configuration

All Jira operations require proper authentication credentials stored in a Kubernetes Secret.

NameTypeRequiredDescription
credentials.secretNamestringYName of the Secret containing the Jira credentials.

The referenced Secret should contain the following keys:

  • domain: The domain of your Jira instance or Jira api (e.g., https://yourcompany.atlassian.net)
  • username: Your Jira username or email
  • password: Your Jira API token or password

Issue Management

Create Issue

Creates a new Jira issue with specified details.

Configuration

NameTypeRequiredDescription
createIssue.projectKeystringYThe key of the Jira project where the issue will be created.
createIssue.summarystringYThe summary or title of the issue.
createIssue.descriptionstringNThe description of the issue. Supports markdown formatting.
createIssue.adfDescriptionobjectNADF (Atlassian Document Format) content for complex formatting. Alternative to description.
createIssue.issueTypestringNThe type of issue to create (e.g., 'Bug', 'Task', 'Story').
createIssue.assigneeEmailstringNEmail of the user to assign the issue to.
createIssue.labelsarrayNLabels to add to the issue for categorization.
createIssue.customFieldsobjectNCustom fields to set. Keys should match Jira custom field IDs.
createIssue.issueAliasstringNOverride for the freight metadata key used to reference the created issue id. Defaults to jira-issue-key.

Output

NameTypeDescription
keystringThe key/id of the created Jira issue (e.g., EXT-123).

Example

This example creates a new Jira issue to track a promotion, assigns it to a team member, and adds relevant labels.

steps:
- uses: jira
as: create-promotion-issue
config:
credentials:
secretName: jira-credentials
createIssue:
projectKey: PROMOTE
summary: "Promote ${{ imageFrom(vars.imageRepo).Tag }} to ${{ ctx.stage }}"
description: "Promoteing ${{ imageFrom(vars.imageRepo).RepoURL }}:${{ imageFrom(vars.imageRepo).Tag }} to ${{ ctx.stage }} environment. Promotion ID: ${{ ctx.promotion }}. Freight: ${{ ctx.targetFreight.name }}."
issueType: Task
assigneeEmail: devops@company.com
labels:
- promotion
- "${{ ctx.stage }}"
- "release-${{ imageFrom(vars.imageRepo).Tag }}"
# Use the created issue key in subsequent steps
- uses: jira
config:
credentials:
secretName: jira-credentials
updateIssue:
issueKey: "${{ outputs['create-promotion-issue'].key }}"
status: "IN PROGRESS"

Update Issue

Updates an existing Jira issue with new information.

Configuration

NameTypeRequiredDescription
updateIssue.issueKeystringYThe Jira Issue Key (e.g., EXT-123).
updateIssue.summarystringNUpdated summary or title of the issue.
updateIssue.descriptionstringNUpdated description. Supports markdown formatting.
updateIssue.adfDescriptionobjectNADF content for complex formatting. Alternative to description.
updateIssue.issueTypestringNUpdated issue type.
updateIssue.assigneeEmailstringNEmail of the user to assign the issue to.
updateIssue.statusstringNStatus to set for the issue (e.g., 'IN PROGRESS', 'DONE').
updateIssue.addLabelsarrayNLabels to add to the issue.
updateIssue.removeLabelsarrayNLabels to remove from the issue.
updateIssue.customFieldsobjectNCustom fields to update.

Output

This step does not produce any output.

Example

This example updates an existing issue's status and adds a comment with promotion details.

steps:
- uses: jira
config:
credentials:
secretName: jira-credentials
updateIssue:
issueKey: PROMOTE-123
status: "IN PROGRESS"
summary: "Promote ${{ imageFrom(vars.imageRepo).Tag }} to ${{ ctx.stage }} - IN PROGRESS"
addLabels:
- promoting
- "${{ ctx.stage }}-promotion"
customFields:
customfield_10000: "${{ ctx.stage }} Environment"
customfield_10001: "${{ ctx.promotion }}"

Delete Issue

Deletes a Jira issue and, optionally, its subtasks.

Configuration

NameTypeRequiredDescription
deleteIssue.issueKeystringYThe Jira Issue Key (e.g., EXT-123).
deleteIssue.deleteSubtasksbooleanNIf true, all subtasks will be deleted as well.

Output

This step does not produce any output.

Example

This example deletes a Jira issue and all its subtasks when a promotion fails.

steps:
# existing steps create issue and other promotion steps
# ....
# ....
# on failure cleanup logic
- as: on-failure-cleanup-issue
uses: jira
if: ${{ failure() }}
config:
credentials:
secretName: jira-credentials
deleteIssue:
issueKey: "${{ freightMetadata(ctx.targetFreight.name, 'jira-issue-key') }}"
deleteSubtasks: true

Search Issues

Searches for Jira issues using JQL (Jira Query Language).

Configuration

NameTypeRequiredDescription
searchIssue.jqlstringYThe JQL query to search for issues.
searchIssue.expectMultiplebooleanNIf true, expects multiple results and returns the first matching result. If false, expects single result and fails with >1 results.
searchIssue.fieldsarrayNList of fields to include in search results.
searchIssue.expandsarrayNList of fields to expand in search results.

Output

NameTypeDescription
issueobjectThe found Jira issue object containing all requested fields and expansions.

Example

This example searches for open promotion issues in a specific project and expects multiple results.

steps:
- uses: jira
as: find-open-promotions
config:
credentials:
secretName: jira-credentials
searchIssue:
jql: 'project = PROMOTE AND status != "Done" AND labels = "${{ ctx.stage }}-promotion" AND created >= -7d'
expectMultiple: true
fields:
- summary
- status
- assignee
- created
expands:
- changelog
# Use search results in subsequent steps to notify team
# Note: This is just an example of using search outputs and may not be syntactically valid
- uses: http
config:
method: POST
url: https://slack.com/api/chat.postMessage
headers:
- name: Authorization
value: "Bearer ${{ secret('slack-credentials').token }}"
- name: Content-Type
value: application/json
body: |
${{ quote({
"channel": "#promotions",
"text": "Found issue" + outputs['find-open-promotions'].issue.key + " for " + ctx.stage + " environment"
}) }}

Comment Management

Add Comment

Adds a comment to an existing Jira issue.

Configuration

NameTypeRequiredDescription
commentOnIssue.issueKeystringYThe Jira Issue Key (e.g., EXT-123).
commentOnIssue.bodystringNText content of the comment.
commentOnIssue.adfBodyobjectNADF content for complex formatting. Alternative to body.

Output

NameTypeDescription
commentIDstringThe ID of the created comment that can be used for later operations.

Example

This example adds a comment to a Jira issue with promotion progress information.

steps:
- uses: jira
as: add-progress-comment
config:
credentials:
secretName: jira-credentials
commentOnIssue:
issueKey: "${{ freightMetadata(ctx.targetFreight.name, 'jira-issue-key') }}"
body: "Promotion started. Environment: ${{ ctx.stage }}. Image: ${{ imageFrom(vars.imageRepo).RepoURL }}:${{ imageFrom(vars.imageRepo).Tag }}. Promotion: ${{ ctx.promotion }}. Status: Promoting to ${{ ctx.stage }} environment..."
# Later use the comment ID if needed
- uses: jira
config:
credentials:
secretName: jira-credentials
deleteComment:
issueKey: "${{ freightMetadata(ctx.targetFreight.name, 'jira-issue-key') }}"
commentID: "${{ quote(outputs['add-progress-comment'].commentID) }}"

Delete Comment

Removes a specific comment from a Jira issue.

Configuration

NameTypeRequiredDescription
deleteComment.issueKeystringYThe Jira Issue Key (e.g., EXT-123).
deleteComment.commentIDstringYThe ID of the comment to delete.

Output

This step does not produce any output.

Example

This example deletes a specific comment from a Jira issue.

steps:
- uses: jira
config:
credentials:
secretName: jira-credentials
deleteComment:
issueKey: "${{ freightMetadata(ctx.targetFreight.name, 'jira-issue-key') }}"
commentID: "${{ outputs['previous-comment-step'].commentID }}"

Status Tracking

Wait for Status

Waits for a Jira issue to reach a specific status before proceeding.

Configuration

NameTypeRequiredDescription
waitForStatus.issueKeystringYThe Jira Issue Key (e.g., EXT-123).
waitForStatus.expectedStatusstringYThe expected status to wait for (e.g., 'IN PROGRESS', 'DONE').

Output

This step does not produce any output.

Example

This example waits for a change request issue to be approved before proceeding with promotion.

steps:
- uses: jira
config:
credentials:
secretName: jira-credentials
waitForStatus:
issueKey: "${{ freightMetadata(ctx.targetFreight.name, 'change-request-key') }}"
expectedStatus: "Approved"
# promotion steps continue after approval...
- uses: helm-template
config:
path: ./charts
vars:
imageTag: "${{ imageFrom(vars.imageRepo).Tag }}"
environment: "${{ ctx.stage }}"
Content Formatting

The Jira configuration supports setting issue and comment content using description or body fields. These are plain text fields that do not support special formatting such as Markdown. For rich formatting capabilities, use the ADF (Atlassian Document Format) alternatives adfDescription or adfBody. For more information about ADF structure and formatting, see the Atlassian Document Format documentation.

Multi-Stage Workflow

The Jira promotion step automatically stores created issue keys in the Freight metadata, allowing subsequent stages to reference the same issue. This enables tracking a single Jira issue across multiple promotion stages.

Accessing Issue Keys from Freight Metadata

Use the freightMetadata() template function to retrieve issue keys stored by previous stages:

# Access the default issue key
issueKey: ${{ freightMetadata(ctx.targetFreight.name, 'jira-issue-key') }}

# Access a custom issue key (when issueAlias was used during creation)
issueKey: ${{ freightMetadata(ctx.targetFreight.name, 'my-custom-alias') }}

Example

This comprehensive example demonstrates using the Jira promotion step across multiple stages in a promotion pipeline, tracking a single issue from its creation during testing through its final promotion to production:

---
apiVersion: kargo.akuity.io/v1alpha1
kind: Stage
metadata:
name: test
namespace: kargo-proj
spec:
requestedFreight:
- origin:
kind: Warehouse
name: nginx
sources:
direct: true
promotionTemplate:
spec:
vars:
- name: imageRepo
value: public.ecr.aws/nginx/nginx
steps:
# Create initial promotion issue
- as: create-promotion-issue
uses: jira
config:
credentials:
secretName: jira
createIssue:
projectKey: PROMOTE
issueType: Task
summary: "Promote Release ${{ imageFrom(vars.imageRepo).Tag }}"
assigneeEmail: "devops@company.com"
adfDescription:
type: doc
version: 1
content:
- type: paragraph
content:
- type: text
text: " "
- type: heading
attrs:
level: 3
content:
- type: text
text: "Automated promotion issue for release "
- type: text
text: "${{ imageFrom(vars.imageRepo).Tag }}"
marks:
- type: code
- type: paragraph
content:
- type: text
text: "Image:"
marks:
- type: strong
- type: text
text: " "
- type: text
text: "${{ imageFrom(vars.imageRepo).RepoURL }}:${{ imageFrom(vars.imageRepo).Tag }}"
marks:
- type: code
- type: paragraph
content:
- type: text
text: "Project:"
marks:
- type: strong
- type: text
text: " "
- type: text
text: "${{ ctx.project }}"
marks:
- type: code
labels:
- "automated-promotion"
- "env-${{ ctx.stage }}"
- "release-${{ imageFrom(vars.imageRepo).Tag }}"
- "project-${{ ctx.project }}"

# Update the Argo CD Application directly. Not ideal for practical purposes.
- as: update-app
uses: argocd-update
config:
apps:
- name: test-app
namespace: argocd
sources:
- repoURL: https://github.com/company/app-config.git
kustomize:
images:
- repoURL: public.ecr.aws/nginx/nginx
tag: ${{ imageFrom("public.ecr.aws/nginx/nginx").Tag }}

# Add progress comment
- as: comment-on-issue
uses: jira
config:
credentials:
secretName: jira
commentOnIssue:
issueKey: ${{ outputs['create-promotion-issue'].key }}
body: "Release ${{ imageFrom(vars.imageRepo).Tag }} has been promoted to ${{ ctx.stage }} environment. Freight: ${{ ctx.targetFreight.name }}. Ready for testing."

# Cleanup on failure
- as: on-failure-cleanup-issue
uses: jira
if: ${{ failure() }}
config:
credentials:
secretName: jira
deleteIssue:
issueKey: ${{ outputs['create-promotion-issue'].key }}
deleteSubtasks: true

---
apiVersion: kargo.akuity.io/v1alpha1
kind: Stage
metadata:
name: uat
namespace: kargo-proj
spec:
requestedFreight:
- origin:
kind: Warehouse
name: nginx
sources:
stages:
- test
promotionTemplate:
spec:
vars:
- name: imageRepo
value: public.ecr.aws/nginx/nginx
steps:
# Wait for manual approval to proceed to UAT
- as: wait-approval
uses: jira
config:
credentials:
secretName: jira
waitForStatus:
issueKey: ${{ freightMetadata(ctx.targetFreight.name, 'jira-issue-key') }}
expectedStatus: UAT

# Update the Argo CD Application directly. Not ideal for practical purposes.
- as: update-app
uses: argocd-update
config:
apps:
- name: uat-app
namespace: argocd
sources:
- repoURL: https://github.com/company/app-config.git
kustomize:
images:
- repoURL: ${{ vars.imageRepo }}
tag: ${{ imageFrom(vars.imageRepo).Tag }}

# Update issue with UAT progress
- as: comment-on-issue
uses: jira
config:
credentials:
secretName: jira
commentOnIssue:
issueKey: ${{ freightMetadata(ctx.targetFreight.name, 'jira-issue-key') }}
body: "Release ${{ imageFrom(vars.imageRepo).Tag }} has been promoted to ${{ ctx.stage }} environment. Promotion: ${{ ctx.promotion }}. Status: Promoteed and ready for uat validation."

# Update environment labels
- as: update-issue-labels
uses: jira
config:
credentials:
secretName: jira
updateIssue:
issueKey: ${{ freightMetadata(ctx.targetFreight.name, 'jira-issue-key') }}
removeLabels:
- "env-test"
addLabels:
- "env-${{ ctx.stage }}"
- "promotion-${{ ctx.promotion }}"

# Cleanup comments on failure
- as: on-failure-cleanup-comment
uses: jira
if: ${{ failure() && status('comment-on-issue') == 'Succeeded' }}
config:
credentials:
secretName: jira
deleteComment:
issueKey: ${{ freightMetadata(ctx.targetFreight.name, 'jira-issue-key') }}
commentID: ${{ quote(outputs['comment-on-issue'].commentID) }}

---
apiVersion: kargo.akuity.io/v1alpha1
kind: Stage
metadata:
name: prod
namespace: kargo-proj
spec:
requestedFreight:
- origin:
kind: Warehouse
name: nginx
sources:
stages:
- uat
promotionTemplate:
spec:
vars:
- name: imageRepo
value: public.ecr.aws/nginx/nginx
steps:
# Find the issue by searching for release label
- as: search-issue
uses: jira
config:
credentials:
secretName: jira
searchIssue:
jql: "created <= 1d and labels IN (release-${{ imageFrom(vars.imageRepo).Tag }}) ORDER BY created DESC"
expectMultiple: true
fields:
- key

# Wait for final production approval
- as: wait-approval
uses: jira
config:
credentials:
secretName: jira
waitForStatus:
issueKey: ${{ outputs['search-issue'].key }}
expectedStatus: RELEASED

# Update the Argo CD Application directly. Not ideal for practical purposes.
- as: update-app
uses: argocd-update
config:
apps:
- name: prod-app
namespace: argocd
sources:
- repoURL: https://github.com/company/app-config.git
kustomize:
images:
- repoURL: public.ecr.aws/nginx/nginx
tag: ${{ imageFrom("public.ecr.aws/nginx/nginx").Tag }}

# Add final completion comment
- as: comment-on-issue
uses: jira
config:
credentials:
secretName: jira
commentOnIssue:
issueKey: ${{ outputs['search-issue'].key }}
body: "Release ${{ imageFrom(vars.imageRepo).Tag }} has been successfully promoted to ${{ ctx.stage }} environment. promotion completed for promotion ${{ ctx.promotion }}. All systems operational and release is live!"

# Update to production labels
- as: update-issue-labels
uses: jira
config:
credentials:
secretName: jira
updateIssue:
issueKey: ${{ outputs['search-issue'].key }}
removeLabels:
- "env-stage"
addLabels:
- "env-${{ ctx.stage }}"
- "released-${{ imageFrom(vars.imageRepo).Tag }}"
- "promotion-${{ ctx.promotion }}"

# Cleanup on failure
- as: on-failure-cleanup-comment
uses: jira
if: ${{ failure() && status('comment-on-issue') == 'Succeeded' }}
config:
credentials:
secretName: jira
deleteComment:
issueKey: ${{ outputs['search-issue'].key }}
commentID: ${{ quote(outputs['comment-on-issue'].commentID) }}

This multi-stage workflow demonstrates:

  • Issue Creation: The test stage creates a comprehensive Jira issue with ADF formatting
  • Freight Metadata: The issue key is automatically stored in freight metadata for later stages
  • Status Tracking: Each stage waits for specific approval statuses before proceeding
  • Progressive Updates: Labels and comments are updated as the release moves through environments
  • Error Handling: Cleanup steps run on failures to maintain clean state
  • Search Functionality: The prod stage demonstrates finding issues by label when freight metadata isn't available