Skip to content
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

Release v0.5.0 #118

Merged
merged 19 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9631bf4
Don't mark new releases as pre-release
jeremystretch Sep 5, 2024
e67588e
#52: Correct test method name
jeremystretch Sep 6, 2024
a4a0946
Correct BranchChangesMergedView name
jeremystretch Sep 6, 2024
662dbcb
Fixes #81: Fix event rule trigger for branch_reverted signal
jeremystretch Sep 6, 2024
f8816e7
91 ignore differences in alert for active branch
arthanson Sep 9, 2024
807a686
Fixes #102: Record individual object actions in branch job logs
jeremystretch Sep 10, 2024
94d75cb
Closes #90: Implement branch archiving (#96)
jeremystretch Sep 10, 2024
0fa0955
88 enable branching in graphql (#104)
arthanson Sep 10, 2024
d8f1cfd
Fixes #94: Resolve model field name for custom field data
jeremystretch Sep 10, 2024
e5ba5d1
Closes #84: Introduce the `max_active_branches` config parameter (#100)
jeremystretch Sep 10, 2024
ba0cb48
Update changelog
jeremystretch Sep 10, 2024
d5193bd
Closes #112: Document the need for create permissions in PostgreSQL
jeremystretch Sep 11, 2024
be5c2a4
Closes #97: Introduce the `exempt_models` config parameter (#109)
jeremystretch Sep 11, 2024
ef6e16f
Closes #101: Permit (but warn about) database queries issued before b…
jeremystretch Sep 11, 2024
7ae83ca
Fixes: #83 - Add Share button for object views when a branch is selec…
bctiemann Sep 11, 2024
dfc041d
Closes #115: Note that netbox_branching must be last entry in PLUGINS
jeremystretch Sep 11, 2024
9c40af6
Update changelog
jeremystretch Sep 11, 2024
00e3416
Closes #116: Disable branching support for applicable core models
jeremystretch Sep 12, 2024
b623e53
Release v0.5.0
jeremystretch Sep 12, 2024
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
1 change: 0 additions & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,3 @@ jobs:
release_name: ${{ needs.get-next-version.outputs.release-version }}
body: ${{ needs.get-release-notes.outputs.release-notes }}
draft: false
prerelease: true
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,25 @@ This [NetBox](http://netboxlabs.com/oss/netbox/) plugin introduces branching fun

Brief installation instructions are provided below. For a complete installation guide, please refer to the included documentation.

1. Activate the NetBox virtual environment:
1. Grant PostgreSQL permission for the NetBox database user to create schemas:

```postgresql
GRANT CREATE ON DATABASE $database TO $user;
```

2. Activate the NetBox virtual environment:

```
$ source /opt/netbox/venv/bin/activate
```

2. Install the plugin from [PyPI](https://pypi.org/project/netboxlabs-netbox-branching/):
3. Install the plugin from [PyPI](https://pypi.org/project/netboxlabs-netbox-branching/):

```
$ pip install netboxlabs-netbox-branching
```

3. Add `netbox_branching` to `PLUGINS` in `configuration.py`:
4. Add `netbox_branching` to the end of `PLUGINS` in `configuration.py`. Note that `netbox_branching` **MUST** be the last plugin listed.

```python
PLUGINS = [
Expand All @@ -32,7 +38,7 @@ PLUGINS = [
]
```

4. Create `local_settings.py` to override the `DATABASES` & `DATABASE_ROUTERS` settings. This enables dynamic schema support.
5. Create `local_settings.py` to override the `DATABASES` & `DATABASE_ROUTERS` settings. This enables dynamic schema support.

```python
from netbox_branching.utilities import DynamicSchemaDict
Expand All @@ -49,7 +55,7 @@ DATABASE_ROUTERS = [
]
```

5. Run NetBox migrations:
6. Run NetBox migrations:

```
$ ./manage.py migrate
Expand Down
21 changes: 21 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Change Log

## v0.5.0

### Enhancements

* [#83](https://github.com/netboxlabs/nbl-netbox-branching/issues/83) - Add a "share" button under object views when a branch is active
* [#84](https://github.com/netboxlabs/nbl-netbox-branching/issues/84) - Introduce the `max_working_branches` configuration parameter
* [#88](https://github.com/netboxlabs/nbl-netbox-branching/issues/88) - Add branching support for NetBox's graphQL API
* [#90](https://github.com/netboxlabs/nbl-netbox-branching/issues/90) - Introduce the ability to archive & deprovision merged branches without deleting them
* [#97](https://github.com/netboxlabs/nbl-netbox-branching/issues/97) - Introduce the `exempt_models` config parameter to disable branching support for plugin models
* [#116](https://github.com/netboxlabs/nbl-netbox-branching/issues/116) - Disable branching support for applicable core models

### Bug Fixes

* [#81](https://github.com/netboxlabs/nbl-netbox-branching/issues/81) - Fix event rule triggering for the `branch_reverted` event
* [#91](https://github.com/netboxlabs/nbl-netbox-branching/issues/91) - Disregard the active branch (if any) when alerting on changes under object views
* [#94](https://github.com/netboxlabs/nbl-netbox-branching/issues/94) - Fix branch merging after modifying an object with custom field data
* [#101](https://github.com/netboxlabs/nbl-netbox-branching/issues/101) - Permit (but warn about) database queries issued before branching support has been initialized
* [#102](https://github.com/netboxlabs/nbl-netbox-branching/issues/102) - Record individual object actions in branch job logs

---

## v0.4.0

### Enhancements
Expand Down
38 changes: 37 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,46 @@
# Configuration Parameters

## `exempt_models`

Default: `[]` (empty list)

A list of models provided by other plugins which should be exempt from branching support. (Only models which support change logging need be listed; all other models are ineligible for branching support.)

!!! warning
A model may not be exempted from branching support if it has one or more relationships to models for which branching is supported. Branching **must** be supported consistently for all inter-related models; otherwise, data corruption can occur. Configure this setting only if you have a specific need to disable branching for certain models provided by plugins.

Models must be specified by app label and model name, as such:

```python
exempt_models = (
'my_plugin.foo',
'my_plugin.bar',
)
```

It is also possible to exclude _all_ models from within a plugin by substituting an asterisk (`*`) for the model name:

```python
exempt_models = (
'my_plugin.*',
)
```

---

## `max_working_branches`

Default: None

The maximum number of operational branches that can exist simultaneously. This count excludes branches which have been merged or archived.

---

## `max_branches`

Default: None

The maximum number of branches that can exist simultaneously, including merged branches that have not been deleted. It may be desirable to limit the total number of provisioned branches to safeguard against excessive database size.
The maximum total number of branches that can exist simultaneously, including merged branches that have not been deleted. It may be desirable to limit the total number of provisioned branches to safeguard against excessive database size.

---

Expand Down
13 changes: 12 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ sequenceDiagram

## Getting Started

### Database Preparation

Before installing this plugin, ensure that the PostgreSQL user as which NetBox authenticates has permission to create new schemas in the database. This can be achieved by issuing the following command in the PostgreSQL shell (substituting `$database` and `$user` with their respective values):

```postgresql
GRANT CREATE ON DATABASE $database TO $user;
```

### Plugin Installation

#### 1. Virtual Environment
Expand All @@ -97,7 +105,7 @@ pip install netboxlabs-netbox-branching

#### 3. Enable Plugin

Add `netbox_branching` to the list `PLUGINS` list in `configuration.py`.
Add `netbox_branching` to **the end** of the `PLUGINS` list in `configuration.py`.

```python
PLUGINS = [
Expand All @@ -106,6 +114,9 @@ PLUGINS = [
]
```

!!! warning
`netbox_branching` must be the **last** (or only) plugin in the list. Branching support will not be registered for models provided by any plugin appearing later in the list.

!!! note
If there are no plugins already installed, you might need to create this parameter. If so, be sure to define `PLUGINS` as a list _containing_ the plugin name as above, rather than just the name.

Expand Down
1 change: 1 addition & 0 deletions docs/models/branch.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ The current status of the branch. This must be one of the following values.
| Merging | A job is running to merge changes from the branch into main |
| Reverting | A job is running to revert previously merged changes in main |
| Merged | Changes from this branch have been successfully merged into main |
| Archived | A merged branch which has been deprovisioned in the database |
| Failed | Provisioning the schema for this branch has failed |

### Last Sync
Expand Down
4 changes: 2 additions & 2 deletions docs/using-branches/reverting-a-branch.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

Once a branch has been merged, it is generally no longer needed, and can no longer be activated. However, occasionally you may find it necessary to undo the changes from a branch (due to an error or an otherwise undesired state). This can be done by _reverting_ the branch. Only merged branches can be reverted.

!!! note
Only branches which have not yet been deleted can be reverted. Once a branch is deleted, reversion is no longer possible.
!!! warning
Only branches which have not yet been archived or deleted can be reverted. Once a branch's schema has been deprovisioned, it can no longer be reverted.

Before reverting a branch, review the changes listed under its "Merged Changes" tab. NetBox will attempt to undo these specific changes when reverting the branch.

Expand Down
2 changes: 2 additions & 0 deletions docs/using-branches/syncing-merging.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ While a branch is being merged, its status will show "merging."
!!! tip
You can check on the status of the merging job under the "Jobs" tab of the branch view.

Once a branch has been merged, it can be [reverted](./reverting-a-branch.md), archived, or deleted. Archiving a branch removes its associated schema from the PostgreSQL database to deallocate space. An archived branch cannot be restored, however the branch record is retained for future reference.

## Dealing with Conflicts

In the event an object has been modified in both your branch _and_ in main in a diverging manner, this will be flagged as a conflict. For example, if both you and another user have modified the description of an interface to two different values in main and in the branch, this represents a conflict.
Expand Down
31 changes: 24 additions & 7 deletions netbox_branching/__init__.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured

from netbox.plugins import PluginConfig
from netbox.plugins import PluginConfig, get_plugin_config
from netbox.registry import registry


class AppConfig(PluginConfig):
name = 'netbox_branching'
verbose_name = 'NetBox Branching'
description = 'A git-like branching implementation for NetBox'
version = '0.4.0'
version = '0.5.0'
base_url = 'branching'
min_version = '4.1'
middleware = [
'netbox_branching.middleware.BranchMiddleware'
]
default_settings = {
# The maximum number of working branches (excludes merged & archived branches)
'max_working_branches': None,

# The maximum number of branches which can be provisioned simultaneously
'max_branches': None,

# Models from other plugins which should be excluded from branching support
'exempt_models': [],

# This string is prefixed to the name of each new branch schema during provisioning
'schema_prefix': 'branch_',
}
Expand All @@ -39,11 +45,22 @@ def ready(self):
)

# Record all object types which support branching in the NetBox registry
if 'branching' not in registry['model_features']:
registry['model_features']['branching'] = {
k: v for k, v in registry['model_features']['change_logging'].items()
if k not in constants.EXCLUDED_APPS
}
exempt_models = (
*constants.EXEMPT_MODELS,
*get_plugin_config('netbox_branching', 'exempt_models'),
)
branching_models = {}
for app_label, models in registry['model_features']['change_logging'].items():
# Wildcard exclusion for all models in this app
if f'{app_label}.*' in exempt_models:
continue
models = [
model for model in models
if f'{app_label}.{model}' not in exempt_models
]
if models:
branching_models[app_label] = models
registry['model_features']['branching'] = branching_models


config = AppConfig
12 changes: 11 additions & 1 deletion netbox_branching/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class BranchStatusChoices(ChoiceSet):
MERGING = 'merging'
REVERTING = 'reverting'
MERGED = 'merged'
ARCHIVED = 'archived'
FAILED = 'failed'

CHOICES = (
Expand All @@ -21,14 +22,21 @@ class BranchStatusChoices(ChoiceSet):
(MERGING, _('Merging'), 'orange'),
(REVERTING, _('Reverting'), 'orange'),
(MERGED, _('Merged'), 'blue'),
(ARCHIVED, _('Archived'), 'gray'),
(FAILED, _('Failed'), 'red'),
)

TRANSITIONAL = (
PROVISIONING,
SYNCING,
MERGING,
REVERTING
REVERTING,
)

WORKING = (
NEW,
READY,
*TRANSITIONAL,
)


Expand All @@ -37,10 +45,12 @@ class BranchEventTypeChoices(ChoiceSet):
SYNCED = 'synced'
MERGED = 'merged'
REVERTED = 'reverted'
ARCHIVED = 'archived'

CHOICES = (
(PROVISIONED, _('Provisioned'), 'green'),
(SYNCED, _('Synced'), 'cyan'),
(MERGED, _('Merged'), 'blue'),
(REVERTED, _('Reverted'), 'orange'),
(ARCHIVED, _('Archived'), 'gray'),
)
21 changes: 17 additions & 4 deletions netbox_branching/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,21 @@
# URL query parameter name
QUERY_PARAM = '_branch'

# Apps which are explicitly excluded from branching
EXCLUDED_APPS = (
'netbox_branching',
'netbox_changes',
# Models for which branching support is explicitly disabled
EXEMPT_MODELS = (
# Exempt applicable core NetBox models
'core.*',
'extras.branch',
'extras.customfield',
'extras.customfieldchoiceset',
'extras.customlink',
'extras.eventrule',
'extras.exporttemplate',
'extras.notificationgroup',
'extras.savedfilter',
'extras.webhook',

# Exempt all models from this plugin and from netbox-changes
'netbox_branching.*',
'netbox_changes.*',
)
7 changes: 7 additions & 0 deletions netbox_branching/database.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import warnings

from netbox.registry import registry

from .contextvars import active_branch
Expand All @@ -14,6 +16,11 @@ class BranchAwareRouter:
the active branch (if any).
"""
def _get_db(self, model, **hints):
# Warn & exit if branching support has not yet been initialized
if 'branching' not in registry['model_features']:
warnings.warn(f"Routing database query for {model} before branching support is initialized.")
return

# Bail if the model does not support branching
app_label, model_name = model._meta.label.lower().split('.')
if model_name not in registry['model_features']['branching'].get(app_label, []):
Expand Down
8 changes: 8 additions & 0 deletions netbox_branching/forms/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

__all__ = (
'BranchActionForm',
'ConfirmationForm',
)


Expand Down Expand Up @@ -36,3 +37,10 @@ def clean(self):
raise forms.ValidationError(_("All conflicts must be acknowledged in order to merge the branch."))

return self.cleaned_data


class ConfirmationForm(forms.Form):
confirm = forms.BooleanField(
required=True,
label=_('Confirm')
)
13 changes: 7 additions & 6 deletions netbox_branching/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ def get_active_branch(request):
"""
Return the active Branch (if any).
"""
# The active Branch is specified by HTTP header for REST API requests.
if request.path_info.startswith(reverse('api-root')) and (schema_id := request.headers.get(BRANCH_HEADER)):
branch = Branch.objects.get(schema_id=schema_id)
if not branch.ready:
return HttpResponseBadRequest(f"Branch {branch} is not ready for use (status: {branch.status})")
return branch
# The active Branch is specified by HTTP header for REST & GraphQL API requests.
if request.path_info.startswith(reverse('api-root')) or request.path_info.startswith(reverse('graphql')):
if schema_id := request.headers.get(BRANCH_HEADER):
branch = Branch.objects.get(schema_id=schema_id)
if not branch.ready:
return HttpResponseBadRequest(f"Branch {branch} is not ready for use (status: {branch.status})")
return branch

# Branch activated/deactivated by URL query parameter
elif QUERY_PARAM in request.GET:
Expand Down
Loading