Skip to content

chore: update Renovate and Dependabot config#467

Merged
olivermeyer merged 3 commits intomainfrom
chore/update-renovate-dependabot
Mar 17, 2026
Merged

chore: update Renovate and Dependabot config#467
olivermeyer merged 3 commits intomainfrom
chore/update-renovate-dependabot

Conversation

@olivermeyer
Copy link
Collaborator

Unifying our usage of Renovate vs Dependabot with other projects:

  • Use Renovate exclusively for regular dependency updates and lock file management
    • Group all updates to GitHub Actions
    • Group all minor and patch updates to Python dependencies
  • Use Dependabot only for security alerts and updates

The dependabot.yml file was referenced in a spec; I'm removing that line.

Copilot AI review requested due to automatic review settings March 9, 2026 13:38
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR consolidates dependency update tooling by making Renovate the sole tool for regular dependency version updates and lock file maintenance, while retaining Dependabot only for security vulnerability alerts (which don't require a dependabot.yml config file). The Renovate config is enhanced with package grouping rules and lock file maintenance scheduling.

Changes:

  • Deleted .github/dependabot.yml to stop Dependabot version updates, since Renovate now handles all regular dependency updates
  • Updated renovate.json to scope managers to pep621 and github-actions, added grouped package rules for minor/patch Python deps and GitHub Actions, and enabled weekly lock file maintenance
  • Removed the dependabot.yml reference from the build chain specification's directory tree

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
.github/dependabot.yml Fully deleted — Dependabot version updates replaced by Renovate
renovate.json Expanded config: restricted managers, added grouping rules, lock file maintenance, changed schedule to "at any time"
specifications/SPEC-BUILD-CHAIN-CICD-SERVICE.md Removed dependabot.yml line from the .github/ directory tree diagram

@olivermeyer olivermeyer force-pushed the chore/update-renovate-dependabot branch from d0dce04 to bae0b9e Compare March 9, 2026 13:53
@codecov
Copy link

codecov bot commented Mar 9, 2026

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
714 1 713 15
View the top 1 failed test(s) by shortest run time
tests.aignostics.application.cli_test::test_cli_run_submit_and_describe_and_cancel_and_download_and_delete
Stack Traces | 1174s run time
runner = <typer.testing.CliRunner object at 0x7f9787be8440>
tmp_path = PosixPath('.../pytest-20/popen-gw3/test_cli_run_submit_and_descri0')
silent_logging = None
record_property = <function record_property.<locals>.append_property at 0x7f9787be4250>

    @pytest.mark.e2e
    @pytest.mark.long_running
    @pytest.mark.flaky(retries=3, delay=5)
    @pytest.mark.timeout(timeout=60 * 10)
    def test_cli_run_submit_and_describe_and_cancel_and_download_and_delete(  # noqa: PLR0915
        runner: CliRunner, tmp_path: Path, silent_logging, record_property
    ) -> None:
        """Check run submit command runs successfully."""
        record_property("tested-item-id", "TC-APPLICATION-CLI-02")
        csv_content = "external_id;checksum_base64_crc32c;resolution_mpp;width_px;height_px;staining_method;tissue;disease;"
        csv_content += "platform_bucket_url\n"
        csv_content += (
            f"{SPOT_0_FILENAME};{SPOT_0_CRC32C};{SPOT_0_RESOLUTION_MPP};{SPOT_0_WIDTH};{SPOT_0_HEIGHT}"
            f";H&E;LUNG;LUNG_CANCER;{SPOT_0_GS_URL}"
        )
        csv_path = tmp_path / "dummy.csv"
        csv_path.write_text(csv_content)
        result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "submit",
                HETA_APPLICATION_ID,
                str(csv_path),
                "--note",
                "note_of_this_complex_test",
                "--tags",
                "cli-test,test_cli_run_submit_and_describe_and_cancel_and_download_and_delete,further-tag",
                "--deadline",
                (datetime.now(tz=UTC) + timedelta(minutes=10)).isoformat(),
                "--onboard-to-aignostics-portal",
                "--gpu-type",
                PIPELINE_GPU_TYPE,
                "--force",
            ],
        )
        output = normalize_output(result.stdout)
        assert re.search(
            r"Submitted run with id '[0-9a-f-]+' for '",
            output,
        ), f"Output '{output}' doesn't match expected pattern"
        assert result.exit_code == 0
    
        # Extract run ID from the output
        run_id_match = re.search(r"Submitted run with id '([0-9a-f-]+)' for '", output)
        assert run_id_match, f"Failed to extract run ID from output '{output}'"
        run_id = run_id_match.group(1)
    
        # Test that we can find this run by it's note via the query parameter
        list_result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "list",
                "--query",
                "note_of_this_complex_test",
            ],
        )
        assert list_result.exit_code == 0
        list_output = normalize_output(list_result.stdout)
        assert run_id in list_output, f"Run ID '{run_id}' not found when filtering by note via query"
    
        # Test that we can find this run by it's tag via the query parameter
        list_result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "list",
                "--query",
                "test_cli_run_submit_and_describe_and_cancel_and_download_and_delete",
            ],
        )
        assert list_result.exit_code == 0
        list_output = normalize_output(list_result.stdout)
        assert run_id in list_output, f"Run ID '{run_id}' not found when filtering by tag via query"
    
        # Test that we cannot find this run by another tag via the query parameter
        list_result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "list",
                "--query",
                "another_tag",
            ],
        )
        assert list_result.exit_code == 0
        list_output = normalize_output(list_result.stdout)
        assert run_id not in list_output, f"Run ID '{run_id}' found when filtering by another tag via query"
    
        # Test that we can find this run by it's note
        list_result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "list",
                "--note-regex",
                "note_of_this_complex_test",
            ],
        )
        assert list_result.exit_code == 0
        list_output = normalize_output(list_result.stdout)
        assert run_id in list_output, f"Run ID '{run_id}' not found when filtering by note"
    
        # but not another note
        list_result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "list",
                "--note-regex",
                "other_note",
            ],
        )
        assert list_result.exit_code == 0
        list_output = normalize_output(list_result.stdout)
        assert run_id not in list_output, f"Run ID '{run_id}' found when filtering by other note"
    
        # Test that we can find this run by one of its tags
        list_result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "list",
                "--tags",
                "test_cli_run_submit_and_describe_and_cancel_and_download_and_delete",
            ],
        )
        assert list_result.exit_code == 0
        list_output = normalize_output(list_result.stdout)
        assert run_id in list_output, f"Run ID '{run_id}' not found when filtering by one tag"
    
        # but not another tag
        list_result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "list",
                "--tags",
                "other-tag",
            ],
        )
        assert list_result.exit_code == 0
        list_output = normalize_output(list_result.stdout)
        assert run_id not in list_output, f"Run ID '{run_id}' found when filtering by other tag"
    
        # Test that we can find this run by two of its tags
        list_result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "list",
                "--tags",
                "cli-test,test_cli_run_submit_and_describe_and_cancel_and_download_and_delete",
            ],
        )
        assert list_result.exit_code == 0
        list_output = normalize_output(list_result.stdout)
        assert run_id in list_output, f"Run ID '{run_id}' not found when filtering by two tags"
    
        # Test that we can find this run by all of its tags
        list_result = runner.invoke(
            cli,
            [
                "application",
                "run",
                "list",
                "--tags",
                "cli-test,test_cli_run_submit_and_describe_and_cancel_and_download_and_delete,further-tag",
            ],
        )
        assert list_result.exit_code == 0
        list_output = normalize_output(list_result.stdout)
