atlassian-cli is an independent, community open-source project, not affiliated with, endorsed by, or sponsored by Atlassian, and is not Atlassian's official CLI (acli). Product names are used only to identify compatibility.

Why run Jira commands in GitHub Actions

A Jira GitHub Actions setup lets your pipeline update Jira as code moves through it: move an issue to "In Review" when a pull request opens, transition it to "Deployed" when production succeeds, and drop a comment linking the ticket back to the exact build. The tool that makes this practical from a runner is a command-line client, and atlassian-cli is a single self-contained binary you can install in one step and script against.

Doing this in CI removes the manual step everyone forgets: dragging the card across the board after a release. Instead of a human keeping Jira in sync with reality, the pipeline that actually performed the deploy records what happened. The status change is tied to a real event (a green build, a successful deploy), so the board reflects the true state of the work rather than someone's best guess at standup.

How this differs from acli: atlassian-cli is an independent, community open-source project. It is not Atlassian's official CLI (acli) and is not affiliated with Atlassian. Use the official acli if you want first-party vendor support; use atlassian-cli if you want one free MIT-licensed Rust binary that spans Jira, Confluence, Bitbucket, and Jira Service Management and scripts cleanly inside CI.

Install the CLI on a runner

The default GitHub-hosted ubuntu-latest runner already ships with the Rust toolchain, so the simplest install is a single line. Add it as a step before any Jira commands:

# Simplest: build and install from crates.io
- name: Install atlassian-cli
  run: cargo install atlassian-cli

cargo install compiles from source, which adds a minute or two to the job. For faster pipelines you have two other options that are equally valid:

Whichever route you pick, the result is the same: an atlassian-cli binary on the PATH that later steps can call. Confirm it resolved with a version check:

- name: Verify install
  run: atlassian-cli --version

Authenticate with GitHub secrets

Never put an API token in a workflow file. Store three values as repository secrets (Settings → Secrets and variables → Actions): your site URL, your account email, and an API token. For the difference between an API token and a personal access token, see Atlassian API token vs PAT.

In the workflow, expose those secrets as environment variables inside a step and pass them to auth login. Quoting the variables keeps them safe if a value contains special characters:

- name: Authenticate to Jira
  env:
    JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
    JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}
    JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
  run: |
    atlassian-cli auth login \
      --profile ci \
      --base-url "$JIRA_BASE_URL" \
      --email "$JIRA_EMAIL" \
      --token "$JIRA_API_TOKEN" \
      --default

This writes a profile named ci to the runner's config file. Because the filesystem persists across steps within a single job, every later step in that job can call atlassian-cli without re-authenticating. GitHub automatically masks secret values in logs, and the credentials vanish when the ephemeral runner is destroyed. Full flag details are in Authentication & Profiles.

Add a cheap gate right after login so the job fails fast on a bad or expired token instead of halfway through your Jira steps:

# Exit non-zero if credentials are invalid
- name: Verify Jira auth
  run: atlassian-cli auth test --profile ci --format quiet

Transition issues on deploy

The core action is moving an issue to a new workflow status once something real happens. That is jira issue transition, which takes an issue key and a transition name:

atlassian-cli jira issue transition DEV-123 --transition "Deployed"

The transition name must match one that exists on the issue's workflow (for example "Deployed", "Done", or "In Review"). To confirm the available names for a project, run atlassian-cli jira workflows list locally, or check the board configuration.

In a real pipeline the issue key is not hard-coded. A common convention is to embed the key in the branch name or commit message (DEV-123 fix login redirect) and extract it at runtime:

# Pull the first PROJECT-NUMBER token from the latest commit subject
- name: Resolve issue key
  id: jira
  run: |
    KEY=$(git log -1 --pretty=%s | grep -oE '[A-Z]+-[0-9]+' | head -1)
    echo "key=$KEY" >> "$GITHUB_OUTPUT"

- name: Move issue to Deployed
  if: steps.jira.outputs.key != ''
  run: atlassian-cli jira issue transition ${{ steps.jira.outputs.key }} --transition "Deployed"

Because this step runs after your deploy step, and a failed step stops the job by default, the transition only fires when the deploy actually succeeded. The board never shows "Deployed" for a release that rolled back.

Comment build status back to Jira

A status change tells you where an issue is; a comment tells you what happened. The jira issue comments add subcommand posts a comment to an issue and accepts the body via --body:

atlassian-cli jira issue comments add DEV-123 \
  --body "Deployed to production. Build passed."

The value of doing this in CI is context. Interpolate GitHub Actions variables so the comment links the ticket straight back to the commit and the pipeline run that produced it:

- name: Comment deploy status on Jira
  if: steps.jira.outputs.key != ''
  run: |
    atlassian-cli jira issue comments add ${{ steps.jira.outputs.key }} \
      --body "Deployed ${{ github.sha }} to production. Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"

Now anyone reading the Jira issue sees exactly which commit shipped and can click through to the logs. You can post comments on failure too by adding a step with if: failure(), so a broken build leaves a trail on the ticket instead of dying silently in the Actions tab.

Mapping pipeline events to CLI commands

Most CI-to-Jira automation is a handful of these building blocks wired to different triggers. This table maps common pipeline moments to the command that handles them:

Pipeline event Desired Jira change Command
Pull request opened Move to In Review jira issue transition KEY --transition "In Review"
Build passed Record the result jira issue comments add KEY --body "..."
Deploy to production Move to Deployed / Done jira issue transition KEY --transition "Deployed"
Deploy failed Flag the ticket jira issue comments add KEY --body "Deploy failed"
Release cut Gather shipped issues jira issue search --jql "..." --format json

A complete deploy workflow

Here is an end-to-end .github/workflows/deploy.yml that ties the pieces together: install, authenticate, deploy, then update Jira. It runs on pushes to main.

name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install atlassian-cli
        run: cargo install atlassian-cli

      - name: Authenticate to Jira
        env:
          JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
          JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}
          JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
        run: |
          atlassian-cli auth login \
            --profile ci \
            --base-url "$JIRA_BASE_URL" \
            --email "$JIRA_EMAIL" \
            --token "$JIRA_API_TOKEN" \
            --default
          atlassian-cli auth test --profile ci --format quiet

      - name: Resolve issue key
        id: jira
        run: |
          KEY=$(git log -1 --pretty=%s | grep -oE '[A-Z]+-[0-9]+' | head -1)
          echo "key=$KEY" >> "$GITHUB_OUTPUT"

      - name: Deploy application
        run: ./scripts/deploy.sh

      - name: Update Jira on success
        if: success() && steps.jira.outputs.key != ''
        run: |
          atlassian-cli jira issue transition ${{ steps.jira.outputs.key }} --transition "Deployed"
          atlassian-cli jira issue comments add ${{ steps.jira.outputs.key }} \
            --body "Deployed ${{ github.sha }} in run ${{ github.run_id }}."

      - name: Flag Jira on failure
        if: failure() && steps.jira.outputs.key != ''
        run: |
          atlassian-cli jira issue comments add ${{ steps.jira.outputs.key }} \
            --body "Deploy failed in run ${{ github.run_id }}. See Actions logs."

The two conditional steps at the end split the happy path from the failure path. On a green deploy the issue moves to "Deployed" and gets a comment; on a red one it keeps its status but records what went wrong. For heavier batch work (transitioning every issue in a completed release at once) see calling the Jira API from the command line, which covers JQL-driven bulk patterns you can reuse in the same workflow.

Beyond GitHub Actions

None of this is GitHub-specific. atlassian-cli is a single binary, so the same three moves (install, auth login from your secret store, run jira commands) drop into any runner. Only the secret and scripting syntax changes. A minimal GitLab CI job looks like this:

# .gitlab-ci.yml
deploy:
  stage: deploy
  script:
    - cargo install atlassian-cli
    - atlassian-cli auth login --profile ci --base-url "$JIRA_BASE_URL" --email "$JIRA_EMAIL" --token "$JIRA_API_TOKEN" --default
    - atlassian-cli jira issue transition "$CI_ISSUE_KEY" --transition "Deployed"

The identical approach works in Jenkins (inject credentials with the Credentials Binding plugin), CircleCI (context or project environment variables), and Bitbucket Pipelines (repository variables). If your CI can run a shell and hold a secret, it can drive Jira. The full command surface for every product is in the command reference.

Wire Jira into your pipeline

Install the free, MIT-licensed binary and add Jira automation to your next workflow in minutes.

Try atlassian-cli

FAQ

How do I install a Jira CLI in a GitHub Actions workflow?

Add an install step before your Jira commands. On the default ubuntu-latest runner the Rust toolchain is already present, so run: cargo install atlassian-cli. For faster jobs, download a prebuilt binary from the GitHub releases page and add it to the PATH, or use Homebrew with brew install omar16100/atlassian-cli/atlassian-cli. Any of the three leaves a single atlassian-cli binary that later steps can call.

How do I authenticate atlassian-cli in CI without exposing my API token?

Store the base URL, email, and API token as GitHub repository secrets, then reference them as environment variables in a run step and pass them to auth login: atlassian-cli auth login --profile ci --base-url "$JIRA_BASE_URL" --email "$JIRA_EMAIL" --token "$JIRA_API_TOKEN" --default. Never hard-code the token in the workflow file. GitHub masks secret values in logs, and the credentials only exist for the duration of the job.

Can I automatically transition a Jira issue when a deploy succeeds?

Yes. After your deploy step succeeds, run atlassian-cli jira issue transition KEY --transition "Deployed", where KEY is the issue key. A common pattern is to extract the key from the branch name or commit message, for example ISSUE_KEY=$(git log -1 --pretty=%s | grep -oE '[A-Z]+-[0-9]+' | head -1). Because the step only runs when earlier steps pass, the transition happens only on a genuinely successful deploy.

How do I post build or deploy status as a Jira comment from CI?

Use the comments add subcommand: atlassian-cli jira issue comments add KEY --body "Deployed to production in run 12345". You can interpolate GitHub Actions context such as github.sha and github.run_id into the body so the comment links the Jira issue back to the exact pipeline run and commit.

Does atlassian-cli work in GitLab CI or Jenkins, not just GitHub Actions?

Yes. atlassian-cli is a single self-contained binary, so it runs in any CI system that can execute a shell: GitLab CI, Jenkins, CircleCI, and Bitbucket Pipelines included. The pattern is identical everywhere: install the binary, run auth login with credentials from your CI secret store, then call the same jira commands. Only the secret syntax differs between platforms.

Related Resources