Skip to content

Commit

Permalink
Merge pull request #79 from netboxlabs/develop
Browse files Browse the repository at this point in the history
Release v0.4.0
  • Loading branch information
jeremystretch authored Sep 5, 2024
2 parents 1158ef6 + dd3885b commit 3332632
Show file tree
Hide file tree
Showing 17 changed files with 362 additions and 71 deletions.
96 changes: 96 additions & 0 deletions .github/workflows/lint-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Lint and tests
on:
workflow_dispatch:
pull_request:
push:
branches:
- "!release"

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

permissions:
contents: write
checks: write
pull-requests: write

jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install .
pip install .[dev]
pip install .[test]
- name: Build documentation
run: mkdocs build
- name: Run pycodestyle
run: |
pycodestyle --ignore=W504,E501 netbox_branching/
tests:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
python-version: [ "3.10", "3.11", "3.12" ]
services:
redis:
image: redis
ports:
- 6379:6379
postgres:
image: postgres
env:
POSTGRES_USER: netbox
POSTGRES_PASSWORD: netbox
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Checkout netbox-branching
uses: actions/checkout@v4
with:
path: netbox-branching
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Checkout netbox
uses: actions/checkout@v4
with:
repository: "netbox-community/netbox"
path: netbox
- name: Install netbox-branching
working-directory: netbox-branching
run: |
# Include tests directory for test
sed -i 's/exclude-package-data/#exclude-package-data/g' pyproject.toml
python -m pip install --upgrade pip
pip install .
pip install .[test]
- name: Install dependencies & configure plugin
working-directory: netbox
run: |
ln -s $(pwd)/../netbox-branching/testing/configuration.py netbox/netbox/configuration.py
ln -s $(pwd)/../netbox-branching/testing/local_settings.py netbox/netbox/local_settings.py
python -m pip install --upgrade pip
pip install -r requirements.txt -U
- name: Run tests
working-directory: netbox
run: |
python netbox/manage.py test netbox_branching.tests --keepdb
19 changes: 19 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Change Log

## v0.4.0

### Enhancements

* [#52](https://github.com/netboxlabs/nbl-netbox-branching/issues/52) - Introduce the `max_branches` config parameter
* [#71](https://github.com/netboxlabs/nbl-netbox-branching/issues/71) - Ensure the consistent application of logging messages
* [#76](https://github.com/netboxlabs/nbl-netbox-branching/issues/76) - Validate required configuration items on initialization

### Bug Fixes

* [#57](https://github.com/netboxlabs/nbl-netbox-branching/issues/57) - Avoid recording ChangeDiff records for unsupported object types
* [#59](https://github.com/netboxlabs/nbl-netbox-branching/issues/59) - `BranchAwareRouter` should consider branching support for model when determining database connection to use
* [#61](https://github.com/netboxlabs/nbl-netbox-branching/issues/61) - Fix transaction rollback when performing a dry run sync
* [#66](https://github.com/netboxlabs/nbl-netbox-branching/issues/66) - Capture object representation on ChangeDiff when creating a new object within a branch
* [#69](https://github.com/netboxlabs/nbl-netbox-branching/issues/69) - Represent null values for ChangeDiff fields consistently in REST API
* [#73](https://github.com/netboxlabs/nbl-netbox-branching/issues/73) - Ensure all relevant branch diffs are updated when an object is modified in main

---

## v0.3.1

### Bug Fixes
Expand Down
17 changes: 17 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Configuration Parameters

## `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.

---

## `schema_prefix`

Default: `branch_`

The string to prefix to the unique branch ID when provisioning the PostgreSQL schema for a branch. Per [the PostgreSQL documentation](https://www.postgresql.org/docs/16/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS), this string must begin with a letter or underscore.

Note that a valid prefix is required, as the randomly-generated branch ID alone may begin with a digit, which would not qualify as a valid schema name.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ nav:
- Syncing & Merging: 'using-branches/syncing-merging.md'
- Reverting a Branch: 'using-branches/reverting-a-branch.md'
- REST API: 'rest-api.md'
- Configuration: 'configuration.md'
- Data Model:
- Branch: 'models/branch.md'
- BranchEvent: 'models/branchevent.md'
Expand Down
29 changes: 27 additions & 2 deletions netbox_branching/__init__.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,49 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured

from netbox.plugins import PluginConfig
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.3.1'
version = '0.4.0'
base_url = 'branching'
min_version = '4.1'
middleware = [
'netbox_branching.middleware.BranchMiddleware'
]
default_settings = {
# The maximum number of branches which can be provisioned simultaneously
'max_branches': None,

# This string is prefixed to the name of each new branch schema during provisioning
'schema_prefix': 'branch_',
}

def ready(self):
super().ready()
from . import events, search, signal_receivers
from . import constants, events, search, signal_receivers
from .utilities import DynamicSchemaDict

# Validate required settings
if type(settings.DATABASES) is not DynamicSchemaDict:
raise ImproperlyConfigured(
"netbox_branching: DATABASES must be a DynamicSchemaDict instance."
)
if 'netbox_branching.database.BranchAwareRouter' not in settings.DATABASE_ROUTERS:
raise ImproperlyConfigured(
"netbox_branching: DATABASE_ROUTERS must contain 'netbox_branching.database.BranchAwareRouter'."
)

# 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
}


config = AppConfig
6 changes: 6 additions & 0 deletions netbox_branching/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@

# URL query parameter name
QUERY_PARAM = '_branch'

# Apps which are explicitly excluded from branching
EXCLUDED_APPS = (
'netbox_branching',
'netbox_changes',
)
18 changes: 13 additions & 5 deletions netbox_branching/database.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from netbox.registry import registry

from .contextvars import active_branch


Expand All @@ -11,15 +13,21 @@ class BranchAwareRouter:
A Django database router that returns the appropriate connection/schema for
the active branch (if any).
"""
def db_for_read(self, model, **hints):
def _get_db(self, model, **hints):
# 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, []):
return

# Return the schema for the active branch (if any)
if branch := active_branch.get():
return f'schema_{branch.schema_name}'
return None

def db_for_read(self, model, **hints):
return self._get_db(model, **hints)

def db_for_write(self, model, **hints):
if branch := active_branch.get():
return f'schema_{branch.schema_name}'
return None
return self._get_db(model, **hints)

def allow_relation(self, obj1, obj2, **hints):
# Permit relations from the branch schema to the main (public) schema
Expand Down
2 changes: 1 addition & 1 deletion netbox_branching/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('core', '0011_move_objectchange'),
('extras', '0118_notifications'),
('extras', '0119_notifications'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

Expand Down
Loading

0 comments on commit 3332632

Please sign in to comment.