Skip to content

Commit 278db39

Browse files
committed
feat(action): updated this action from Docker to Composite type
1 parent 3940cd5 commit 278db39

9 files changed

+169
-60
lines changed

CHANGELOG.md

+26
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
# CHANGELOG
2+
3+
> All notable changes to this project are documented in this file.
4+
> This list is not exhaustive - only important changes, fixes, and new features in the code are reflected here.
5+
6+
<sub>The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
7+
</sub>
8+
9+
---
10+
11+
## Unreleased
12+
13+
### ✨ New features
14+
15+
- **action**: updated this action from Docker to Composite type *(Tomas Sebestik - d926676)*
16+
17+
### 🐛 Bug fixes
18+
19+
- add dynamic ref to action.yml file for development testing *(Tomas Sebestik - 39cd704)*
20+
21+
### 📖 Documentation
22+
23+
- **caller-workflow**: add caller workflow for easy copy to target repo *(Tomas Sebestik - d651127)*
24+
25+
---
26+
127
## v0.1.1 (2024-02-14)
228

329

Dockerfile

-35
This file was deleted.

action.yml

+70-10
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,74 @@
1-
name: "GitHub to JIRA Issue Sync"
2-
description: "Performs simple one way syncing of GitHub issues into JIRA."
3-
branding:
4-
icon: "fast-forward"
5-
color: "green"
1+
---
2+
name: Sync GitHub Pull requests and Issues to JIRA
3+
description: >
4+
Synchronizes Issues, Issue comments and Pull Requests from Espressif GitHub to Espressif JIRA.
5+
66
inputs:
77
cron_job:
88
description: >
9-
Whether the action is run as a cron job.
10-
Set true to trigger syncing of new PRs.
11-
required: false
9+
THIS INPUT IS INCLUDED ONLY FOR COMPATIBILITY WITH LEGACY CALLER WORKFLOWS.
10+
ALL LOGIC IS DETERMINED BASED ON THE ACTION TRIGGER; THIS INPUT DOES EFFECTIVELY NOTHING
11+
Indicates whether the action is being run as a scheduled cron job
12+
If so, the it syncs new pull requests during the cron job execution.
13+
14+
jira-project:
15+
description: >
16+
The key of the JIRA project where issues will be created or updated.
17+
It can be passed either as an input `with: jira-project: <jira_key>`
18+
or as an environment variable `ENV: JIRA_PROJECT: <jira_key>` (legacy).
19+
If this is not passed one way or another, a check in the sync script will cause the action to fail.
20+
21+
jira-component:
22+
description: 'The JIRA component to which the issues will be assigned. Default = "GitHub"'
23+
default: 'GitHub'
24+
25+
jira-issue-type:
26+
description: 'The type of JIRA issue to be created if no labels to the issue are set. Default = "Task"'
27+
default: 'Task'
28+
1229
runs:
13-
using: "docker"
14-
image: "Dockerfile"
30+
using: composite
31+
steps:
32+
- name: Checkout action repository (espressif/sync-jira-actions)
33+
uses: actions/checkout@v4
34+
with:
35+
repository: espressif/sync-jira-actions
36+
37+
- name: Set up Python
38+
uses: actions/setup-python@v5
39+
with:
40+
python-version: '3.11'
41+
cache: pip
42+
43+
- name: Install Python dependencies
44+
shell: bash
45+
run: |
46+
python -m venv venv
47+
source venv/bin/activate
48+
pip install --upgrade pip
49+
pip install -r requirements.txt
50+
51+
- name: Install Node.js
52+
uses: actions/setup-node@v4
53+
with:
54+
node-version: '20'
55+
cache: npm
56+
57+
- name: Install npm dependencies (markdown2confluence)
58+
shell: bash
59+
run: npm ci
60+
61+
- name: Run sync_to_jira.py
62+
shell: bash
63+
run: |
64+
source venv/bin/activate
65+
python sync_jira_actions/sync_to_jira.py
66+
env:
67+
GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} # Needs to be passed from caller workflow; by ENV (secure), not by input
68+
JIRA_PASS: ${{ env.JIRA_PASS }} # Needs to be passed from caller workflow; by ENV (secure), not by input
69+
JIRA_URL: ${{ env.JIRA_URL }} # Needs to be passed from caller workflow; by ENV (secure), not by input
70+
JIRA_USER: ${{ env.JIRA_USER }} # Needs to be passed from caller workflow; by ENV (secure), not by input
71+
INPUT_CRON_JOB: ${{ github.event_name == 'schedule' && 'true' || '' }}
72+
JIRA_PROJECT: ${{ inputs.jira-project }}
73+
JIRA_COMPONENT: ${{ inputs.jira-component }}
74+
JIRA_ISSUE_TYPE: ${{ inputs.jira-issue-type }}