>       assert run_id in list_output, f"Run ID '{run_id}' not found when filtering by all tags"
E       AssertionError: Run ID '4125ed29-e0fa-4391-a60e-ebd395bc672e' not found when filtering by all tags
E       assert '4125ed29-e0fa-4391-a60e-ebd395bc672e' in 'Error: Failed to list runs: Failed to retrieve application runs: (500)Reason: Internal Server ErrorHTTP response headers: HTTPHeaderDict({\'date\': \'Tue, 17 Mar 2026 15:57:10 GMT\', \'server\': \'envoy\', \'content-length\': \'34\', \'content-type\': \'application/json\', \'x-trace-id\': \'6142a8629ca4f885c45a07418c8b6b4d\', \'x-envoy-upstream-service-time\': \'5067\', \'vary\': \'Accept-Encoding\'})HTTP response body: {"detail":"Internal server error"}'

.../aignostics/application/cli_test.py:548: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Copilot AI review requested due to automatic review settings March 11, 2026 14:30
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@olivermeyer olivermeyer marked this pull request as ready for review March 17, 2026 15:20
@olivermeyer olivermeyer added the claude Trigger Claude Code automation label Mar 17, 2026
@claude
Copy link

claude bot commented Mar 17, 2026

🤖 Claude Code Automated Review - PR #467

