Skip to content

ARO-26764: promote OCM label prefix and validation skip reason to API package#8577

Closed
tuxerrante wants to merge 11 commits into
openshift:mainfrom
tuxerrante:tuxerrante/promote-api-constants
Closed

ARO-26764: promote OCM label prefix and validation skip reason to API package#8577
tuxerrante wants to merge 11 commits into
openshift:mainfrom
tuxerrante:tuxerrante/promote-api-constants

Conversation

@tuxerrante
Copy link
Copy Markdown

@tuxerrante tuxerrante commented May 22, 2026

What this PR does / why we need it:

Follow-up to #8424 (review feedback from @jparrill).

Promotes two controller-private constants to the API package so that external consumers (ARO-HCP, OCM) can reference them programmatically instead of hardcoding strings:

  1. OCMLabelPrefix ("api.openshift.com/") — the label key prefix used by OCM to tag HostedCluster resources, mirrored to HostedControlPlane. Previously a hardcoded string in the predicate code; now lives alongside LimitedSupportLabel in api/hypershift/v1beta1/hostedcluster_types.go.

  2. ReleaseImageValidationSkippedReason ("ReleaseImageValidationSkipped") — the condition reason set on ValidReleaseImage when the skip annotation is present. Previously a controller-private constant; now lives alongside AsExpectedReason and InvalidImageReason in api/hypershift/v1beta1/hostedcluster_conditions.go.

Which issue(s) this PR fixes:

Fixes sub-tasks of ARO-26764:

Notes:

Test plan:

  • go vet — clean
  • go test -race — all pass (hostedcluster package and subpackages)
  • make lint — clean (the api-lint finding is pre-existing in azure.go, not from these changes)

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added ability to skip release image validation for HostedClusters via annotations
    • Enhanced label and annotation synchronization with improved filtering capabilities
  • Tests

    • Comprehensive test coverage added for validation behavior, controller reconciliation logic, and resource event filtering

tuxerrante and others added 11 commits May 5, 2026 17:13
Reduce self-induced HostedCluster reconciles by filtering the primary watch to
spec changes and explicit metadata triggers that already affect reconciliation.

Preserve mirrored annotation and label behavior with focused falsification tests
so stale queued requests still reconcile the latest HostedCluster state.

Signed-off-by: Alessandro Affinito <aaffinit@redhat.com>
Commit-Message-Assisted-by: Claude (via Claude Code)
Co-authored-by: Cursor <cursoragent@cursor.com>
Track when release image validation was skipped so same-generation annotation
changes can invalidate a cached True ValidReleaseImage condition.

Add a focused regression test matrix covering skip annotation add and remove
transitions without a generation bump.

Signed-off-by: Alessandro Affinito <aaffinit@redhat.com>
Commit-Message-Assisted-by: Claude (via Claude Code)
Co-authored-by: Cursor <cursoragent@cursor.com>
Update the new HostedCluster predicate code to use the k8sutil-scoped
annotation constants introduced on current main so the branch verifies cleanly
after rebasing.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep HostedControlPlane label mirroring aligned with the shared actionable label
prefix list so the watch predicate and reconciliation logic stay in sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the dynamic platform override subtest titles with explicit static names
so the HostedCluster predicate tests satisfy deterministic naming checks
without changing the existing assertion style used in this package.

Signed-off-by: Alessandro Affinito <aaffinit@redhat.com>
Commit-Message-Assisted-by: Claude (via Claude Code)
Co-authored-by: Cursor <cursoragent@cursor.com>
…neric names

annotationPrefixChanged and prefixedAnnotations are used for both
annotations and labels. Rename to prefixedKeyChanged and prefixedEntries
with generic parameter names to avoid reader confusion when the
functions are called with label maps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…on is present

Guard the validateReleaseImage call so it is not invoked when the skip
annotation is set. Previously the call ran but its result was discarded
by the switch branch, relying on an internal short-circuit. Making the
guard explicit avoids unnecessary work and makes intent clearer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the local ptrToTime helper with ptr.To from k8s.io/utils/ptr,
which is already a dependency in this package. Rename the predicate
local variable to pred so it does not shadow the controller-runtime
predicate package import.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the hardcoded "api.openshift.com/" label prefix to the API package
as OCMLabelPrefix so consumers outside the controller (ARO-HCP, OCM)
have a single source of truth for the prefix used to mirror labels from
HostedCluster to HostedControlPlane.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…I package

Move releaseImageValidationSkippedReason from a controller-private
constant to the API package as ReleaseImageValidationSkippedReason,
alongside the existing AsExpectedReason and InvalidImageReason. This
allows external consumers (ARO-HCP, OCM) to inspect the ValidReleaseImage
condition reason programmatically without hardcoding the string.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@openshift-merge-bot
Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label May 22, 2026
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 22, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 22, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented May 22, 2026

