Skip to content

Commit

Permalink
breaking(sync_issue_to_jira.yaml): Comment Jira issue URL on GitHub i…
Browse files Browse the repository at this point in the history
…ssue (#15)

* Comment Jira issue URL on GitHub issue
* Use Jira API instead of Jira automation
* Add support for multiple Jira components
  • Loading branch information
carlcsaposs-canonical authored Feb 27, 2023
1 parent dedec33 commit 650c704
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 33 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/sync_issue_to_jira.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Workflow file: [sync_issue_to_jira.yaml](sync_issue_to_jira.yaml)

## Usage
Add `.yaml` file to `.github/workflows/`
```yaml
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.
name: Sync issue to Jira

on:
issues:
types: [opened, reopened, closed]

jobs:
sync:
name: Sync GitHub issue to Jira
uses: canonical/data-platform-workflows/.github/workflows/sync_issue_to_jira.yaml@v2
with:
jira-base-url: https://warthogs.atlassian.net
jira-project-key: DPE
jira-component-names: mysql-k8s,mysql-router-k8s
secrets:
jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
jira-user-email: ${{ secrets.JIRA_USER_EMAIL }}
permissions:
issues: write # Needed to create GitHub issue comment
```
185 changes: 153 additions & 32 deletions .github/workflows/sync_issue_to_jira.yaml
Original file line number Diff line number Diff line change
@@ -1,54 +1,175 @@
# Copyright 2022 Canonical Ltd.
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.

# Context: https://support.atlassian.com/cloud-automation/docs/jira-automation-triggers/#Incoming-webhook
# Source: https://github.com/beliaev-maksim/github-to-jira-automation
# Usage documentation: sync_issue_to_jira.md

on:
workflow_call:
inputs:
jira-component-name:
description: Name of Jira component (e.g. mysql-k8s)
jira-base-url:
description: URL of Jira instance (e.g. "https://warthogs.atlassian.net"). Do not include trailing slash
required: true
type: string
jira-project-key:
description: Jira project key (e.g. "DPE")
required: true
type: string
jira-component-names:
description: Comma separated list of Jira component names (e.g. "mysql-k8s,mysql-router-k8s")
required: false
type: string
secrets:
jira-webhook-url:
description: Jira webhook URL
jira-api-token:
# https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/
description: Jira API token
required: true
jira-user-email:
description: User email address for Jira API token
required: true


jobs:
sync:
name: Sync issue
create-jira-issue:
name: Create Jira issue
if: ${{ github.event.action == 'opened' }}
runs-on: ubuntu-latest
steps:
- name: Update Jira ticket
- name: Login to Jira API
uses: atlassian/gajira-login@v3
env:
# put into env vars to properly escape special bash chars
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_DESCRIPTION: ${{ github.event.issue.body }}
JIRA_BASE_URL: ${{ inputs.jira-base-url }}
JIRA_USER_EMAIL: ${{ secrets.jira-user-email }}
JIRA_API_TOKEN: ${{ secrets.jira-api-token }}
- name: Determine Jira issue type
id: issue-type
run: |
if ${{ contains(github.event.issue.labels.*.name, 'bug') }}; then
ISSUE_TYPE=bug
if ${{ contains(github.event.issue.labels.*.name, 'bug') }}
then
echo "type=Bug" >> $GITHUB_OUTPUT
else
ISSUE_TYPE=story
echo "type=Story" >> $GITHUB_OUTPUT
fi
- name: Create components JSON
id: components
shell: python
run: |
import json
import os
components = [
{"name": component}
for component in "${{ inputs.jira-component-names }}".split(",")
if component
]
output = f"components={json.dumps(components)}"
print(output)
output_file = os.environ["GITHUB_OUTPUT"]
with open(output_file, "a") as file:
file.write(output)
- name: Create Jira issue
id: create
uses: atlassian/gajira-create@v3
with:
project: ${{ inputs.jira-project-key }}
issuetype: ${{ steps.issue-type.outputs.type }}
summary: ${{ github.event.issue.title }}
fields: '{"components": ${{ steps.components.outputs.components }}, "assignee": null}'
- name: Add GitHub issue URL to Jira issue
run: |
curl --request POST \
--url "${{ inputs.jira-base-url }}/rest/api/3/issue/${{ steps.create.outputs.issue }}/remotelink" \
--user "${{ secrets.jira-user-email }}:${{ secrets.jira-api-token }}" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '{"object": {"url": "${{ github.event.issue.html_url }}", "title": "Issue #${{ github.event.issue.number }} · ${{ github.repository }}"}}'
- name: Comment Jira issue URL on GitHub issue
run: gh issue comment ${{ github.event.issue.number }} --body "${{ inputs.jira-base-url }}/browse/${{ steps.create.outputs.issue }}" --repo ${{ github.repository }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# send Jira request
update-jira-issue:
name: Update Jira issue
if: ${{ github.event.action != 'opened' }}
runs-on: ubuntu-latest
steps:
- name: Get Jira issue key
id: get-jira-issue-key
shell: python
run: |
import json
import os
import subprocess
# Canonical doesn't encourage discussions in Jira on public project issues.
# Thus, it is NOT recommended to put description in Jira in order to push conversation to GitHub
# if strongly required, then replace '--arg body ""' with the next line
# --arg body "$ISSUE_DESCRIPTION"
data=$( jq -n \
--arg title "$ISSUE_TITLE" \
--arg url '${{ github.event.issue.html_url }}' \
--arg submitter '${{ github.event.issue.user.login }}' \
--arg body "" \
--arg type "$ISSUE_TYPE" \
--arg action '${{ github.event.action }}' \
--arg component '${{ inputs.jira-component-name }}' \
'{title: $title, url: $url, submitter: $submitter, body: $body, type: $type, action: $action, component: $component}' )
def run_gh_cli(*args):
"""Run command with GitHub CLI"""
output = subprocess.check_output(
[
"gh",
"api",
"-H",
"Accept: application/vnd.github+json",
"-H",
"X-GitHub-Api-Version: 2022-11-28",
*args,
]
)
return json.loads(output)
curl -X POST -H 'Content-type: application/json' --data "${data}" "${{ secrets.jira-webhook-url }}"
# First five issue comments
github_issue_comments = run_gh_cli(
"${{ github.event.issue.comments_url }}",
"--method",
"GET",
"--raw-field",
"per_page=5",
)
for comment in github_issue_comments:
user = comment["user"]
if user["login"] == "github-actions[bot]":
assert user["id"] == 41898282
assert user["type"] == "Bot"
# Example: https://warthogs.atlassian.net/browse/DPE-994
jira_issue_link = comment["body"]
if not jira_issue_link.startswith("${{ inputs.jira-base-url }}"):
continue
# Example: DPE-994
jira_issue_key = jira_issue_link.split("/")[-1]
output_file = os.environ["GITHUB_OUTPUT"]
with open(output_file, "a") as file:
file.write(f"jira_issue_key={jira_issue_key}")
break
else:
print("Jira issue not found")
exit(1)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Determine Jira issue transition ID
id: transition-id
run: |
if ${{ github.event.action == 'closed' && github.event.issue.state_reason == 'completed' }}
then
echo "name=Done" >> $GITHUB_OUTPUT
echo "id=61" >> $GITHUB_OUTPUT
elif ${{ github.event.action == 'closed' && github.event.issue.state_reason == 'not_planned' }}
then
echo "name=Rejected" >> $GITHUB_OUTPUT
echo "id=71" >> $GITHUB_OUTPUT
elif ${{ github.event.action == 'reopened'}}
then
echo "name=Untriaged" >> $GITHUB_OUTPUT
echo "id=81" >> $GITHUB_OUTPUT
else
echo "github.event.action=${{ github.event.action }}"
echo "github.event.issue.state_reason=${{ github.event.issue.state_reason }}"
echo "Unknown transition"
exit 1
fi
- name: Transition issue to ${{ steps.transition-id.outputs.name }}
run: |
curl --request POST \
--url "${{ inputs.jira-base-url }}/rest/api/3/issue/${{ steps.get-jira-issue-key.outputs.jira_issue_key }}/transitions" \
--user "${{ secrets.jira-user-email }}:${{ secrets.jira-api-token }}" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '{"transition": {"id": "${{ steps.transition-id.outputs.id }}"}}'
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Usage

[Reusable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows) are located at [.github/workflows](.github/workflows)
[Reusable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows) (and documentation) are located at [.github/workflows](.github/workflows)

Workflows that do **not** begin with an underscore (e.g. `foo.yaml`) may be called outside this repository.

Expand Down

0 comments on commit 650c704

Please sign in to comment.