✅ APPROVED - Excellent Configuration Refactoring

Summary: This PR successfully consolidates dependency management by transitioning from a hybrid Dependabot/Renovate setup to a Renovate-only approach. All changes are configuration-only with no code modifications, and CI checks are passing.


📋 Review Findings

✅ PASSING - All Critical Checks

1. Test Markers

  • Status: N/A (No test changes in this PR)
  • Verification: Only configuration files modified

2. Test Coverage

  • Status: N/A (No code changes requiring test coverage)
  • Current Coverage: Maintained (no changes to source code)

3. Code Quality

  • Lint Status: Currently running, no failures expected
  • Audit Status: ✅ Passed (1m32s)
  • CodeQL: ✅ Passed (1m5s)
  • JSON Validation: ✅ Valid renovate.json syntax confirmed

4. Conventional Commits

  • Primary Commit: chore: update Renovate and Dependabot config
  • Type: chore (correct for configuration changes)
  • Format: Follows conventional commit standard ✅

📝 Changes Analysis

Files Modified (3 files, +18/-31 lines)

1. .github/dependabot.yml - DELETED

  • Action: Removed Dependabot version updates configuration
  • Rationale: Consolidating to Renovate-only for version updates
  • Impact: Dependabot will still handle security alerts (GitHub default)
  • Note: Dependabot bot references remain in workflows (expected and correct)

2. renovate.json - ENHANCED

Changes:

  • Schedule: Changed from "before 2am every weekday"["at any time"]

    • Benefit: More responsive to upstream updates
    • Impact: PRs may arrive throughout the day instead of only early morning
  • Enabled Managers: Explicitly set to ["pep621", "github-actions"]

    • Benefit: Clear and explicit about what Renovate manages
    • Aligns with: Project uses pyproject.toml (pep621) and GitHub Actions
  • Lock File Maintenance: Added with Monday 5am schedule

    • Benefit: Keeps uv.lock fresh without dependency changes
    • Best Practice: Separate from version updates
  • Package Rules: Intelligent grouping added

    • Python deps: Groups minor/patch updates together
      • Benefit: Reduces PR noise, easier to review
      • Safe: Only groups non-breaking changes
    • GitHub Actions: Groups all actions updates
      • Benefit: Single PR for workflow dependency updates
  • Removed: ignorePaths for plugins/manifest/package.json

    • Note: Path doesn't exist in current repo (legacy cleanup)

3. specifications/SPEC-BUILD-CHAIN-CICD-SERVICE.md - UPDATED

  • Change: Removed dependabot.yml from module structure diagram
  • Correctness: ✅ Accurately reflects new state
  • Only remaining reference: copilot-instructions.md (correct)

🏗️ Architecture Compliance ✅

