Skip to content

Commit

Permalink
Migrate to pydantic (#214)
Browse files Browse the repository at this point in the history
* Initial pydantic testing.

* Implement `host find`.

  - Also makes get_list do the logic of checking hit limits and exception handling.
  - Only the API module has any idea of endpoint addresses for pydantic calls. The rest of the client code does not care.
  - Implements a IPAddressField for Hosts to reduce the number of str-fields we have. We should ideally have none.

* Clean up authentication mess. (#206)

* Clean up authentication mess.

  - Cleans up the names for the auth functions.
  - Adds a LoginFailedError exception.
  - Passes on params from the pre-relogin command to the post-login command.
  - Reintroduces the previous behaviour where failing the login upon startup exists mreg.

* Fix `host find -comment` metavar (#207)

* Allow oneshot commands from the terminal. (#208)

* Allow oneshot commands from the terminal.

This patch allows the use of mreg-cli without interaction, ala:

`mreg-cli host info foo`

This will then feed the command `host info foo` to the cli and then exit.

Also adds an option to force token only login. Good for scripts. :)

* Improve connection errors. (#209)

- No micromanagment of error types, just dump the error text back to the user.

* Fix a bug where not having any default URL breaks application start. (#212)

* Use corrolation_id for logging across commands. (#213)

* Make `host remove` a bit safer to use. (#211)

## The problem...

It was much too easy to do `host remove foo -f` and have it bite in the worst possible way.

## The solution?

In this PR, `-force` is no longer a catch-all for making `host remove`, well, remove the host. If the host has cnames, ptrs, mx, srvs or ipadresses across multiple vlans, the user needs to declare a desire to override each of these explicitly via the new option `-override`.

## Supported input

Accepted overrides are `cname`, `ipadress`, `mx`, `srv`, `ptr`, `naptr`. Invalid overrides offered as parameters to `-override` are errors and the command will report on the unexpected input and stop before executing anything.

The choice to have these as textual inputs is intended with the explicit goal of making their use require more than tab-completing an option.

## Example usage

`host remove foo -force -override cname,ipaddress,mx`.

This would allow deletion / removal of a host with cnames, ipadresses across different vlans, and mx set. However, any ptr or srv RRs will still cause the deletion to cancel.

## Example warning from `host remove`

```
WARNING: : bar.example.org requires force and cnames as overrides for deletion:
  1 cnames, override with 'cname'
    - fubar.example.org
  multiple ipaddresses on the same VLAN. Must use 'force'."
```

## Notes:

1. `-force` alone works on multiple ipadresses from the same VLAN.
2. `-override` requires the presence of `-force`. The documentation states this both from expanded inline help and `host remove -h`.


---------

Co-authored-by: pederhan <[email protected]>

* Add Endpoint enum, migrate add_user, refactor MacAddress.

  - Also differentiates between get_list and get_list_unique where one expects many or one hit.
  - Further improve models with better cleaning of macaddress.
  - Avoid string literals for endpoints, use an Enum with optional identifier application.

* Make api.get_host generic.

  - api.get_host now allows for lookups by id, ipaddress, macaddress or hostname, and if all that fails checks for CNAMEs.
  - Add network endpoints and more.
  - Make models frozen so they can be used as hash keys, returning new objects of one tries to assign to them via acceptable methods. __setattr__ and __delattr__ are overridden to cause AttributeErrors if used.
  -  Migrate `host add` and `host remove`
  - Document (some) of the older API calls with exceptions.

* Refactoring for readability.

* Remove redudant docstring.

* Rename HostModel to Host.

* Refactoring and cleaning up host processing.

  - Host output now uses class methods from the models involved to print multiple entries.
  - clean_hostname is copied around a bit to support old and new code... :(
  - Models with a host parameter also get a method to resolve the host.
  - Added support for created_at and updated_at.

* Typing, Zones and some more RRs.

  - We don't use clean_hostname, we have a hostname type.
  - Make roles look sane for the consumer of the cli.

* Use class methods for lookups, object methods for API operations.

  - Models know their endpoint
  - This allows for class.get, class.create, obj.delete, obj.refetch, obj.patch
  - patch/create return the new obj
  - Needs refactoring of model file, it's getting large.

* Fix host comparison.

* Type fixes.

* Move knowledge of endpoint ID mapping peculiarities to Endpoints only, the models don't know and don't care.

* Allow for manually setting ip or pass network to host add.

  - This does not rely on getting the IP from the server first, it uses the servers API directly.

* Look up field names by alias

* Use dict.get() with no default

* Make pylance happy with explicit type

* Split the models.py into smaller files.

* Add a run script for pyinstaller.

* Either raise an exception *or* use cli_{warning,error}.

* Fix host add (again).

* Upgrade models.py to Pydantic V2 semantics (#215)

* Upgrade models.py to Pydantic V2 semantics

* Use old-style unions

* Fix imports + use of built-in generics

* Move `NameList` to fields.py

* Migrate to python 3.11.

  - Updates syntax for types via pyupgrade and manual Union resolution. Some Unions had to remain due to "TypeError: unsupported operand type(s) for |: 'str' and 'NoneType'" etc. Not sure why.
  - Update setup.cfg and github actions to document python requirement.

* Require setuptools due to python 3.12+

* Require a newer version of setuptools.

* Newer image, force upgrade of pip, and drop caches,

* Use tox to test pyinstaller for 3.11 and 3.12.

* Add `from __future__ import annotations` lint rule (#216)

* Add `from __future__ import annotations` lint rule

Also run pyupgrade

* Remove most `if TYPE_CHECKING` blocks, upgrade stub file

* Finish up the last bits of core host commands...

  - set_comment and set_contact are done.
   - history is... horrific, but done. The old one is retained for comparative testing for now.
   - Almost all utility functions are now *gone*. :D
   - Avoid validating email etc on the client side, let the server do validation. It'd be sad if the validators disagreed, which they very well may.

* Add Host.get_by_any_means_or_raise and use it wisely. :)

* Acutally support multi-host lookups with info and fix bacnet display.

* Add group lookup support to host info.

* Refactor hostgroup parent parsing.

* Refactor and add group output support.

  - Allow endpoint.external_id_field be called either as a class or an object method. This cleans up class methods that want to introspect the id field.
  - Add group output support (and add callback)
  - Present inherited parents for groups.
  - Remove spurious host lookup in add.

* Refactor away the function-based API and migrated a/aaaa commands.

  - No more `h = add_host(...)`. Now there is only `Host.create(...)` etc.
  - Added a NetworkOrIP type that holds either a network or IP and has some introspection. Handy when doing IP/Network stuffs.
  - Added more required endpoints.
  - Ensured that get_by_ip will return lists (ip,host) is unique, ip alone is not.
  - Migrated a/aaaa commands in hostcommands/a_aaaa.py.

* host cname commands migration.

  - Also short-cirucuited some other non-migrated commands due to breaking changes.

* Hinfo support.

  - Hinfo does not have an ID field. Yay. More endpoint fiddling.
  - Also improve CNAME handling via better user reporting.

* Well, that was effin' awful.

  - We use names as identifier for endpoints here and there. Like for hosts. Names for hosts are mutable. Refetching a host then can't be done via the name post-patch as we may have modified the name.
  - This is "solved" by magically checking against an id field in models during refetch and using that instead of the expected identifier. This works as the endpoint mechanics know how to search (!) for id...
  - Splits Zone into ForwardZone (and eventually ReverseZone).
  - Add Loc support.

* Add RR MX support.

* Add `get_typed()` utility function

* Add NAPTR and PTR support.

  - Also extends network model support for non-json endpoints.
  - Also adds PTR lookups to host info (via get_by_any_means).

* Add `Atom` & `Label` models + base Host Policy model (#217)

* Unified HostPolicy models (Role & Atom)

* Add very stern warning

* Add hostpolicy endpoints to `requires_search_for_id`

* Add `get_by_name` for host policy models

* Implement datetime fields on `HostPolicy`

* Add `policy info`

* Add `Atom.output`

* Use most narrow exception type

* Add `# noqa: A003`

* Break host policy loop on match

* Add SRV support.

  - Also abstract out and generalize get_by_data and renaming it get_by_query_unique

* Finalize RR support.

  - Adds support for SSHFP, TXT, and TTL.
  - Refactors some TTL support into a usable abstraction.

* Add inline comments for `HostPolicy` validator

* Add `WithName` mixin (#218)

* Ensure resource exists

* Add `APIMixin.get_by_field_or_raise`

* Hack: Inherit from `APIMixin[Any]`

* Remove invalid superclass

* Use `BaseModel` as generic type for `WithName`

* Fix `ensure_name_*` error messages

* Use `Any` as type argument for `WithName`

* Add `WithName.__name_field__`

* Clarify `__name_field__` docstring

* Add `get_by_name_or_raise`, refactor `get_by_name`

* Fix `WithName` method docstrings

* Remove TODO

* Better exception modelling. (#219)

* Better exception modelling.

  - More exceptions, and they are raised explicitly rather than using `cli_*`-commands.

* Use `Self` type annotation for `APIMixin` (#222)

* Use `Self` type annotation for `APIMixin`

* Fix `__init_subclass__`

* Allow kwargs to be passed to `__init_subclass__`

* Require `BaseModel` inheritance

* dhcp commands and exception usage. (#223)

* Add dhcp comands, clean up exceptions.

* Migrate explicit use of CliError

* Migrate HostGroup to use NameList. :)

* Uniform exception names (#225)

* Make Errors end with Error, warnings have no suffix.

* Add policy commands (#220)

* Add roles and atoms endpoints to name field check

* Use `Mapping` annotation in `APIMixin.patch`

`dict` invariant and will not accept an argument of `dict[str, str]` when the type annotation is `dict[str, str | None]`. Yeah...

* Add type annotations for `Namespace` attributes

* Pydantic group commands (#224)

* Add group commands.

Co-authored-by: pederhan <[email protected]>

* Labels and some permission work. (#226)

* Labels and some permission work.
* Allow create not to fetch, as Label.create() will... fail...
* Add missing `cli_info` calls, use `print_msg=`

---------

Co-authored-by: pederhan <[email protected]>

* Permission commands migrated. (#228)

* Permission commands migrated.

---------

Co-authored-by: pederhan <[email protected]>

* Zone commands (#227)

* Zone commands

* Use illegal hack to create zones

* Re-add zone_basepath for development

Why was it gone?

* Delegation abomination

* Make `with_*` methods available outside `Endpoint`

* Get/create/delete delegations

* Add Zone.get_delegation_{and,or}_raise`

Really re-inventing the wheel here just because the endpoint has 2 component placeholders...

* Remove WithName mixin from `Delegation`

* Add `zone list`

* Move `with_*` methods back into `Endpoints`

* Add `zone set_ns`

* Fix `ReverseZoneDelegation.is_reverse()`

* Remove unused Delegation.type_by_name

* Replace `WithName` with `APIMixin`in `Zone`

* Fix invalid imports

* Add `zone info`

* Fix incorrect endpoint values, reorder endpoints

* Require force for `delegation_create` if zone does not exist

* Add `Zone.get_zone_{and,or}_raise`

* Simplify Zone.delete_delegation

* Add `delegation_list`

* Add `zone set_soa`

* Add `zone delegation_comment_set`

* Add `zone delegation_comment_remove`

* Add `zone set_default_ttl`

* Improve TTL printing

* Remove unused zone functions

* Change `output_ttl` param order for consistency

* Use `get_by_name*` instead of `get_by_field*`

* Remove unused imports

* Comments, docstrings, CLI messages

* Fix incorrect method used in `host sshfp_remove` (#233)

* Support segmenting tokens per user and url. (#229)

* Support segmenting tokens per user and url.

* Clean up debugging code.

* Exit after showing token, allowing for scripted use.

* Only print the token itself, not the Token header prefix.

* Add utility functions for setting/getting auth header (#231)

* Revert line breaks in overload definitions.

---------

Co-authored-by: Peder Hovdan Andresen <[email protected]>

* Set prompt to default to the server one is connected to. (#234)

* Set prompt to default show the name of the server.

* Update documentation on defaults.

* Remove `use_json` (#235)

* Fix/standardize some patch commands (#236)

* Add `WithHistory` + fetching history for deleted objects (#237)

* Remove `use_json` (#235)

* Add `WithHistory`, remove history methods from `APIMixin`

* Access attribute directly

* Network commands (#238)

* Add more flexible JSON types

* Add `ExcludedRange` model type

I was not able to find a single network with an excluded range, so it's hard to test...

* Allow `max_hits_to_allow=None`

* Add `network create`

* Add `network info`

* Add `network find`

* Make JSON type names less verbose

* Handle non-str args in `NetworkOrIP` validator

* Refactor Network `get_*` methods

* Add `network find -ip` support

* Support `limit=None` in `APIMixin.get_by_query`

* Raise `InputFailure` in `IPAddressField` validator

* Only support IP args with`network find -ip`

* Add `network list_unused_addresses`

* Add `network list_used_addresses`

* Add `network remove`

* Replace `cli_warning` calls with exceptions

* Add `network add_excluded_range`

* Add `network remove_excluded_range`

* Add new command `network list_excluded_ranges`

* Add `network {set/unset}_*` commands

* Handle location and category tags from config

* Fix sample config tags

* Update help text of `network set_reserved`

* Add pagination support for `get_typed` (#240)

* Add pagination support for `get_typed`

* Fix missing param in docstring

* Handle non-paginated results in `get_list`

* Define metadata and requirements in pyproject.toml (#239)

* Migrate fully to pyproject.toml

* Add dev dependencies

* Fix whitespace

* Compile requirements files from pyproject

* Fix broken command(s) in CI (#243)

* Fix wrong args attribute name in `naptr_show`
* Tests: Use `label set_description`

* Fix missing pyinstaller dev dependency (#246)

* Fix DHCP commands (#245)

* Fix `dhcp assoc`

* Fix `dhcp disassoc`

* Refactor `dhcp` commands

* Remove redundant name binding

* Improve `ipaddress_from_ip_arg()` exceptions

* Improve `ipaddress_from_ip_arg` docstring

* Add period when finding subzones (#248)

* Validate GET responses with Pydantic (#241)

* Validate responses with Pydantic

* Specify part of statement `type: ignore` applies to

* Replace all `get_list` calls with `get_typed`

* Use `TypeAliasType` from typing-extensions

* Revert accidental find and replace change

* HACK: Use `cast()` in `get_list_unique()`

* Add source url comment to recursive JSON type

* Add helper functions for response validation

* Remove `ResponseLike`

* Raise MREG ValidationError on failed validation

* Validate response in `get_list_unique`

* Improve exception handling for failed validation

* Add `HistoryResource` from #232

Also directly validates results to `HistoryItem` instead of going through a dict.

* Fix typo

* Strip None values when sending JSON (#249)

* Strip None values when sending JSON

* Recursively strip

* Require SOCKS dependencies (#244)

* Require SOCKS dependencies

* Add pyinstaller dev dependency

* Add `--version` option (#252)

* Show git commit in `--version` (#253)

* Print git commit in `--version`

* Use versioneer to determine git revision

* Use `setuptools_scm`

* Fix scm version

* Fully integrate dynamic versioning

* Delete versioneer-created gitattributes file

* Copy policies from one host to another. (#257)

- This PR allows for copying of all policies (roles) from one host to another via a new command, `policy host_copy`.

* Support multiple destinations in host_copy. (#259)

* Support multiple destinations in host_copy.

  - Also reduces output noise.
  - Also handles the situation where a destination already has the role in question.
  - Requires Role to be hashable.

* Instantiate JSON mapping validator at top level (#260)

* Import host_submodules explicitly. (#262)

* Add publishing workflow and contribution instructions (#254)

* Publishing

* Add branch condition to publish workflow

* Wording

* Remove usage of requirements.txt files

* Add basepython resolution for numbered envs

* Use uv in tox workflows

* Unfinished publish workflow

* trying stuff

* Do not specify tox env in build workflow

* Move pyinstaller dependency to tox

* Actually run tox

* Fix binary dist path

* Revert incorrect binary path

* Fix underscore in artifact name

* verbose pypi

* Use test pypi

* Use `mreg-cli-v*` tag pattern

* Dump workflow info

* Add branch check

* Try to create release

* Try to use trusted publishing

* Remove unused pypi vars

* Try to rename binaries

* Try to actually read actions docs

* Fix bin  name

* Publish a4

* Rename binary after creation

* Remove publishing branch

* Make built binary executable

* Remove executable step

* Build on master and publish to real pypi

* Update publishing instructions

* Exit explicitly only on master branch

* Add artifact and version info, move `-desc`to Removed

* Final publishing test run

* Enable master protection again

* Make GitHub release non-prelease

* Add missing newline

* Fix CONTRIBUTING markdown lint violations

Does not "fix" the ordered list rule violation, since indenting the code blocks looks very awkward.

* Add authors to pyproject.toml (#263)

* Add authors to pyproject.toml

* Add historical authors

* Add AUTHORS file

* Make testsuite work again (#255)

* Make the cli exceptions write to outputmanager

* Replace formatted datetime strings in output

* Fix workflow annotations about GH action versions

* Update testsuite json with modified label commands

* Workaround for json-incapable server

* Also use workaround for patch requests

* Use OutputManager instead of the cli_* methods

* Use specialized exceptions. (#256)

- This PR migrates all use of CliError and CliWarning to more specialized exceptions.
  - Also fix a bug with handling broken filter expressions.
  - Prefixes Errors with ERROR as not everyone has color vision.

* Cull utility functions that aren't used anymore

* Further culling of... old stuff.

* Fix valid_numeric_ttl min and max value handling

* Use `APIMixin.patch()` in `Zone.set_default_ttl()`

* Add missing OK message for `host add`

* Remove IP/network from `host add` OK message

* Verified behaviour for all zone commands

I have looked at the new output and api calls for the "zone" commands in
the testsuite and it looks good to me. Updating testsuite-result.json to
reflect that.

* Verified behaviour for all group commands

I have looked at the new output and api calls for the "group" commands
in the testsuite and it looks good to me.
Fixed a bug in history.py concerning how history is printed when owners
or hosts are added/removed from hostgroups.
Made a minor change to the datetime regex in diff.py to handle the extra
space that comes before a single digit date.

* Fix fetching network from location header (#258)

* Extract fetching resource by location to separate method

Fixes failing `network create` tests

* Use `field_for_endpoint()`

* Prefer using location header verbatim

Adds handling for endpoints that return invalid location headers.

* Remove `field_for_endpoint()`

* Remove placeholder comment, move src comments

* Remove special label handling, never re-fetch labels

* Add a check for frozen/force to "host add"

We forgot to check if the network was frozen in "host add". Added a
check for that in this commit, but we'll probably have to do
something similar in a_aaaa.py.

Went through more command output and verified it. Mostly network
commands this time.

Modified diff.py to not care about length of white space. Since ip
addresses can vary between runs, formatted output can vary in length,
spesifically how much whitespace is added.

* Fix fetching paginated endpoints twice in `get_list_generic` (#261)

* Fix fetching paginated endpoints twice in `get_list_generic`

* Break instead of return

* Refactor `get_list_generic` result checking

* Fix network excluded range output.

  - Also use IPAddressField for ips in excluded ranges.

* Fix delegeation response.

  - Add support for "delegation" scope akin to "zone" scope in server responses for zones.

* Implement logging. (#266)

* Implement logging.

  - Migrates out logging and recording commands to their own command files.
  - During the logging setup there was an issue trying to untangle commands and conventions, so most commands are now refactored into proper command files.
  - Add logging to API calls and output.
  - Move CliExit to exceptions.py...
  - When logging API calls, also logs the clients corrolation ID (for requests and respones) and the servers request ID (per request/response) for easier server side debugging. :)
  - Restrict logging (to errors only) when running the test suite, it's... noisy. :D

---------

Co-authored-by: Peder Hovdan Andresen <[email protected]>

* Support sending more than str to post. (#264)

* Support sending more than str to post.

Also fix some ruffs.

* Consistent signatures for get_list_generic.

---------

Co-authored-by: Peder Hovdan Andresen <[email protected]>

* Fix a bug in remove_excluded_range

models.Network.remove_excluded_range had a bug where it wouldn't match
the supplied parameters even when a range existed.
Solved by converting the ip address values to strings.

This commit also updates the rest of the "network" part of the test
suite results.

* Add network set_category/set_location commands

* Escape error messages (#269)

* Escape exception messages in HTML text

* Only escape message, not formatted exc

* Escape messages only in formatted exceptions (#271)

* Escape messages only in formatted exceptions

* Rename `escaped()` to `escape()`

* Add `QueryParams` type (#273)

* Add `QueryParams` type

* Remove redundant dict comprehension

* Add interactive diffing (#270)

Revert "Use dumb terminal only for diff.py"

This reverts commit 42a70de.

Use dumb terminal only for diff.py

Remove vertical borders for easier copying

Add comment about review mode

Invert conditional

Docstrings, ordering

Comments, names, docstrings

Don't review in CI

Change choices (order + choice)

Remove unused state

Revert "Run diff.py on testsuite results"

This reverts commit def4bc5.

Run diff.py on testsuite results

Refactor diff.py

Add interactive diffing

* Add force req for frozen nets to a_add, aaaa_add

Also:
- Add "rich" to requirements-dev.txt, it was missing
- Update testsuite-result.json with more verified test output

* Fix problems with history output

Also, update more test resuls

* Add minor quality of life + message changes to diff.py (#275)

* Remove `getattr()` usage in `_request_wrapper()`. (#274)

* Remove LoginFailedError message hard coding. (#277)

* Remove hardcoded LoginFailed output.

Fixes #272

* Fix quote usage and handle direction (im)possibly being unassigned. (#279)

* Add a regex for macaddress to diff.py

Macaddresses were caught by the IPv6 regex, which made certain commands
in the testsuite look like the wrong type of parameter was supplied.

* Add OK message to a_add when success

Also, avoid refetching the host twice.

* Remove unnecessary warning from dhcp assoc

dhcp assoc <hostname> <ip> would warn that hostname isn't a valid ip
address. This commit changes the code so the exception isn't raised but
otherwise it works the same.

Also:
- A minor change to an error message about a host having multiple ips.
- Verified the output from the rest of the commands in the dhcp section.

* Remove stripping of None values from PATCH calls (#282)

Also ensures nullable and non-nullable TTL fields are treated differently.

* Improve diff numbering + messages (#284)

* Add number to diff when reviewing

* Improve diff messages

* Handle `DiffError`

* Add `ERROR` msg prefix for exceptions

* Fix inconsistent stdout/stderr printing

* Remove parenthesis around plural s

* Fix `host set_comment` with empty string (#283)

* Use Pydantic v2 style model config in `FrozenModel` (#285)

* Use object repr when PATCH validation fails

* Improve type safety of validators (#286)

* Improve type safety of validators

* Remove unused import

* Improve safety of TTL methods for non-nullable fields (#287)

* Improve safety of TTL methods for non-nullable fields

* Add external id field for `Endpoint.Nameservers`

* Add QueryParam annotations for inline params

* Replace IDs & IPs in test result URLs (#288)

* Replace IDs & IPs in test result URLs

* Simplify `unquote_url`

* Expand match group explanations

* Fix comment typo

* A few code changes + changes to testsuite-result (#289)

- Changes to testsuite-result.json that came from #288
- The rest of the changes to testsuite-result.json, manually verified
- a_aaaa.py: Add a message and a requirement for force when adding an additional IP address to a host.
- rr.py: Replace occurrences of str(host.id) with host.id in API requests.

* Write back original lines in diff review (#290)

* Write back non-placeholder lines in diff reviews

* Refactor results to classes

* Rename `TestSuiteLog` to `TestSuiteResult`

* Delete .pyi file

* Fix missing None check

* Accept int values in queries

* Add missing annotations import

* Use uv in CI (#292)

* Use uv in CI

* Use official uv action

* Add build dependencies to pyproject.toml

* Use uv run?

* Set up python with uv in CI

* idk

* Use venv

* uv run?

* Use uv python when building too

* Remove system python env var

---------

Co-authored-by: pederhan <[email protected]>
Co-authored-by: Terje Kvernes <[email protected]>
Co-authored-by: Terje Kvernes <[email protected]>
Co-authored-by: Peder Hovdan Andresen <[email protected]>

* Build Linux PyInstaller binary in CentOS 8 container (#293)

* Build PyInstaller binary in CentOS 8 container

* Use single release step

* Change publish tag pattern (#294)

* Update contributing instructions

* Add `getattr` default in `APIMixin.refetch` (#295)

* Don't pass params for pagination requests (#296)

* Reorder overloads (#297)

* Fix cli.py type checking errors (#299)

* Fix cli.py type checking errors

* Fix comment

* Explain noqa Ruff codes

* Fix unquoted regex error handling (#298)

* Add error msg builder with underlined suggestions (#300)

* Add error msg builder with underlined suggestions

* Refactor error message building

* Add docstrings

* Add defaults for url and domain config options (#301)

---------

Co-authored-by: Peder Hovdan Andresen <[email protected]>
Co-authored-by: pederhan <[email protected]>
Co-authored-by: Øyvind Hagberg <[email protected]>
  • Loading branch information
4 people authored Oct 8, 2024
1 parent 32af34b commit 07e070e
Show file tree
Hide file tree
Showing 67 changed files with 24,709 additions and 16,584 deletions.
127 changes: 127 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
name: build mreg-cli

on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+**'

concurrency:
group: build-mreg-cli-${{ github.head_ref }}

jobs:
build_pypi:
name: Build wheels and source distribution
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Exit if not on master branch
if: github.ref_name != 'master'
run: exit -1

- name: Install uv
uses: astral-sh/setup-uv@v2

- name: Set up Python 3.12
run: uv python install 3.12

- name: Install build dependencies
run: |
uv venv
uv pip install --upgrade build
- name: Build source distribution
run: uv run python -m build

- uses: actions/upload-artifact@v4
with:
name: pypi_artifacts
path: dist/*
if-no-files-found: error

build_pyinstaller:
name: Build pyinstaller binary
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version:
- '3.12'
include:
- os: ubuntu-latest
container: centos:8
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}

steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v2

- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Run PyInstaller with Tox
run: |
uv venv
uv pip install tox-uv tox-gh-actions
tox
- name: Rename binary
run: |
mv dist/mreg-cli${{ contains(matrix.os, 'windows') && '.exe' || '' }} dist/mreg-cli-${{ matrix.os }}-${{ matrix.python-version }}${{ contains(matrix.os, 'windows') && '.exe' || '' }}
- uses: actions/upload-artifact@v4
with:
name: mreg-cli-${{ matrix.os }}-${{ matrix.python-version }}${{ contains(matrix.os, 'windows') && '.exe' || '' }}
path: dist/mreg-cli-${{ matrix.os }}-${{ matrix.python-version }}${{ contains(matrix.os, 'windows') && '.exe' || '' }}
if-no-files-found: error

publish_pypi:
name: Publish PyPI release
needs:
- build_pypi
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: pypi_artifacts
path: dist

- name: Push build artifacts to PyPI
uses: pypa/[email protected]

publish_github:
name: Publish GitHub release
needs:
- build_pypi
- build_pyinstaller
runs-on: ubuntu-latest

steps:
- name: Download PyInstaller binaries
uses: actions/download-artifact@v4
with:
pattern: mreg-cli-*
path: dist
merge-multiple: true

- name: Download wheel and source distributions
uses: actions/download-artifact@v4
with:
pattern: pypi_artifacts
path: dist
merge-multiple: true

- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
files: dist/*
body: |
Release ${{ github.ref_name }}
draft: false
prerelease: false

58 changes: 22 additions & 36 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,42 +1,33 @@
on: [push, pull_request]


name: CI
jobs:
test:
name: Integration
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04] # For python3.6
os: [ubuntu-22.04]
python-version:
- '3.6'
- '3.7'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'
env:
# Disable colors and formatting in Rich console output
TERM: dumb
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache pip
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: v1-pip-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('requirements-*.txt') }}
restore-keys: |
v1-pip-${{ runner.os }}-${{ matrix.python-version }}
v1-pip-${{ runner.os }}
v1-pip-
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Install mreg-cli
run: |
pip install -r requirements.txt
pip install -e .
uv venv
uv pip install -e .[dev]
- name: Test and compare api calls
run: ci/run_testsuite_and_record.sh
run: uv run ci/run_testsuite_and_record.sh

tox:
name: tox
Expand All @@ -45,24 +36,19 @@ jobs:
fail-fast: false
matrix:
python-version:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox tox-gh-actions
python -m pip install -r requirements.txt
python -m pip install -r requirements-dev.txt
uv venv
uv pip install tox-uv tox-gh-actions
- name: Test with tox
run: tox r
run: uv run tox r

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ wheels/
.installed.cfg
*.egg
MANIFEST
mreg_cli/_version.py

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
12 changes: 12 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Dmytro Karpenko
Fredrik Larsen
Magnus Hirth
Marius Bakke
Nico
Nils Hiorth
Paal Braathen
Peder Hovdan Andresen
Safet Amedov
Terje Kvernes
Øyvind Hagberg
Øyvind Kolbu
36 changes: 36 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

The big Pydantic update. The entire codebase has been rewritten to use Pydantic for request and response validation. This brings with it a huge improvement to the development experience and the robustness of the code.

### Added

- `--version` option to display current application version and exit.
Version number is in the form of `major.minor.patch` if installed from a published version.
Shows a version number including the commit hash if installed from a git repository in the form of `major.minor.patch.dev123+gabc1234`.
See [Default versioning scheme](https://setuptools-scm.readthedocs.io/en/latest/usage/#default-versioning-scheme) in the [setuptools_scm](https://github.com/pypa/setuptools_scm/) documentation for more information.
- The version can be accessed programmatically with `mreg_cli.__version__`.
- `label set_description` command to set the description of a label.
- `network list_excluded_ranges` command to list the excluded ranges of a network.
- Application can now store tokens for multiple servers and will pick the correct one based on the server URL.
- Building binaries for Windows, Linux and MacOS, and publishing the package to PyPI on each GitHub release.

### Changed

- The application now uses Pydantic internally to validate request and response data. This should make the code more robust and easier to maintain.
- Application now attempts to send JSON for every request. This should improve the consistency of the API responses.
- Version now follows Semantic Versioning 2.0.0 and is automatically determined based on the most recent git tag (`mreg-cli-v*`). As part of this change, the verison has been bumped from 0.9.10 to 1.0.0. See the Added section for more information on how version numbers are accessed.

### Removed

- `label rename -desc` option. Description modification is now done through the new `label set_description` command.

### Fixed

- Hopefully more than we broke.
38 changes: 38 additions & 0 deletions CONTRIBUTING
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Contributing

If you would like to contribute to this project, please follow these steps:

1. Fork the repository
2. Create a new branch (`git checkout -b feature/branch-name`)
3. Make changes
4. Commit your changes (`git commit -am 'Add some feature'`)
5. Push to the branch (`git push origin feature/branch-name`)
6. Create a Pull Request

## Publishing

Publishing new versions is automatically handled by GitHub actions for versions tagged with `x.y.z[.prerelease]` (`1.2.3`, `1.2.3.rc1`, etc.). If you are a maintainer, you can create a new release by following these steps:

1. Switch to the `master` branch:

```bash
git checkout master
```

2. Create a new tag:

```bash
git tag 1.2.3
```

3. Push the tag to the upstream repository:

```bash
git push upstream 1.2.3
```

To push a tag together with a new commit:

```bash
git push upstream master --tags
```
Loading

0 comments on commit 07e070e

Please sign in to comment.