@tuxerrante: This pull request references ARO-26764 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the enhancement to target the "5.0.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

Follow-up to #8424 (review feedback from @jparrill).

Promotes two controller-private constants to the API package so that external consumers (ARO-HCP, OCM) can reference them programmatically instead of hardcoding strings:

  1. OCMLabelPrefix ("api.openshift.com/") — the label key prefix used by OCM to tag HostedCluster resources, mirrored to HostedControlPlane. Previously a hardcoded string in the predicate code; now lives alongside LimitedSupportLabel in api/hypershift/v1beta1/hostedcluster_types.go.

  2. ReleaseImageValidationSkippedReason ("ReleaseImageValidationSkipped") — the condition reason set on ValidReleaseImage when the skip annotation is present. Previously a controller-private constant; now lives alongside AsExpectedReason and InvalidImageReason in api/hypershift/v1beta1/hostedcluster_conditions.go.

Which issue(s) this PR fixes:

Fixes sub-tasks of ARO-26764:

Notes:

Test plan:

  • go vet — clean
  • go test -race — all pass (hostedcluster package and subpackages)
  • make lint — clean (the api-lint finding is pre-existing in azure.go, not from these changes)

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

📝 Walkthrough

Walkthrough

This PR refactors HostedCluster reconciliation to use a predicate-driven architecture and configurable metadata mirroring. It adds a new hostedClusterPrimaryPredicate that filters reconciliation events to only meaningful HostedCluster changes (generation, deletion, actionable annotations/labels). Release image validation is refactored to support skipping via annotation through a new shouldValidateReleaseImage helper. HostedControlPlane metadata mirroring is updated to use prefix-based configuration (hostedClusterMirroredAnnotations, hostedClusterActionableAnnotationPrefixes, hostedClusterActionableLabelPrefixes) instead of hardcoded iterators. New constants define the skipped validation reason and OCM label prefix. Comprehensive unit tests validate the predicate logic, reconciliation condition stamping, release image validation decisions, and metadata cleanup behavior.

Suggested reviewers

  • muraee
  • xiuwang
  • jparrill

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Stable And Deterministic Test Names ❓ Inconclusive Tests in PR use standard Go testing, not Ginkgo. Check specifies "Ginkgo test names" but applies to standard Go tests which use t.Run() for table-driven tests. Applicability is unclear. Clarify: Does the check apply to standard Go t.Run() test cases or only Ginkgo's It()/Describe()/Context()/When() constructs? All test names in PR are stable and deterministic.
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'ARO-26764: promote OCM label prefix and validation skip reason to API package' directly matches the main objective of the PR: promoting two constants to the API package for external consumers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Test Structure And Quality ✅ Passed New tests use standard Go testing framework (not Ginkgo), with table-driven subtests, meaningful assertion messages, fake clients (no cluster resources), and follow existing codebase patterns.
Microshift Test Compatibility ✅ Passed PR adds only standard Go unit tests (using testing.T), not Ginkgo e2e tests. The custom check targets Ginkgo e2e tests only; these unit tests are out of scope.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests were added in this PR. All new test files use standard Go testing.T pattern (unit tests), not Ginkgo syntax. Check not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed PR adds API constants and refactors controller logic without introducing pod scheduling constraints (affinity, topology spread, nodeSelectors) that would break SNO, Two-Node, or HyperShift topologies.
Ote Binary Stdout Contract ✅ Passed No OTE Binary Stdout Contract violations detected. Modified files contain only data constants, helper functions, and test cases—no process-level stdout writes.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR adds only standard Go unit tests (using testing.T) for controller logic, not Ginkgo e2e tests. Check specifically applies to Ginkgo e2e tests only; therefore not applicable here.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci openshift-ci Bot added area/api Indicates the PR includes changes for the API area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release and removed do-not-merge/needs-area labels May 22, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 22, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: tuxerrante
Once this PR has been reviewed and has the lgtm label, please assign csrwng for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@hypershift-jira-solve-ci
Copy link
Copy Markdown

hypershift-jira-solve-ci Bot commented May 22, 2026

I now have all the information needed. The root cause is clear. The last two commits on the PR use the prefix api(hostedcluster): which is not in the allowed conventional commit types list. Let me verify the specific commit messages and the allowed types:

The gitlint configuration allows these types: fix, feat, chore, docs, style, refactor, perf, test, revert, ci, build

The two failing commits use api(hostedcluster): as their prefix — api is NOT in the allowed types list.

Test Failure Analysis Complete

Job Information

Test Failure Analysis

