Build
* build(dev-infra): avoid removing packages other than the ones installed here ([`cfcf0ae`](https://github.com/irtnog/lethbridge/commit/cfcf0ae53a79025eb0aaf57fead4e53069abee29))
* build(dev-infra): add pre-commit targets plus some convenience aliases ([`7b4b09d`](https://github.com/irtnog/lethbridge/commit/7b4b09d3a4aa8fc60b8e996873e4170c35ce168d))
* build(dev-infra): update pre-commit hooks ([`178c7e6`](https://github.com/irtnog/lethbridge/commit/178c7e62dc0623b23eb13590b77320ee4cd96895))
* build(packaging): install pre-commit in the dev environment ([`8cc0cd2`](https://github.com/irtnog/lethbridge/commit/8cc0cd2a94bd0070fc0542ab089bd32f4b036213))
* build(dev-infra): add a quick smoke test target ([`e505b2b`](https://github.com/irtnog/lethbridge/commit/e505b2b0b9d09f0dff7d6a67ad87ba28b2aea0f1))
* build(packaging): add elpy RPC dependencies to the dev environment ([`cd8512b`](https://github.com/irtnog/lethbridge/commit/cd8512be8996142daf45a00022793e02d37e3182))
* build(dev-infra): add build dependency installation/removal targets ([`368e7a9`](https://github.com/irtnog/lethbridge/commit/368e7a93f044157cc31669e427dfc5f137a151fa))
* build(dev-infra): launch databases for developing Alembic migrations ([`14754e1`](https://github.com/irtnog/lethbridge/commit/14754e1f1191874a0c00a915dc256d4b85fa5f20))
* build(dev-infra): add targets for intermediate container stages, Docker cleanup ([`a36ea7f`](https://github.com/irtnog/lethbridge/commit/a36ea7fb1764dff8daa03079dcbbf73088d26ccc))
* build(dev-infra): simplify Python version check ([`a9ad65d`](https://github.com/irtnog/lethbridge/commit/a9ad65d85fa16329409d0d6dd15656cfa7cdb58b))
* build(dev-infra): consolidate make target aliases into one rule ([`e11b9c8`](https://github.com/irtnog/lethbridge/commit/e11b9c8713a6ae48320a49f60514b9937b25c162))
* build(dev-infra): work around outdated versions of pip, setuptools on older operating systems ([`0ae30ba`](https://github.com/irtnog/lethbridge/commit/0ae30bacbfe950a6a59e6ce6bd2aa7f8b404aff0))
* build(dev-infra): detect the active Python version
This affects some of the target pathnames. ([`77e18e4`](https://github.com/irtnog/lethbridge/commit/77e18e472594bad3fd2544478bae1cbec692da8f))
* build(dev-infra): install psycopg2cffi in the local dev environment
This matches the Docker container image build process. ([`4cc5ef8`](https://github.com/irtnog/lethbridge/commit/4cc5ef8eb1b0a3586e7b6370b04472ddc6e84cc0))
* build(dev-infra): define some useful shortcuts using make ([`faa7f4b`](https://github.com/irtnog/lethbridge/commit/faa7f4bc784d6955b0ac085e849c6af0a3090493))
* build: rename action to better reflect its purpose ([`848ce7a`](https://github.com/irtnog/lethbridge/commit/848ce7a793bb737f7a3306944d2c50445b7bf149))
Ci
* ci(release): adopt semantic versioning and automate releases ([`ea38049`](https://github.com/irtnog/lethbridge/commit/ea380492adc74a9ec44ba42d4baae7625a4cdc1b))
* ci(test): validate the code against supported Python versions after linting ([`2a9be11`](https://github.com/irtnog/lethbridge/commit/2a9be117736b54ba05b413fe5d3621dd497f2dd1))
* ci(lint): simplify further by reusing the pre-commit hook ([`3ea9bdc`](https://github.com/irtnog/lethbridge/commit/3ea9bdc4a5fd6bf67643acb62b1d039e60c31514))
* ci(lint): simplify code style checks by relying on runner defaults ([`3efe833`](https://github.com/irtnog/lethbridge/commit/3efe833e1e7c365b690085cb62849ce33940903d))
* ci(lint): document workflow triggers ([`d54a8a0`](https://github.com/irtnog/lethbridge/commit/d54a8a0629102714e53b7a0d13d9dd5d100505e0))
Documentation
* docs(schemas): explain why &34;Object of type... not in session&34; can be ignored ([`4254226`](https://github.com/irtnog/lethbridge/commit/4254226dad179d3327139bc11034066ffdc88a88))
* docs(schemas): explain the purpose of the stack in the Spansh schema test code ([`c6a6134`](https://github.com/irtnog/lethbridge/commit/c6a6134856ad7ef6349f30022746fb35e97945a0))
* docs(dev-infra): re-arrange comments and add vertical whitespace to improve section separation ([`f171ede`](https://github.com/irtnog/lethbridge/commit/f171edeca3d22799654045735ac2692fed229657))
* docs(packaging): add reference to PyPI classifiers list ([`d231ff6`](https://github.com/irtnog/lethbridge/commit/d231ff623193f922139f2875a67d26f872e15171))
* docs(dev-infra): explain what each set of make targets does ([`6246e4a`](https://github.com/irtnog/lethbridge/commit/6246e4abd4c8027f5e347a974c240de33362dc29))
* docs(docker): explain how the multi-stage build works to newcomers ([`ccce08f`](https://github.com/irtnog/lethbridge/commit/ccce08f672f6d50810ec1d1bf6686b9fd7d6a550))
* docs(docker): unhide example environment variables ([`3369da8`](https://github.com/irtnog/lethbridge/commit/3369da89ff23711acf3fa75947107eea4091ccf9))
* docs: add how to back up Docker volumes to the lessons learned ([`e477cff`](https://github.com/irtnog/lethbridge/commit/e477cff3f87455cdda31dfb748fb989a57cf62ea))
Feature
* feat(packaging): bump to pre-alpha phase ([`7e0ec7d`](https://github.com/irtnog/lethbridge/commit/7e0ec7df13fc11d3284684a856fa1fd98b27c281))
* feat(docker): check the first argument for a subcommand and act accordingly ([`320fc90`](https://github.com/irtnog/lethbridge/commit/320fc908067539ed760ad8b4e0fbd9bf839f092e))
* feat(docker): parameterize the version of Python used in the container image ([`415a070`](https://github.com/irtnog/lethbridge/commit/415a0703c0f08722bea793ff906c715ed01fb0c9))
* feat(docker): initialize or update the database at container start ([`f6de7f2`](https://github.com/irtnog/lethbridge/commit/f6de7f2922c68e05713a00981a9cd19132f73d64))
* feat(cli): implement foreground imports of Spansh data dumps ([`1de48e5`](https://github.com/irtnog/lethbridge/commit/1de48e57481495418f3864b26c94fca7be5a826e))
* feat(migrations): use Alembic to manage database schema changes ([`bf48ba8`](https://github.com/irtnog/lethbridge/commit/bf48ba8cf86981c5451ce141e5270aff6cfb9061))
Fix
* fix: remove unused imports ([`266aeb4`](https://github.com/irtnog/lethbridge/commit/266aeb47591bfbfa8079f0e9abfdc88bdcce0b5c))
* fix(database): prevent updates of all other classes using outdated data ([`37a4ef5`](https://github.com/irtnog/lethbridge/commit/37a4ef58d8c7f7a3d26141ac14de7cafcb706239))
* fix(database): prevent updates to a system from using outdated data ([`8b24f34`](https://github.com/irtnog/lethbridge/commit/8b24f34bba56ccd0fd98096b3baf2bdb76131423))
* fix(dev-infra): remove virtual env dependencies on system packages
This addresses issues with outdated packages conflicting with project
dependencies. ([`ab366e2`](https://github.com/irtnog/lethbridge/commit/ab366e224a1137884a8c5a485a1f24198a539c62))
* fix(docker): exclude Python bytecode from the container image
This improves Docker build cache management by excluding what are in
effect temporary files from the build context. ([`e706f73`](https://github.com/irtnog/lethbridge/commit/e706f7343c88c884670acceb7b60a5df826c5f0e))
* fix(docker): pass Lethbridge options specified in the container command to setup commands ([`5adcad7`](https://github.com/irtnog/lethbridge/commit/5adcad73ed3a75a268bd713c5a1b763fb6bfd03e))
* fix(cli): apply CLI logging level options to each configured logger ([`5ec4365`](https://github.com/irtnog/lethbridge/commit/5ec4365afaf35b705d8a0f42f2dc9c8b59f9f720))
* fix(database): make all Thargoid war state fields optional ([`b39ea43`](https://github.com/irtnog/lethbridge/commit/b39ea4301c49e36835c648f7815e531236682fdc))
* fix(docker): propagate the default database URI to the corresponding container environment variable ([`c1d8171`](https://github.com/irtnog/lethbridge/commit/c1d8171333e93b6cbd9552a33d0b748f40d37b94))
* fix(__main__): remove references to psycopg2cffi
This should be user-controlled. ([`281ac82`](https://github.com/irtnog/lethbridge/commit/281ac8250344032c2350d1c011e5257a0abb97b3))
* fix(cli): configure the actual root logger, not the application root ([`0a11704`](https://github.com/irtnog/lethbridge/commit/0a11704f16f49759727aff3d0d6f6d5f7eb8420d))
Refactor
* refactor: sort imports ([`73597b0`](https://github.com/irtnog/lethbridge/commit/73597b04dfa32243b6eef1cba779930e7aa53048))
* refactor(packaging): re-sort sections alphabetically ([`08e5ac2`](https://github.com/irtnog/lethbridge/commit/08e5ac2d777876904fb444603f4c13a9dbb6257e))
* refactor(database): generalize validation function and move to base class
We can re-use the same code with different decorations in sibling
classes without having to copy/paste. ([`cb51380`](https://github.com/irtnog/lethbridge/commit/cb5138070e6a8ade71a1c54fd9a1c755da331a07))
* refactor(docker): drop planned support for MySQL/MariaDB
Getting [pytest-mysql](https://github.com/ClearcodeHQ/pytest-mysql) to
work has proven too difficult at this time. ([`d7d441a`](https://github.com/irtnog/lethbridge/commit/d7d441a18c174a4937dedb593f3a324b79bdcc7b))
* refactor(database): remove unused imports ([`cb5fe6a`](https://github.com/irtnog/lethbridge/commit/cb5fe6a28a49059cc2ca6c54cf683b600480c390))
* refactor(cli): break apart long string contants ([`344e6e1`](https://github.com/irtnog/lethbridge/commit/344e6e1f54542f10d03a6a3b372e9ae1a31bbc80))
* refactor(cli): simplify submodule loading ([`bae4188`](https://github.com/irtnog/lethbridge/commit/bae4188a05b809838ff36076635d32809b81be10))
* refactor(docker): optimize the build with better cache management ([`9869a96`](https://github.com/irtnog/lethbridge/commit/9869a96a493a4c0e7dd3c5bc2d6d0066938fcba0))
* refactor(docker): switch to composite Compose files
This enables overriding configuration items like port mappings:
https://stackoverflow.com/questions/48851190/docker-compose-override-a-ports-property-instead-of-merging-it
https://mindbyte.nl/2018/04/04/overwrite-ports-in-docker-compose.html ([`c51727e`](https://github.com/irtnog/lethbridge/commit/c51727e31db84b44c4dfaffa6ade026b82d0784f))
* refactor(docker): re-arrange layers in the build environment to cleanly separate test resources ([`72ea6a2`](https://github.com/irtnog/lethbridge/commit/72ea6a25454389ccfb0d2d832755e3d4f395ace5))
* refactor(cli): switch to a declarative logging configuration ([`9522726`](https://github.com/irtnog/lethbridge/commit/9522726be9d424dcbf18839a9021c00d76ad9dc3))
Test
* test(cli): add more data to the Spansh import integration test ([`19a1209`](https://github.com/irtnog/lethbridge/commit/19a1209444310e445db8c357f87e18688da3cb2c))
* test(schema): add a smaller galaxy data fixture to speed up Spansh schema testing ([`f9d6ee2`](https://github.com/irtnog/lethbridge/commit/f9d6ee2429554f054c3ceb3aa93d6ad9dc7f153e))
* test(schema): make sure the System actually deserialized properly when getting and dumping it ([`3ede652`](https://github.com/irtnog/lethbridge/commit/3ede65263c876e7b54ed5e525b5ea2021715015b))
* test(schemas): suppress approximate match warnings ([`0913087`](https://github.com/irtnog/lethbridge/commit/09130876e37e9fa0cc74bf26ec46a07e7071912d))
* test: run CLI tests last since they&39;re more properly integration tests ([`2979650`](https://github.com/irtnog/lethbridge/commit/29796506e40e6daa6fe327aa962b77febc8c78f6))
* test(database): capture &34;approximately equal&34; warnings ([`9286334`](https://github.com/irtnog/lethbridge/commit/92863349795bcf9e8ed3a67a393a6ba8b35bd03d))
* test(database): check the station outfitting model ([`6a02351`](https://github.com/irtnog/lethbridge/commit/6a023519a83b4728f9e7cefa57ffe4ba4e65e261))
* test(database): simplify the test station ([`c296485`](https://github.com/irtnog/lethbridge/commit/c296485aa22414ca15e21223cfbda89c65bdd420))
* test(database): check the station model ([`cffec43`](https://github.com/irtnog/lethbridge/commit/cffec43689493ed63c24376d5744f577f82ee990))
* test(cli): inline function args ([`f27e947`](https://github.com/irtnog/lethbridge/commit/f27e9473cd5fa8982fee9b90b51c089c8f4a46ae))
* test: mark slow tests so they can be skipped if desired ([`a8274d9`](https://github.com/irtnog/lethbridge/commit/a8274d9b533d4b5366049c2afa9931ac6236f51d))
* test: only generate the fixture corresponding to the mock_db_uri param
Previously, this was generating both
[postgresql](https://pypi.org/project/pytest-postgresql/) and
[tmp_path](https://docs.pytest.org/en/7.1.x/how-to/tmp_path.html) for
both fixture params, when really we wanted one or the other. ([`dbc4f36`](https://github.com/irtnog/lethbridge/commit/dbc4f36f86c2b732546db76f4f4690d76fd4f582))
* test: reconfigure smoke tests to use SQLite ([`3ad2637`](https://github.com/irtnog/lethbridge/commit/3ad263705159763c0e5de5e0f036b9853101a126))
* test: run cli tests after config, database tests but before schema tests
The cli tests exercise config, database, and schema functionality, but
since their test parameters are simpler, they function like smoke
tests for the much more complex schema tests. ([`8e65569`](https://github.com/irtnog/lethbridge/commit/8e65569500bf2f98a4593d633b404ba128fe15f8))
* test(cli): verify that Spansh imports work properly ([`a53463f`](https://github.com/irtnog/lethbridge/commit/a53463fe7de882812c1c8299dbc3e13f90480a3e))
* test(cli): verify that database schema migrations work properly ([`480a80c`](https://github.com/irtnog/lethbridge/commit/480a80cfa210723941abfa9084d160c14f450e0a))
* test: make mock_config_file available for integration tests ([`7de80f0`](https://github.com/irtnog/lethbridge/commit/7de80f0d3cc80fbeb632d1c256b0e9d5e186872d))
* test: increase the scope of the mock galaxy data fixture ([`65d263e`](https://github.com/irtnog/lethbridge/commit/65d263e777f0e67e7311c1e3301ab47416d600aa))
* test: convert mock galaxy data back into Spansh format for future integration testing ([`ad7a6f3`](https://github.com/irtnog/lethbridge/commit/ad7a6f3ea6364ef6b4e413d133f2f3a3d89a111f))
* test: switch to new mock database session with the schema already applied ([`49ca0f0`](https://github.com/irtnog/lethbridge/commit/49ca0f0d372de184d728764b5ea24a7e95d0bd74))
* test(cli): move configuration CLI tests to separate file ([`1dce5ec`](https://github.com/irtnog/lethbridge/commit/1dce5ecb805831cbfc57756815e2e46eac223abd))
* test: add Thargoid stronghold system to test data ([`2132e5e`](https://github.com/irtnog/lethbridge/commit/2132e5e5469958f197674082539662431d531e0b))