CI/CD Workflow Impact

Verified: No breaking changes to workflows

  • .github/workflows/_claude-code.yml: Still references dependabot[bot] in allowed_bots (✅ correct, for security PRs)
  • .github/workflows/ci-cd.yml: Still excludes dependabot[bot] from certain checks (✅ correct)
  • Why this is safe: Dependabot will continue to run for security alerts only, while Renovate handles version updates

Labels Applied ✅

Both tools apply correct labels:

  • Renovate: bot, renovate, dependencies, skip:test:long_running, skip:codecov
  • Dependabot (security): bot, dependabot, dependencies, skip:test:long_running

Impact: CI/CD workflows will continue to function correctly, skipping long-running tests on dependency PRs as intended.


🔒 Security & Compliance

Security Posture ✅

  1. Dependabot Security Alerts: ✅ Still active (GitHub default)

    • Dependabot will continue to create PRs for vulnerabilities
    • Only version update PRs are moved to Renovate
  2. Renovate Security Updates: ✅ Enabled via config:recommended

    • Includes config:base which enables vulnerability alerts
  3. No Secrets Exposure: ✅ Only configuration changes, no tokens/credentials

Medical Device Compliance

  • Impact: None (configuration-only change)
  • Ketryx Reporting: Unaffected
  • Audit Trail: Maintained through git history

📚 Documentation Updates

✅ GOOD - Specification Updated

  • SPEC-BUILD-CHAIN-CICD-SERVICE.md correctly updated to reflect removal

📌 RECOMMENDATION - Update CLAUDE.md

While not blocking, consider updating these files to document the new approach:

Optional Documentation Enhancements

.github/CLAUDE.md

Current state: Line 567 mentions "Excludes: dependabot, renovate PRs" in context of automated PR review.

Suggested addition (around line 567-580):

## Dependency Management Strategy

**Renovate** (Primary Tool):
- Handles all **version updates** for Python dependencies and GitHub Actions
- Schedule: "at any time" for updates, Monday 5am for lock file maintenance
- Groups: Minor/patch Python updates, all GitHub Actions updates
- Labels: `bot`, `renovate`, `dependencies`, `skip:test:long_running`, `skip:codecov`

**Dependabot** (Security Only):
- Handles **security alerts and updates only** (no version updates)
- GitHub's default configuration applies
- Labels: `bot`, `dependabot`, `dependencies`, `skip:test:long_running`

**Why both?**: This hybrid approach leverages Renovate's superior grouping and scheduling while retaining Dependabot's direct integration with GitHub Security Advisories.

Root CLAUDE.md

Suggested addition in "Development Workflow" section:

### Dependency Updates

This project uses **Renovate** for dependency version updates:
- Updates arrive throughout the day ("at any time" schedule)
- Minor/patch Python dependencies grouped together
- GitHub Actions updates grouped together
- Lock file maintenance: Mondays at 5am

Dependabot runs only for **security vulnerability alerts**.

**Reviewing dependency PRs**:
```bash
# Dependency PRs skip long-running tests automatically
# Review the changes and merge if CI passes
gh pr view <number>
gh pr merge <number> --squash

</details>

---

## 🎯 Recommendations

### ⚡ Immediate Actions
**None required** - PR is ready to merge as-is.

### 🔄 Post-Merge Monitoring
1. **Watch for first Renovate PR**: Verify grouping works as expected
2. **Lock file maintenance**: Check Monday 5am for lock file update PR
3. **Dependabot behavior**: Confirm no version update PRs (only security)

### 📖 Optional Enhancements
- Add dependency management documentation to `.github/CLAUDE.md` (see details above)
- Consider documenting the rationale for "at any time" vs scheduled updates

---

## 🎉 Praise

**Excellent work!** This PR demonstrates:
1. ✅ **Clear communication**: PR description explains the change and rationale
2. ✅ **Proper cleanup**: Removed legacy `ignorePaths` reference
3. ✅ **Documentation hygiene**: Updated specification to match reality
4. ✅ **Best practices**: Intelligent grouping and scheduling in Renovate config
5. ✅ **Minimal impact**: Configuration-only change reduces risk

The transition from hybrid to Renovate-primary is the right architectural decision for this project.

---

## ✅ Final Verdict

**APPROVED** - Ready to merge

**Blocking Issues**: None  
**Suggestions**: Optional documentation enhancements (non-blocking)  
**CI Status**: ✅ Passing (audit, CodeQL, lint in progress)

**Merge Command**:
```bash
gh pr merge 467 --squash