Error

Commit c081f95207:
1: CT1 Title does not start with one of fix, feat, chore, docs, style, refactor, perf, test, revert, ci, build: "api(hostedcluster): promote ReleaseImageValidationSkippedReason to API package"

Commit 4030c3ec05:
1: CT1 Title does not start with one of fix, feat, chore, docs, style, refactor, perf, test, revert, ci, build: "api(hostedcluster): promote OCM label prefix to API package constant"

make: *** [Makefile:599: run-gitlint] Error 2

Summary

The gitlint CI check failed because the two most recent commits (c081f95207 and 4030c3ec05) use api as the conventional commit type prefix, but api is not in the repository's allowed types list. The .gitlint config at the repo root defines the allowed types as: fix, feat, chore, docs, style, refactor, perf, test, revert, ci, build. All 9 other commits in this PR use valid prefixes (fix, refactor, test) and pass gitlint — only these two commits are rejected.

Root Cause

The two failing commits use api(hostedcluster): as their conventional commit prefix. The api type is not one of the 11 allowed conventional commit types defined in the repository's .gitlint configuration file:

[contrib-title-conventional-commits]
types = fix,feat,chore,docs,style,refactor,perf,test,revert,ci,build

The gitlint tool enforces the contrib-title-conventional-commits rule (CT1), which requires every commit title to begin with one of the listed types. Since api is not in this list, both commits fail validation.

This is purely a commit message formatting issue — not a code or test problem. The other 9 commits in this PR (fix(...), refactor(...), test(...)) all pass because they use allowed types.

Recommendations

Option 1 (Recommended): Reword the two failing commit messages to use an allowed type that accurately describes the change. Since these commits move existing constants from a controller-private scope to the public API package, refactor is the most appropriate type:

  • refactor(hostedcluster): promote ReleaseImageValidationSkippedReason to API package
  • refactor(hostedcluster): promote OCM label prefix to API package constant

Use git rebase -i to edit the two commits and change api(hostedcluster):refactor(hostedcluster):.

Option 2: If the team wants api as a first-class commit type, add it to .gitlint:

types = fix,feat,chore,docs,style,refactor,perf,test,revert,ci,build,api

This would require a separate PR and team consensus.

Evidence
Evidence Detail
Failing commit 1 c081f95207api(hostedcluster): promote ReleaseImageValidationSkippedReason to API package
Failing commit 2 4030c3ec05api(hostedcluster): promote OCM label prefix to API package constant
Gitlint rule CT1 (contrib-title-conventional-commits)
Allowed types fix, feat, chore, docs, style, refactor, perf, test, revert, ci, build
Missing type api — used by both failing commits but not in the allowed list
Config file .gitlint at repo root
Passing commits 9/11 commits in the PR pass (using fix, refactor, test prefixes)
Exit code make run-gitlint exited with code 2 (2 violations found)

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
hypershift-operator/controllers/hostedcluster/hostedcluster_predicates_test.go (1)

299-305: ⚡ Quick win

Use hyperv1.OCMLabelPrefix in test label keys instead of hardcoded prefix.

This avoids drift with the newly promoted API constant and keeps tests aligned with controller behavior.

Suggested patch
-				hc.Labels = map[string]string{"api.openshift.com/id": "old"}
+				hc.Labels = map[string]string{hyperv1.OCMLabelPrefix + "id": "old"}
 				return hc
 			}(),
 			newHC: func() *hyperv1.HostedCluster {
 				hc := newHostedClusterForPredicateTests(1, nil)
-				hc.Labels = map[string]string{"api.openshift.com/id": "new"}
+				hc.Labels = map[string]string{hyperv1.OCMLabelPrefix + "id": "new"}
 				return hc
 			}(),
@@
-				hc.Labels = map[string]string{"api.openshift.com/id": "old"}
+				hc.Labels = map[string]string{hyperv1.OCMLabelPrefix + "id": "old"}
 				return hc
 			}(),
As per coding guidelines, "`**/*.go`: Code changes must use golang common kubernetes patterns and best practices."