package-lock.json

+38
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"dependencies": {
3+
"@shogobg/markdown2confluence": "^0.1.6"
4+
}
5+
}

sync_jira_actions/sync_issue.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ def handle_issue_opened(jira, event):
4444
return
4545

4646
print('Creating new JIRA issue for new GitHub issue')
47-
_create_jira_issue(jira, event['issue'])
47+
issue = _create_jira_issue(jira, event['issue'])
48+
print(f'✔️ Successfully synchronized new GitHub issue #{gh_issue["number"]} to JIRA issue {issue.key}')
4849

4950

5051
def handle_issue_edited(jira, event):
@@ -133,7 +134,8 @@ def handle_comment_created(jira, event):
133134
gh_comment = event['comment']
134135

135136
jira_issue = _find_jira_issue(jira, event['issue'], True)
136-
jira.add_comment(jira_issue.id, _get_jira_comment_body(gh_comment))
137+
jira_comment = jira.add_comment(jira_issue.id, _get_jira_comment_body(gh_comment))
138+
print(f'✔️ Successfully synchronized comment (ID: {jira_comment.id}) for JIRA issue {jira_issue.key}')
137139

138140

139141
def handle_comment_edited(jira, event):
@@ -152,15 +154,17 @@ def handle_comment_edited(jira, event):
152154
break
153155

154156
if not found: # if we didn't find the old comment, make a new comment about the edit
155-
jira.add_comment(jira_issue.id, _get_jira_comment_body(gh_comment))
157+
jira_comment = jira.add_comment(jira_issue.id, _get_jira_comment_body(gh_comment))
158+
print(f'✔️ Successfully synchronized comment (ID: {jira_comment.id}) for JIRA issue {jira_issue.key}')
156159

157160

158161
def handle_comment_deleted(jira, event):
159162
gh_comment = event['comment']
160163
jira_issue = _find_jira_issue(jira, event['issue'], True)
161-
jira.add_comment(
164+
jira_comment = jira.add_comment(
162165
jira_issue.id, f"@{gh_comment['user']['login']} deleted [GitHub issue comment|{gh_comment['html_url']}]"
163166
)
167+
print(f'✔️ Successfully synchronized deleted comment (ID: {jira_comment.id}) for JIRA issue {jira_issue.key}')
164168

165169

166170
# Works both for issues and pull requests
@@ -224,7 +228,7 @@ def _markdown2wiki(markdown):
224228
mdf.write('\n')
225229

226230
try:
227-
subprocess.check_call(['markdown2confluence', md_path, conf_path])
231+
subprocess.check_call(['npx', 'markdown2confluence', md_path, conf_path]) # noqa: S603, S607
228232
with open(conf_path, 'r', encoding='utf-8') as file:
229233
result = file.read()
230234
if len(result) > 16384: # limit any single body of text to 16KB (JIRA API limits total text to 32KB)
@@ -445,7 +449,8 @@ def _find_jira_issue(jira, gh_issue, make_new=False, retries=5):
445449
"""
446450
url = gh_issue['html_url']
447451
jql_query = f'issue in issuesWithRemoteLinksByGlobalId("{url}") order by updated desc'
448-
print(f'JQL query: {jql_query}')
452+
if os.environ.get('ACTIONS_RUNNER_DEBUG') == 'true':
453+
print(f'JQL query: {jql_query}') # Print the JQL query only in debug mode
449454
res = jira.search_issues(jql_query)
450455
if not res:
451456
print(f"WARNING: No JIRA issues have a remote link with globalID '{url}'")

sync_jira_actions/sync_pr.py

+1
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ def sync_remain_prs(jira):
4444
issue = _find_jira_issue(jira, gh_issue)
4545
if issue is None:
4646
_create_jira_issue(jira, gh_issue)
47+
print(f'✔️ Successfully synchronized PR #{pr.number}')

sync_jira_actions/sync_to_jira.py

+17-9
Original file line numberDiff line numberDiff line change
@@ -40,36 +40,44 @@ def applicationlinks(self):
4040

4141
def main():
4242
if 'GITHUB_REPOSITORY' not in os.environ:
43-
print('Not running in GitHub action context, nothing to do')
43+
print('Not running in GitHub action context, nothing to do')
4444
return
4545

4646
if not os.environ['GITHUB_REPOSITORY'].startswith('espressif/'):
47-
print('Not an Espressif repo, nothing to sync to JIRA')
47+
print('Not an Espressif repo, nothing to sync to JIRA')
4848
return
4949

50+
# For backward compatibility; handles situation if JIRA_PROJECT is not set in caller workflow either as input or ENV
51+
if 'JIRA_PROJECT' not in os.environ:
52+
print('❌ JIRA_PROJECT not set, fail!')
53+
raise SystemExit(1)
54+
5055
# Connect to Jira server
5156
print('Connecting to Jira Server...')
5257

5358
# Check if the JIRA_PASS is token or password
5459
token_or_pass = os.environ['JIRA_PASS']
5560
if token_or_pass.startswith('token:'):
56-
print('Authenticating with JIRA_TOKEN ...')
61+
if os.environ.get('ACTIONS_RUNNER_DEBUG') == 'true':
62+
print('Authenticating with JIRA_TOKEN ...')
5763
token = token_or_pass[6:] # Strip the 'token:' prefix
5864
jira = _JIRA(os.environ['JIRA_URL'], token_auth=token)
5965
else:
60-
print('Authenticating with JIRA_USER and JIRA_PASS ...')
66+
if os.environ.get('ACTIONS_RUNNER_DEBUG') == 'true':
67+
print('Authenticating with JIRA_USER and JIRA_PASS ...')
6168
jira = _JIRA(os.environ['JIRA_URL'], basic_auth=(os.environ['JIRA_USER'], token_or_pass))
6269

6370
# Check if it's a cron job
64-
if os.environ.get('INPUT_CRON_JOB'):
71+
if os.environ.get('INPUT_CRON_JOB') == 'true':
6572
print('Running as a cron job. Syncing remaining PRs...')
6673
sync_remain_prs(jira)
6774
return
6875

6976
# The path of the file with the complete webhook event payload. For example, /github/workflow/event.json.
7077
with open(os.environ['GITHUB_EVENT_PATH'], 'r', encoding='utf-8') as file:
7178
event = json.load(file)
72-
print(json.dumps(event, indent=4))
79+
if os.environ.get('ACTIONS_RUNNER_DEBUG') == 'true':
80+
print(json.dumps(event, indent=4))
7381

7482
event_name = os.environ['GITHUB_EVENT_NAME']
7583

@@ -79,16 +87,16 @@ def main():
7987
inputs = event.get('inputs')
8088

8189
if not inputs:
82-
print('Triggered workflow_dispatch event without correct inputs. Exiting...')
90+
print('Triggered workflow_dispatch event without correct inputs. Exiting...')
8391
return
8492

8593
input_action = inputs.get('action')
8694
issue_numbers = inputs.get('issue-numbers')
8795
if input_action != 'mirror-issues':
88-
print('This action needs input "mirror-issues". Exiting...')
96+
print('This action needs input "mirror-issues". Exiting...')
8997
return
9098
if not issue_numbers:
91-
print('This action needs inputs "issue-numbers". Exiting...')
99+
print('This action needs inputs "issue-numbers". Exiting...')
92100
return
93101

94102
print(f'Starting manual sync of issues: {issue_numbers}')

tests/test_sync_to_jira.py

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def test_handle_issue_opened_event(mock_environment, sync_to_jira_main, monkeypa
5555
}
5656
mock_environment.write_text(json.dumps(event_data))
5757
monkeypatch.setenv('GITHUB_EVENT_NAME', 'issues')
58+
monkeypatch.setenv('JIRA_PROJECT', 'TEST_PROJECT')
5859

5960
with patch('sync_jira_actions.sync_to_jira.handle_issue_opened') as mock_handle_issue_opened:
6061
sync_to_jira_main()

0 commit comments

Comments
 (0)