Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions backend/infrahub/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ class MainSettings(BaseSettings):
default=True,
description="When enabled, diff updates are triggered for active branches after a branch merge.",
)
delete_branch_after_merge: bool = Field(
default=False,
description="When enabled, the Infrahub branch is automatically deleted after a successful merge.",
)

@field_validator("docs_index_path", mode="before")
@classmethod
Expand Down Expand Up @@ -496,6 +500,11 @@ class GitSettings(BaseSettings):
use_explicit_merge_commit: bool = Field(
default=False, description="Whether to allow explicit merge commits when infrahub merges branches"
)
delete_git_branch_after_merge: bool = Field(
default=False,
description="When enabled, the corresponding Git branch is deleted after the Infrahub branch is deleted. "
"Requires main.delete_branch_after_merge to be enabled.",
)

@model_validator(mode="after")
def validate_sync_branch_names(self) -> Self:
Expand Down Expand Up @@ -1030,6 +1039,12 @@ class Settings(BaseSettings):
trace: TraceSettings = TraceSettings()
experimental_features: ExperimentalFeaturesSettings = ExperimentalFeaturesSettings()

@model_validator(mode="after")
def validate_git_branch_deletion_requires_branch_deletion(self) -> Self:
if self.git.delete_git_branch_after_merge and not self.main.delete_branch_after_merge:
raise ValueError("'delete_git_branch_after_merge' requires 'delete_branch_after_merge' to be enabled")
return self

@property
def enterprise_features(self) -> list[EnterpriseFeatures]:
"""Returns a list of enterprise features that are enabled based on the settings."""
Expand Down
19 changes: 18 additions & 1 deletion backend/tests/unit/test_config.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import os
import re
import ssl
from pathlib import Path
from unittest.mock import patch

import pytest
from pydantic import ValidationError

from infrahub.config import SETTINGS, GitSettings, HTTPSettings, StorageSettings, UserInfoMethod, load
from infrahub.config import (
SETTINGS,
GitSettings,
HTTPSettings,
MainSettings,
Settings,
StorageSettings,
UserInfoMethod,
load,
)
from tests.conftest import TestHelper

TEST_DATA_DIR = Path(__file__).parent / "test_data"
Expand Down Expand Up @@ -42,6 +52,13 @@ def test_invalid_git_settings__sync_branch_names() -> None:
GitSettings(import_sync_branch_names=["main", "infrahub/.*", "release/.*", "a[b"])


def test_delete_git_branch_after_merge_without_delete_branch_after_merge_raises() -> None:
with pytest.raises(ValueError, match=re.escape("requires 'delete_branch_after_merge' to be enabled")):
Settings(
git=GitSettings(delete_git_branch_after_merge=True), main=MainSettings(delete_branch_after_merge=False)
)


def test_storage_max_file_size() -> None:
assert StorageSettings().max_file_size == 50
assert StorageSettings(max_file_size=100).max_file_size == 100
Expand Down
8 changes: 4 additions & 4 deletions dev/wip/ifc-2336/implementation-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Add optional automatic branch deletion after merge. Both Infrahub branch deletio

| Phase | Description | Priority | Status | Tests |
|-------|-----------------------------------------|----------|-------------|----------------------|
| 1 | Configuration settings | P1 | ⬜ Todo | 3 unit tests |
| 1 | Configuration settings | P1 | ✅ Done | 3 unit tests |
| 2 | Auto-delete Infrahub branch after merge | P1 | ⬜ Todo | 4 functional tests |
| 3 | Git branch deletion workflow | P2 | ⬜ Todo | 3 unit tests |
| 4 | Manual delete with Git option | P3 | ⬜ Todo | 2 unit tests |
Expand Down Expand Up @@ -52,10 +52,10 @@ uv run invoke format && uv run invoke lint

### Manual Test Flow

1. Set only `delete_git_branch_after_merge = true` (leave `delete_branch_after_merge = false`), restart — verify startup fails with a clear validation error
2. Set `delete_branch_after_merge = true` in `infrahub.toml`, restart service
1. Set only `[git] delete_git_branch_after_merge = true` (leave `[main] delete_branch_after_merge = false`), restart — verify startup fails with a clear validation error
2. Set `[main] delete_branch_after_merge = true` in `infrahub.toml`, restart service
2. Create a branch, make a change, merge via `BranchMerge` GraphQL mutation
3. Verify branch no longer appears in branch list
4. Repeat via proposed change merge — same result
5. Set `delete_git_branch_after_merge = true` as well, merge a Git-synced branch
5. Set `[git] delete_git_branch_after_merge = true` as well, merge a Git-synced branch
6. Verify branch deleted from Git repositories; per-repo failures appear in repo task logs
50 changes: 33 additions & 17 deletions dev/wip/ifc-2336/phase-1.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,64 @@
# Phase 1: Configuration Settings

**Status:** ⬜ Todo
**Status:** ✅ Done
**Priority:** P1
**Requirements:** FR-001, FR-002, FR-011

---

## Goal

Add two global configuration settings to `MainSettings`. Both default to `False` to preserve backward compatibility (FR-011).
Add `delete_branch_after_merge` to `MainSettings` and `delete_git_branch_after_merge` to `GitSettings`. Both default to `False` to preserve backward compatibility (FR-011). Cross-field validation lives at the top-level `Settings` class since the two fields are in different sub-settings.

---

## Checklist

