Skip to content

Commit 426d8b0

Browse files
authored
Merge branch 'main' into fail-fast
2 parents 3ab3790 + 365f951 commit 426d8b0

8 files changed

Lines changed: 184 additions & 42 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ fedmsg.d/sync2jira.py
2121
*.pyc
2222
__pycache__
2323
.vscode/settings.json
24+
.worktrees/

.tekton/build-pipeline.yaml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ spec:
1818
- name: name
1919
value: show-sbom
2020
- name: bundle
21-
value: quay.io/konflux-ci/tekton-catalog/task-show-sbom:0.1@sha256:beb0616db051952b4b861dd8c3e00fa1c0eccbd926feddf71194d3bb3ace9ce7
21+
value: quay.io/konflux-ci/tekton-catalog/task-show-sbom:0.1@sha256:e2c1b4eac642f32e91f3bc5d3cb48c5c70888aaf45c3650d9ea34573de7a7fd5
2222
- name: kind
2323
value: task
2424
resolver: bundles
@@ -134,7 +134,7 @@ spec:
134134
- name: name
135135
value: git-clone-oci-ta
136136
- name: bundle
137-
value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.1@sha256:56f65a16d3d0485c64ad85af2c1f3e9b0bb4d02d63f2fd0ebb9498d219ca723d
137+
value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.1@sha256:306b69e6db435ad4a7cf258b6219d9b998eb37da44f5e9ac882ac86a08109154
138138
- name: kind
139139
value: task
140140
resolver: bundles
@@ -163,7 +163,7 @@ spec:
163163
- name: name
164164
value: prefetch-dependencies-oci-ta
165165
- name: bundle
166-
value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.2@sha256:4c9ff416bfd127e1f960bd0218127c7e198dbd15827c1a8bf58ac5eb023dd9e2
166+
value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.2@sha256:c651d767709bea1bb2f52c37d19d332af4706fbbfe450724e314b286597795a2
167167
- name: kind
168168
value: task
169169
resolver: bundles
@@ -210,7 +210,7 @@ spec:
210210
- name: name
211211
value: buildah-oci-ta
212212
- name: bundle
213-
value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.7@sha256:7d5818e082e5534cf63946c1a1d380c0ee6b10b5c915340368c9ca081b97c02a
213+
value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.7@sha256:c422f1e52e446440dfca22983ca360e37242f3331c00539b3f9426be52c9c37c
214214
- name: kind
215215
value: task
216216
resolver: bundles
@@ -241,7 +241,7 @@ spec:
241241
- name: name
242242
value: build-image-index
243243
- name: bundle
244-
value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.2@sha256:985d1efe861b02524a7679ecd855624b3d4e3a2e835b6f8a97ec7d135898ec0b
244+
value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.2@sha256:05d3d8a5ded44c51b074a56a408ddf5d65c56b4c15e110abb1a99e3aff269d49
245245
- name: kind
246246
value: task
247247
resolver: bundles
@@ -335,7 +335,7 @@ spec:
335335
- name: name
336336
value: ecosystem-cert-preflight-checks
337337
- name: bundle
338-
value: quay.io/konflux-ci/tekton-catalog/task-ecosystem-cert-preflight-checks:0.2@sha256:b612fd73d81822113e2c12f44a72eed218540aaa8e9f3e42223bddb01a0689cb
338+
value: quay.io/konflux-ci/tekton-catalog/task-ecosystem-cert-preflight-checks:0.2@sha256:329b14911d93ad5425c8f6cf57112d344aae0c219117278faa47731763a27853
339339
- name: kind
340340
value: task
341341
resolver: bundles
@@ -361,7 +361,7 @@ spec:
361361
- name: name
362362
value: sast-snyk-check-oci-ta
363363
- name: bundle
364-
value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.4@sha256:49b7d09db82e6cad98152db8f16707ca3d90a1709e846e3ed8c91a433c88724f
364+
value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.4@sha256:c5e640a7741dfba035ced5e3ac30c82bba9bfe04f60e1631509205dcf884a0ea
365365
- name: kind
366366
value: task
367367
resolver: bundles
@@ -383,7 +383,7 @@ spec:
383383
- name: name
384384
value: clamav-scan
385385
- name: bundle
386-
value: quay.io/konflux-ci/tekton-catalog/task-clamav-scan:0.3@sha256:b2f25599a10ab0846e4659f76b5b78c0fddf561404656fda52055eda31e70d83
386+
value: quay.io/konflux-ci/tekton-catalog/task-clamav-scan:0.3@sha256:78f0349720a18e25546fd57a0eb15925ec4da6d9e1d9290b73a4770ae9ad77f5
387387
- name: kind
388388
value: task
389389
resolver: bundles
@@ -435,7 +435,7 @@ spec:
435435
- name: name
436436
value: sast-unicode-check-oci-ta
437437
- name: bundle
438-
value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.3@sha256:8817f5081c10d9debf25601d6d99d7eddde19435be1ff24741d9025931639959
438+
value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.4@sha256:0ca0203c25e22c9f12cc32436f6bf02df19fd177ba5f84926d804c711146974e
439439
- name: kind
440440
value: task
441441
resolver: bundles
@@ -497,7 +497,7 @@ spec:
497497
- name: name
498498
value: rpms-signature-scan
499499
- name: bundle
500-
value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2@sha256:00417785ba16344c10e8682bf58eeb6ef058cedd88ae2d86bb14ced220135374
500+
value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2@sha256:f2df541f49b5310f343b55f58b0881a46a2b46c5df39a9c34563c5042b106f6f
501501
- name: kind
502502
value: task
503503
resolver: bundles

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM registry.access.redhat.com/ubi10/ubi:10.1-1767602397@sha256:937cb57b9dead25a68ca3b40f40db874dcf7b97dd0b438aca32c54e26220b415
1+
FROM registry.access.redhat.com/ubi10/ubi:10.1-1769662757@sha256:64b34b13c0dda61ed9b977bde8068eb0d350f4afb75142715e83be68373e4848
22

