-
Notifications
You must be signed in to change notification settings - Fork 40
IFC-1361: Merge core read only repositories on branch merge #7459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IFC-1361: Merge core read only repositories on branch merge #7459
Conversation
WalkthroughThe changes implement handling for read-only repository merging during branch operations. The code extends the merge workflow to distinguish between CoreRepository and CoreReadOnlyRepository types through a new repository_kind field. New asynchronous methods are added to query and process each repository type separately, enqueuing GitRepositoryMerge workflows with the appropriate kind identifier. The merge task handler is updated to route read-only repositories through a dedicated merge path that compares and propagates source repository references to the destination. The GitRepositoryMerge model is modified to include the repository_kind field and make the default_branch field optional. Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (3)
🧰 Additional context used🧬 Code graph analysis (1)backend/infrahub/core/merge.py (3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
🔇 Additional comments (1)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. 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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (1)
backend/infrahub/git/tasks.py (1)
479-479: Consider a more explicit condition for read-only repository detection.The condition
elif not model.default_branch:implicitly distinguishes read-only repositories. This could be clearer by checking the repository kind directly or adding a comment explaining the logic.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
backend/infrahub/core/merge.py(2 hunks)backend/infrahub/git/models.py(1 hunks)backend/infrahub/git/tasks.py(3 hunks)backend/tests/unit/core/diff/test_coordinator_lock.py(2 hunks)changelog/5978.added.md(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{md,mdx}
📄 CodeRabbit inference engine (CLAUDE.md)
Lint Markdown/MDX files with markdownlint using
.markdownlint.yaml
Files:
changelog/5978.added.md
backend/**/*
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Run backend tests with
pytestor viainvoketasks
Files:
backend/infrahub/git/models.pybackend/infrahub/git/tasks.pybackend/tests/unit/core/diff/test_coordinator_lock.pybackend/infrahub/core/merge.py
**/*.py
📄 CodeRabbit inference engine (.github/instructions/python-docstring.instructions.md)
**/*.py: Use triple double quotes (""") for all Python docstrings
Write docstrings in Google-style format
Include a brief one-line description at the top of each docstring
Add a detailed description section when additional context is needed
Document function/method parameters under an Args/Parameters section without typing information
Include a Returns section describing the return value
Include a Raises section listing possible exceptions
Provide an Examples section demonstrating usage when helpfulUse ruff and mypy to validate and lint Python files
**/*.py: Use type hints for all Python function parameters and return values
Prefer asynchronous code in Python when feasible
Define asynchronous Python functions withasync def
Useawaitfor asynchronous calls in Python
Use Pydantic models instead of standard dataclasses
Use ruff and mypy for linting and type checking
**/*.py: Use type hints for all Python function parameters and return values
Use async/await whenever possible in Python code
Define asynchronous functions withasync def
Await asynchronous calls withawait
Use Pydantic models instead of standard dataclasses for data modeling
Use triple quotes (""") for all Python docstrings
Write docstrings in Google-style format
Include docstring sections when applicable: one-line summary, optional details, Args (without types), Returns, Raises, Examples
Validate and lint Python with ruff and mypy
Files:
backend/infrahub/git/models.pybackend/infrahub/git/tasks.pybackend/tests/unit/core/diff/test_coordinator_lock.pybackend/infrahub/core/merge.py
backend/tests/**/*
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place backend tests in
backend/tests/
Files:
backend/tests/unit/core/diff/test_coordinator_lock.py
🧬 Code graph analysis (4)
backend/infrahub/git/models.py (1)
backend/infrahub/git/base.py (1)
default_branch(175-176)
backend/infrahub/git/tasks.py (1)
backend/infrahub/message_bus/types.py (1)
kind(72-75)
backend/tests/unit/core/diff/test_coordinator_lock.py (3)
backend/infrahub/core/schema/__init__.py (1)
SchemaRoot(47-99)backend/infrahub/core/schema/manager.py (1)
register_schema(202-209)backend/infrahub/core/branch/models.py (1)
update_schema_hash(125-133)
backend/infrahub/core/merge.py (4)
backend/infrahub/core/protocols.py (2)
CoreReadOnlyRepository(495-497)CoreRepository(500-502)backend/infrahub/core/manager.py (4)
NodeManager(135-1363)query(138-155)query(159-176)query(179-273)backend/infrahub/git/models.py (1)
GitRepositoryMerge(86-95)backend/infrahub/services/adapters/workflow/local.py (1)
submit_workflow(33-41)
🪛 LanguageTool
changelog/5978.added.md
[grammar] ~1-~1: Use a hyphen to join words.
Context: Merge core read only repositories on branch merge
(QB_NEW_EN_HYPHEN)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: E2E-testing-version-upgrade / From 1.3.0
- GitHub Check: E2E-testing-invoke-demo-start
- GitHub Check: backend-benchmark
- GitHub Check: E2E-testing-playwright
- GitHub Check: backend-docker-integration
- GitHub Check: validate-generated-documentation
- GitHub Check: backend-tests-functional
- GitHub Check: documentation
- GitHub Check: backend-tests-integration
- GitHub Check: backend-tests-unit
🔇 Additional comments (9)
backend/infrahub/git/tasks.py (2)
455-455: LGTM - Logger initialization.Adding logger initialization improves observability for the merge workflow.
465-477: LGTM - Enhanced logging for STAGING merge path.The added logging statements provide clear visibility into the merge workflow progress.
backend/tests/unit/core/diff/test_coordinator_lock.py (2)
19-19: LGTM - Import for read-only repository schema.The import is correctly added to support registering read-only repository schemas in tests.
58-65: LGTM - Test setup extended for read-only repositories.The test fixture now registers both regular and read-only repository schemas, mirroring the production behavior introduced in this PR. The duplication is intentional to create two separate schema registrations.
backend/infrahub/core/merge.py (3)
9-9: LGTM - Import updated for read-only repositories.The import correctly includes
CoreReadOnlyRepositoryto support the new merge workflow.
226-227: LGTM - Repository merge logic separated.The refactoring separates read-only and regular repository merges, improving code clarity and maintainability.
249-273: LGTM - Regular repository merge logic preserved.The existing merge logic for regular repositories is correctly preserved with appropriate status checks and conditional merge criteria.
backend/infrahub/git/models.py (2)
91-91: Optional internal_status is properly handled—no changes needed.All code paths correctly handle
Nonevalues:
- Equality comparisons (
if model.internal_status == RepositoryInternalStatus.ACTIVE.value) safely returnFalsewhenNone, preventing unwanted execution pathsInfrahubRepository.new()uses a default value ("active") for the field, preventing runtime errors- No attribute access or method calls are performed on
internal_statuswithout prior validation
95-95: No issues found - code safely handles optionaldefault_branchfield.The field
default_branch_name: str | NoneinInfrahubRepositoryBase(backend/infrahub/git/base.py:143) is properly handled through a property at line 175-176 that returnsself.default_branch_name or registry.default_branch. Even whenmodel.default_branchisNoneand passed toInfrahubRepository.init()asdefault_branch_name, accessingrepo.default_branchsafely returns a fallback value, ensuring all code paths receive a valid string.
| @@ -0,0 +1 @@ | |||
| Merge core read only repositories on branch merge | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use hyphenation for compound adjective.
The phrase "read only" should be hyphenated as "read-only" when used as a compound adjective.
Apply this diff:
-Merge core read only repositories on branch merge
+Merge core read-only repositories on branch merge📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Merge core read only repositories on branch merge | |
| Merge core read-only repositories on branch merge |
🧰 Tools
🪛 LanguageTool
[grammar] ~1-~1: Use a hyphen to join words.
Context: Merge core read only repositories on branch merge
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
In changelog/5978.added.md around lines 1 to 1 the phrase "read only" is used as
a compound adjective; update it to "read-only" so the line reads "Merge core
read-only repositories on branch merge".
CodSpeed Performance ReportMerging #7459 will not alter performanceComparing Summary
|
|
I wonder if an issue with this is that the repositories are branch agnostic nodes but for the read-only repositories the commit is a branch aware attribute. So perhaps the issue here is actually that we don't merge such an attribute. Can can talk about this in the backend meeting tomorrow. |
c732252 to
3406885
Compare
backend/infrahub/git/models.py
Outdated
| repository_id: str = Field(..., description="The unique ID of the Repository") | ||
| repository_name: str = Field(..., description="The name of the repository") | ||
| internal_status: str = Field(..., description="Administrative status of the repository") | ||
| internal_status: str | None = Field(default=None, description="Administrative status of the repository") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The read-only repository would also have an internal_status attribute so I don't think we need to make this optional. We can just include the information we got in the query when creating the GitRepositoryMerge model.
backend/infrahub/git/tasks.py
Outdated
| ) | ||
|
|
||
| if model.internal_status == RepositoryInternalStatus.STAGING.value: | ||
| log.info(f"Merging {InfrahubKind.GENERICREPOSITORY}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using InfrahubKind.GENERICREPOSITORY, I'd suggest that we add a string "repository_type" to GitRepositoryMerge and log the correct type.
backend/infrahub/git/tasks.py
Outdated
| await repo_main.save() | ||
| log.info(f"Finished merging {InfrahubKind.GENERICREPOSITORY}") | ||
|
|
||
| elif not model.default_branch: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of checking if a default_branch has been set I'd suggest we check against the "repository_type" I mentioned above both for read only repository here and for the other kind just above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
backend/infrahub/git/models.py (1)
86-96: Keepinternal_statusrequired onGitRepositoryMergeand populate it for read‑only mergesThe domain model treats
internal_statusas always present for repositories (including read‑only ones), while onlydefault_branchis naturally optional. Makinginternal_statusoptional here mainly compensates for not passing it from some call sites (e.g.,merge_core_read_only_repositories), and forces downstream workflow logic to handle aNonethat should not really occur.To keep the contract tighter and consistent with
GitRepositoryAddReadOnlyandRepositoryBranchInfo, consider:
- Keeping
default_branchoptional (as now), but revertinginternal_statusto required:internal_status: str = Field(..., description="Administrative status of the repository")- Updating the read‑only merge path to pass it through (see comment in
merge_core_read_only_repositories), e.g.internal_status=repo.internal_status.value.This preserves flexibility around
default_branchwhile avoiding a nullableinternal_statusthat does not reflect the underlying data model.
🧹 Nitpick comments (1)
backend/infrahub/core/merge.py (1)
225-247: Read‑only repo merge behavior: confirm eligibility rules and propagateinternal_statusThe split into
merge_core_read_only_repositories()andmerge_core_repositories()is a good separation of concerns and keeps the mainmerge_repositories()logic readable.For the read‑only path specifically:
No status/sync gating vs. core repos
- Core repos are gated by
internal_statusandsync_with_git:
- INACTIVE repos are skipped.
- Merges only occur when
self.source_branch.sync_with_gitorinternal_status == STAGING.- Read‑only repos are merged unconditionally as long as they exist in both branches.
If the intent is that read‑only repos should always have their branch‑scoped ref/commit aligned on merge (regardless of
internal_status), this difference is fine but a brief comment would help future maintainers understand why they diverge.If instead they are meant to obey the same lifecycle semantics as core repos, consider reusing the same gating checks here.
Pass
internal_statusintoGitRepositoryMergeAssuming
CoreReadOnlyRepositoryexposes aninternal_statussimilar toCoreRepository, you can enrich the workflow input and avoid the need for an optionalinternal_statusonGitRepositoryMergeby including it here:model = GitRepositoryMerge( repository_id=repo.id, repository_name=repo.name.value, internal_status=repo.internal_status.value, source_branch=self.source_branch.name, destination_branch=self.destination_branch.name, destination_branch_id=str(self.destination_branch.get_uuid()), )That keeps the merge workflow’s contract consistent across core and read‑only repositories and may allow tightening
GitRepositoryMerge.internal_statusback to a required field.Make the “main” query branch explicit (optional)
For readability and to avoid relying on NodeManager’s implicit default branch, you could mirror the branch usage from the rest of
BranchMerger:repos_in_main_list = await NodeManager.query( schema=CoreReadOnlyRepository, db=self.db, branch=self.destination_branch, )This makes it clear that “main” here is exactly the
destination_branchused for the graph merge.None of these points are blockers, but clarifying the intended eligibility rules and passing
internal_statuswould tighten the API and reduce surprises for consumers of the merge workflow.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
backend/infrahub/core/merge.py(2 hunks)backend/infrahub/git/models.py(1 hunks)backend/infrahub/git/tasks.py(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- backend/infrahub/git/tasks.py
🧰 Additional context used
🧬 Code graph analysis (1)
backend/infrahub/core/merge.py (4)
backend/infrahub/core/manager.py (4)
NodeManager(78-1411)query(81-98)query(102-119)query(122-216)backend/infrahub/git/models.py (1)
GitRepositoryMerge(86-95)backend/infrahub/core/node/standard.py (1)
get_uuid(65-69)backend/infrahub/services/adapters/workflow/local.py (1)
submit_workflow(33-41)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: validate-generated-documentation
- GitHub Check: documentation
- GitHub Check: backend-tests-integration
- GitHub Check: backend-tests-functional
- GitHub Check: backend-tests-unit
- GitHub Check: Cloudflare Pages
🔇 Additional comments (1)
backend/infrahub/core/merge.py (1)
5-16: NewCoreReadOnlyRepositoryimport is appropriate and scopedThe added
CoreReadOnlyRepositoryimport cleanly reflects the new read‑only merge behavior introduced below and keeps dependencies constrained to the protocols module. No issues from a dependency or layering perspective.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
backend/infrahub/core/enums.py(1 hunks)backend/infrahub/core/merge.py(3 hunks)backend/infrahub/git/models.py(2 hunks)backend/infrahub/git/tasks.py(4 hunks)backend/tests/unit/git/test_git_rpc.py(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- backend/infrahub/git/tasks.py
🧰 Additional context used
🧬 Code graph analysis (3)
backend/infrahub/git/models.py (2)
backend/infrahub/core/enums.py (1)
RepositoryTypes(20-22)backend/infrahub/git/base.py (1)
default_branch(187-188)
backend/tests/unit/git/test_git_rpc.py (1)
backend/infrahub/core/enums.py (1)
RepositoryTypes(20-22)
backend/infrahub/core/merge.py (4)
backend/infrahub/git/models.py (1)
GitRepositoryMerge(87-97)backend/infrahub/core/enums.py (1)
RepositoryTypes(20-22)backend/infrahub/core/manager.py (4)
NodeManager(78-1411)query(81-98)query(102-119)query(122-216)backend/infrahub/services/adapters/workflow/local.py (1)
submit_workflow(33-41)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: documentation
- GitHub Check: json-schema
- GitHub Check: validate-generated-documentation
- GitHub Check: Cloudflare Pages
🔇 Additional comments (4)
backend/infrahub/git/models.py (1)
4-4: LGTM: Model changes support both repository types.The changes correctly distinguish between CoreRepository and CoreReadOnlyRepository workflows:
default_branchis now optional (used only for CoreRepository, not CoreReadOnlyRepository)repository_typeexplicitly identifies the repository kind for downstream processingAlso applies to: 96-97
backend/infrahub/core/enums.py (1)
18-22: LGTM: Clean enum definition for repository types.The enum provides type-safe distinction between CoreRepository and CoreReadOnlyRepository, used consistently across the merge workflow.
backend/tests/unit/git/test_git_rpc.py (1)
14-14: LGTM: Test correctly updated for new required field.The test now explicitly sets
repository_type=RepositoryTypes.CoreRepository, matching the updatedGitRepositoryMergemodel signature.Also applies to: 147-147
backend/infrahub/core/merge.py (1)
9-9: LGTM: Repository merge workflow properly split by type.The refactoring cleanly separates CoreRepository and CoreReadOnlyRepository merge paths, with explicit
repository_typefields passed to workflows for proper routing downstream.Also applies to: 17-17, 227-228, 275-275
backend/infrahub/core/enums.py
Outdated
|
|
||
|
|
||
| class RepositoryTypes(enum.StrEnum): | ||
| CoreRepository = "core_repository" | ||
| CoreReadOnlyRepository = "core_read_only_repository" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be removed if you used the InfrahubKind constants such as REPOSITORY and READONLYREPOSITORY?
backend/infrahub/git/models.py
Outdated
| destination_branch_id: str = Field(..., description="The ID of the destination branch") | ||
| default_branch: str = Field(..., description="The default branch in Git") | ||
| default_branch: str | None = Field(default=None, description="The default branch in Git") | ||
| repository_type: RepositoryTypes = Field(..., description="The type of the repository.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other places we use repository_kind: str = Field(..., description="The kind of the repository"). Could this serve the same purpose?
Fixes #5978
This PR adds functionality for merging modified read only repositories from other branches into main branch. Existing implementation takes care of merging modified core repositories.
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.