-
Notifications
You must be signed in to change notification settings - Fork 7
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
Add WithName
mixin
#218
Merged
pederhan
merged 12 commits into
unioslo:migrate_to_pydantic
from
pederhan:ensure-resource-exists
May 7, 2024
Merged
Add WithName
mixin
#218
pederhan
merged 12 commits into
unioslo:migrate_to_pydantic
from
pederhan:ensure-resource-exists
May 7, 2024
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pederhan
changed the title
Ensure resource exists
Ensure resource (does not) exist(s) given a field + value
May 6, 2024
terjekv
reviewed
May 6, 2024
pederhan
commented
May 6, 2024
pederhan
changed the title
Ensure resource (does not) exist(s) given a field + value
Add May 6, 2024
WithName
mixin
pederhan
added a commit
that referenced
this pull request
Oct 8, 2024
* 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]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
No description provided.