Reviewed by Claude Code (Sonnet 4.5) following CLAUDE.md guidance
Medical Device Software - Highest Standards Applied ✨

],
"timezone": "Europe/Berlin",
"schedule": "before 2am every weekday",
"schedule": ["at any time"],
Copy link

Choose a reason for hiding this comment

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

✅ Excellent Change: Moving from "before 2am every weekday" to ["at any time"] makes Renovate more responsive to upstream updates.

Impact: Dependency update PRs will arrive throughout the day instead of only early morning. This provides:

  • Faster security updates
  • More timely bug fixes
  • Better alignment with upstream release cycles

Note: Lock file maintenance still runs on a schedule (Monday 5am), which prevents PR spam from lock file updates.

Comment on lines +20 to 31
"packageRules": [
{
"groupName": "minor and patch dependencies",
"matchManagers": ["pep621"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "GitHub Actions",
"matchManagers": ["github-actions"],
"separateMajorMinor": false
}
]
Copy link

Choose a reason for hiding this comment

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

✅ Smart Grouping Strategy: These package rules demonstrate best practices:

1. Python Dependencies Grouping (lines 21-25):

  • Groups only minor and patch updates together
  • Why this is safe: Semver guarantees these are non-breaking changes
  • Benefit: Reduces PR noise while keeping major updates separate for careful review
  • Example: If 5 packages have patch updates, you get 1 PR instead of 5

2. GitHub Actions Grouping (lines 26-30):

  • Groups ALL GitHub Actions updates (including major versions)
  • separateMajorMinor: false - intentional choice
  • Why this works: Actions are typically backwards compatible, and failures are caught in CI
  • Benefit: Workflow dependencies stay in sync

This approach balances convenience with safety - well done! 🎯

Comment on lines +16 to +19
"lockFileMaintenance": {
"enabled": true,
"schedule": ["before 5am on monday"]
},
Copy link

Choose a reason for hiding this comment

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

✅ Lock File Maintenance: Great addition!

What this does:

  • Regenerates uv.lock file even when no dependency versions change
  • Updates transitive dependencies (dependencies of dependencies)
  • Runs Monday mornings before European business hours

Why separate from updates:

  • Lock file regeneration can happen without changing pyproject.toml
  • Prevents conflict with version update PRs
  • Monday schedule means fresh lock file for the week

Medical device benefit: Ensures dependency resolution is fresh and reproducible across dev/staging/production environments.

│ └── _ketryx_report_and_check.yml # Compliance reporting
├── copilot-instructions.md # AI pair programming guidelines
└── dependabot.yml # Automated dependency updates
└── copilot-instructions.md # AI pair programming guidelines
Copy link

Choose a reason for hiding this comment

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

✅ Accurate Documentation: Great attention to detail!

The specification now correctly reflects that dependabot.yml has been removed. This kind of documentation hygiene is especially important in medical device software where specifications must accurately reflect implementation.

Note: Dependabot still runs for security alerts (GitHub's default behavior), just not for version updates anymore. This is the right architectural decision.

@olivermeyer olivermeyer merged commit 4a1ef54 into main Mar 17, 2026
25 of 30 checks passed
@sonarqubecloud
Copy link

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

Labels

claude Trigger Claude Code automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants