Here’s a comprehensive solution for integrating GitHub Actions deployments with on-premises Jira 9:
Using Jira Deployments REST API Correctly: The deployments API endpoint is /rest/deployments/1.0/deployment (note: no ‘s’ at the end). The payload structure must include:
deploymentSequenceNumber: Unique identifier for this deployment (we use the GitHub Actions run number)
updateSequenceNumber: Timestamp or incrementing number (we use Unix timestamp)
associations: Array of objects with associationType: 'issueIdOrKeys' and array of issue keys
displayName: Human-readable deployment name (e.g., ‘Production Deploy #1234’)
url: Link back to the GitHub Actions run for traceability
description: Deployment details
lastUpdated: ISO8601 timestamp
state: MUST be one of the allowed values (see below)
pipeline: Object with id, displayName, url for the pipeline/workflow
environment: Object with id, displayName, type for target environment
Allowed Deployment State Values: Jira only accepts these specific state values:
successful: Deployment completed successfully (use this instead of ‘deployed’ or ‘completed’)
failed: Deployment failed (use this instead of ‘error’ or ‘unsuccessful’)
pending: Deployment in progress
cancelled: Deployment was aborted
rolled_back: Deployment was rolled back
Using any other value causes Jira to accept the API call (returning 200) but silently discard the deployment. This is the most common issue.
Environment Types: The environment type field must be one of:
production: Production environment
staging: Staging/pre-production environment
testing: Test environment
development: Development environment
unmapped: Other environments
These are hardcoded in Jira and don’t need pre-configuration. The environment id should be a stable identifier (we use ‘prod’, ‘staging’, etc.), and displayName is what appears in Jira UI.
Mapping Deployment Events to Jira Issues: Extract issue keys from commit messages using regex pattern ([A-Z]+-[0-9]+). Our GitHub Actions workflow parses all commits in the push event, deduplicates the issue keys, then includes them in the associations array:
associations: [
{
associationType: "issueIdOrKeys",
values: ["PROJ-123", "PROJ-456"]
}
]
If no issue keys are found, we skip posting the deployment to Jira rather than posting an orphaned deployment.
On-Prem Jira Connectivity with GitHub Integration: For on-premises Jira behind a firewall, GitHub’s cloud-hosted runners cannot reach your instance directly. Solutions:
-
Self-Hosted Runner (our approach): Deploy a GitHub Actions runner inside your network with access to Jira. This runner executes the deployment workflow steps including the Jira API call. Configure the runner to use your internal DNS/network routing.
-
Reverse Proxy: Set up a public-facing proxy that forwards deployment API calls to internal Jira. This requires careful security configuration and API token management.
-
Firewall Rules: Allowlist GitHub Actions IP ranges in your firewall. GitHub publishes these ranges in their meta API, but they change frequently, making this approach maintenance-heavy.
We chose the self-hosted runner approach for security and reliability. The runner is deployed as a Kubernetes pod in our cluster with network access to Jira.
Authentication: Use a Jira API token (not password) for the service account. Create a dedicated service account with permissions:
- Browse Projects permission on all relevant projects
- Create Attachments permission (required by deployments API)
- No other permissions needed
Store the API token in GitHub Secrets and reference it in the workflow. Use Basic Auth with username (email) and token as password.
Complete GitHub Actions Example:
- name: Post deployment to Jira
run: |
ISSUE_KEYS=$(git log --format=%B -n 20 | grep -oE '[A-Z]+-[0-9]+' | sort -u | jq -R . | jq -s .)
curl -X POST "${JIRA_URL}/rest/deployments/1.0/deployment" \
-u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
deploymentSequenceNumber: ${GITHUB_RUN_NUMBER},
updateSequenceNumber: $(date +%s),
associations: [{associationType: issueIdOrKeys, values: ${ISSUE_KEYS}}],
displayName: Production Deploy #${GITHUB_RUN_NUMBER},
url: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID},
state: successful,
lastUpdated: $(date -u +%Y-%m-%dT%H:%M:%SZ),
pipeline: {id: ${GITHUB_WORKFLOW}, displayName: ${GITHUB_WORKFLOW}, url: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions},
environment: {id: production, displayName: Production, type: production}
}"
Troubleshooting: If deployments still don’t appear:
- Check Jira application logs for deployment API errors (usually in atlassian-jira.log)
- Verify service account has Browse Projects permission on the target projects
- Confirm issue keys in payload actually exist and are accessible
- Test with a minimal payload and single known issue key first
- Use Jira’s REST API browser (if available) to test the endpoint directly
After implementing these fixes, deployments now appear correctly in Jira’s environment tracking panel, giving our product team visibility into which issues are deployed to which environments without leaving Jira.