Skip to content

jira: add labels.update_mode replace|merge for label updates - #5443

Open
Drenovik wants to merge 3 commits into
prometheus:mainfrom
Drenovik:jira-labels-update-mode
Open

jira: add labels.update_mode replace|merge for label updates#5443
Drenovik wants to merge 3 commits into
prometheus:mainfrom
Drenovik:jira-labels-update-mode

Conversation

@Drenovik

Copy link
Copy Markdown

Depends on #5442

What changed

  • notify/jira/config.go: adds JiraLabelUpdateMode (replace default, merge),
    UpdateModeValue(), and validation rejecting any other value.
  • notify/jira/types.go: adds issue.Update *issueUpdate, issueUpdate{Labels []labelOp},
    labelOp{Add string} to represent Jira's update.labels: [{add: ...}] operation.
  • notify/jira/jira.go: on PUT, when enable_update is true and update_mode is merge,
    labels are sent as update.labels add-operations instead of a fields.labels SET, and
    fields.labels is omitted from that request. replace (default) behavior is unchanged
    from today. enable_update: false still wins over update_mode (skip takes priority
    over merge).
  • Test harness fix: the existing /issue/MONITORING-1 PUT test handler only inspected a
    raw JSON map; reworked it to unmarshal into the typed issue{} struct so
    Fields/Update are structurally asserted, not just spot-checked.
  • New test cases for config unmarshal (valid/invalid update_mode), notifier
    merge/replace/skip interactions, and raw-JSON checks that fields.labels and
    update.labels are never both present in one request body.
  • Docs and CHANGELOG updated.

Why