- [ ] Add `delete_branch_after_merge` to `MainSettings`
- [ ] Add `delete_git_branch_after_merge` to `MainSettings`
- [ ] Add cross-field validator that rejects `delete_git_branch_after_merge=True` when `delete_branch_after_merge=False`
- [ ] Write unit tests
- [x] Add `delete_branch_after_merge` to `MainSettings`
- [x] Add `delete_git_branch_after_merge` to `GitSettings`
- [x] Add cross-field validator on `Settings` that rejects `git.delete_git_branch_after_merge=True` when `main.delete_branch_after_merge=False`
- [x] Write unit tests

---

## Implementation

### 1.1 Add settings and validator to MainSettings
### 1.1 Add `delete_branch_after_merge` to `MainSettings`

**File:** `backend/infrahub/config.py`

Locate the `MainSettings` class and add two new fields plus a `@model_validator`:
```python
class MainSettings(BaseSettings):
# ... existing fields ...
delete_branch_after_merge: bool = Field(
default=False,
description="When enabled, the Infrahub branch is automatically deleted after a successful merge.",
)
```

### 1.2 Add `delete_git_branch_after_merge` to `GitSettings`

```python
from pydantic import model_validator
from typing import Self
class GitSettings(BaseSettings):
# ... existing fields ...
delete_git_branch_after_merge: bool = Field(
default=False,
description="When enabled, the corresponding Git branch is deleted after the Infrahub branch is deleted. "
"Requires main.delete_branch_after_merge to be enabled.",
)
```

class MainSettings(BaseSettings):
### 1.3 Add cross-field validator to `Settings`

```python
class Settings(BaseSettings):
# ... existing fields ...
delete_branch_after_merge: bool = False
delete_git_branch_after_merge: bool = False

@model_validator(mode="after")
def validate_git_branch_deletion_requires_branch_deletion(self) -> Self:
if self.delete_git_branch_after_merge and not self.delete_branch_after_merge:
if self.git.delete_git_branch_after_merge and not self.main.delete_branch_after_merge:
raise ValueError(
"'delete_git_branch_after_merge' requires 'delete_branch_after_merge' to be enabled"
"'git.delete_git_branch_after_merge' requires 'main.delete_branch_after_merge' to be enabled"
)
return self
```
Expand All @@ -56,8 +72,8 @@ Pydantic raises `ValidationError` on load, which `load_and_exit()` catches, prin
**File:** `backend/tests/unit/test_config.py`

- `test_delete_branch_after_merge_defaults_to_false` — assert `MainSettings().delete_branch_after_merge is False`
- `test_delete_git_branch_after_merge_defaults_to_false` — assert `MainSettings().delete_git_branch_after_merge is False`
- `test_delete_git_branch_after_merge_without_delete_branch_after_merge_raises` — assert `ValidationError` is raised when `delete_git_branch_after_merge=True, delete_branch_after_merge=False`
- `test_delete_git_branch_after_merge_defaults_to_false` — assert `GitSettings().delete_git_branch_after_merge is False`
- `test_delete_git_branch_after_merge_without_delete_branch_after_merge_raises` — assert `ValidationError` is raised when `Settings(git={"delete_git_branch_after_merge": True}, main={"delete_branch_after_merge": False})`

**Verification:**

Expand Down
2 changes: 2 additions & 0 deletions docs/docs/reference/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Here are a few common methods of setting configuration:
| `INFRAHUB_PUBLIC_URL` | Define the public URL of the Infrahub, might be required for OAuth2 and OIDC depending on your infrastructure. | None | None |
| `INFRAHUB_SCHEMA_STRICT_MODE` | Enable strict schema validation. When set to `False`, `human_friendly_id` schema fields should not necessarily target a unique combination of peer attributes. | boolean | True |
| `INFRAHUB_DIFF_UPDATE_AFTER_MERGE` | When enabled, diff updates are triggered for active branches after a branch merge. | boolean | True |
| `INFRAHUB_DELETE_BRANCH_AFTER_MERGE` | When enabled, the Infrahub branch is automatically deleted after a successful merge. | boolean | False |

## Api

Expand All @@ -59,6 +60,7 @@ Here are a few common methods of setting configuration:
| `INFRAHUB_GIT_USER_EMAIL` | Email of the git user. This will be used as the user email when Infrahub commits code to a repository | string | infrahub@opsmill.com |
| `INFRAHUB_GIT_GLOBAL_CONFIG_FILE` | The location of the git config file. This will be set as the system `GIT_CONFIG_GLOBAL` environment variable if the environment variable is not initially set | string | /opt/infrahub/.gitconfig |
| `INFRAHUB_GIT_USE_EXPLICIT_MERGE_COMMIT` | Whether to allow explicit merge commits when infrahub merges branches | boolean | False |
| `INFRAHUB_GIT_DELETE_GIT_BRANCH_AFTER_MERGE` | When enabled, the corresponding Git branch is deleted after the Infrahub branch is deleted. Requires main.delete_branch_after_merge to be enabled. | boolean | False |

## Dev

Expand Down
6 changes: 6 additions & 0 deletions frontend/app/src/shared/api/rest/types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1716,6 +1716,12 @@ export interface components {
* @default true
*/
diff_update_after_merge: boolean;
/**
* Delete Branch After Merge
* @description When enabled, the Infrahub branch is automatically deleted after a successful merge.
* @default false
*/
delete_branch_after_merge: boolean;
};
/** Menu */
Menu: {
Expand Down
6 changes: 6 additions & 0 deletions schema/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -5023,6 +5023,12 @@
"title": "Diff Update After Merge",
"description": "When enabled, diff updates are triggered for active branches after a branch merge.",
"default": true
},
"delete_branch_after_merge": {
"type": "boolean",
"title": "Delete Branch After Merge",
"description": "When enabled, the Infrahub branch is automatically deleted after a successful merge.",
"default": false
}
},
"additionalProperties": false,
Expand Down
Loading