Also applies to: 313-314

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@hypershift-operator/controllers/hostedcluster/hostedcluster_predicates_test.go`
around lines 299 - 305, Replace the hardcoded label prefix "api.openshift.com"
used in the test setup with the shared constant hyperv1.OCMLabelPrefix so tests
track the promoted API constant; update both instances where labels are set
(inside the anonymous newHC functions that call
newHostedClusterForPredicateTests and assign hc.Labels) to use
hyperv1.OCMLabelPrefix + "/id" as the key instead of the literal string.
hypershift-operator/controllers/hostedcluster/hostedcluster_hcp_labels_test.go (1)

27-27: ⚡ Quick win

Use the promoted API prefix constant instead of hardcoded "api.openshift.com/".

This test should derive the actionable label key from hyperv1.OCMLabelPrefix so it stays aligned with the API contract and avoids drift.

Proposed change
 			Labels: map[string]string{
-				"api.openshift.com/id": "stale",
+				hyperv1.OCMLabelPrefix + "id": "stale",
 				"other":                "keep",
 			},
 		},
 	}
@@
-	if _, exists := hcp.Labels["api.openshift.com/id"]; exists {
+	if _, exists := hcp.Labels[hyperv1.OCMLabelPrefix+"id"]; exists {
 		t.Fatal("expected stale api.openshift.com label to be removed from hosted control plane")
 	}
As per coding guidelines, "Design APIs contract-first following OpenShift and Kubernetes best practices."

Also applies to: 39-39

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@hypershift-operator/controllers/hostedcluster/hostedcluster_hcp_labels_test.go`
at line 27, The test currently uses the hardcoded label key
"api.openshift.com/id" (appearing twice) which can drift from the promoted API
prefix; replace both occurrences by deriving the label key from the promoted
constant hyperv1.OCMLabelPrefix (e.g. build the actionable key by appending "id"
to hyperv1.OCMLabelPrefix) so the test uses the official prefix; update any
assertions or map keys in hostedcluster_hcp_labels_test.go (the places that
reference "api.openshift.com/id") to use the constructed key instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@hypershift-operator/controllers/hostedcluster/hostedcluster_hcp_labels_test.go`:
- Line 27: The test currently uses the hardcoded label key
"api.openshift.com/id" (appearing twice) which can drift from the promoted API
prefix; replace both occurrences by deriving the label key from the promoted
constant hyperv1.OCMLabelPrefix (e.g. build the actionable key by appending "id"
to hyperv1.OCMLabelPrefix) so the test uses the official prefix; update any
assertions or map keys in hostedcluster_hcp_labels_test.go (the places that
reference "api.openshift.com/id") to use the constructed key instead.

In
`@hypershift-operator/controllers/hostedcluster/hostedcluster_predicates_test.go`:
- Around line 299-305: Replace the hardcoded label prefix "api.openshift.com"
used in the test setup with the shared constant hyperv1.OCMLabelPrefix so tests
track the promoted API constant; update both instances where labels are set
(inside the anonymous newHC functions that call
newHostedClusterForPredicateTests and assign hc.Labels) to use
hyperv1.OCMLabelPrefix + "/id" as the key instead of the literal string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: bbbbec7b-58be-4859-91c9-5f8fe3e708e3

📥 Commits

Reviewing files that changed from the base of the PR and between d24af10 and c081f95.

⛔ Files ignored due to path filters (2)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (8)
  • api/hypershift/v1beta1/hostedcluster_conditions.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_hcp_labels_test.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_predicates.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_predicates_test.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_reconciliation_condition_test.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_release_image_validation_test.go

@tuxerrante
Copy link
Copy Markdown
Author

Folded into #8424 directly — the 2 API promotion commits are now part of the main PR.

@tuxerrante tuxerrante closed this May 22, 2026
@tuxerrante tuxerrante deleted the tuxerrante/promote-api-constants branch May 22, 2026 10:18
@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

❌ Patch coverage is 83.92857% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 40.42%. Comparing base (e09cc2d) to head (c081f95).
⚠️ Report is 196 commits behind head on main.

Files with missing lines Patch % Lines
...trollers/hostedcluster/hostedcluster_controller.go 74.35% 9 Missing and 1 partial ⚠️
...trollers/hostedcluster/hostedcluster_predicates.go 89.04% 6 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8577      +/-   ##
==========================================
+ Coverage   37.39%   40.42%   +3.02%     
==========================================
  Files         751      756       +5     
  Lines       91806    93277    +1471     
==========================================
+ Hits        34333    37708    +3375     
+ Misses      54838    52866    -1972     
- Partials     2635     2703      +68     
Files with missing lines Coverage Δ
...trollers/hostedcluster/hostedcluster_predicates.go 89.04% <89.04%> (ø)
...trollers/hostedcluster/hostedcluster_controller.go 43.12% <74.35%> (-0.12%) ⬇️

... and 73 files with indirect coverage changes

Flag Coverage Δ
cmd-support 34.44% <ø> (+1.87%) ⬆️
cpo-hostedcontrolplane 41.76% <ø> (+5.28%) ⬆️
cpo-other 40.31% <ø> (+2.58%) ⬆️
hypershift-operator 50.76% <83.92%> (+2.90%) ⬆️
other 31.58% <ø> (+3.80%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api Indicates the PR includes changes for the API area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants