Коммит
8c8cbf1659
11
action.yml
11
action.yml
|
@ -1,6 +1,6 @@
|
|||
name: 'Sync Code Scanning and JIRA'
|
||||
description: "Let's you manage Code Scanning alerts from JIRA by creating an
|
||||
issue for each alert and keeping the states synced."
|
||||
name: 'Sync GitHub Advanced Security and Jira'
|
||||
description: "This helps sync GHAS alerts to JIRA by creating an
|
||||
issue for each alert."
|
||||
inputs:
|
||||
jira_url:
|
||||
description: 'URL of the JIRA instance'
|
||||
|
@ -14,6 +14,11 @@ inputs:
|
|||
jira_project:
|
||||
description: 'JIRA project key'
|
||||
required: true
|
||||
jira_labels:
|
||||
description: 'JIRA bug label(s). (e.g. valid format can be "red-team,blue-team,green-team", or "red-team")
|
||||
This tool will split the values entered by commas. Spaces in the double quotes
|
||||
will be respected and saved.'
|
||||
required: false
|
||||
github_token:
|
||||
description: 'GitHub API token with the required permissions'
|
||||
required: false
|
||||
|
|
8
cli.py
8
cli.py
|
@ -53,7 +53,7 @@ def serve(args):
|
|||
jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token)
|
||||
s = Sync(
|
||||
github,
|
||||
jira.getProject(args.jira_project),
|
||||
jira.getProject(args.jira_project, args.jira_labels),
|
||||
direction=direction_str_to_num(args.direction),
|
||||
)
|
||||
server.run_server(s, args.secret, port=args.port)
|
||||
|
@ -81,7 +81,10 @@ def sync(args):
|
|||
github = ghlib.GitHub(args.gh_url, args.gh_token)
|
||||
jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token)
|
||||
jira_project = jira.getProject(
|
||||
args.jira_project, args.issue_end_state, args.issue_reopen_state
|
||||
args.jira_project,
|
||||
args.issue_end_state,
|
||||
args.issue_reopen_state,
|
||||
args.jira_labels,
|
||||
)
|
||||
repo_id = args.gh_org + "/" + args.gh_repo
|
||||
|
||||
|
@ -197,6 +200,7 @@ def main():
|
|||
default=os.getenv("GH2JIRA_JIRA_TOKEN"),
|
||||
)
|
||||
credential_base.add_argument("--jira-project", help="JIRA project key")
|
||||
credential_base.add_argument("--jira-labels", help="JIRA bug label(s)")
|
||||
credential_base.add_argument(
|
||||
"--secret",
|
||||
help="Webhook secret. Alternatively, the GH2JIRA_SECRET may be set.",
|
||||
|
|
|
@ -9,6 +9,7 @@ cd / && pipenv run /gh2jira sync \
|
|||
--jira-user "$INPUT_JIRA_USER" \
|
||||
--jira-token "$INPUT_JIRA_TOKEN" \
|
||||
--jira-project "$INPUT_JIRA_PROJECT" \
|
||||
--jira-labels "$INPUT_JIRA_LABELS" \
|
||||
--direction "$INPUT_SYNC_DIRECTION" \
|
||||
--issue-end-state "$INPUT_ISSUE_END_STATE" \
|
||||
--issue-reopen-state "$INPUT_ISSUE_REOPEN_STATE" \
|
||||
|
|
14
jiralib.py
14
jiralib.py
|
@ -50,8 +50,8 @@ class Jira:
|
|||
def auth(self):
|
||||
return self.user, self.token
|
||||
|
||||
def getProject(self, projectkey, endstate, reopenstate):
|
||||
return JiraProject(self, projectkey, endstate, reopenstate)
|
||||
def getProject(self, projectkey, endstate, reopenstate, labels):
|
||||
return JiraProject(self, projectkey, endstate, reopenstate, labels)
|
||||
|
||||
def list_hooks(self):
|
||||
resp = requests.get(
|
||||
|
@ -96,8 +96,9 @@ class Jira:
|
|||
|
||||
|
||||
class JiraProject:
|
||||
def __init__(self, jira, projectkey, endstate, reopenstate):
|
||||
def __init__(self, jira, projectkey, endstate, reopenstate, labels):
|
||||
self.jira = jira
|
||||
self.labels = labels.split(",") if labels else []
|
||||
self.projectkey = projectkey
|
||||
self.j = self.jira.j
|
||||
self.endstate = endstate
|
||||
|
@ -123,6 +124,7 @@ class JiraProject:
|
|||
summary=STATE_ISSUE_SUMMARY,
|
||||
description=STATE_ISSUE_TEMPLATE,
|
||||
issuetype={"name": "Bug"},
|
||||
labels=self.labels,
|
||||
)
|
||||
elif len(issues) > 1:
|
||||
issues.sort(key=lambda i: i.id()) # keep the oldest issue
|
||||
|
@ -168,6 +170,7 @@ class JiraProject:
|
|||
alert_key=util.make_alert_key(repo_id, alert_num),
|
||||
),
|
||||
issuetype={"name": "Bug"},
|
||||
labels=self.labels,
|
||||
)
|
||||
logger.info(
|
||||
"Created issue {issue_key} for alert {alert_num} in {repo_id}.".format(
|
||||
|
@ -209,6 +212,7 @@ class JiraIssue:
|
|||
self.j = self.project.j
|
||||
self.endstate = self.project.endstate
|
||||
self.reopenstate = self.project.reopenstate
|
||||
self.labels = self.project.labels
|
||||
|
||||
def is_managed(self):
|
||||
if parse_alert_info(self.rawissue.fields.description)[0] is None:
|
||||
|
@ -275,6 +279,10 @@ class JiraIssue:
|
|||
)
|
||||
)
|
||||
|
||||
def persist_labels(self, labels):
|
||||
if labels:
|
||||
self.rawissue.update(fields={"labels": self.labels})
|
||||
|
||||
|
||||
def parse_alert_info(desc):
|
||||
"""
|
||||
|
|
3
sync.py
3
sync.py
|
@ -14,6 +14,7 @@ class Sync:
|
|||
self.github = github
|
||||
self.jira = jira_project
|
||||
self.direction = direction
|
||||
self.labels = self.jira.labels
|
||||
|
||||
def alert_created(self, repo_id, alert_num):
|
||||
self.sync(
|
||||
|
@ -103,10 +104,12 @@ class Sync:
|
|||
# we have to push back the state to JIRA, because "fixed"
|
||||
# alerts cannot be transitioned to "open"
|
||||
issue.adjust_state(alert.get_state())
|
||||
issue.persist_labels(self.labels)
|
||||
return alert.get_state()
|
||||
else:
|
||||
# The user treats JIRA as the source of truth
|
||||
alert.adjust_state(issue.get_state())
|
||||
issue.persist_labels(self.labels)
|
||||
return issue.get_state()
|
||||
|
||||
def sync_repo(self, repo_id, states=None):
|
||||
|
|
Загрузка…
Ссылка в новой задаче