Compare commits
4 commits
92678ea6bf
...
main
Author | SHA1 | Date | |
---|---|---|---|
6df22f8cd5 | |||
03dd1a485d | |||
b0f8c48e99 | |||
031145db01 |
7 changed files with 210 additions and 33 deletions
86
.woodpecker.yml
Normal file
86
.woodpecker.yml
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
branches: main
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
code_lint:
|
||||||
|
image: python
|
||||||
|
commands:
|
||||||
|
- pip install poetry
|
||||||
|
- poetry install
|
||||||
|
- pip install black
|
||||||
|
- echo "----------------- running lint ------------------"
|
||||||
|
- python --version && poetry --version && black --version
|
||||||
|
- poetry run black .
|
||||||
|
|
||||||
|
unit_tests:
|
||||||
|
image: thekevjames/nox
|
||||||
|
commands:
|
||||||
|
- pip install poetry
|
||||||
|
- poetry install
|
||||||
|
- echo "----------------- running tests ------------------"
|
||||||
|
- python --version && poetry --version && nox --version
|
||||||
|
- poetry run nox
|
||||||
|
|
||||||
|
static_analysis:
|
||||||
|
image: python
|
||||||
|
commands:
|
||||||
|
- pip install poetry
|
||||||
|
- poetry install
|
||||||
|
- pip install mypy
|
||||||
|
- echo "----------------- running analysis ------------------"
|
||||||
|
- python --version && poetry --version && mypy --version
|
||||||
|
- poetry run mypy .
|
||||||
|
|
||||||
|
build_dist:
|
||||||
|
image: python
|
||||||
|
commands:
|
||||||
|
- pip install poetry
|
||||||
|
- poetry install
|
||||||
|
- echo "----------------- running analysis ------------------"
|
||||||
|
- python --version && poetry --version
|
||||||
|
- poetry build
|
||||||
|
when:
|
||||||
|
branch: main
|
||||||
|
|
||||||
|
release_prep:
|
||||||
|
image: python
|
||||||
|
commands:
|
||||||
|
- echo "----------------- preparing release ------------------"
|
||||||
|
- python tools/extract-changelog.py
|
||||||
|
|
||||||
|
gitea_release:
|
||||||
|
image: plugins/gitea-release
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: gitea_release_token
|
||||||
|
base_url: https://git.martyoeh.me
|
||||||
|
files: dist/*
|
||||||
|
title: NEWEST_VERSION.md
|
||||||
|
note: NEWEST_CHANGES.md
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
tag: v*
|
||||||
|
|
||||||
|
pypi_release:
|
||||||
|
image: python
|
||||||
|
commands:
|
||||||
|
- pip install poetry
|
||||||
|
- poetry install
|
||||||
|
- echo "----------------- publishing to pypi ------------------"
|
||||||
|
- poetry publish --username "$PYPI_USERNAME" --password "$PYPI_PASSWORD"
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
tag: v*
|
||||||
|
|
||||||
|
notify_matrix:
|
||||||
|
image: plugins/matrix
|
||||||
|
settings:
|
||||||
|
homeserver: https://matrix.org
|
||||||
|
roomid:
|
||||||
|
from_secret: matrix_roomid
|
||||||
|
userid:
|
||||||
|
from_secret: matrix_userid
|
||||||
|
accesstoken:
|
||||||
|
from_secret: matrix_token
|
||||||
|
when:
|
||||||
|
status: [ success, failure ]
|
||||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -5,13 +5,19 @@ 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.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project tries to adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project tries to adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
<!-- ## [Unreleased] -->
|
||||||
|
|
||||||
|
## [0.4.1] - 2022-01-05
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added pypi release publication
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
* Compatible with Python stretching back to version 3.7
|
* Compatible with Python stretching back to version 3.7
|
||||||
|
|
||||||
## [0.4] - 2021-12-06
|
## [0.4.0] - 2021-12-06
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
|
67
README.md
67
README.md
|
@ -1,15 +1,34 @@
|
||||||
# habit-migrate
|
# habitmove
|
||||||
|
|
||||||
Can take an export of nomie habits in json format and convert it to be importable in Loop Habit Tracker.
|
Takes habit in one habit-tracking application and transforms them ready to use for another.
|
||||||
|
|
||||||
Confirmed working for nomie version 5.6.4 and Loop Habit Tracker version 2.0.2.
|
Currently can take an export of nomie habits in json format and convert it to be importable in Loop Habit Tracker.
|
||||||
|
Plans for reverse migration are on the roadmap, and ultimately this tool ideally understands more and more habit formats to prevent app lock-in.
|
||||||
|
|
||||||
|
Confirmed working for nomie version 5.6.4 and Loop Habit Tracker version 2.0.2 and 2.0.3.
|
||||||
Presumably works for other nomie 5.x versions and other Loop 2.x versions as well,
|
Presumably works for other nomie 5.x versions and other Loop 2.x versions as well,
|
||||||
but that is untested.
|
but that is untested.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Installation can be accomplished through *pip*:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install habitmove
|
||||||
|
```
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
`habitmove` requires at least Python 3.7.
|
||||||
|
It has only been tested on GNU/Linux (amd64) though it should work on other platforms.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Run as a commandline utility habit migrate currently takes a single argument, the nomie database `.json` file.
|
Run as a cli utility `habitmove` currently takes a single argument: the nomie database `.json` file to import habits from.
|
||||||
The output as importable Loop Habit Tracker database will be written to `output.db` in present working directory.
|
|
||||||
|
Invoked like: `habitmove nomie-export.json`.
|
||||||
|
|
||||||
|
The output as a Loop Habit Tracker database will be written to `output.db` in the present working directory.
|
||||||
|
|
||||||
Can also take an existing Loop Habit database (exported from the application),
|
Can also take an existing Loop Habit database (exported from the application),
|
||||||
and add the nomie exported habits and checkmarks to it.
|
and add the nomie exported habits and checkmarks to it.
|
||||||
|
@ -18,34 +37,28 @@ it will not (should not™️) overwrite anything.
|
||||||
If there are any duplicated habits however,
|
If there are any duplicated habits however,
|
||||||
it will add duplications of the existing repetitions into the database.
|
it will add duplications of the existing repetitions into the database.
|
||||||
|
|
||||||
Invoked like: `python run.py nomie-export.json`.
|
## Development
|
||||||
Note, however, that -- until a packaged version is released -- you will need to have some packages in your environment.
|
|
||||||
If you wish to run it un-packaged, install [poetry](https://python-poetry.org/) and let it do all dependency management by doing:
|
|
||||||
|
|
||||||
```
|
To enable easy development on the app,
|
||||||
|
install [poetry](https://python-poetry.org/) and let it do all dependency management for you by doing:
|
||||||
|
|
||||||
|
```bash
|
||||||
poetry install
|
poetry install
|
||||||
poetry run habitmove <nomie-json>
|
poetry run habitmove <nomie-json>
|
||||||
```
|
```
|
||||||
|
|
||||||
In the future there might be an easier road to using this package but that's the way it is for now.
|
To see a set up more closely resembling the final cli environment,
|
||||||
|
with its libraries loaded as environmental dependencies enter the poetry shell:
|
||||||
|
|
||||||
The package can also be used as a library to load nomie data
|
```bash
|
||||||
or move data into Loop Habit Tracker.
|
poetry shell
|
||||||
|
```
|
||||||
|
|
||||||
|
The package can eventually also be used as a library to load nomie data to work with in Python,
|
||||||
|
or to move data into Loop Habit Tracker.
|
||||||
|
Take a look at the `Parser` and `Transformer` interfaces respectively.
|
||||||
|
|
||||||
## Roadmap
|
To run tests for the app, simply invoke `pytest` through `poetry run pytest` or from within the `poetry shell`.
|
||||||
|
To run larger scale test automation, make sure you habe nox installed and run `poetry run ` or again through the shell.
|
||||||
* [ ] clean up README
|
|
||||||
* [x] begin adding tests
|
|
||||||
* [x] add some unit tests for various functions
|
|
||||||
* [ ] and at least an integration test for the stable database (loop-2021-12-02.db or equivalent)
|
|
||||||
* [ ] test most components
|
|
||||||
* [ ] abstract migration target away from loop
|
|
||||||
* [ ] abstract import away from nomie
|
|
||||||
* [ ] abstract importer/migrator themselves to work with other targets
|
|
||||||
* [ ] allow migration to/from nomie/loop
|
|
||||||
* [ ] cmdline options for
|
|
||||||
* [ ] ignoring/adding/overwriting duplicated timestamps
|
|
||||||
* [ ] output file
|
|
||||||
* [ ] from/to
|
|
||||||
|
|
||||||
|
You can exclude integration tests that take longer and inspect the complete database output of the program through the parameters `-m "not e2e"` for both `pytest` and `nox` (which also does it automatically).
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "habitmove"
|
name = "habitmove"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
description = "migrate nomie data to loop habits tracker"
|
description = "migrate nomie data to loop habits tracker"
|
||||||
|
license="GPL-3.0-only"
|
||||||
|
readme="README.md"
|
||||||
|
repository="https://git.martyoeh.me/Marty/habit-migrate"
|
||||||
authors = ["Marty Oehme <marty.oehme@gmail.com>"]
|
authors = ["Marty Oehme <marty.oehme@gmail.com>"]
|
||||||
packages = [
|
packages = [
|
||||||
{ include = "habitmove", from = "src"},
|
{ include = "habitmove", from = "src"},
|
||||||
|
@ -35,3 +38,13 @@ show_missing = true
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
|
[[tool.mypy.overrides]]
|
||||||
|
module = [
|
||||||
|
"click",
|
||||||
|
"click.testing",
|
||||||
|
"pytest",
|
||||||
|
"nox",
|
||||||
|
"importlib-metadata"
|
||||||
|
]
|
||||||
|
ignore_missing_imports = true
|
||||||
|
|
|
@ -4,6 +4,6 @@ import sys
|
||||||
try:
|
try:
|
||||||
from importlib.metadata import version as metadata_version
|
from importlib.metadata import version as metadata_version
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from importlib_metadata import version as metadata_version
|
from importlib_metadata import version as metadata_version # type: ignore
|
||||||
|
|
||||||
__version__ = str(metadata_version(__name__))
|
__version__ = str(metadata_version(__name__))
|
||||||
|
|
|
@ -55,10 +55,11 @@ def habit_list_add_ids(c: sqlite3.Cursor, habitlist: list[Habit]) -> dict[int, H
|
||||||
:return habit_id_dict: The habit collection as a dict with the keys
|
:return habit_id_dict: The habit collection as a dict with the keys
|
||||||
consisting of the habit's sqlite database ID.
|
consisting of the habit's sqlite database ID.
|
||||||
"""
|
"""
|
||||||
with_id = {}
|
with_id: dict[int, Habit] = {}
|
||||||
for h in habitlist:
|
for h in habitlist:
|
||||||
sql_id = fetch_habit_id(c, h.uuid or "")
|
sql_id = fetch_habit_id(c, h.uuid or "")
|
||||||
with_id[sql_id] = h
|
if sql_id is not None:
|
||||||
|
with_id[sql_id] = h
|
||||||
|
|
||||||
return with_id
|
return with_id
|
||||||
|
|
||||||
|
@ -74,6 +75,8 @@ def fetch_habit_id(cursor: sqlite3.Cursor, uuid: str) -> Optional[int]:
|
||||||
if id is not None:
|
if id is not None:
|
||||||
return id[0]
|
return id[0]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def add_to_database(
|
def add_to_database(
|
||||||
cursor: sqlite3.Cursor, habits: dict[int, Habit], repetition: Repetition
|
cursor: sqlite3.Cursor, habits: dict[int, Habit], repetition: Repetition
|
||||||
|
|
56
tools/extract-changelog.py
Normal file
56
tools/extract-changelog.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
## Extracts the version and newest changes from a semantic changelog.
|
||||||
|
#
|
||||||
|
# Important, it only works with three-parted version numbers
|
||||||
|
# a-la 1.2.3 or 313.01.1888 -- needs \d.\d.\d to work.
|
||||||
|
#
|
||||||
|
# The version number and changeset will be put in `NEWEST_VERSION.md`
|
||||||
|
# and `NEWEST_CHANGES.md` respectively, for further use in releases.
|
||||||
|
OUTPUT_FILE_VERSION = "NEWEST_VERSION.md"
|
||||||
|
OUTPUT_FILE_CHANGES = "NEWEST_CHANGES.md"
|
||||||
|
|
||||||
|
|
||||||
|
def getVersion(file):
|
||||||
|
for line in file:
|
||||||
|
m = re.match(r"^## \[(\d+\.\d+\.\d+)\]", line)
|
||||||
|
if m and m.group(1):
|
||||||
|
return m.group(1)
|
||||||
|
|
||||||
|
|
||||||
|
def getSection(file):
|
||||||
|
inRecordingMode = False
|
||||||
|
for line in file:
|
||||||
|
if not inRecordingMode:
|
||||||
|
if re.match(r"^## \[\d+\.\d+\.\d+\]", line):
|
||||||
|
inRecordingMode = True
|
||||||
|
elif re.match(r"^## \[\d+\.\d+\.\d+\]", line):
|
||||||
|
inRecordingMode = False
|
||||||
|
break
|
||||||
|
elif re.match(r"^$", line):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
yield line
|
||||||
|
|
||||||
|
|
||||||
|
def toFile(fname, content):
|
||||||
|
file = open(fname, "w")
|
||||||
|
file.write(content)
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
|
with open("CHANGELOG.md") as file:
|
||||||
|
title = getVersion(file)
|
||||||
|
print(title)
|
||||||
|
toFile(OUTPUT_FILE_VERSION, title)
|
||||||
|
|
||||||
|
with open("CHANGELOG.md") as file:
|
||||||
|
newest_changes_gen = getSection(file)
|
||||||
|
newest_changes = ""
|
||||||
|
for line in newest_changes_gen:
|
||||||
|
newest_changes += line
|
||||||
|
print("[Extracted Changelog]")
|
||||||
|
print(newest_changes)
|
||||||
|
toFile(OUTPUT_FILE_CHANGES, newest_changes)
|
||||||
|
|
||||||
|
file.close()
|
Loading…
Reference in a new issue