33
ARG SYNC2JIRA_GIT_REPO=https://github.com/release-engineering/Sync2Jira.git
44
ARG SYNC2JIRA_GIT_REF=main

Dockerfile.sync-page

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM registry.access.redhat.com/ubi10/ubi:10.1-1767602397@sha256:937cb57b9dead25a68ca3b40f40db874dcf7b97dd0b438aca32c54e26220b415
1+
FROM registry.access.redhat.com/ubi10/ubi:10.1-1769662757@sha256:64b34b13c0dda61ed9b977bde8068eb0d350f4afb75142715e83be68373e4848
22

33
ARG SYNC2JIRA_GIT_REPO=https://github.com/release-engineering/Sync2Jira.git
44
ARG SYNC2JIRA_GIT_REF=main

sync2jira/downstream_issue.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ def get_jira_client(issue, config):
295295
return client
296296

297297

298-
def _get_existing_jira_issue(client, issue, config):
298+
def get_existing_jira_issue(client, issue, config):
299299
"""
300300
Get a jira issue by the linked remote issue.
301301
@@ -1415,7 +1415,7 @@ def update_jira(client, config, issue):
14151415
# First, check to see if we have a matching issue using the new method.
14161416
# If we do, then bail out. No sync needed.
14171417
log.info("Looking for matching downstream issue via new method.")
1418-
existing = _get_existing_jira_issue(client, issue, config)
1418+
existing = get_existing_jira_issue(client, issue, config)
14191419
if existing:
14201420
# If we found an existing JIRA issue already
14211421
log.info("Found existing, matching downstream %r.", existing.key)

sync2jira/downstream_pr.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,11 @@ def update_jira(client, config, pr):
225225
if not pr.jira_key:
226226
create_pr_issue = pr.downstream.get("create_pr_issue", False)
227227
if create_pr_issue:
228-
# Convert PR to Issue-like object for creation
229-
_create_jira_issue_from_pr(client, pr, config)
228+
if existing := d_issue.get_existing_jira_issue(client, pr, config):
229+
log.info(f"Found existing JIRA issue {existing.key} for PR {pr.url}")
230+
update_jira_issue(existing, pr, client)
231+
else:
232+
_create_jira_issue_from_pr(client, pr, config)
230233
else:
231234
log.info("No JIRA key found in PR, skipping.")
232235
return

tests/test_downstream_issue.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ class MockIssue(object):
214214
@mock.patch("jira.client.JIRA")
215215
def test_get_existing_newstyle(self, mock_client, mock_get_query, mock_filter):
216216
"""
217-
This tests '_get_existing_jira_issue' function.
217+
This tests 'get_existing_jira_issue' function.
218218
"""
219219
mock_issue_1: JIssue = MagicMock(spec=JIssue, name="mock_issue_1")
220220
mock_issue_1.key = "MOCK-1"
@@ -271,7 +271,7 @@ def test_get_existing_newstyle(self, mock_client, mock_get_query, mock_filter):
271271
mock_get_query.return_value = x["jira_results"]
272272
mock_client.search_issues.return_value = x["search_issues"]
273273
mock_filter.return_value = x["filter_results"]
274-
result = d._get_existing_jira_issue(
274+
result = d.get_existing_jira_issue(
275275
client=mock_client, issue=self.mock_issue, config=self.mock_config
276276
)
277277
self.assertEqual(result, x["expected"])
@@ -916,7 +916,7 @@ def update_state(
916916
self.assertEqual(actual, expected, f"In scenario {scenario}")
917917

918918
@mock.patch(PATH + "get_jira_client")
919-
@mock.patch(PATH + "_get_existing_jira_issue")
919+
@mock.patch(PATH + "get_existing_jira_issue")
920920
@mock.patch(PATH + "_update_jira_issue")
921921
@mock.patch(PATH + "_create_jira_issue")
922922
@mock.patch("jira.client.JIRA")
@@ -953,7 +953,7 @@ def test_sync_with_jira_matching(
953953
mock_existing_jira_issue_legacy.assert_not_called()
954954

955955
@mock.patch(PATH + "get_jira_client")
956-
@mock.patch(PATH + "_get_existing_jira_issue")
956+
@mock.patch(PATH + "get_existing_jira_issue")
957957
@mock.patch(PATH + "_update_jira_issue")
958958
@mock.patch(PATH + "_create_jira_issue")
959959
@mock.patch("jira.client.JIRA")
@@ -988,7 +988,7 @@ def test_sync_with_jira_down(
988988
mock_existing_jira_issue_legacy.assert_not_called()
989989

990990
@mock.patch(PATH + "get_jira_client")
991-
@mock.patch(PATH + "_get_existing_jira_issue")
991+
@mock.patch(PATH + "get_existing_jira_issue")
992992
@mock.patch(PATH + "_update_jira_issue")
993993
@mock.patch(PATH + "_create_jira_issue")
994994
@mock.patch("jira.client.JIRA")

tests/test_downstream_pr.py

Lines changed: 159 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -411,51 +411,189 @@ def test_sync_with_jira_create_pr_issue_disabled(
411411
# Assert everything was called correctly
412412
mock_update_jira.assert_not_called()
413413

414+
@mock.patch(PATH + "d_issue")
415+
def test_update_jira_service_unavailable(self, mock_d_issue):
416+
"""Test 'update_jira' when in development mode and the Jira service is unavailable."""
417+
418+
# Set up return values
419+
self.mock_config["sync2jira"]["develop"] = False
420+
mock_d_issue.check_jira_status.return_value = False
421+
422+
# Call the function
423+
with self.assertRaises(RuntimeError):
424+
d.update_jira(self.mock_client, self.mock_config, self.mock_pr)
425+
414426
@mock.patch(PATH + "_create_jira_issue_from_pr")
427+
@mock.patch(PATH + "update_jira_issue")
428+
@mock.patch(PATH + "matcher")
415429
@mock.patch(PATH + "d_issue")
416-
def test_update_jira_create_pr_issue_enabled(
417-
self, mock_d_issue, mock_create_jira_issue_from_pr
430+
def test_update_jira_with_no_key_create_enabled_no_issue(
431+
self,
432+
mock_d_issue,
433+
mock_matcher,
434+
mock_update_jira_issue,
435+
mock_create_jira_issue_from_pr,
418436
):
419-
"""
420-
Test 'update_jira' when create_pr_issue is enabled and no JIRA key is found.
437+
"""Test 'update_jira' when no JIRA key is found, issue creation is
438+
enabled, and the issue is not found.
421439
"""
422440
# Set up return values
423-
mock_client = MagicMock()
424441
mock_d_issue.check_jira_status.return_value = True
425-
self.mock_pr.jira_key = None
442+
mock_matcher.return_value = self.mock_pr.jira_key = None
426443
self.mock_pr.downstream = {"create_pr_issue": True}
444+
mock_d_issue.get_existing_jira_issue.return_value = None
427445

428446
# Call the function
429-
d.update_jira(mock_client, self.mock_config, self.mock_pr)
447+
d.update_jira(self.mock_client, self.mock_config, self.mock_pr)
430448

431449
# Assert everything was called correctly
432-
mock_d_issue.check_jira_status.assert_called_with(mock_client)
433-
mock_create_jira_issue_from_pr.assert_called_with(
434-
mock_client, self.mock_pr, self.mock_config
435-
)
436-
mock_client.search_issues.assert_not_called()
450+
mock_update_jira_issue.assert_not_called()
451+
mock_create_jira_issue_from_pr.assert_called()
437452

438453
@mock.patch(PATH + "_create_jira_issue_from_pr")
454+
@mock.patch(PATH + "update_jira_issue")
455+
@mock.patch(PATH + "matcher")
439456
@mock.patch(PATH + "d_issue")
440-
def test_update_jira_create_pr_issue_disabled(
441-
self, mock_d_issue, mock_create_jira_issue_from_pr
457+
def test_update_jira_with_no_key_create_enabled_issue_exists(
458+
self,
459+
mock_d_issue,
460+
mock_matcher,
461+
mock_update_jira_issue,
462+
mock_create_jira_issue_from_pr,
442463
):
443-
"""
444-
Test 'update_jira' when create_pr_issue is disabled and no JIRA key is found.
464+
"""Test 'update_jira' when no JIRA key is found, issue creation is
465+
enabled, and the issue exists.
445466
"""
446467
# Set up return values
447-
mock_client = MagicMock()
448468
mock_d_issue.check_jira_status.return_value = True
449-
self.mock_pr.jira_key = None
469+
mock_matcher.return_value = self.mock_pr.jira_key = None
470+
self.mock_pr.downstream = {"create_pr_issue": True}
471+
mock_d_issue.get_existing_jira_issue.return_value = self.mock_existing
472+
473+
# Call the function
474+
d.update_jira(self.mock_client, self.mock_config, self.mock_pr)
475+
476+
# Assert everything was called correctly
477+
mock_update_jira_issue.assert_called()
478+
mock_create_jira_issue_from_pr.assert_not_called()
479+
480+
@mock.patch(PATH + "_create_jira_issue_from_pr")
481+
@mock.patch(PATH + "update_jira_issue")
482+
@mock.patch(PATH + "matcher")
483+
@mock.patch(PATH + "d_issue")
484+
def test_update_jira_with_no_key_create_disabled(
485+
self,
486+
mock_d_issue,
487+
mock_matcher,
488+
mock_update_jira_issue,
489+
mock_create_jira_issue_from_pr,
490+
):
491+
"""Test 'update_jira' when no JIRA key is found and issue creation is disabled."""
492+
# Set up return values
493+
mock_d_issue.check_jira_status.return_value = True
494+
mock_matcher.return_value = self.mock_pr.jira_key = None
450495
self.mock_pr.downstream = {"create_pr_issue": False}
451496

452497
# Call the function
453-
d.update_jira(mock_client, self.mock_config, self.mock_pr)
498+
d.update_jira(self.mock_client, self.mock_config, self.mock_pr)
499+
500+
# Assert everything was (not) called correctly
501+
mock_update_jira_issue.assert_not_called()
502+
mock_create_jira_issue_from_pr.assert_not_called()
503+
504+
@mock.patch(PATH + "_create_jira_issue_from_pr")
505+
@mock.patch(PATH + "update_jira_issue")
506+
@mock.patch(PATH + "matcher")
507+
@mock.patch(PATH + "d_issue")
508+
def test_update_jira_with_no_key_create_unspecified(
509+
self,
510+
mock_d_issue,
511+
mock_matcher,
512+
mock_update_jira_issue,
513+
mock_create_jira_issue_from_pr,
514+
):
515+
"""Test 'update_jira' when no JIRA key is found and issue creation is unspecified."""
516+
# Set up return values
517+
mock_d_issue.check_jira_status.return_value = True
518+
mock_matcher.return_value = self.mock_pr.jira_key = None
519+
520+
# Call the function
521+
d.update_jira(self.mock_client, self.mock_config, self.mock_pr)
522+
523+
# Assert everything was (not) called correctly
524+
mock_update_jira_issue.assert_not_called()
525+
mock_create_jira_issue_from_pr.assert_not_called()
526+
527+
@mock.patch(PATH + "_create_jira_issue_from_pr")
528+
@mock.patch(PATH + "update_jira_issue")
529+
@mock.patch(PATH + "matcher")
530+
@mock.patch(PATH + "d_issue")
531+
def test_update_jira_with_key_found_and_unique_issue(
532+
self,
533+
mock_d_issue,
534+
mock_matcher,
535+
mock_update_jira_issue,
536+
mock_create_jira_issue_from_pr,
537+
):
538+
"""Test 'update_jira' when JIRA key is found and the issue is found."""
539+
# Set up return values
540+
mock_d_issue.check_jira_status.return_value = True
541+
mock_matcher.return_value = self.mock_pr.jira_key
542+
543+
# Call the function
544+
d.update_jira(self.mock_client, self.mock_config, self.mock_pr)
454545

455546
# Assert everything was called correctly
456-
mock_d_issue.check_jira_status.assert_called_with(mock_client)
547+
mock_update_jira_issue.assert_called()
548+
mock_create_jira_issue_from_pr.assert_not_called()
549+
550+
@mock.patch(PATH + "_create_jira_issue_from_pr")
551+
@mock.patch(PATH + "update_jira_issue")
552+
@mock.patch(PATH + "matcher")
553+
@mock.patch(PATH + "d_issue")
554+
def test_update_jira_with_key_found_and_no_issue(
555+
self,
556+
mock_d_issue,
557+
mock_matcher,
558+
mock_update_jira_issue,
559+
mock_create_jira_issue_from_pr,
560+
):
561+
"""Test 'update_jira' when JIRA key is found and the issue is not found."""
562+
# Set up return values
563+
mock_d_issue.check_jira_status.return_value = True
564+
mock_matcher.return_value = self.mock_pr.jira_key
565+
self.mock_client.search_issues.return_value = []
566+
567+
# Call the function
568+
d.update_jira(self.mock_client, self.mock_config, self.mock_pr)
569+
570+
# Assert everything was (not) called correctly
571+
mock_update_jira_issue.assert_not_called()
572+
mock_create_jira_issue_from_pr.assert_not_called()
573+
574+
@mock.patch(PATH + "_create_jira_issue_from_pr")
575+
@mock.patch(PATH + "update_jira_issue")
576+
@mock.patch(PATH + "matcher")
577+
@mock.patch(PATH + "d_issue")
578+
def test_update_jira_with_key_found_and_multiple_issues(
579+
self,
580+
mock_d_issue,
581+
mock_matcher,
582+
mock_update_jira_issue,
583+
mock_create_jira_issue_from_pr,
584+
):
585+
"""Test 'update_jira' when JIRA key is found and the search returns multiple issues."""
586+
# Set up return values
587+
mock_d_issue.check_jira_status.return_value = True
588+
mock_matcher.return_value = self.mock_pr.jira_key
589+
self.mock_client.search_issues.return_value = ["MOCK-123", "MOCK-456"]
590+
591+
# Call the function
592+
d.update_jira(self.mock_client, self.mock_config, self.mock_pr)
593+
594+
# Assert everything was called correctly: should exit without calling subroutines
595+
mock_update_jira_issue.assert_not_called()
457596
mock_create_jira_issue_from_pr.assert_not_called()
458-
mock_client.search_issues.assert_not_called()
459597

460598
def _setup_pr_for_issue_creation(self, **overrides):
461599
"""

0 commit comments

Comments
 (0)