enable_update: false (this PR's predecessor) fully stops label updates, which is
sometimes too blunt - users may still want Alertmanager's templated labels applied on
update, while preserving labels added by humans/automation. update_mode: merge
achieves this using Jira's native incremental label API instead of a destructive
replace.

Design notes / limitations

  • Merge is additive only: it never removes a label that disappears from the
    Alertmanager template between updates. This is called out explicitly in the docs -
    a "smart sync" (diffing old vs new label sets) was considered and rejected as
    unnecessary complexity for this use case.
  • enable_update: false always wins over update_mode: merge - if both are set, labels
    are skipped entirely, not merged.
  • The legacy YAML list form cannot express update_mode (or enable_update); users need
    the object form to opt in.

Testing

  • Unit tests: go test ./notify/jira/ ./config/ -count=1, including the MONITORING-1
    harness rework asserting typed Fields/Update equality, plus new cases for
    merge/replace/skip combinations and unmarshal validation of update_mode.
  • Manual end-to-end testing against a private Jira Data Center instance: created an
    issue with update_mode: merge, manually added a foreign label, triggered an update,
    and confirmed both the Alertmanager-managed labels were present and the manually
    added label survived (add-only semantics behaved as intended against a real Jira
    API, not just a test double). Also re-verified the enable_update: false path from
    the predecessor PR still works unchanged with this code present, and exercised
    several edge cases (empty label list, idempotent repeated updates, a label value
    rejected by Jira's own validation) to confirm no partial/corrupted writes occur in
    any case.

Pull Request Checklist

Please check all the applicable boxes.

  • Please list all open issue(s) discussed with maintainers related to this change
  • Is this a new Receiver integration?
    • N/A - existing jira_configs receiver, not a new receiver type
  • Is this a bugfix?
    • N/A - this is not a bugfix
  • Is this a new feature?
    • I have added tests that test the new feature's functionality
  • Does this change affect performance?
    • N/A - no performance-sensitive path touched
  • Is this a breaking change?
    • My changes do not break the existing cluster messages
    • My changes do not break the existing api
  • I have added/updated the required documentation
  • I have signed-off my commits
  • I will follow best practices for contributing to this project

Which user-facing changes does this PR introduce?

[ENHANCEMENT] jira: Add labels.update_mode (replace|merge) for non-destructive label updates.

Support object-form labels with enable_update while keeping the legacy
YAML list fully compatible. When enable_update is false, omit labels on
PUT so manual/automation labels are not wiped (create still sets labels).

Signed-off-by: Drenovik <forget.alphabet071@slmails.com>
Adds an opt-in merge mode that appends labels via Jira's update.labels
add operations instead of replacing fields.labels wholesale, so labels
added manually or by automation are preserved. Default remains replace
(today's behavior); enable_update: false still wins over update_mode.

Signed-off-by: Drenovik <forget.alphabet071@slmails.com>
@Drenovik
Drenovik requested a review from a team as a code owner August 11, 2026 16:06
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: aa16132e-6002-4730-b861-16cf2e171ce1

📥 Commits

Reviewing files that changed from the base of the PR and between bda93e5 and 92da4c7.

📒 Files selected for processing (3)
  • notify/jira/config.go
  • notify/jira/jira_test.go
  • notify/jira/types.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • notify/jira/types.go
  • notify/jira/config.go
  • notify/jira/jira_test.go

📝 Walkthrough

Walkthrough

Changes

Jira label updates

Layer / File(s) Summary
Label configuration and compatibility
notify/jira/config.go, config/config_test.go, config/testdata/conf.jira-legacy-labels.yml, notify/jira/jira_test.go
Jira supports legacy label lists and structured label settings. Structured settings define label values, update enablement, and replace or merge behavior.
Label update request flow
notify/jira/types.go, notify/jira/jira.go, notify/jira/jira_test.go
Issue creation always sends configured labels. Existing-issue updates can omit labels, replace labels, or add labels without removing existing values.
Migration coverage and documentation
notify/jira/jira_test.go, docs/configuration.md, CHANGELOG.md
Tests cover YAML parsing and Jira request behavior. Documentation and the changelog describe the configuration forms and update modes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Alertmanager
  participant JiraNotifier
  participant JiraAPI
  Alertmanager->>JiraNotifier: Process notification
  JiraNotifier->>JiraAPI: Create issue with configured labels
  JiraNotifier->>JiraAPI: Update issue
  alt Updates disabled
    JiraNotifier->>JiraAPI: Send fields without labels
  else Merge mode
    JiraNotifier->>JiraAPI: Send update.labels add operations
  else Replace mode
    JiraNotifier->>JiraAPI: Send fields with labels
  end
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the Jira label update mode change and uses the repository's area-prefixed format.
Description check ✅ Passed The description covers the change, rationale, limitations, testing, checklist, documentation, sign-off, and release notes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
notify/jira/types.go (1)

36-39: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

Drop omitempty on labelOp.Add.

add is the operation payload, not an optional attribute. If a label template renders to an empty string, omitempty serializes the element as {}, which Jira rejects as an invalid update operation. Without omitempty the request carries {"add": ""}, which produces a clearer Jira validation error.

♻️ Proposed change
 type labelOp struct {
-	Add string `json:"add,omitempty"`
+	Add string `json:"add"`
 }
🤖 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 `@notify/jira/types.go` around lines 36 - 39, Update the Add field in the
labelOp struct to remove the json omitempty option, ensuring empty label values
serialize as an explicit add payload rather than an empty object.
notify/jira/jira_test.go (1)

1716-1724: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove or use the wantEnableUpdateNil field.

No table case sets wantEnableUpdateNil, so the assertion at Line 1796 never runs. Either delete the field, or set it to true for the cases where enable_update is omitted.

♻️ Proposed change
 	for _, tc := range []struct {
-		name                string
-		yaml                string
-		wantValues          []string
-		wantEnableUpdate    bool
-		wantEnableUpdateNil bool
-		wantUpdateMode      JiraLabelUpdateMode
-		wantErr             string
+		name             string
+		yaml             string
+		wantValues       []string
+		wantEnableUpdate bool
+		wantUpdateMode   JiraLabelUpdateMode
+		wantErr          string
 	}{

Then drop the if tc.wantEnableUpdateNil block at Lines 1796-1798.

🤖 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 `@notify/jira/jira_test.go` around lines 1716 - 1724, Remove the unused
wantEnableUpdateNil field and its conditional assertion block in the
table-driven test, since no test case sets it and the nil-state assertion never
executes.
notify/jira/config.go (1)

115-132: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Start the exported method comment with the identifier name.

The comment on UnmarshalYAML does not begin with the method name. The repository lints Go comments with godot and revive. Align the comment with the convention used by the other exported identifiers in this file.

Also consider validating UpdateMode in JiraConfig validation as well. UnmarshalYAML is the only place that rejects an unknown mode. A JiraLabelsConfig built programmatically or decoded from JSON keeps the invalid value, and UpdateModeValue then returns it unchanged, which jira.go treats as replace.

♻️ Proposed comment fix
-// Supports both the legacy list and the new object form.
+// UnmarshalYAML supports both the legacy list form and the new object form.
 func (l *JiraLabelsConfig) UnmarshalYAML(unmarshal func(any) error) error {
🤖 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 `@notify/jira/config.go` around lines 115 - 132, Update the exported comment
for JiraLabelsConfig.UnmarshalYAML so it begins with “UnmarshalYAML”. Also
extend JiraConfig validation to reject JiraLabelsConfig.UpdateMode values other
than empty, JiraLabelUpdateReplace, or JiraLabelUpdateMerge, covering
programmatic and JSON-created configurations consistently with UnmarshalYAML.

Source: Coding guidelines

🤖 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 `@notify/jira/config.go`:
- Around line 115-132: Update the exported comment for
JiraLabelsConfig.UnmarshalYAML so it begins with “UnmarshalYAML”. Also extend
JiraConfig validation to reject JiraLabelsConfig.UpdateMode values other than
empty, JiraLabelUpdateReplace, or JiraLabelUpdateMerge, covering programmatic
and JSON-created configurations consistently with UnmarshalYAML.

In `@notify/jira/jira_test.go`:
- Around line 1716-1724: Remove the unused wantEnableUpdateNil field and its
conditional assertion block in the table-driven test, since no test case sets it
and the nil-state assertion never executes.

In `@notify/jira/types.go`:
- Around line 36-39: Update the Add field in the labelOp struct to remove the
json omitempty option, ensuring empty label values serialize as an explicit add
payload rather than an empty object.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 46c08fc4-f476-4ffe-9569-0ef06c1a961d

📥 Commits

Reviewing files that changed from the base of the PR and between 8d7515a and bda93e5.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • config/config_test.go
  • config/testdata/conf.jira-legacy-labels.yml
  • docs/configuration.md
  • notify/jira/config.go
  • notify/jira/jira.go
  • notify/jira/jira_test.go
  • notify/jira/types.go

Signed-off-by: Drenovik <forget.alphabet071@slmails.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants