mirror of
https://github.com/jrnl-org/jrnl.git
synced 2025-05-10 16:48:31 +02:00
Compare commits
264 commits
Author | SHA1 | Date | |
---|---|---|---|
|
7923e815f7 | ||
|
72d4968471 | ||
|
c286012bef | ||
|
c415c68443 | ||
|
e5fc8be2a8 | ||
|
20a087f64c | ||
|
a2eb68963b | ||
|
89be61ccf8 | ||
|
98d0bcac20 | ||
|
a282440118 | ||
|
7e72386da1 | ||
|
6f1e8e5853 | ||
|
906a3fed78 | ||
|
8329cf5537 | ||
|
1dd2d48068 | ||
|
43310f399d | ||
|
591f2457c3 | ||
|
8be5b722aa | ||
|
7249adb232 | ||
|
fbd1b9e78b | ||
|
2581c43ae7 | ||
|
2035619587 | ||
|
37f634ac80 | ||
|
d1e3e546f2 | ||
|
f8d80b2877 | ||
|
8589b2ed65 | ||
|
6645b1e36f | ||
|
316b9761d5 | ||
|
e2a62e99a0 | ||
|
692d0cb132 | ||
|
573e34fb48 | ||
|
f2bb5eb501 | ||
|
7ad6fca011 | ||
|
640150bcbe | ||
|
75c98a408c | ||
|
b8a8de98c3 | ||
|
85eb730186 | ||
|
024ea00a95 | ||
|
1530ad39a1 | ||
|
505a9b6846 | ||
|
30c341ef8b | ||
|
ccb64b1721 | ||
|
a1b3a612a5 | ||
|
247129c760 | ||
|
bb71dff815 | ||
|
ba18bed4d7 | ||
|
eb5fe6fef1 | ||
|
16a0f043b1 | ||
|
b760759906 | ||
|
2ce567e495 | ||
|
1143fba023 | ||
|
41279ae943 | ||
|
985187f866 | ||
|
53fef9021d | ||
|
df4a5a5867 | ||
|
3f3bf3e77e | ||
|
1b79f0b340 | ||
|
428549778c | ||
|
d9dae7af04 | ||
|
5f6be07fbd | ||
|
a94f7c6161 | ||
|
086c34a6a7 | ||
|
0044b2dee8 | ||
|
0cc4acd494 | ||
|
0d5bf1e467 | ||
|
85a98afcd9 | ||
|
96d89ca9d5 | ||
|
de79733957 | ||
|
af1b9f128e | ||
|
5145190584 | ||
|
314576ae13 | ||
|
87c022780d | ||
|
a8bd0bcd44 | ||
|
2f0c5d2eb9 | ||
|
ae32ca6917 | ||
|
5856517b0f | ||
|
1586cc2b49 | ||
|
bcf41ddd17 | ||
|
4017c4acb5 | ||
|
a646801c15 | ||
|
cb504c4bfb | ||
|
21e4552360 | ||
|
cdb9a220bd | ||
|
2d3809e6f7 | ||
|
0ff69bd24c | ||
|
dec4855816 | ||
|
89eaf3440a | ||
|
7953309c78 | ||
|
17e1ba60e5 | ||
|
4d84c491f1 | ||
|
79cf67eca6 | ||
|
c8c49b1ba2 | ||
|
8f2cb9c355 | ||
|
9ac27704fb | ||
|
97b39dfd76 | ||
|
8fc158e35b | ||
|
83d4878044 | ||
|
c9c71b40ef | ||
|
8cd4ac24a8 | ||
|
ca6b4a08a7 | ||
|
be9dbf52e0 | ||
|
4c4e36a534 | ||
|
7c4e3ad76e | ||
|
0c2c40d494 | ||
|
ecf5f07dbb | ||
|
8957ceb74d | ||
|
0deadc03c8 | ||
|
d5a5401db9 | ||
|
0aefdb3f21 | ||
|
9ad1c9f26b | ||
|
48b61f6953 | ||
|
2af05e4008 | ||
|
a13abe446b | ||
|
5ce9d47126 | ||
|
581af57bfd | ||
|
60abba3bfe | ||
|
5323ca64fa | ||
|
1b2fa594e8 | ||
|
36677fdccd | ||
|
896be7fb5f | ||
|
a2a6618959 | ||
|
39291bf1ce | ||
|
fbd468e03e | ||
|
d91c857fdc | ||
|
8eb124b54c | ||
|
f3624a3fa2 | ||
|
de4cf5219e | ||
|
7fdc43b69d | ||
|
df37641fa8 | ||
|
8edc14cfe7 | ||
|
8f2ac67659 | ||
|
c5ba4cb198 | ||
|
d44515f764 | ||
|
ccd68f1e78 | ||
|
fc16c6c3e8 | ||
|
b4e8bb0e12 | ||
|
5ca5ee6723 | ||
|
ce50158167 | ||
|
d5f7182cf4 | ||
|
9d97df04a7 | ||
|
bf32d59844 | ||
|
caf3cdea3d | ||
|
434c32003f | ||
|
48a31e8154 | ||
|
3fe3eda27b | ||
|
65070cb675 | ||
|
311d0b51b6 | ||
|
aca0a185b7 | ||
|
14bf9ac55f | ||
|
cf145123f5 | ||
|
c2a97f3100 | ||
|
296c459252 | ||
|
a176913bda | ||
|
721167a079 | ||
|
7e94208574 | ||
|
ef016cfb76 | ||
|
c2cbf36a87 | ||
|
6379533065 | ||
|
eec83daaf5 | ||
|
00a6724900 | ||
|
69e098d6e5 | ||
|
5bf24d6eac | ||
|
b6f1e76ae4 | ||
|
1fdb76008e | ||
|
681b477543 | ||
|
c2fa27329c | ||
|
299bf090fc | ||
|
a8f5f54a62 | ||
|
75f97ce32f | ||
|
09a96e6db9 | ||
|
f9558f960a | ||
|
1de94ca929 | ||
|
b639915fd4 | ||
|
12525e21ec | ||
|
3177578c64 | ||
|
4ea2fa8c31 | ||
|
a1c24359d2 | ||
|
6529fbf211 | ||
|
d881880c38 | ||
|
0a01420e9d | ||
|
c6f22a2753 | ||
|
c7b204022a | ||
|
1c7ad4d5bb | ||
|
be4cc1abe8 | ||
|
4969d28988 | ||
|
6962c399ea | ||
|
9533b55d8f | ||
|
c4d7f37cc2 | ||
|
5c4724d524 | ||
|
dfdd9b69cb | ||
|
475923d6d5 | ||
|
2674639383 | ||
|
d2fc602618 | ||
|
85bd7d40a5 | ||
|
303ca98d0b | ||
|
c63367b067 | ||
|
42ac0d33cc | ||
|
2a59c708b2 | ||
|
75b703d39f | ||
|
0f4fdf89b2 | ||
|
d2756db940 | ||
|
cfcbd8e6b7 | ||
|
cb69bb474c | ||
|
525cce3e92 | ||
|
cf6aef7ae0 | ||
|
b77ea37b2c | ||
|
488998cd33 | ||
|
f5378dea74 | ||
|
23b169708c | ||
|
b899130009 | ||
|
bb838ed83a | ||
|
4c53cd8830 | ||
|
1aa1ac0976 | ||
|
f4db877ddd | ||
|
0da41a1328 | ||
|
9970873ff5 | ||
|
129428ef80 | ||
|
e1501fd4d1 | ||
|
34c7903300 | ||
|
dd09ece4e7 | ||
|
c6b9114c42 | ||
|
7a9bc929a5 | ||
|
235ba679e3 | ||
|
32f7b9de62 | ||
|
9735a60883 | ||
|
b4088bf8b8 | ||
|
a1de9589b5 | ||
|
875b6d2b35 | ||
|
12355e087c | ||
|
6e8d6e9aee | ||
|
2a05aad0e9 | ||
|
4f1a21819d | ||
|
12e663ee93 | ||
|
9edc7c5cc0 | ||
|
793a5e22c5 | ||
|
10cf68161e | ||
|
21c4aa0b3a | ||
|
649254d0ac | ||
|
f5dc5fbae0 | ||
|
5124a805c8 | ||
|
982e597742 | ||
|
4a7057c038 | ||
|
78d11d74bd | ||
|
b1843ab14b | ||
|
4cb5d1e436 | ||
|
959e18ad91 | ||
|
4292d85a22 | ||
|
9f4ca2683f | ||
|
3e44027ab5 | ||
|
98d2a3b3ec | ||
|
0d8fc9028c | ||
|
f5e5d817be | ||
|
d5f00edb9d | ||
|
6e9fade8dd | ||
|
7045e97a24 | ||
|
fdc87ff8c4 | ||
|
81313c2445 | ||
|
0b8b4244bd | ||
|
7a8b86aadb | ||
|
1f59c15f5e | ||
|
da0c49da83 | ||
|
8f2eb27793 | ||
|
a1a68f7eea | ||
|
cd850c068d |
70 changed files with 2329 additions and 1743 deletions
7
.github/actions/run_tests/action.yaml
vendored
7
.github/actions/run_tests/action.yaml
vendored
|
@ -11,16 +11,17 @@ runs:
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
allow-prereleases: true
|
||||||
|
|
||||||
- name: Capture full Python version in env
|
- name: Capture full Python version in env
|
||||||
run: echo "PYTHON_FULL_VERSION=$(python --version)" >> $GITHUB_ENV
|
run: echo "PYTHON_FULL_VERSION=$(python --version)" >> $GITHUB_ENV
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: poetry cache # Change CACHE_STRING secret to bust the cache
|
- name: poetry cache # Change CACHE_STRING secret to bust the cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .venv
|
path: .venv
|
||||||
key: ${{ runner.os }}-${{ hashFiles('poetry.lock') }}-${{ env.PYTHON_FULL_VERSION }}-${{ inputs.cache-string }}
|
key: ${{ runner.os }}-${{ hashFiles('poetry.lock') }}-${{ env.PYTHON_FULL_VERSION }}-${{ inputs.cache-string }}
|
||||||
|
@ -33,7 +34,7 @@ runs:
|
||||||
echo '::endgroup::'
|
echo '::endgroup::'
|
||||||
|
|
||||||
echo '::group::Other dependencies'
|
echo '::group::Other dependencies'
|
||||||
poetry install --remove-untracked
|
poetry sync
|
||||||
echo '::endgroup::'
|
echo '::endgroup::'
|
||||||
|
|
||||||
echo 'DEPS_INSTALLED=true' >> $GITHUB_ENV
|
echo 'DEPS_INSTALLED=true' >> $GITHUB_ENV
|
||||||
|
|
4
.github/workflows/changelog.yaml
vendored
4
.github/workflows/changelog.yaml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.JRNL_BOT_TOKEN }}
|
token: ${{ secrets.JRNL_BOT_TOKEN }}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ jobs:
|
||||||
|
|
||||||
if [[ "$(git rev-parse "origin/$BRANCH")" != "$GITHUB_SHA" ]]; then
|
if [[ "$(git rev-parse "origin/$BRANCH")" != "$GITHUB_SHA" ]]; then
|
||||||
# Normal build on a branch (no tag)
|
# Normal build on a branch (no tag)
|
||||||
echo "::debug::BRANCH: $BRANCH $(git rev-parse origin/$BRANCH)"
|
echo "::debug::BRANCH: $BRANCH $(git rev-parse "origin/$BRANCH")"
|
||||||
echo "::debug::GITHUB_SHA: $GITHUB_SHA"
|
echo "::debug::GITHUB_SHA: $GITHUB_SHA"
|
||||||
echo "::error::$BRANCH has been updated since build started. Aborting changelog."
|
echo "::error::$BRANCH has been updated since build started. Aborting changelog."
|
||||||
exit 1
|
exit 1
|
||||||
|
|
10
.github/workflows/docs.yaml
vendored
10
.github/workflows/docs.yaml
vendored
|
@ -36,10 +36,10 @@ jobs:
|
||||||
os: [ ubuntu-latest ]
|
os: [ ubuntu-latest ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
@ -50,13 +50,13 @@ jobs:
|
||||||
run: echo "PYTHON_FULL_VERSION=$(python --version)" >> "$GITHUB_ENV"
|
run: echo "PYTHON_FULL_VERSION=$(python --version)" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: poetry cache
|
- name: poetry cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .venv
|
path: .venv
|
||||||
key: ${{ runner.os }}-${{ hashFiles('poetry.lock') }}-${{ env.PYTHON_FULL_VERSION }}-${{ secrets.CACHE_STRING }}
|
key: ${{ runner.os }}-${{ hashFiles('poetry.lock') }}-${{ env.PYTHON_FULL_VERSION }}-${{ secrets.CACHE_STRING }}
|
||||||
|
|
||||||
- name: npm cache
|
- name: npm cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: node_modules
|
path: node_modules
|
||||||
key: ${{ runner.os }}-pa11y-v3
|
key: ${{ runner.os }}-pa11y-v3
|
||||||
|
@ -65,7 +65,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
pip install poetry
|
pip install poetry
|
||||||
poetry config --local virtualenvs.in-project true
|
poetry config --local virtualenvs.in-project true
|
||||||
poetry install --no-root --remove-untracked
|
poetry sync --no-root
|
||||||
npm install
|
npm install
|
||||||
echo "node_modules/.bin" >> "$GITHUB_PATH"
|
echo "node_modules/.bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
|
|
119
.github/workflows/release.yaml
vendored
119
.github/workflows/release.yaml
vendored
|
@ -19,11 +19,6 @@ on:
|
||||||
type: boolean
|
type: boolean
|
||||||
required: true
|
required: true
|
||||||
default: true
|
default: true
|
||||||
include_brew:
|
|
||||||
description: 'Publish to Homebrew?'
|
|
||||||
type: boolean
|
|
||||||
required: true
|
|
||||||
default: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
validate:
|
validate:
|
||||||
|
@ -66,12 +61,12 @@ jobs:
|
||||||
echo "JRNL_VERSION=$JRNL_VERSION" >> "$GITHUB_ENV"
|
echo "JRNL_VERSION=$JRNL_VERSION" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.11'
|
python-version: '3.13'
|
||||||
|
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.JRNL_BOT_TOKEN }}
|
token: ${{ secrets.JRNL_BOT_TOKEN }}
|
||||||
|
|
||||||
|
@ -112,111 +107,3 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
pypi_version="$(find dist/jrnl-*.tar.gz | sed -r 's!dist/jrnl-(.*)\.tar\.gz!\1!')"
|
pypi_version="$(find dist/jrnl-*.tar.gz | sed -r 's!dist/jrnl-(.*)\.tar\.gz!\1!')"
|
||||||
echo "pypi_version=$pypi_version" >> "$GITHUB_OUTPUT"
|
echo "pypi_version=$pypi_version" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
release_homebrew:
|
|
||||||
if: ${{ github.event.inputs.include_brew == 'true' }}
|
|
||||||
needs: release_pypi
|
|
||||||
name: "Release to Homebrew"
|
|
||||||
runs-on: macos-latest
|
|
||||||
env:
|
|
||||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
|
||||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
|
||||||
HOME_REPO: ${{ secrets.HOME_REPO }}
|
|
||||||
steps:
|
|
||||||
- name: Get version
|
|
||||||
run: |
|
|
||||||
JRNL_VERSION="${{ github.event.inputs.version }}"
|
|
||||||
PYPI_VERSION="${{ needs.release_pypi.outputs.pypi_version }}"
|
|
||||||
|
|
||||||
echo "::debug::jrnl version: $JRNL_VERSION"
|
|
||||||
echo "::debug::pypi version: $PYPI_VERSION"
|
|
||||||
|
|
||||||
echo "JRNL_VERSION=$JRNL_VERSION" >> "$GITHUB_ENV"
|
|
||||||
echo "PYPI_VERSION=$PYPI_VERSION" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Set env variables
|
|
||||||
env:
|
|
||||||
REPO_OWNER: ${{ github.repository_owner }}
|
|
||||||
run: |
|
|
||||||
if [[ $JRNL_VERSION =~ (alpha|beta) ]]; then
|
|
||||||
echo '::debug::Prerelease (not a full release)'
|
|
||||||
{
|
|
||||||
echo "RELEASE_TYPE=pre"
|
|
||||||
echo "FORMULA_REPO=${REPO_OWNER}/homebrew-prerelease"
|
|
||||||
echo "BOT_REPO=jrnl-bot/homebrew-prerelease"
|
|
||||||
echo "FORMULA_NAME=jrnl-beta"
|
|
||||||
} >> "$GITHUB_ENV"
|
|
||||||
else
|
|
||||||
echo '::debug::Full release (not a prerelease)'
|
|
||||||
if [[ "${{ github.repository }}" == "${HOME_REPO}" ]]; then
|
|
||||||
REPO_OWNER="homebrew"
|
|
||||||
fi
|
|
||||||
{
|
|
||||||
echo "RELEASE_TYPE=full"
|
|
||||||
echo "FORMULA_REPO=${REPO_OWNER}/homebrew-core"
|
|
||||||
echo "BOT_REPO=jrnl-bot/homebrew-core"
|
|
||||||
echo "FORMULA_NAME=jrnl"
|
|
||||||
} >> "$GITHUB_ENV"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Tap formula
|
|
||||||
run: |
|
|
||||||
brew tap "${FORMULA_REPO}"
|
|
||||||
echo '::debug::Set tap directory'
|
|
||||||
echo "BREW_TAP_DIRECTORY=$(brew --repo "${FORMULA_REPO}")" >> "$GITHUB_ENV"
|
|
||||||
- name: Install dependencies
|
|
||||||
run: brew install pipgrip
|
|
||||||
|
|
||||||
- name: Query PyPI API
|
|
||||||
uses: nick-invision/retry@v2
|
|
||||||
with:
|
|
||||||
timeout_seconds: 10
|
|
||||||
max_attempts: 30
|
|
||||||
retry_wait_seconds: 10
|
|
||||||
command: |
|
|
||||||
curl -Ls https://pypi.org/pypi/jrnl/json > api_response.json
|
|
||||||
# if query doesn't have our version yet, give it some time before trying again
|
|
||||||
if [[ "null" == "$(jq ".releases[\"${PYPI_VERSION}\"][1].url" -r api_response.json)" ]]; then
|
|
||||||
echo "::debug::PYPI_VERSION: $PYPI_VERSION"
|
|
||||||
echo "::debug::JQ VALUE: $(jq ".releases[\"${PYPI_VERSION}\"][1].url" -r api_response.json)"
|
|
||||||
echo "::group::cat api_response.json"
|
|
||||||
cat api_response.json
|
|
||||||
echo "::endgroup::"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Update Homebrew Formula
|
|
||||||
uses: nick-invision/retry@v2
|
|
||||||
with:
|
|
||||||
timeout_minutes: 8
|
|
||||||
max_attempts: 6
|
|
||||||
retry_wait_seconds: 30
|
|
||||||
command: >
|
|
||||||
brew bump-formula-pr "${FORMULA_NAME}"
|
|
||||||
--url $(jq ".releases[\"${PYPI_VERSION}\"][1].url" -r api_response.json)
|
|
||||||
--sha256 $(jq ".releases[\"${PYPI_VERSION}\"][1].digests.sha256" -r api_response.json)
|
|
||||||
--no-audit
|
|
||||||
--write-only
|
|
||||||
--force
|
|
||||||
|
|
||||||
- name: Create Pull Request
|
|
||||||
uses: peter-evans/create-pull-request@v4
|
|
||||||
with:
|
|
||||||
path: ${{ env.BREW_TAP_DIRECTORY }}
|
|
||||||
token: ${{ secrets.JRNL_BOT_TOKEN }}
|
|
||||||
push-to-fork: ${{ env.BOT_REPO }}
|
|
||||||
|
|
||||||
committer: ${{ secrets.JRNL_BOT_NAME }} <${{ secrets.JRNL_BOT_EMAIL }}>
|
|
||||||
author: ${{ secrets.JRNL_BOT_NAME }} <${{ secrets.JRNL_BOT_EMAIL }}>
|
|
||||||
|
|
||||||
title: jrnl ${{ env.JRNL_VERSION }}
|
|
||||||
body: Created with `brew bump-formula-pr`
|
|
||||||
|
|
||||||
branch: jrnl-${{ env.JRNL_VERSION }}--
|
|
||||||
branch-suffix: random
|
|
||||||
commit-message: |
|
|
||||||
jrnl ${{ env.JRNL_VERSION }}
|
|
||||||
|
|
||||||
Update jrnl to ${{ env.JRNL_VERSION }}
|
|
||||||
|
|
||||||
${{ secrets.RELEASE_COAUTHORS }}
|
|
||||||
|
|
4
.github/workflows/testing_pipelines.yaml
vendored
4
.github/workflows/testing_pipelines.yaml
vendored
|
@ -14,6 +14,8 @@ on:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/**'
|
- '.github/workflows/**'
|
||||||
- '.github/actions/**'
|
- '.github/actions/**'
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * SAT'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
@ -26,7 +28,7 @@ jobs:
|
||||||
os: [ ubuntu-latest ]
|
os: [ ubuntu-latest ]
|
||||||
steps:
|
steps:
|
||||||
- run: git config --global core.autocrlf false
|
- run: git config --global core.autocrlf false
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Check workflow files
|
- name: Check workflow files
|
||||||
uses: docker://rhysd/actionlint:latest
|
uses: docker://rhysd/actionlint:latest
|
||||||
with:
|
with:
|
||||||
|
|
4
.github/workflows/testing_prs.yaml
vendored
4
.github/workflows/testing_prs.yaml
vendored
|
@ -37,11 +37,11 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [ '3.10', '3.11' ]
|
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
|
||||||
os: [ ubuntu-latest, macos-latest, windows-latest ]
|
os: [ ubuntu-latest, macos-latest, windows-latest ]
|
||||||
steps:
|
steps:
|
||||||
- run: git config --global core.autocrlf false
|
- run: git config --global core.autocrlf false
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
uses: ./.github/actions/run_tests
|
uses: ./.github/actions/run_tests
|
||||||
with:
|
with:
|
||||||
|
|
4
.github/workflows/testing_schedule.yaml
vendored
4
.github/workflows/testing_schedule.yaml
vendored
|
@ -17,11 +17,11 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [ '3.10', '3.11' ]
|
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
|
||||||
os: [ ubuntu-latest, macos-latest, windows-latest ]
|
os: [ ubuntu-latest, macos-latest, windows-latest ]
|
||||||
steps:
|
steps:
|
||||||
- run: git config --global core.autocrlf false
|
- run: git config --global core.autocrlf false
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
uses: ./.github/actions/run_tests
|
uses: ./.github/actions/run_tests
|
||||||
with:
|
with:
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -19,6 +19,7 @@ var/
|
||||||
node_modules/
|
node_modules/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
.flakeheaven_cache/
|
||||||
|
|
||||||
# Versioning
|
# Versioning
|
||||||
.python-version
|
.python-version
|
||||||
|
@ -39,7 +40,7 @@ exp/
|
||||||
objects.inv
|
objects.inv
|
||||||
searchindex.js
|
searchindex.js
|
||||||
|
|
||||||
# virtaulenv
|
# virtualenv
|
||||||
.venv*/
|
.venv*/
|
||||||
env/
|
env/
|
||||||
env*/
|
env*/
|
||||||
|
|
|
@ -5,6 +5,13 @@
|
||||||
# Required
|
# Required
|
||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
|
# Set the OS
|
||||||
|
build:
|
||||||
|
os: ubuntu-22.04
|
||||||
|
tools:
|
||||||
|
python: "3"
|
||||||
|
|
||||||
|
|
||||||
# Build documentation in the docs/ directory
|
# Build documentation in the docs/ directory
|
||||||
mkdocs:
|
mkdocs:
|
||||||
configuration: mkdocs.yml
|
configuration: mkdocs.yml
|
242
CHANGELOG.md
242
CHANGELOG.md
|
@ -2,52 +2,180 @@
|
||||||
|
|
||||||
## [Unreleased](https://github.com/jrnl-org/jrnl/)
|
## [Unreleased](https://github.com/jrnl-org/jrnl/)
|
||||||
|
|
||||||
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.0-beta3...HEAD)
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.2.1...HEAD)
|
||||||
|
|
||||||
**Packaging:**
|
|
||||||
|
|
||||||
- Lock ruaml.yaml version until bug is fixed [\#1738](https://github.com/jrnl-org/jrnl/pull/1738) ([wren](https://github.com/wren))
|
|
||||||
|
|
||||||
## [v4.0-beta3](https://pypi.org/project/jrnl/v4.0-beta3/) (2023-04-29)
|
|
||||||
|
|
||||||
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.0-beta2...v4.0-beta3)
|
|
||||||
|
|
||||||
**Fixed bugs:**
|
**Fixed bugs:**
|
||||||
|
|
||||||
- jrnl reads extraneous text files when reading folder journal [\#1692](https://github.com/jrnl-org/jrnl/issues/1692)
|
- poetry warning - "poetry.dev-dependencies" section is deprecated [\#1975](https://github.com/jrnl-org/jrnl/issues/1975)
|
||||||
- jrnl crashes when adding tag argument after `--change-time` [\#1644](https://github.com/jrnl-org/jrnl/issues/1644)
|
- Homebrew autobump error on jrnl release [\#1961](https://github.com/jrnl-org/jrnl/issues/1961)
|
||||||
- Only read text files that look like entries when opening folder journal [\#1697](https://github.com/jrnl-org/jrnl/pull/1697) ([micahellison](https://github.com/micahellison))
|
|
||||||
|
|
||||||
**Documentation:**
|
**Build:**
|
||||||
|
|
||||||
- Update contributing.md links in documentation [\#1726](https://github.com/jrnl-org/jrnl/pull/1726) ([ahosking](https://github.com/ahosking))
|
- Remove release step to publish to Homebrew [\#1994](https://github.com/jrnl-org/jrnl/pull/1994) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
## [v4.0-beta2](https://pypi.org/project/jrnl/v4.0-beta2/) (2023-04-22)
|
|
||||||
|
|
||||||
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.0-beta...v4.0-beta2)
|
|
||||||
|
|
||||||
**Documentation:**
|
|
||||||
|
|
||||||
- Fix various typos [\#1718](https://github.com/jrnl-org/jrnl/pull/1718) ([hezhizhen](https://github.com/hezhizhen))
|
|
||||||
|
|
||||||
**Packaging:**
|
**Packaging:**
|
||||||
|
|
||||||
- Update dependency cryptography to v40.0.2 [\#1723](https://github.com/jrnl-org/jrnl/pull/1723) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency rich to v14 [\#1989](https://github.com/jrnl-org/jrnl/pull/1989) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency flakeheaven to v3.3.0 [\#1722](https://github.com/jrnl-org/jrnl/pull/1722) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency python to 3.13 [\#1988](https://github.com/jrnl-org/jrnl/pull/1988) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency pytest to v7.3.1 [\#1720](https://github.com/jrnl-org/jrnl/pull/1720) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency tox to v4.25.0 [\#1986](https://github.com/jrnl-org/jrnl/pull/1986) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency black to v23.3.0 [\#1715](https://github.com/jrnl-org/jrnl/pull/1715) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency tzlocal to v5.3.1 [\#1984](https://github.com/jrnl-org/jrnl/pull/1984) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency flake8-type-checking to v2.4.0 [\#1714](https://github.com/jrnl-org/jrnl/pull/1714) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency jinja2 to v3.1.6 [\#1983](https://github.com/jrnl-org/jrnl/pull/1983) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency rich to v13.3.4 [\#1713](https://github.com/jrnl-org/jrnl/pull/1713) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency poethepoet to v0.33.1 [\#1982](https://github.com/jrnl-org/jrnl/pull/1982) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency tox to v4.4.12 [\#1712](https://github.com/jrnl-org/jrnl/pull/1712) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency pytest to v8.3.5 [\#1981](https://github.com/jrnl-org/jrnl/pull/1981) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency cryptography to v44.0.2 [\#1980](https://github.com/jrnl-org/jrnl/pull/1980) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruff to v0.11.3 [\#1978](https://github.com/jrnl-org/jrnl/pull/1978) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
## [v4.0-beta](https://pypi.org/project/jrnl/v4.0-beta/) (2023-03-25)
|
## [v4.2.1](https://pypi.org/project/jrnl/v4.2.1/) (2025-02-25)
|
||||||
|
|
||||||
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.3...v4.0-beta)
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.2...v4.2.1)
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Typing animation in landing page is broken [\#1969](https://github.com/jrnl-org/jrnl/issues/1969)
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Update dependency pytest to \>=8.1.1 [\#1974](https://github.com/jrnl-org/jrnl/pull/1974) ([wren](https://github.com/wren))
|
||||||
|
- Update dependency black to v25 [\#1973](https://github.com/jrnl-org/jrnl/pull/1973) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tzlocal to v5.3 [\#1972](https://github.com/jrnl-org/jrnl/pull/1972) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruamel.yaml to v0.18.10 [\#1967](https://github.com/jrnl-org/jrnl/pull/1967) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency jinja2 to v3.1.5 [\#1966](https://github.com/jrnl-org/jrnl/pull/1966) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency cryptography to v44 [\#1962](https://github.com/jrnl-org/jrnl/pull/1962) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-bdd to v8.1.0 [\#1952](https://github.com/jrnl-org/jrnl/pull/1952) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.32.2 [\#1951](https://github.com/jrnl-org/jrnl/pull/1951) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency keyring to v25.6.0 [\#1948](https://github.com/jrnl-org/jrnl/pull/1948) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruff to v0.9.7 [\#1947](https://github.com/jrnl-org/jrnl/pull/1947) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.9.4 [\#1946](https://github.com/jrnl-org/jrnl/pull/1946) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.24.1 [\#1945](https://github.com/jrnl-org/jrnl/pull/1945) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
## [v4.2](https://pypi.org/project/jrnl/v4.2/) (2024-11-17)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.2-beta...v4.2)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add Python 3.13 support [\#1893](https://github.com/jrnl-org/jrnl/issues/1893)
|
||||||
|
- Add calendar heatmap display format [\#1759](https://github.com/jrnl-org/jrnl/pull/1759) ([alichtman](https://github.com/alichtman))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- -contains doesn't accept multiple search terms, doesn't work with -and [\#1877](https://github.com/jrnl-org/jrnl/issues/1877)
|
||||||
|
- Tests failing on develop branch starting with pytest-bdd 7.1.2 [\#1875](https://github.com/jrnl-org/jrnl/issues/1875)
|
||||||
|
- Ignore color when used in a pipeline [\#1839](https://github.com/jrnl-org/jrnl/issues/1839)
|
||||||
|
- Fix -contains to allow multiple terms with "OR" logic unless -and is added [\#1890](https://github.com/jrnl-org/jrnl/pull/1890) ([eigenric](https://github.com/eigenric))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Recommend pipx as default installation method [\#1888](https://github.com/jrnl-org/jrnl/issues/1888)
|
||||||
|
- Remove documentation recommendation to install pipx through brew or pip [\#1886](https://github.com/jrnl-org/jrnl/issues/1886)
|
||||||
|
- Document security risks of using a computer that someone else has admin access to [\#1793](https://github.com/jrnl-org/jrnl/issues/1793)
|
||||||
|
- Recommend pipx as easiest installation method for all OSes and remove warning about apt [\#1889](https://github.com/jrnl-org/jrnl/pull/1889) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Docs accessibility checker failure - contrast ratio [\#1934](https://github.com/jrnl-org/jrnl/issues/1934)
|
||||||
|
- Docs accessibility test runner failing [\#1932](https://github.com/jrnl-org/jrnl/issues/1932)
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Update actions/cache action to v4 [\#1847](https://github.com/jrnl-org/jrnl/pull/1847) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update actions/setup-python action to v5 [\#1848](https://github.com/jrnl-org/jrnl/pull/1848) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency black to v24.8.0 [\#1923](https://github.com/jrnl-org/jrnl/pull/1923) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency cryptography to v43.0.3 [\#1942](https://github.com/jrnl-org/jrnl/pull/1942) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency jinja2 to v3.1.4 [\#1892](https://github.com/jrnl-org/jrnl/pull/1892) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency keyring to v25.4.1 [\#1924](https://github.com/jrnl-org/jrnl/pull/1924) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency mkdocs to v1.6.1 [\#1895](https://github.com/jrnl-org/jrnl/pull/1895) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pa11y-ci to v3.1.0 [\#1831](https://github.com/jrnl-org/jrnl/pull/1831) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency parse-type to v0.6.4 [\#1936](https://github.com/jrnl-org/jrnl/pull/1936) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update peter-evans/create-pull-request action to v7 [\#1929](https://github.com/jrnl-org/jrnl/pull/1929) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.29.0 [\#1925](https://github.com/jrnl-org/jrnl/pull/1925) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest to v7.4.4 [\#1845](https://github.com/jrnl-org/jrnl/pull/1845) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-bdd to v7.3.0 [\#1896](https://github.com/jrnl-org/jrnl/pull/1896) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-xdist to v3.6.1 [\#1897](https://github.com/jrnl-org/jrnl/pull/1897) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency python-dateutil to v2.9.0 [\#1898](https://github.com/jrnl-org/jrnl/pull/1898) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency requests to v2.32.3 [\#1899](https://github.com/jrnl-org/jrnl/pull/1899) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.9.2 [\#1937](https://github.com/jrnl-org/jrnl/pull/1937) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruamel.yaml to v0.18.6 [\#1855](https://github.com/jrnl-org/jrnl/pull/1855) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruff to v0.7.0 [\#1938](https://github.com/jrnl-org/jrnl/pull/1938) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.23.0 [\#1935](https://github.com/jrnl-org/jrnl/pull/1935) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency typed.js to v2.1.0 [\#1861](https://github.com/jrnl-org/jrnl/pull/1861) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency xmltodict to v0.14.2 [\#1940](https://github.com/jrnl-org/jrnl/pull/1940) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update nick-invision/retry action to v3 [\#1851](https://github.com/jrnl-org/jrnl/pull/1851) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update peter-evans/create-pull-request action to v6 [\#1852](https://github.com/jrnl-org/jrnl/pull/1852) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
## [v4.1](https://pypi.org/project/jrnl/v4.1/) (2023-11-04)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.1-beta2...v4.1)
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Add Python 3.12 support [\#1761](https://github.com/jrnl-org/jrnl/pull/1761) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Set new required build fields in the ReadTheDocs config file [\#1803](https://github.com/jrnl-org/jrnl/pull/1803) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Replace flake8 and isort with ruff linter and add `black --check` to linting step [\#1763](https://github.com/jrnl-org/jrnl/pull/1763) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Add note about messages going to `stderr` and the implication for piping [\#1768](https://github.com/jrnl-org/jrnl/pull/1768) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Drop/replace ansiwrap dependency [\#1191](https://github.com/jrnl-org/jrnl/issues/1191)
|
||||||
|
- Use rich instead of ansiwrap to wrap text [\#1693](https://github.com/jrnl-org/jrnl/pull/1693) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Update actions/checkout action to v4 [\#1788](https://github.com/jrnl-org/jrnl/pull/1788) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency black to v23.10.1 [\#1811](https://github.com/jrnl-org/jrnl/pull/1811) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency cryptography to v41.0.5 [\#1815](https://github.com/jrnl-org/jrnl/pull/1815) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency keyring to v24.2.0 [\#1760](https://github.com/jrnl-org/jrnl/pull/1760) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency mkdocs to v1.5.3 [\#1795](https://github.com/jrnl-org/jrnl/pull/1795) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency parse-type to v0.6.2 [\#1762](https://github.com/jrnl-org/jrnl/pull/1762) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.24.1 [\#1806](https://github.com/jrnl-org/jrnl/pull/1806) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest to v7.4.3 [\#1816](https://github.com/jrnl-org/jrnl/pull/1816) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-bdd to v7 [\#1807](https://github.com/jrnl-org/jrnl/pull/1807) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.6.0 [\#1794](https://github.com/jrnl-org/jrnl/pull/1794) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruamel.yaml to v0.18.3 [\#1813](https://github.com/jrnl-org/jrnl/pull/1813) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruff to v0.1.3 [\#1810](https://github.com/jrnl-org/jrnl/pull/1810) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.11.3 [\#1782](https://github.com/jrnl-org/jrnl/pull/1782) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tzlocal to v5.2 [\#1814](https://github.com/jrnl-org/jrnl/pull/1814) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
**Special thanks:**
|
||||||
|
- jrnl uses UTC instead of local time for entries in WSL/Ubuntu [\#1607](https://github.com/jrnl-org/jrnl/issues/1607) investigated and reported upstream by [giuseppedandrea](https://github.com/giuseppedandrea)
|
||||||
|
|
||||||
|
## [v4.0.1](https://pypi.org/project/jrnl/v4.0.1/) (2023-06-20)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.0.1-beta...v4.0.1)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- jrnl crashes when running `jrnl --list --format json` and `jrnl --list --format yaml` [\#1737](https://github.com/jrnl-org/jrnl/issues/1737)
|
||||||
|
- Refactor --template code [\#1711](https://github.com/jrnl-org/jrnl/pull/1711) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Fix linting issue in CI pipeline [\#1743](https://github.com/jrnl-org/jrnl/pull/1743) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Update dependency ruamel.yaml to v0.17.28 [\#1749](https://github.com/jrnl-org/jrnl/pull/1749) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency requests to v2.31.0 [\#1748](https://github.com/jrnl-org/jrnl/pull/1748) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruamel.yaml to v0.17.26 [\#1746](https://github.com/jrnl-org/jrnl/pull/1746) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tzlocal to v5 [\#1741](https://github.com/jrnl-org/jrnl/pull/1741) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-xdist to v3.3.1 [\#1740](https://github.com/jrnl-org/jrnl/pull/1740) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.20.0 [\#1735](https://github.com/jrnl-org/jrnl/pull/1735) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency mkdocs to v1.4.3 [\#1733](https://github.com/jrnl-org/jrnl/pull/1733) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.3.5 [\#1729](https://github.com/jrnl-org/jrnl/pull/1729) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency requests to v2.30.0 [\#1728](https://github.com/jrnl-org/jrnl/pull/1728) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.5.1 [\#1727](https://github.com/jrnl-org/jrnl/pull/1727) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update peter-evans/create-pull-request action to v5 [\#1719](https://github.com/jrnl-org/jrnl/pull/1719) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency flake8-simplify to v0.20.0 [\#1716](https://github.com/jrnl-org/jrnl/pull/1716) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
## [v4.0](https://pypi.org/project/jrnl/v4.0/) (2023-05-20)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.0-beta3...v4.0)
|
||||||
|
|
||||||
|
🚨 **BREAKING CHANGES** 🚨
|
||||||
|
|
||||||
|
**Deprecated:**
|
||||||
|
|
||||||
|
- Drop Python 3.9 and use Python 3.11 official release [\#1611](https://github.com/jrnl-org/jrnl/pull/1611) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
**Implemented enhancements:**
|
**Implemented enhancements:**
|
||||||
|
|
||||||
- Display locations of config file and documentation after initial install [\#1694](https://github.com/jrnl-org/jrnl/issues/1694)
|
|
||||||
- Don't import cryptography package if not needed [\#1521](https://github.com/jrnl-org/jrnl/issues/1521)
|
|
||||||
- Add message with config location and docs location when installation is complete [\#1695](https://github.com/jrnl-org/jrnl/pull/1695) ([micahellison](https://github.com/micahellison))
|
- Add message with config location and docs location when installation is complete [\#1695](https://github.com/jrnl-org/jrnl/pull/1695) ([micahellison](https://github.com/micahellison))
|
||||||
- Prompt to include colors in config when first running jrnl [\#1687](https://github.com/jrnl-org/jrnl/pull/1687) ([micahellison](https://github.com/micahellison))
|
- Prompt to include colors in config when first running jrnl [\#1687](https://github.com/jrnl-org/jrnl/pull/1687) ([micahellison](https://github.com/micahellison))
|
||||||
- Add ability to use template with `--template` [\#1667](https://github.com/jrnl-org/jrnl/pull/1667) ([alichtman](https://github.com/alichtman))
|
- Add ability to use template with `--template` [\#1667](https://github.com/jrnl-org/jrnl/pull/1667) ([alichtman](https://github.com/alichtman))
|
||||||
|
@ -59,25 +187,15 @@
|
||||||
|
|
||||||
**Fixed bugs:**
|
**Fixed bugs:**
|
||||||
|
|
||||||
- Combinations of `--change-time`, `--delete`, and `--edit` don't work consistently [\#1696](https://github.com/jrnl-org/jrnl/issues/1696)
|
- Only read text files that look like entries when opening folder journal [\#1697](https://github.com/jrnl-org/jrnl/pull/1697) ([micahellison](https://github.com/micahellison))
|
||||||
- jrnl doesn't display count of entries deleted after deleting entries with `--delete` [\#1666](https://github.com/jrnl-org/jrnl/issues/1666)
|
|
||||||
- Templated entries should not be saved if the raw text is identical to the original template [\#1652](https://github.com/jrnl-org/jrnl/issues/1652)
|
|
||||||
- Adding an entry with a combination of flags causes a journal overwrite [\#1639](https://github.com/jrnl-org/jrnl/issues/1639)
|
|
||||||
- jrnl does not update version key in config file [\#1638](https://github.com/jrnl-org/jrnl/issues/1638)
|
|
||||||
- jrnl should not create 0-length "encrypted" file on startup [\#1493](https://github.com/jrnl-org/jrnl/issues/1493)
|
|
||||||
- Save empty journal on install instead of just creating a zero-length file [\#1690](https://github.com/jrnl-org/jrnl/pull/1690) ([micahellison](https://github.com/micahellison))
|
- Save empty journal on install instead of just creating a zero-length file [\#1690](https://github.com/jrnl-org/jrnl/pull/1690) ([micahellison](https://github.com/micahellison))
|
||||||
- Allow combinations of `--change-time`, `--delete`, and `--edit` while correctly counting the number of entries affected [\#1669](https://github.com/jrnl-org/jrnl/pull/1669) ([wren](https://github.com/wren))
|
- Allow combinations of `--change-time`, `--delete`, and `--edit` while correctly counting the number of entries affected [\#1669](https://github.com/jrnl-org/jrnl/pull/1669) ([wren](https://github.com/wren))
|
||||||
- Don't save templated journal entries if the received raw text is the same as the template itself [\#1653](https://github.com/jrnl-org/jrnl/pull/1653) ([Briscoooe](https://github.com/Briscoooe))
|
- Don't save templated journal entries if the received raw text is the same as the template itself [\#1653](https://github.com/jrnl-org/jrnl/pull/1653) ([Briscoooe](https://github.com/Briscoooe))
|
||||||
- Add tag to XML file when edited DayOne entry and is searchable afterward [\#1648](https://github.com/jrnl-org/jrnl/pull/1648) ([jonakeys](https://github.com/jonakeys))
|
- Add tag to XML file when edited DayOne entry and is searchable afterward [\#1648](https://github.com/jrnl-org/jrnl/pull/1648) ([jonakeys](https://github.com/jonakeys))
|
||||||
- Update version key in config file after version changes [\#1646](https://github.com/jrnl-org/jrnl/pull/1646) ([jonakeys](https://github.com/jonakeys))
|
- Update version key in config file after version changes [\#1646](https://github.com/jrnl-org/jrnl/pull/1646) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
|
||||||
**Deprecated:**
|
|
||||||
|
|
||||||
- Drop Python 3.9 and use Python 3.11 official release [\#1611](https://github.com/jrnl-org/jrnl/pull/1611) ([micahellison](https://github.com/micahellison))
|
|
||||||
|
|
||||||
**Build:**
|
**Build:**
|
||||||
|
|
||||||
- Support pytest-bdd 6 [\#1534](https://github.com/jrnl-org/jrnl/issues/1534)
|
|
||||||
- Update copyright notices for 2023 [\#1660](https://github.com/jrnl-org/jrnl/pull/1660) ([wren](https://github.com/wren))
|
- Update copyright notices for 2023 [\#1660](https://github.com/jrnl-org/jrnl/pull/1660) ([wren](https://github.com/wren))
|
||||||
- Fix bug where changelog is always slightly out of date on release tags [\#1631](https://github.com/jrnl-org/jrnl/pull/1631) ([wren](https://github.com/wren))
|
- Fix bug where changelog is always slightly out of date on release tags [\#1631](https://github.com/jrnl-org/jrnl/pull/1631) ([wren](https://github.com/wren))
|
||||||
- Add `simplify` plugin to linting checks [\#1630](https://github.com/jrnl-org/jrnl/pull/1630) ([wren](https://github.com/wren))
|
- Add `simplify` plugin to linting checks [\#1630](https://github.com/jrnl-org/jrnl/pull/1630) ([wren](https://github.com/wren))
|
||||||
|
@ -85,11 +203,8 @@
|
||||||
|
|
||||||
**Documentation:**
|
**Documentation:**
|
||||||
|
|
||||||
- Document template extension behavior [\#1677](https://github.com/jrnl-org/jrnl/issues/1677)
|
- Update contributing.md links in documentation [\#1726](https://github.com/jrnl-org/jrnl/pull/1726) ([ahosking](https://github.com/ahosking))
|
||||||
- Visual Studio Code may store unencrypted temporary files [\#1675](https://github.com/jrnl-org/jrnl/issues/1675)
|
- Fix various typos [\#1718](https://github.com/jrnl-org/jrnl/pull/1718) ([hezhizhen](https://github.com/hezhizhen))
|
||||||
- Document `-tagged`, `-not -tagged`, and `-not -starred` [\#1668](https://github.com/jrnl-org/jrnl/issues/1668)
|
|
||||||
- Documentation Change [\#1651](https://github.com/jrnl-org/jrnl/issues/1651)
|
|
||||||
- Update console examples on jrnl.sh front page [\#1622](https://github.com/jrnl-org/jrnl/issues/1622)
|
|
||||||
- Update documentation front page text [\#1698](https://github.com/jrnl-org/jrnl/pull/1698) ([micahellison](https://github.com/micahellison))
|
- Update documentation front page text [\#1698](https://github.com/jrnl-org/jrnl/pull/1698) ([micahellison](https://github.com/micahellison))
|
||||||
- Support mkdocs 1.4.2 and fix its missing breadcrumb [\#1691](https://github.com/jrnl-org/jrnl/pull/1691) ([micahellison](https://github.com/micahellison))
|
- Support mkdocs 1.4.2 and fix its missing breadcrumb [\#1691](https://github.com/jrnl-org/jrnl/pull/1691) ([micahellison](https://github.com/micahellison))
|
||||||
- Document temporary file extension behavior when using template [\#1686](https://github.com/jrnl-org/jrnl/pull/1686) ([micahellison](https://github.com/micahellison))
|
- Document temporary file extension behavior when using template [\#1686](https://github.com/jrnl-org/jrnl/pull/1686) ([micahellison](https://github.com/micahellison))
|
||||||
|
@ -102,17 +217,18 @@
|
||||||
|
|
||||||
**Packaging:**
|
**Packaging:**
|
||||||
|
|
||||||
- Update dependency cryptography to v40 [\#1710](https://github.com/jrnl-org/jrnl/pull/1710) ([renovate[bot]](https://github.com/apps/renovate))
|
- Lock ruamel.yaml version to v0.17.21 until bug is fixed [\#1738](https://github.com/jrnl-org/jrnl/pull/1738) ([wren](https://github.com/wren))
|
||||||
- Update dependency poethepoet to v0.19.0 [\#1709](https://github.com/jrnl-org/jrnl/pull/1709) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency black to v23.3.0 [\#1715](https://github.com/jrnl-org/jrnl/pull/1715) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency tzlocal to v4.3 [\#1708](https://github.com/jrnl-org/jrnl/pull/1708) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency cryptography to v40.0.2 [\#1723](https://github.com/jrnl-org/jrnl/pull/1723) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency tox to v4.4.7 [\#1707](https://github.com/jrnl-org/jrnl/pull/1707) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency flake8-type-checking to v2.4.0 [\#1714](https://github.com/jrnl-org/jrnl/pull/1714) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency rich to v13.3.2 [\#1706](https://github.com/jrnl-org/jrnl/pull/1706) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency flakeheaven to v3.3.0 [\#1722](https://github.com/jrnl-org/jrnl/pull/1722) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency pytest-xdist to v3.2.1 [\#1705](https://github.com/jrnl-org/jrnl/pull/1705) ([renovate[bot]](https://github.com/apps/renovate))
|
|
||||||
- Update dependency pytest to v7.2.2 [\#1704](https://github.com/jrnl-org/jrnl/pull/1704) ([renovate[bot]](https://github.com/apps/renovate))
|
|
||||||
- Update dependency ipdb to v0.13.13 [\#1703](https://github.com/jrnl-org/jrnl/pull/1703) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency ipdb to v0.13.13 [\#1703](https://github.com/jrnl-org/jrnl/pull/1703) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency flake8-type-checking to v2.3.1 [\#1702](https://github.com/jrnl-org/jrnl/pull/1702) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency poethepoet to v0.19.0 [\#1709](https://github.com/jrnl-org/jrnl/pull/1709) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency cryptography to v39.0.2 [\#1701](https://github.com/jrnl-org/jrnl/pull/1701) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency pytest to v7.3.1 [\#1720](https://github.com/jrnl-org/jrnl/pull/1720) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
- Update dependency rich to v13 [\#1654](https://github.com/jrnl-org/jrnl/pull/1654) ([renovate[bot]](https://github.com/apps/renovate))
|
- Update dependency pytest-xdist to v3.2.1 [\#1705](https://github.com/jrnl-org/jrnl/pull/1705) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.3.4 [\#1713](https://github.com/jrnl-org/jrnl/pull/1713) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.4.7 [\#1707](https://github.com/jrnl-org/jrnl/pull/1707) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tzlocal to v4.3 [\#1708](https://github.com/jrnl-org/jrnl/pull/1708) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
## [v3.3](https://pypi.org/project/jrnl/v3.3/) (2022-10-29)
|
## [v3.3](https://pypi.org/project/jrnl/v3.3/) (2022-10-29)
|
||||||
|
|
||||||
|
@ -211,6 +327,10 @@
|
||||||
|
|
||||||
🚨 **BREAKING CHANGES** 🚨
|
🚨 **BREAKING CHANGES** 🚨
|
||||||
|
|
||||||
|
**Deprecated:**
|
||||||
|
|
||||||
|
- Drop support for Python 3.7 and 3.8 [\#1412](https://github.com/jrnl-org/jrnl/pull/1412) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
**Implemented enhancements:**
|
**Implemented enhancements:**
|
||||||
|
|
||||||
- Show name of journal when creating a password/encrypting [\#1478](https://github.com/jrnl-org/jrnl/pull/1478) ([jonakeys](https://github.com/jonakeys))
|
- Show name of journal when creating a password/encrypting [\#1478](https://github.com/jrnl-org/jrnl/pull/1478) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
@ -233,10 +353,6 @@
|
||||||
- Display "No entry to save, because no text was received" after empty entry on cmdline [\#1459](https://github.com/jrnl-org/jrnl/pull/1459) ([apainintheneck](https://github.com/apainintheneck))
|
- Display "No entry to save, because no text was received" after empty entry on cmdline [\#1459](https://github.com/jrnl-org/jrnl/pull/1459) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
- Yaml export errors now don't show stack trace [\#1449](https://github.com/jrnl-org/jrnl/pull/1449) ([apainintheneck](https://github.com/apainintheneck))
|
- Yaml export errors now don't show stack trace [\#1449](https://github.com/jrnl-org/jrnl/pull/1449) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
|
||||||
**Deprecated:**
|
|
||||||
|
|
||||||
- Drop support for Python 3.7 and 3.8 [\#1412](https://github.com/jrnl-org/jrnl/pull/1412) ([micahellison](https://github.com/micahellison))
|
|
||||||
|
|
||||||
**Build:**
|
**Build:**
|
||||||
|
|
||||||
- Pin `pytest-bdd` to \<6.0 to temporarily avoid breaking changes [\#1536](https://github.com/jrnl-org/jrnl/pull/1536) ([wren](https://github.com/wren))
|
- Pin `pytest-bdd` to \<6.0 to temporarily avoid breaking changes [\#1536](https://github.com/jrnl-org/jrnl/pull/1536) ([wren](https://github.com/wren))
|
||||||
|
|
|
@ -117,6 +117,11 @@ These formats are mainly intended for piping or exporting your journal to other
|
||||||
programs. Even so, they can still be used in the same way as any other format (like
|
programs. Even so, they can still be used in the same way as any other format (like
|
||||||
written to a file, or displayed in your terminal, if you want).
|
written to a file, or displayed in your terminal, if you want).
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
You may see boxed messages like "2 entries found" when using these formats, but
|
||||||
|
those messages are written to `stderr` instead of `stdout`, and won't be piped when
|
||||||
|
using the `|` operator.
|
||||||
|
|
||||||
### JSON
|
### JSON
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
|
|
|
@ -7,24 +7,14 @@ License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
On Mac and Linux, the easiest way to install `jrnl` is using
|
The easiest way to install `jrnl` is using
|
||||||
[Homebrew](http://brew.sh/):
|
[pipx](https://pipx.pypa.io/stable/installation/)
|
||||||
|
with [Python](https://www.python.org/) 3.10+:
|
||||||
``` sh
|
|
||||||
brew install jrnl
|
|
||||||
```
|
|
||||||
|
|
||||||
On other platforms, install `jrnl` using [Python](https://www.python.org/) 3.10+ and [pipx](https://pipxproject.github.io/pipx/):
|
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
pipx install jrnl
|
pipx install jrnl
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
|
||||||
`pipx` should be installed through either `brew` or `pip`. Missing dependencies and other issues
|
|
||||||
may occur when installing `pipx` through `apt` or another package manager. Further installation
|
|
||||||
instructions can be found in [pipx's documentation](https://pipxproject.github.io/pipx/installation/).
|
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
Do not use `sudo` while installing `jrnl`. This may lead to path issues.
|
Do not use `sudo` while installing `jrnl`. This may lead to path issues.
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,35 @@ program there are some limitations to be aware of.
|
||||||
passwords can be easily circumvented by someone with basic security skills
|
passwords can be easily circumvented by someone with basic security skills
|
||||||
to access to your encrypted `jrnl` file.
|
to access to your encrypted `jrnl` file.
|
||||||
|
|
||||||
|
## Plausible deniability
|
||||||
|
|
||||||
|
You may be able to hide the contents of your journal behind a layer of encryption,
|
||||||
|
but if someone has access to your configuration file, then they can figure out that
|
||||||
|
you have a journal, where that journal file is, and when you last edited it.
|
||||||
|
With a sufficient power imbalance, someone may be able to force you to unencrypt
|
||||||
|
it through non-technical means.
|
||||||
|
|
||||||
|
## Spying
|
||||||
|
|
||||||
|
While `jrnl` can protect against unauthorized access to your journal entries while
|
||||||
|
it isn't open, it cannot protect you against an unsafe computer/location.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
- Someone installs a keylogger, tracking what you type into your journal.
|
||||||
|
- Someone watches your screen while you write your entry.
|
||||||
|
- Someone installs a backdoor into `jrnl` or poisons your journal into revealing your entries.
|
||||||
|
|
||||||
|
## Saved Passwords
|
||||||
|
|
||||||
|
When creating an encrypted journal, you'll be prompted as to whether or not you
|
||||||
|
want to "store the password in your keychain." This keychain is accessed using
|
||||||
|
the [Python keyring library](https://pypi.org/project/keyring/), which has different
|
||||||
|
behavior depending on your operating system.
|
||||||
|
|
||||||
|
In Windows, the keychain is the Windows Credential Manager (WCM), which can't be locked
|
||||||
|
and can be accessed by any other application running under your username. If this is
|
||||||
|
a concern for you, you may not want to store your password.
|
||||||
|
|
||||||
## Shell history
|
## Shell history
|
||||||
|
|
||||||
Since you can enter entries from the command line, any tool that logs command
|
Since you can enter entries from the command line, any tool that logs command
|
||||||
|
@ -198,25 +227,6 @@ vim.api.nvim_create_autocmd( {"BufNewFile","BufReadPre" }, {
|
||||||
|
|
||||||
Please see `:h <option>` in Neovim for more information about the options mentioned.
|
Please see `:h <option>` in Neovim for more information about the options mentioned.
|
||||||
|
|
||||||
## Plausible deniability
|
|
||||||
|
|
||||||
You may be able to hide the contents of your journal behind a layer of encryption,
|
|
||||||
but if someone has access to your configuration file, then they can figure out that
|
|
||||||
you have a journal, where that journal file is, and when you last edited it.
|
|
||||||
With a sufficient power imbalance, someone may be able to force you to unencrypt
|
|
||||||
it through non-technical means.
|
|
||||||
|
|
||||||
## Saved Passwords
|
|
||||||
|
|
||||||
When creating an encrypted journal, you'll be prompted as to whether or not you
|
|
||||||
want to "store the password in your keychain." This keychain is accessed using
|
|
||||||
the [Python keyring library](https://pypi.org/project/keyring/), which has different
|
|
||||||
behavior depending on your operating system.
|
|
||||||
|
|
||||||
In Windows, the keychain is the Windows Credential Manager (WCM), which can't be locked
|
|
||||||
and can be accessed by any other application running under your username. If this is
|
|
||||||
a concern for you, you may not want to store your password.
|
|
||||||
|
|
||||||
## Notice any other risks?
|
## Notice any other risks?
|
||||||
|
|
||||||
Please let the maintainers know by [filing an issue on GitHub](https://github.com/jrnl-org/jrnl/issues).
|
Please let the maintainers know by [filing an issue on GitHub](https://github.com/jrnl-org/jrnl/issues).
|
||||||
|
|
|
@ -139,3 +139,9 @@ Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
|
||||||
.rst-content .tip .admonition {
|
.rst-content .tip .admonition {
|
||||||
background: var(--light-blue);
|
background: var(--light-blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* hack to bypass a11y issue with conflicting highlight.css files */
|
||||||
|
code.language-xml span.hljs-meta span.hljs-string {
|
||||||
|
color: var(--green) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
@ -65,7 +65,7 @@ License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
<a href="overview">Documentation</a>
|
<a href="overview">Documentation</a>
|
||||||
<a href="installation" class="cta">Get Started</a>
|
<a href="installation" class="cta">Get Started</a>
|
||||||
<a href="http://github.com/jrnl-org/jrnl" title="View on Github">Fork on GitHub</a>
|
<a href="http://github.com/jrnl-org/jrnl" title="View on Github">Fork on GitHub</a>
|
||||||
<a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Collect+your+thoughts+and+notes+without+leaving+the+command+line.+https%3A%2F%2Fjrnl.sh+via+@JrnlSh"><i class="icon twitter"></i>Tell your friends on Twitter</a>
|
<a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Collect+your+thoughts+and+notes+without+leaving+the+command+line.+https%3A%2F%2Fjrnl.sh+via+@JrnlSh">Tell your friends on X</a>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<section>
|
<section>
|
||||||
|
@ -103,7 +103,7 @@ License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
<footer>
|
<footer>
|
||||||
jrnl is made with love by <a href="https://github.com/jrnl-org/jrnl/graphs/contributors" title="Contributors">many fabulous people</a>. If you need help, <a href="https://github.com/jrnl-org/jrnl/issues/new/choose" title="Open a new issue on Github">submit an issue</a> on Github.
|
jrnl is made with love by <a href="https://github.com/jrnl-org/jrnl/graphs/contributors" title="Contributors">many fabulous people</a>. If you need help, <a href="https://github.com/jrnl-org/jrnl/issues/new/choose" title="Open a new issue on Github">submit an issue</a> on Github.
|
||||||
</footer>
|
</footer>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.12/typed.min.js"></script>
|
<script src="https://unpkg.com/typed.js@2.1.0/dist/typed.umd.js"></script>
|
||||||
<script>
|
<script>
|
||||||
new Typed("#typed", {
|
new Typed("#typed", {
|
||||||
strings: [
|
strings: [
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
mkdocs>=1.4
|
mkdocs>=1.4
|
||||||
jinja2==3.1.2
|
jinja2==3.1.6
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = "v4.0"
|
__version__ = "v4.2.1"
|
||||||
|
|
28
jrnl/args.py
28
jrnl/args.py
|
@ -78,7 +78,7 @@ def parse_args(args: list[str] = []) -> argparse.Namespace:
|
||||||
"""
|
"""
|
||||||
We gratefully thank all contributors!
|
We gratefully thank all contributors!
|
||||||
Come see the whole list of code and financial contributors at https://github.com/jrnl-org/jrnl
|
Come see the whole list of code and financial contributors at https://github.com/jrnl-org/jrnl
|
||||||
And special thanks to Bad Lip Reading for the Yoda joke in the Writing section above :)"""
|
And special thanks to Bad Lip Reading for the Yoda joke in the Writing section above :)""" # noqa: E501
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -214,7 +214,8 @@ def parse_args(args: list[str] = []) -> argparse.Namespace:
|
||||||
composing.add_argument(
|
composing.add_argument(
|
||||||
"--template",
|
"--template",
|
||||||
dest="template",
|
dest="template",
|
||||||
help="Path to template file. Can be a local path, absolute path, or a path relative to $XDG_DATA_HOME/jrnl/templates/",
|
help="Path to template file. Can be a local path, absolute path, or a path "
|
||||||
|
"relative to $XDG_DATA_HOME/jrnl/templates/",
|
||||||
)
|
)
|
||||||
|
|
||||||
read_msg = (
|
read_msg = (
|
||||||
|
@ -264,14 +265,17 @@ def parse_args(args: list[str] = []) -> argparse.Namespace:
|
||||||
reading.add_argument(
|
reading.add_argument(
|
||||||
"-contains",
|
"-contains",
|
||||||
dest="contains",
|
dest="contains",
|
||||||
|
action="append",
|
||||||
metavar="TEXT",
|
metavar="TEXT",
|
||||||
help="Show entries containing specific text (put quotes around text with spaces)",
|
help="Show entries containing specific text (put quotes around text with "
|
||||||
|
"spaces)",
|
||||||
)
|
)
|
||||||
reading.add_argument(
|
reading.add_argument(
|
||||||
"-and",
|
"-and",
|
||||||
dest="strict",
|
dest="strict",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help='Show only entries that match all conditions, like saying "x AND y" (default: OR)',
|
help='Show only entries that match all conditions, like saying "x AND y" '
|
||||||
|
"(default: OR)",
|
||||||
)
|
)
|
||||||
reading.add_argument(
|
reading.add_argument(
|
||||||
"-starred",
|
"-starred",
|
||||||
|
@ -290,7 +294,8 @@ def parse_args(args: list[str] = []) -> argparse.Namespace:
|
||||||
dest="limit",
|
dest="limit",
|
||||||
default=None,
|
default=None,
|
||||||
metavar="NUMBER",
|
metavar="NUMBER",
|
||||||
help="Show a maximum of NUMBER entries (note: '-n 3' and '-3' have the same effect)",
|
help="Show a maximum of NUMBER entries (note: '-n 3' and '-3' have the same "
|
||||||
|
"effect)",
|
||||||
nargs="?",
|
nargs="?",
|
||||||
type=int,
|
type=int,
|
||||||
)
|
)
|
||||||
|
@ -308,8 +313,12 @@ def parse_args(args: list[str] = []) -> argparse.Namespace:
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
search_options_msg = """ These help you do various tasks with the selected entries from your search.
|
search_options_msg = (
|
||||||
|
" " # Preserves indentation
|
||||||
|
"""
|
||||||
|
These help you do various tasks with the selected entries from your search.
|
||||||
If used on their own (with no search), they will act on your entire journal"""
|
If used on their own (with no search), they will act on your entire journal"""
|
||||||
|
)
|
||||||
exporting = parser.add_argument_group(
|
exporting = parser.add_argument_group(
|
||||||
"Searching Options", textwrap.dedent(search_options_msg)
|
"Searching Options", textwrap.dedent(search_options_msg)
|
||||||
)
|
)
|
||||||
|
@ -360,7 +369,8 @@ def parse_args(args: list[str] = []) -> argparse.Namespace:
|
||||||
"--tags",
|
"--tags",
|
||||||
dest="tags",
|
dest="tags",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Alias for '--format tags'. Returns a list of all tags and number of occurrences",
|
help="Alias for '--format tags'. Returns a list of all tags and number of "
|
||||||
|
"occurrences",
|
||||||
)
|
)
|
||||||
exporting.add_argument(
|
exporting.add_argument(
|
||||||
"--short",
|
"--short",
|
||||||
|
@ -400,7 +410,7 @@ def parse_args(args: list[str] = []) -> argparse.Namespace:
|
||||||
\t jrnl --config-override editor "nano" \n
|
\t jrnl --config-override editor "nano" \n
|
||||||
\t - Override color selections\n
|
\t - Override color selections\n
|
||||||
\t jrnl --config-override colors.body blue --config-override colors.title green
|
\t jrnl --config-override colors.body blue --config-override colors.title green
|
||||||
""",
|
""", # noqa: E501
|
||||||
)
|
)
|
||||||
config_overrides.add_argument(
|
config_overrides.add_argument(
|
||||||
"--co",
|
"--co",
|
||||||
|
@ -430,7 +440,7 @@ def parse_args(args: list[str] = []) -> argparse.Namespace:
|
||||||
\t jrnl --config-file /home/user1/work_config.yaml
|
\t jrnl --config-file /home/user1/work_config.yaml
|
||||||
\t - Use a personal config file stored on a thumb drive: \n
|
\t - Use a personal config file stored on a thumb drive: \n
|
||||||
\t jrnl --config-file /media/user1/my-thumb-drive/personal_config.yaml
|
\t jrnl --config-file /media/user1/my-thumb-drive/personal_config.yaml
|
||||||
""",
|
""", # noqa: E501
|
||||||
)
|
)
|
||||||
|
|
||||||
alternate_config.add_argument(
|
alternate_config.add_argument(
|
||||||
|
|
|
@ -76,7 +76,17 @@ def postconfig_import(args: argparse.Namespace, config: dict, **_) -> int:
|
||||||
journal = open_journal(args.journal_name, config)
|
journal = open_journal(args.journal_name, config)
|
||||||
|
|
||||||
format = args.export if args.export else "jrnl"
|
format = args.export if args.export else "jrnl"
|
||||||
get_importer(format).import_(journal, args.filename)
|
|
||||||
|
if (importer := get_importer(format)) is None:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.ImporterNotFound,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{"format": format},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
importer.import_(journal, args.filename)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -142,7 +152,7 @@ def postconfig_encrypt(
|
||||||
def postconfig_decrypt(
|
def postconfig_decrypt(
|
||||||
args: argparse.Namespace, config: dict, original_config: dict
|
args: argparse.Namespace, config: dict, original_config: dict
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Decrypts into new file. If filename is not set, we encrypt the journal file itself."""
|
"""Decrypts to file. If filename is not set, we encrypt the journal file itself."""
|
||||||
from jrnl.config import update_config
|
from jrnl.config import update_config
|
||||||
from jrnl.install import save_config
|
from jrnl.install import save_config
|
||||||
from jrnl.journals import open_journal
|
from jrnl.journals import open_journal
|
||||||
|
|
|
@ -4,12 +4,10 @@
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
import colorama
|
import colorama
|
||||||
import xdg.BaseDirectory
|
|
||||||
from rich.pretty import pretty_repr
|
from rich.pretty import pretty_repr
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
from ruamel.yaml import constructor
|
from ruamel.yaml import constructor
|
||||||
|
@ -21,13 +19,10 @@ from jrnl.messages import MsgStyle
|
||||||
from jrnl.messages import MsgText
|
from jrnl.messages import MsgText
|
||||||
from jrnl.output import list_journals
|
from jrnl.output import list_journals
|
||||||
from jrnl.output import print_msg
|
from jrnl.output import print_msg
|
||||||
from jrnl.path import home_dir
|
from jrnl.path import get_config_path
|
||||||
|
from jrnl.path import get_default_journal_path
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
DEFAULT_CONFIG_NAME = "jrnl.yaml"
|
|
||||||
XDG_RESOURCE = "jrnl"
|
|
||||||
|
|
||||||
DEFAULT_JOURNAL_NAME = "journal.txt"
|
|
||||||
DEFAULT_JOURNAL_KEY = "default"
|
DEFAULT_JOURNAL_KEY = "default"
|
||||||
|
|
||||||
YAML_SEPARATOR = ": "
|
YAML_SEPARATOR = ": "
|
||||||
|
@ -42,9 +37,10 @@ def make_yaml_valid_dict(input: list) -> dict:
|
||||||
The dict is created through the yaml loader, with the assumption that
|
The dict is created through the yaml loader, with the assumption that
|
||||||
"input[0]: input[1]" is valid yaml.
|
"input[0]: input[1]" is valid yaml.
|
||||||
|
|
||||||
:param input: list of configuration keys in dot-notation and their respective values.
|
:param input: list of configuration keys in dot-notation and their respective values
|
||||||
:type input: list
|
:type input: list
|
||||||
:return: A single level dict of the configuration keys in dot-notation and their respective desired values
|
:return: A single level dict of the configuration keys in dot-notation and their
|
||||||
|
respective desired values
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -73,31 +69,6 @@ def save_config(config: dict, alt_config_path: str | None = None) -> None:
|
||||||
yaml.dump(config, f)
|
yaml.dump(config, f)
|
||||||
|
|
||||||
|
|
||||||
def get_config_directory() -> str:
|
|
||||||
try:
|
|
||||||
return xdg.BaseDirectory.save_config_path(XDG_RESOURCE)
|
|
||||||
except FileExistsError:
|
|
||||||
raise JrnlException(
|
|
||||||
Message(
|
|
||||||
MsgText.ConfigDirectoryIsFile,
|
|
||||||
MsgStyle.ERROR,
|
|
||||||
{
|
|
||||||
"config_directory_path": os.path.join(
|
|
||||||
xdg.BaseDirectory.xdg_config_home, XDG_RESOURCE
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_config_path() -> Path:
|
|
||||||
try:
|
|
||||||
config_directory_path = get_config_directory()
|
|
||||||
except JrnlException:
|
|
||||||
return Path(home_dir(), DEFAULT_CONFIG_NAME)
|
|
||||||
return Path(config_directory_path, DEFAULT_CONFIG_NAME)
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_config() -> dict[str, Any]:
|
def get_default_config() -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"version": __version__,
|
"version": __version__,
|
||||||
|
@ -130,26 +101,12 @@ def get_default_colors() -> dict[str, Any]:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_default_journal_path() -> str:
|
|
||||||
journal_data_path = xdg.BaseDirectory.save_data_path(XDG_RESOURCE) or home_dir()
|
|
||||||
return os.path.join(journal_data_path, DEFAULT_JOURNAL_NAME)
|
|
||||||
|
|
||||||
|
|
||||||
def get_templates_path() -> Path:
|
|
||||||
# jrnl_xdg_resource_path is created by save_data_path if it does not exist
|
|
||||||
jrnl_xdg_resource_path = Path(xdg.BaseDirectory.save_data_path(XDG_RESOURCE))
|
|
||||||
jrnl_templates_path = jrnl_xdg_resource_path / "templates"
|
|
||||||
# Create the directory if needed.
|
|
||||||
jrnl_templates_path.mkdir(exist_ok=True)
|
|
||||||
return jrnl_templates_path
|
|
||||||
|
|
||||||
|
|
||||||
def scope_config(config: dict, journal_name: str) -> dict:
|
def scope_config(config: dict, journal_name: str) -> dict:
|
||||||
if journal_name not in config["journals"]:
|
if journal_name not in config["journals"]:
|
||||||
return config
|
return config
|
||||||
config = config.copy()
|
config = config.copy()
|
||||||
journal_conf = config["journals"].get(journal_name)
|
journal_conf = config["journals"].get(journal_name)
|
||||||
if type(journal_conf) is dict:
|
if isinstance(journal_conf, dict):
|
||||||
# We can override the default config on a by-journal basis
|
# We can override the default config on a by-journal basis
|
||||||
logging.debug(
|
logging.debug(
|
||||||
"Updating configuration with specific journal overrides:\n%s",
|
"Updating configuration with specific journal overrides:\n%s",
|
||||||
|
@ -224,7 +181,7 @@ def update_config(
|
||||||
"""Updates a config dict with new values - either global if scope is None
|
"""Updates a config dict with new values - either global if scope is None
|
||||||
or config['journals'][scope] is just a string pointing to a journal file,
|
or config['journals'][scope] is just a string pointing to a journal file,
|
||||||
or within the scope"""
|
or within the scope"""
|
||||||
if scope and type(config["journals"][scope]) is dict: # Update to journal specific
|
if scope and isinstance(config["journals"][scope], dict):
|
||||||
config["journals"][scope].update(new_config)
|
config["journals"][scope].update(new_config)
|
||||||
elif scope and force_local: # Convert to dict
|
elif scope and force_local: # Convert to dict
|
||||||
config["journals"][scope] = {"journal": config["journals"][scope]}
|
config["journals"][scope] = {"journal": config["journals"][scope]}
|
||||||
|
|
|
@ -11,10 +11,10 @@ from jrnl import time
|
||||||
from jrnl.config import DEFAULT_JOURNAL_KEY
|
from jrnl.config import DEFAULT_JOURNAL_KEY
|
||||||
from jrnl.config import get_config_path
|
from jrnl.config import get_config_path
|
||||||
from jrnl.config import get_journal_name
|
from jrnl.config import get_journal_name
|
||||||
from jrnl.config import get_templates_path
|
|
||||||
from jrnl.config import scope_config
|
from jrnl.config import scope_config
|
||||||
from jrnl.editor import get_text_from_editor
|
from jrnl.editor import get_text_from_editor
|
||||||
from jrnl.editor import get_text_from_stdin
|
from jrnl.editor import get_text_from_stdin
|
||||||
|
from jrnl.editor import read_template_file
|
||||||
from jrnl.exception import JrnlException
|
from jrnl.exception import JrnlException
|
||||||
from jrnl.journals import open_journal
|
from jrnl.journals import open_journal
|
||||||
from jrnl.messages import Message
|
from jrnl.messages import Message
|
||||||
|
@ -23,7 +23,6 @@ from jrnl.messages import MsgText
|
||||||
from jrnl.output import print_msg
|
from jrnl.output import print_msg
|
||||||
from jrnl.output import print_msgs
|
from jrnl.output import print_msgs
|
||||||
from jrnl.override import apply_overrides
|
from jrnl.override import apply_overrides
|
||||||
from jrnl.path import absolute_path
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
|
@ -35,9 +34,9 @@ if TYPE_CHECKING:
|
||||||
def run(args: "Namespace"):
|
def run(args: "Namespace"):
|
||||||
"""
|
"""
|
||||||
Flow:
|
Flow:
|
||||||
1. Run standalone command if it doesn't require config (help, version, etc), then exit
|
1. Run standalone command if it doesn't need config (help, version, etc), then exit
|
||||||
2. Load config
|
2. Load config
|
||||||
3. Run standalone command if it does require config (encrypt, decrypt, etc), then exit
|
3. Run standalone command if it does need config (encrypt, decrypt, etc), then exit
|
||||||
4. Load specified journal
|
4. Load specified journal
|
||||||
5. Start append mode, or search mode
|
5. Start append mode, or search mode
|
||||||
6. Perform actions with results from search mode (if needed)
|
6. Perform actions with results from search mode (if needed)
|
||||||
|
@ -130,74 +129,6 @@ def _is_append_mode(args: "Namespace", config: dict, **kwargs) -> bool:
|
||||||
return append_mode
|
return append_mode
|
||||||
|
|
||||||
|
|
||||||
def _read_template_file(template_arg: str, template_path_from_config: str) -> str:
|
|
||||||
"""
|
|
||||||
This function is called when either a template file is passed with --template, or config.template is set.
|
|
||||||
|
|
||||||
The processing logic is:
|
|
||||||
If --template was not used: Load the global template file.
|
|
||||||
If --template was used:
|
|
||||||
* Check $XDG_DATA_HOME/jrnl/templates/template_arg.
|
|
||||||
* Check template_arg as an absolute / relative path.
|
|
||||||
|
|
||||||
If a file is found, its contents are returned as a string.
|
|
||||||
If not, a JrnlException is raised.
|
|
||||||
"""
|
|
||||||
logging.debug(
|
|
||||||
"Append mode: Either a template arg was passed, or the global config is set."
|
|
||||||
)
|
|
||||||
|
|
||||||
# If filename is unset, we are in this flow due to a global template being configured
|
|
||||||
if not template_arg:
|
|
||||||
logging.debug("Append mode: Global template configuration detected.")
|
|
||||||
global_template_path = absolute_path(template_path_from_config)
|
|
||||||
try:
|
|
||||||
with open(global_template_path, encoding="utf-8") as f:
|
|
||||||
template_data = f.read()
|
|
||||||
return template_data
|
|
||||||
except FileNotFoundError:
|
|
||||||
raise JrnlException(
|
|
||||||
Message(
|
|
||||||
MsgText.CantReadTemplateGlobalConfig,
|
|
||||||
MsgStyle.ERROR,
|
|
||||||
{
|
|
||||||
"global_template_path": global_template_path,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else: # A template CLI arg was passed.
|
|
||||||
logging.debug("Trying to load template from $XDG_DATA_HOME/jrnl/templates/")
|
|
||||||
jrnl_template_dir = get_templates_path()
|
|
||||||
logging.debug(f"Append mode: jrnl templates directory: {jrnl_template_dir}")
|
|
||||||
template_path = jrnl_template_dir / template_arg
|
|
||||||
try:
|
|
||||||
with open(template_path, encoding="utf-8") as f:
|
|
||||||
template_data = f.read()
|
|
||||||
return template_data
|
|
||||||
except FileNotFoundError:
|
|
||||||
logging.debug(
|
|
||||||
f"Couldn't open {template_path}. Treating --template argument like a local / abs path."
|
|
||||||
)
|
|
||||||
pass
|
|
||||||
|
|
||||||
normalized_template_arg_filepath = absolute_path(template_arg)
|
|
||||||
try:
|
|
||||||
with open(normalized_template_arg_filepath, encoding="utf-8") as f:
|
|
||||||
template_data = f.read()
|
|
||||||
return template_data
|
|
||||||
except FileNotFoundError:
|
|
||||||
raise JrnlException(
|
|
||||||
Message(
|
|
||||||
MsgText.CantReadTemplateCLIArg,
|
|
||||||
MsgStyle.ERROR,
|
|
||||||
{
|
|
||||||
"normalized_template_arg_filepath": normalized_template_arg_filepath,
|
|
||||||
"jrnl_template_dir": template_path,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def append_mode(args: "Namespace", config: dict, journal: "Journal", **kwargs) -> None:
|
def append_mode(args: "Namespace", config: dict, journal: "Journal", **kwargs) -> None:
|
||||||
"""
|
"""
|
||||||
Gets input from the user to write to the journal
|
Gets input from the user to write to the journal
|
||||||
|
@ -210,26 +141,22 @@ def append_mode(args: "Namespace", config: dict, journal: "Journal", **kwargs) -
|
||||||
"""
|
"""
|
||||||
logging.debug("Append mode: starting")
|
logging.debug("Append mode: starting")
|
||||||
|
|
||||||
if args.template or config["template"]:
|
template_text = _get_template(args, config)
|
||||||
logging.debug(f"Append mode: template CLI arg detected: {args.template}")
|
|
||||||
# Read template file and pass as raw text into the composer
|
if args.text:
|
||||||
template_data = _read_template_file(args.template, config["template"])
|
|
||||||
raw = _write_in_editor(config, template_data)
|
|
||||||
if raw == template_data:
|
|
||||||
logging.error("Append mode: raw text was the same as the template")
|
|
||||||
raise JrnlException(Message(MsgText.NoChangesToTemplate, MsgStyle.NORMAL))
|
|
||||||
elif args.text:
|
|
||||||
logging.debug(f"Append mode: cli text detected: {args.text}")
|
logging.debug(f"Append mode: cli text detected: {args.text}")
|
||||||
raw = " ".join(args.text).strip()
|
raw = " ".join(args.text).strip()
|
||||||
if args.edit:
|
if args.edit:
|
||||||
raw = _write_in_editor(config, raw)
|
raw = _write_in_editor(config, raw)
|
||||||
|
|
||||||
elif not sys.stdin.isatty():
|
elif not sys.stdin.isatty():
|
||||||
logging.debug("Append mode: receiving piped text")
|
logging.debug("Append mode: receiving piped text")
|
||||||
raw = sys.stdin.read()
|
raw = sys.stdin.read()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raw = _write_in_editor(config)
|
raw = _write_in_editor(config, template_text)
|
||||||
|
|
||||||
|
if template_text is not None and raw == template_text:
|
||||||
|
logging.error("Append mode: raw text was the same as the template")
|
||||||
|
raise JrnlException(Message(MsgText.NoChangesToTemplate, MsgStyle.NORMAL))
|
||||||
|
|
||||||
if not raw or raw.isspace():
|
if not raw or raw.isspace():
|
||||||
logging.error("Append mode: couldn't get raw text or entry was empty")
|
logging.error("Append mode: couldn't get raw text or entry was empty")
|
||||||
|
@ -251,6 +178,23 @@ def append_mode(args: "Namespace", config: dict, journal: "Journal", **kwargs) -
|
||||||
logging.debug("Append mode: completed journal.write()")
|
logging.debug("Append mode: completed journal.write()")
|
||||||
|
|
||||||
|
|
||||||
|
def _get_template(args, config) -> str:
|
||||||
|
# Read template file and pass as raw text into the composer
|
||||||
|
logging.debug(
|
||||||
|
"Get template:\n"
|
||||||
|
f"--template: {args.template}\n"
|
||||||
|
f"from config: {config.get('template')}"
|
||||||
|
)
|
||||||
|
template_path = args.template or config.get("template")
|
||||||
|
|
||||||
|
template_text = None
|
||||||
|
|
||||||
|
if template_path:
|
||||||
|
template_text = read_template_file(template_path)
|
||||||
|
|
||||||
|
return template_text
|
||||||
|
|
||||||
|
|
||||||
def search_mode(args: "Namespace", journal: "Journal", **kwargs) -> None:
|
def search_mode(args: "Namespace", journal: "Journal", **kwargs) -> None:
|
||||||
"""
|
"""
|
||||||
Search for entries in a journal, and return the
|
Search for entries in a journal, and return the
|
||||||
|
|
|
@ -15,6 +15,8 @@ from jrnl.messages import MsgText
|
||||||
from jrnl.os_compat import on_windows
|
from jrnl.os_compat import on_windows
|
||||||
from jrnl.os_compat import split_args
|
from jrnl.os_compat import split_args
|
||||||
from jrnl.output import print_msg
|
from jrnl.output import print_msg
|
||||||
|
from jrnl.path import absolute_path
|
||||||
|
from jrnl.path import get_templates_path
|
||||||
|
|
||||||
|
|
||||||
def get_text_from_editor(config: dict, template: str = "") -> str:
|
def get_text_from_editor(config: dict, template: str = "") -> str:
|
||||||
|
@ -56,9 +58,9 @@ def get_text_from_stdin() -> str:
|
||||||
MsgText.WritingEntryStart,
|
MsgText.WritingEntryStart,
|
||||||
MsgStyle.TITLE,
|
MsgStyle.TITLE,
|
||||||
{
|
{
|
||||||
"how_to_quit": MsgText.HowToQuitWindows
|
"how_to_quit": (
|
||||||
if on_windows()
|
MsgText.HowToQuitWindows if on_windows() else MsgText.HowToQuitLinux
|
||||||
else MsgText.HowToQuitLinux
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -73,3 +75,47 @@ def get_text_from_stdin() -> str:
|
||||||
)
|
)
|
||||||
|
|
||||||
return raw
|
return raw
|
||||||
|
|
||||||
|
|
||||||
|
def get_template_path(template_path: str, jrnl_template_dir: str) -> str:
|
||||||
|
actual_template_path = os.path.join(jrnl_template_dir, template_path)
|
||||||
|
if not os.path.exists(actual_template_path):
|
||||||
|
logging.debug(
|
||||||
|
f"Couldn't open {actual_template_path}. "
|
||||||
|
"Treating template path like a local / abs path."
|
||||||
|
)
|
||||||
|
actual_template_path = absolute_path(template_path)
|
||||||
|
|
||||||
|
return actual_template_path
|
||||||
|
|
||||||
|
|
||||||
|
def read_template_file(template_path: str) -> str:
|
||||||
|
"""
|
||||||
|
Reads the template file given a template path in this order:
|
||||||
|
|
||||||
|
* Check $XDG_DATA_HOME/jrnl/templates/template_path.
|
||||||
|
* Check template_arg as an absolute / relative path.
|
||||||
|
|
||||||
|
If a file is found, its contents are returned as a string.
|
||||||
|
If not, a JrnlException is raised.
|
||||||
|
"""
|
||||||
|
|
||||||
|
jrnl_template_dir = get_templates_path()
|
||||||
|
actual_template_path = get_template_path(template_path, jrnl_template_dir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(actual_template_path, encoding="utf-8") as f:
|
||||||
|
template_data = f.read()
|
||||||
|
return template_data
|
||||||
|
except FileNotFoundError:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.CantReadTemplate,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{
|
||||||
|
"template_path": template_path,
|
||||||
|
"actual_template_path": actual_template_path,
|
||||||
|
"jrnl_template_dir": str(jrnl_template_dir) + os.sep,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -31,11 +31,11 @@ from jrnl.upgrade import is_old_version
|
||||||
|
|
||||||
|
|
||||||
def upgrade_config(config_data: dict, alt_config_path: str | None = None) -> None:
|
def upgrade_config(config_data: dict, alt_config_path: str | None = None) -> None:
|
||||||
"""Checks if there are keys missing in a given config dict, and if so, updates the config file accordingly.
|
"""Checks if there are keys missing in a given config dict, and if so, updates the
|
||||||
This essentially automatically ports jrnl installations if new config parameters are introduced in later
|
config file accordingly. This essentially automatically ports jrnl installations
|
||||||
versions.
|
if new config parameters are introduced in later versions. Also checks for
|
||||||
Also checks for existence of and difference in version number between config dict and current jrnl version,
|
existence of and difference in version number between config dict
|
||||||
and if so, update the config file accordingly.
|
and current jrnl version, and if so, update the config file accordingly.
|
||||||
Supply alt_config_path if using an alternate config through --config-file."""
|
Supply alt_config_path if using an alternate config through --config-file."""
|
||||||
default_config = get_default_config()
|
default_config = get_default_config()
|
||||||
missing_keys = set(default_config).difference(config_data)
|
missing_keys = set(default_config).difference(config_data)
|
||||||
|
@ -167,7 +167,7 @@ def install() -> dict:
|
||||||
|
|
||||||
|
|
||||||
def _initialize_autocomplete() -> None:
|
def _initialize_autocomplete() -> None:
|
||||||
# readline is not included in Windows Active Python and perhaps some other distributions
|
# readline is not included in Windows Active Python and perhaps some other distss
|
||||||
if sys.modules.get("readline"):
|
if sys.modules.get("readline"):
|
||||||
import readline
|
import readline
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,9 @@ import os
|
||||||
import re
|
import re
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import ansiwrap
|
|
||||||
|
|
||||||
from jrnl.color import colorize
|
from jrnl.color import colorize
|
||||||
from jrnl.color import highlight_tags_with_background_color
|
from jrnl.color import highlight_tags_with_background_color
|
||||||
|
from jrnl.output import wrap_with_ansi_colors
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .Journal import Journal
|
from .Journal import Journal
|
||||||
|
@ -89,7 +88,7 @@ class Entry:
|
||||||
}
|
}
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Returns a string representation of the entry to be written into a journal file."""
|
"""Returns string representation of the entry to be written to journal file."""
|
||||||
date_str = self.date.strftime(self.journal.config["timeformat"])
|
date_str = self.date.strftime(self.journal.config["timeformat"])
|
||||||
title = "[{}] {}".format(date_str, self.title.rstrip("\n "))
|
title = "[{}] {}".format(date_str, self.title.rstrip("\n "))
|
||||||
if self.starred:
|
if self.starred:
|
||||||
|
@ -129,7 +128,7 @@ class Entry:
|
||||||
columns = 79
|
columns = 79
|
||||||
|
|
||||||
# Color date / title and bold title
|
# Color date / title and bold title
|
||||||
title = ansiwrap.fill(
|
title = wrap_with_ansi_colors(
|
||||||
date_str
|
date_str
|
||||||
+ " "
|
+ " "
|
||||||
+ highlight_tags_with_background_color(
|
+ highlight_tags_with_background_color(
|
||||||
|
@ -143,35 +142,17 @@ class Entry:
|
||||||
body = highlight_tags_with_background_color(
|
body = highlight_tags_with_background_color(
|
||||||
self, self.body.rstrip(" \n"), self.journal.config["colors"]["body"]
|
self, self.body.rstrip(" \n"), self.journal.config["colors"]["body"]
|
||||||
)
|
)
|
||||||
body_text = [
|
|
||||||
colorize(
|
|
||||||
ansiwrap.fill(
|
|
||||||
line,
|
|
||||||
columns,
|
|
||||||
initial_indent=indent,
|
|
||||||
subsequent_indent=indent,
|
|
||||||
drop_whitespace=True,
|
|
||||||
),
|
|
||||||
self.journal.config["colors"]["body"],
|
|
||||||
)
|
|
||||||
or indent
|
|
||||||
for line in body.rstrip(" \n").splitlines()
|
|
||||||
]
|
|
||||||
|
|
||||||
# ansiwrap doesn't handle lines with only the "\n" character and some
|
body = wrap_with_ansi_colors(body, columns - len(indent))
|
||||||
# ANSI escapes properly, so we have this hack here to make sure the
|
if indent:
|
||||||
# beginning of each line has the indent character and it's colored
|
# Without explicitly colorizing the indent character, it will lose its
|
||||||
# properly. textwrap doesn't have this issue, however, it doesn't wrap
|
# color after a tag appears.
|
||||||
# the strings properly as it counts ANSI escapes as literal characters.
|
|
||||||
# TL;DR: I'm sorry.
|
|
||||||
body = "\n".join(
|
body = "\n".join(
|
||||||
[
|
|
||||||
colorize(indent, self.journal.config["colors"]["body"]) + line
|
colorize(indent, self.journal.config["colors"]["body"]) + line
|
||||||
if not ansiwrap.strip_color(line).startswith(indent)
|
for line in body.splitlines()
|
||||||
else line
|
|
||||||
for line in body_text
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
body = colorize(body, self.journal.config["colors"]["body"])
|
||||||
else:
|
else:
|
||||||
title = (
|
title = (
|
||||||
date_str
|
date_str
|
||||||
|
@ -233,7 +214,7 @@ SENTENCE_SPLITTER = re.compile(
|
||||||
\s+ # AND a sequence of required spaces.
|
\s+ # AND a sequence of required spaces.
|
||||||
)
|
)
|
||||||
|[\uFF01\uFF0E\uFF1F\uFF61\u3002] # CJK full/half width terminals usually do not have following spaces.
|
|[\uFF01\uFF0E\uFF1F\uFF61\u3002] # CJK full/half width terminals usually do not have following spaces.
|
||||||
""",
|
""", # noqa: E501
|
||||||
re.VERBOSE,
|
re.VERBOSE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,8 @@ class Folder(Journal):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_files(journal_path: str) -> list[str]:
|
def _get_files(journal_path: str) -> list[str]:
|
||||||
"""Searches through sub directories starting with journal_path and find all text files that look like entries"""
|
"""Searches through sub directories starting with journal_path and find all text
|
||||||
|
files that look like entries"""
|
||||||
for year_folder in Folder._get_year_folders(pathlib.Path(journal_path)):
|
for year_folder in Folder._get_year_folders(pathlib.Path(journal_path)):
|
||||||
for month_folder in Folder._get_month_folders(year_folder):
|
for month_folder in Folder._get_month_folders(year_folder):
|
||||||
yield from Folder._get_day_files(month_folder)
|
yield from Folder._get_day_files(month_folder)
|
||||||
|
|
|
@ -102,7 +102,7 @@ class Journal:
|
||||||
return self.encryption_method.encrypt(text)
|
return self.encryption_method.encrypt(text)
|
||||||
|
|
||||||
def open(self, filename: str | None = None) -> "Journal":
|
def open(self, filename: str | None = None) -> "Journal":
|
||||||
"""Opens the journal file defined in the config and parses it into a list of Entries.
|
"""Opens the journal file and parses it into a list of Entries
|
||||||
Entries have the form (date, title, body)."""
|
Entries have the form (date, title, body)."""
|
||||||
filename = filename or self.config["journal"]
|
filename = filename or self.config["journal"]
|
||||||
dirname = os.path.dirname(filename)
|
dirname = os.path.dirname(filename)
|
||||||
|
@ -144,7 +144,7 @@ class Journal:
|
||||||
self._store(filename, text)
|
self._store(filename, text)
|
||||||
|
|
||||||
def validate_parsing(self) -> bool:
|
def validate_parsing(self) -> bool:
|
||||||
"""Confirms that the jrnl is still parsed correctly after being dumped to text."""
|
"""Confirms that the jrnl is still parsed correctly after conversion to text."""
|
||||||
new_entries = self._parse(self._to_text())
|
new_entries = self._parse(self._to_text())
|
||||||
return all(entry == new_entries[i] for i, entry in enumerate(self.entries))
|
return all(entry == new_entries[i] for i, entry in enumerate(self.entries))
|
||||||
|
|
||||||
|
@ -225,8 +225,9 @@ class Journal:
|
||||||
@property
|
@property
|
||||||
def tags(self) -> list[Tag]:
|
def tags(self) -> list[Tag]:
|
||||||
"""Returns a set of tuples (count, tag) for all tags present in the journal."""
|
"""Returns a set of tuples (count, tag) for all tags present in the journal."""
|
||||||
# Astute reader: should the following line leave you as puzzled as me the first time
|
# Astute reader: should the following line leave you as puzzled as me the first
|
||||||
# I came across this construction, worry not and embrace the ensuing moment of enlightment.
|
# time I came across this construction, worry not and embrace the ensuing moment
|
||||||
|
# of enlightment.
|
||||||
tags = [tag for entry in self.entries for tag in set(entry.tags)]
|
tags = [tag for entry in self.entries for tag in set(entry.tags)]
|
||||||
# To be read: [for entry in journal.entries: for tag in set(entry.tags): tag]
|
# To be read: [for entry in journal.entries: for tag in set(entry.tags): tag]
|
||||||
tag_counts = {(tags.count(tag), tag) for tag in tags}
|
tag_counts = {(tags.count(tag), tag) for tag in tags}
|
||||||
|
@ -245,7 +246,7 @@ class Journal:
|
||||||
exclude_starred=False,
|
exclude_starred=False,
|
||||||
exclude_tagged=False,
|
exclude_tagged=False,
|
||||||
strict=False,
|
strict=False,
|
||||||
contains=None,
|
contains=[],
|
||||||
exclude=[],
|
exclude=[],
|
||||||
):
|
):
|
||||||
"""Removes all entries from the journal that don't match the filter.
|
"""Removes all entries from the journal that don't match the filter.
|
||||||
|
@ -275,7 +276,7 @@ class Journal:
|
||||||
return 0 < len([tag for tag in tags if tag in excluded_tags])
|
return 0 < len([tag for tag in tags if tag in excluded_tags])
|
||||||
|
|
||||||
if contains:
|
if contains:
|
||||||
contains_lower = contains.casefold()
|
contains_lower = [substring.casefold() for substring in contains]
|
||||||
|
|
||||||
# Create datetime object for comparison below
|
# Create datetime object for comparison below
|
||||||
# this approach allows various formats
|
# this approach allows various formats
|
||||||
|
@ -297,8 +298,20 @@ class Journal:
|
||||||
and (
|
and (
|
||||||
not contains
|
not contains
|
||||||
or (
|
or (
|
||||||
contains_lower in entry.title.casefold()
|
strict
|
||||||
or contains_lower in entry.body.casefold()
|
and all(
|
||||||
|
substring in entry.title.casefold()
|
||||||
|
or substring in entry.body.casefold()
|
||||||
|
for substring in contains_lower
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or (
|
||||||
|
not strict
|
||||||
|
and any(
|
||||||
|
substring in entry.title.casefold()
|
||||||
|
or substring in entry.body.casefold()
|
||||||
|
for substring in contains_lower
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
@ -343,7 +356,8 @@ class Journal:
|
||||||
|
|
||||||
def new_entry(self, raw: str, date=None, sort: bool = True) -> Entry:
|
def new_entry(self, raw: str, date=None, sort: bool = True) -> Entry:
|
||||||
"""Constructs a new entry from some raw text input.
|
"""Constructs a new entry from some raw text input.
|
||||||
If a date is given, it will parse and use this, otherwise scan for a date in the input first.
|
If a date is given, it will parse and use this, otherwise scan for a date in
|
||||||
|
the input first.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
raw = raw.replace("\\n ", "\n").replace("\\n", "\n")
|
raw = raw.replace("\\n ", "\n").replace("\\n", "\n")
|
||||||
|
|
|
@ -90,4 +90,4 @@ class MsgStyle(Enum):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def box_title(self) -> MsgText:
|
def box_title(self) -> MsgText:
|
||||||
return self.value.get("box_title", None)
|
return self.value.get("box_title")
|
||||||
|
|
|
@ -43,8 +43,8 @@ class MsgText(Enum):
|
||||||
Do you want to encrypt your journal? (You can always change this later)
|
Do you want to encrypt your journal? (You can always change this later)
|
||||||
"""
|
"""
|
||||||
UseColorsQuestion = """
|
UseColorsQuestion = """
|
||||||
Do you want jrnl to use colors when displaying entries? (You can always change this later)
|
Do you want jrnl to use colors to display entries? (You can always change this later)
|
||||||
"""
|
""" # noqa: E501 - the line is still under 88 when dedented
|
||||||
YesOrNoPromptDefaultYes = "[Y/n]"
|
YesOrNoPromptDefaultYes = "[Y/n]"
|
||||||
YesOrNoPromptDefaultNo = "[y/N]"
|
YesOrNoPromptDefaultNo = "[y/N]"
|
||||||
ContinueUpgrade = "Continue upgrading jrnl?"
|
ContinueUpgrade = "Continue upgrading jrnl?"
|
||||||
|
@ -105,16 +105,12 @@ class MsgText(Enum):
|
||||||
|
|
||||||
KeyboardInterruptMsg = "Aborted by user"
|
KeyboardInterruptMsg = "Aborted by user"
|
||||||
|
|
||||||
CantReadTemplateGlobalConfig = """
|
CantReadTemplate = """
|
||||||
Could not read template file defined in config:
|
Unable to find a template file {template_path}.
|
||||||
{global_template_path}
|
|
||||||
"""
|
|
||||||
|
|
||||||
CantReadTemplateCLIArg = """
|
The following paths were checked:
|
||||||
Unable to find a template file based on the passed arg, and no global template was detected.
|
* {jrnl_template_dir}{template_path}
|
||||||
The following filepaths were checked:
|
* {actual_template_path}
|
||||||
jrnl XDG Template Directory : {jrnl_template_dir}
|
|
||||||
Local Filepath : {normalized_template_arg_filepath}
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
NoNamedJournal = "No '{journal_name}' journal configured\n{journals}"
|
NoNamedJournal = "No '{journal_name}' journal configured\n{journals}"
|
||||||
|
@ -270,6 +266,11 @@ class MsgText(Enum):
|
||||||
{count} imported to {journal_name} journal
|
{count} imported to {journal_name} journal
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
ImporterNotFound = """
|
||||||
|
No importer found for file type '{format}'.
|
||||||
|
'{format}' is likely to be an export-only format.
|
||||||
|
"""
|
||||||
|
|
||||||
# --- Color --- #
|
# --- Color --- #
|
||||||
InvalidColor = "{key} set to invalid color: {color}"
|
InvalidColor = "{key} set to invalid color: {color}"
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,10 @@ def journal_list_to_yaml(journal_list: dict) -> str:
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
output = StringIO()
|
output = StringIO()
|
||||||
YAML().dump(journal_list, output)
|
dumper = YAML()
|
||||||
|
dumper.width = 1000
|
||||||
|
dumper.dump(journal_list, output)
|
||||||
|
|
||||||
return output.getvalue()
|
return output.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,3 +131,12 @@ def format_msg_text(msg: Message) -> Text:
|
||||||
text = textwrap.dedent(text)
|
text = textwrap.dedent(text)
|
||||||
text = text.strip()
|
text = text.strip()
|
||||||
return Text(text)
|
return Text(text)
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_with_ansi_colors(text: str, width: int) -> str:
|
||||||
|
richtext = Text.from_ansi(text, no_wrap=False, tab_size=None)
|
||||||
|
|
||||||
|
console = Console(width=width, force_terminal=True)
|
||||||
|
with console.capture() as capture:
|
||||||
|
console.print(richtext, sep="", end="")
|
||||||
|
return capture.get()
|
||||||
|
|
|
@ -21,7 +21,7 @@ def apply_overrides(args: "Namespace", base_config: dict) -> dict:
|
||||||
:return: Configuration to be used during runtime with the overrides applied
|
:return: Configuration to be used during runtime with the overrides applied
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
"""
|
"""
|
||||||
overrides = vars(args).get("config_override", None)
|
overrides = vars(args).get("config_override")
|
||||||
if not overrides:
|
if not overrides:
|
||||||
return base_config
|
return base_config
|
||||||
|
|
||||||
|
@ -56,7 +56,8 @@ def _recursively_apply(tree: dict, nodes: list, override_value) -> dict:
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
config (dict): Configuration to modify
|
config (dict): Configuration to modify
|
||||||
nodes (list): Vector of override keys; the length of the vector indicates tree depth
|
nodes (list): Vector of override keys; the length of the vector indicates tree
|
||||||
|
depth
|
||||||
override_value (str): Runtime override passed from the command-line
|
override_value (str): Runtime override passed from the command-line
|
||||||
"""
|
"""
|
||||||
key = nodes[0]
|
key = nodes[0]
|
||||||
|
|
56
jrnl/path.py
56
jrnl/path.py
|
@ -2,6 +2,19 @@
|
||||||
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import xdg.BaseDirectory
|
||||||
|
|
||||||
|
from jrnl.exception import JrnlException
|
||||||
|
from jrnl.messages import Message
|
||||||
|
from jrnl.messages import MsgStyle
|
||||||
|
from jrnl.messages import MsgText
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
XDG_RESOURCE = "jrnl"
|
||||||
|
DEFAULT_CONFIG_NAME = "jrnl.yaml"
|
||||||
|
DEFAULT_JOURNAL_NAME = "journal.txt"
|
||||||
|
|
||||||
|
|
||||||
def home_dir() -> str:
|
def home_dir() -> str:
|
||||||
|
@ -14,3 +27,46 @@ def expand_path(path: str) -> str:
|
||||||
|
|
||||||
def absolute_path(path: str) -> str:
|
def absolute_path(path: str) -> str:
|
||||||
return os.path.abspath(expand_path(path))
|
return os.path.abspath(expand_path(path))
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_journal_path() -> str:
|
||||||
|
journal_data_path = xdg.BaseDirectory.save_data_path(XDG_RESOURCE) or home_dir()
|
||||||
|
return os.path.join(journal_data_path, DEFAULT_JOURNAL_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
def get_templates_path() -> str:
|
||||||
|
"""
|
||||||
|
Get the path to the XDG templates directory. Creates the directory if it
|
||||||
|
doesn't exist.
|
||||||
|
"""
|
||||||
|
# jrnl_xdg_resource_path is created by save_data_path if it does not exist
|
||||||
|
jrnl_xdg_resource_path = Path(xdg.BaseDirectory.save_data_path(XDG_RESOURCE))
|
||||||
|
jrnl_templates_path = jrnl_xdg_resource_path / "templates"
|
||||||
|
# Create the directory if needed.
|
||||||
|
jrnl_templates_path.mkdir(exist_ok=True)
|
||||||
|
return str(jrnl_templates_path)
|
||||||
|
|
||||||
|
|
||||||
|
def get_config_directory() -> str:
|
||||||
|
try:
|
||||||
|
return xdg.BaseDirectory.save_config_path(XDG_RESOURCE)
|
||||||
|
except FileExistsError:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.ConfigDirectoryIsFile,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{
|
||||||
|
"config_directory_path": os.path.join(
|
||||||
|
xdg.BaseDirectory.xdg_config_home, XDG_RESOURCE
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_config_path() -> str:
|
||||||
|
try:
|
||||||
|
config_directory_path = get_config_directory()
|
||||||
|
except JrnlException:
|
||||||
|
return os.path.join(home_dir(), DEFAULT_CONFIG_NAME)
|
||||||
|
return os.path.join(config_directory_path, DEFAULT_CONFIG_NAME)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
from jrnl.plugins.calendar_heatmap_exporter import CalendarHeatmapExporter
|
||||||
from jrnl.plugins.dates_exporter import DatesExporter
|
from jrnl.plugins.dates_exporter import DatesExporter
|
||||||
from jrnl.plugins.fancy_exporter import FancyExporter
|
from jrnl.plugins.fancy_exporter import FancyExporter
|
||||||
from jrnl.plugins.jrnl_importer import JRNLImporter
|
from jrnl.plugins.jrnl_importer import JRNLImporter
|
||||||
|
@ -14,14 +15,15 @@ from jrnl.plugins.xml_exporter import XMLExporter
|
||||||
from jrnl.plugins.yaml_exporter import YAMLExporter
|
from jrnl.plugins.yaml_exporter import YAMLExporter
|
||||||
|
|
||||||
__exporters = [
|
__exporters = [
|
||||||
|
CalendarHeatmapExporter,
|
||||||
|
DatesExporter,
|
||||||
|
FancyExporter,
|
||||||
JSONExporter,
|
JSONExporter,
|
||||||
MarkdownExporter,
|
MarkdownExporter,
|
||||||
TagExporter,
|
TagExporter,
|
||||||
DatesExporter,
|
|
||||||
TextExporter,
|
TextExporter,
|
||||||
XMLExporter,
|
XMLExporter,
|
||||||
YAMLExporter,
|
YAMLExporter,
|
||||||
FancyExporter,
|
|
||||||
]
|
]
|
||||||
__importers = [JRNLImporter]
|
__importers = [JRNLImporter]
|
||||||
|
|
||||||
|
|
117
jrnl/plugins/calendar_heatmap_exporter.py
Normal file
117
jrnl/plugins/calendar_heatmap_exporter.py
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
import calendar
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from rich import box
|
||||||
|
from rich.align import Align
|
||||||
|
from rich.columns import Columns
|
||||||
|
from rich.console import Console
|
||||||
|
from rich.table import Table
|
||||||
|
from rich.text import Text
|
||||||
|
|
||||||
|
from jrnl.plugins.text_exporter import TextExporter
|
||||||
|
from jrnl.plugins.util import get_journal_frequency_nested
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from jrnl.journals import Entry
|
||||||
|
from jrnl.journals import Journal
|
||||||
|
from jrnl.plugins.util import NestedDict
|
||||||
|
|
||||||
|
|
||||||
|
class CalendarHeatmapExporter(TextExporter):
|
||||||
|
"""This Exporter displays a calendar heatmap of the journaling frequency."""
|
||||||
|
|
||||||
|
names = ["calendar", "heatmap"]
|
||||||
|
extension = "cal"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def export_entry(cls, entry: "Entry"):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def print_calendar_heatmap(cls, journal_frequency: "NestedDict") -> str:
|
||||||
|
"""Returns a string representation of the calendar heatmap."""
|
||||||
|
console = Console()
|
||||||
|
cal = calendar.Calendar()
|
||||||
|
curr_year = datetime.now().year
|
||||||
|
curr_month = datetime.now().month
|
||||||
|
curr_day = datetime.now().day
|
||||||
|
hit_first_entry = False
|
||||||
|
with console.capture() as capture:
|
||||||
|
for year, month_journaling_freq in journal_frequency.items():
|
||||||
|
year_calendar = []
|
||||||
|
for month in range(1, 13):
|
||||||
|
if month > curr_month and year == curr_year:
|
||||||
|
break
|
||||||
|
|
||||||
|
entries_this_month = sum(month_journaling_freq[month].values())
|
||||||
|
if not hit_first_entry and entries_this_month > 0:
|
||||||
|
hit_first_entry = True
|
||||||
|
|
||||||
|
if entries_this_month == 0 and not hit_first_entry:
|
||||||
|
continue
|
||||||
|
elif entries_this_month == 0:
|
||||||
|
entry_msg = "No entries"
|
||||||
|
elif entries_this_month == 1:
|
||||||
|
entry_msg = "1 entry"
|
||||||
|
else:
|
||||||
|
entry_msg = f"{entries_this_month} entries"
|
||||||
|
table = Table(
|
||||||
|
title=f"{calendar.month_name[month]} {year} ({entry_msg})",
|
||||||
|
title_style="bold green",
|
||||||
|
box=box.SIMPLE_HEAVY,
|
||||||
|
padding=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
for week_day in cal.iterweekdays():
|
||||||
|
table.add_column(
|
||||||
|
"{:.3}".format(calendar.day_name[week_day]), justify="right"
|
||||||
|
)
|
||||||
|
|
||||||
|
month_days = cal.monthdayscalendar(year, month)
|
||||||
|
for weekdays in month_days:
|
||||||
|
days = []
|
||||||
|
for _, day in enumerate(weekdays):
|
||||||
|
if day == 0: # Not a part of this month, just filler.
|
||||||
|
day_label = Text(str(day or ""), style="white")
|
||||||
|
elif (
|
||||||
|
day > curr_day
|
||||||
|
and month == curr_month
|
||||||
|
and year == curr_year
|
||||||
|
):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
journal_frequency_for_day = (
|
||||||
|
month_journaling_freq[month][day] or 0
|
||||||
|
)
|
||||||
|
day = str(day)
|
||||||
|
# TODO: Make colors configurable?
|
||||||
|
if journal_frequency_for_day == 0:
|
||||||
|
day_label = Text(day, style="red on black")
|
||||||
|
elif journal_frequency_for_day == 1:
|
||||||
|
day_label = Text(day, style="black on yellow")
|
||||||
|
elif journal_frequency_for_day == 2:
|
||||||
|
day_label = Text(day, style="black on green")
|
||||||
|
else:
|
||||||
|
day_label = Text(day, style="black on white")
|
||||||
|
|
||||||
|
days.append(day_label)
|
||||||
|
table.add_row(*days)
|
||||||
|
|
||||||
|
year_calendar.append(Align.center(table))
|
||||||
|
|
||||||
|
# Print year header line
|
||||||
|
console.rule(str(year))
|
||||||
|
console.print()
|
||||||
|
# Print calendar
|
||||||
|
console.print(Columns(year_calendar, padding=1, expand=True))
|
||||||
|
return capture.get()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def export_journal(cls, journal: "Journal"):
|
||||||
|
"""Returns dates and their frequencies for an entire journal."""
|
||||||
|
journal_entry_date_frequency = get_journal_frequency_nested(journal)
|
||||||
|
return cls.print_calendar_heatmap(journal_entry_date_frequency)
|
|
@ -1,10 +1,10 @@
|
||||||
# Copyright © 2012-2023 jrnl contributors
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
from collections import Counter
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from jrnl.plugins.text_exporter import TextExporter
|
from jrnl.plugins.text_exporter import TextExporter
|
||||||
|
from jrnl.plugins.util import get_journal_frequency_one_level
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from jrnl.journals import Entry
|
from jrnl.journals import Entry
|
||||||
|
@ -24,10 +24,6 @@ class DatesExporter(TextExporter):
|
||||||
@classmethod
|
@classmethod
|
||||||
def export_journal(cls, journal: "Journal") -> str:
|
def export_journal(cls, journal: "Journal") -> str:
|
||||||
"""Returns dates and their frequencies for an entire journal."""
|
"""Returns dates and their frequencies for an entire journal."""
|
||||||
date_counts = Counter()
|
date_counts = get_journal_frequency_one_level(journal)
|
||||||
for entry in journal.entries:
|
|
||||||
# entry.date.date() gets date without time
|
|
||||||
date = str(entry.date.date())
|
|
||||||
date_counts[date] += 1
|
|
||||||
result = "\n".join(f"{date}, {count}" for date, count in date_counts.items())
|
result = "\n".join(f"{date}, {count}" for date, count in date_counts.items())
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class FancyExporter(TextExporter):
|
class FancyExporter(TextExporter):
|
||||||
"""This Exporter can convert entries and journals into text with unicode box drawing characters."""
|
"""This Exporter converts entries and journals into text with unicode boxes."""
|
||||||
|
|
||||||
names = ["fancy", "boxed"]
|
names = ["fancy", "boxed"]
|
||||||
extension = "txt"
|
extension = "txt"
|
||||||
|
|
|
@ -12,7 +12,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class TagExporter(TextExporter):
|
class TagExporter(TextExporter):
|
||||||
"""This Exporter can lists the tags for entries and journals, exported as a plain text file."""
|
"""This Exporter lists the tags for entries and journals."""
|
||||||
|
|
||||||
names = ["tags"]
|
names = ["tags"]
|
||||||
extension = "tags"
|
extension = "tags"
|
||||||
|
|
|
@ -1,16 +1,26 @@
|
||||||
# Copyright © 2012-2023 jrnl contributors
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
from collections import Counter
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from jrnl.journals import Journal
|
from jrnl.journals import Journal
|
||||||
|
|
||||||
|
|
||||||
|
class NestedDict(dict):
|
||||||
|
"""https://stackoverflow.com/a/74873621/8740440"""
|
||||||
|
|
||||||
|
def __missing__(self, x):
|
||||||
|
self[x] = NestedDict()
|
||||||
|
return self[x]
|
||||||
|
|
||||||
|
|
||||||
def get_tags_count(journal: "Journal") -> set[tuple[int, str]]:
|
def get_tags_count(journal: "Journal") -> set[tuple[int, str]]:
|
||||||
"""Returns a set of tuples (count, tag) for all tags present in the journal."""
|
"""Returns a set of tuples (count, tag) for all tags present in the journal."""
|
||||||
# Astute reader: should the following line leave you as puzzled as me the first time
|
# Astute reader: should the following line leave you as puzzled as me the first time
|
||||||
# I came across this construction, worry not and embrace the ensuing moment of enlightment.
|
# I came across this construction, worry not and embrace the ensuing moment of
|
||||||
|
# enlightment.
|
||||||
tags = [tag for entry in journal.entries for tag in set(entry.tags)]
|
tags = [tag for entry in journal.entries for tag in set(entry.tags)]
|
||||||
# To be read: [for entry in journal.entries: for tag in set(entry.tags): tag]
|
# To be read: [for entry in journal.entries: for tag in set(entry.tags): tag]
|
||||||
tag_counts = {(tags.count(tag), tag) for tag in tags}
|
tag_counts = {(tags.count(tag), tag) for tag in tags}
|
||||||
|
@ -28,3 +38,26 @@ def oxford_list(lst: list) -> str:
|
||||||
return lst[0] + " or " + lst[1]
|
return lst[0] + " or " + lst[1]
|
||||||
else:
|
else:
|
||||||
return ", ".join(lst[:-1]) + ", or " + lst[-1]
|
return ", ".join(lst[:-1]) + ", or " + lst[-1]
|
||||||
|
|
||||||
|
|
||||||
|
def get_journal_frequency_nested(journal: "Journal") -> NestedDict:
|
||||||
|
"""Returns a NestedDict of the form {year: {month: {day: count}}}"""
|
||||||
|
journal_frequency = NestedDict()
|
||||||
|
for entry in journal.entries:
|
||||||
|
date = entry.date.date()
|
||||||
|
if date.day in journal_frequency[date.year][date.month]:
|
||||||
|
journal_frequency[date.year][date.month][date.day] += 1
|
||||||
|
else:
|
||||||
|
journal_frequency[date.year][date.month][date.day] = 1
|
||||||
|
|
||||||
|
return journal_frequency
|
||||||
|
|
||||||
|
|
||||||
|
def get_journal_frequency_one_level(journal: "Journal") -> Counter:
|
||||||
|
"""Returns a Counter of the form {date (YYYY-MM-DD): count}"""
|
||||||
|
date_counts = Counter()
|
||||||
|
for entry in journal.entries:
|
||||||
|
# entry.date.date() gets date without time
|
||||||
|
date = str(entry.date.date())
|
||||||
|
date_counts[date] += 1
|
||||||
|
return date_counts
|
||||||
|
|
|
@ -18,14 +18,15 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class YAMLExporter(TextExporter):
|
class YAMLExporter(TextExporter):
|
||||||
"""This Exporter can convert entries and journals into Markdown formatted text with YAML front matter."""
|
"""This Exporter converts entries and journals into Markdown formatted text with
|
||||||
|
YAML front matter."""
|
||||||
|
|
||||||
names = ["yaml"]
|
names = ["yaml"]
|
||||||
extension = "md"
|
extension = "md"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def export_entry(cls, entry: "Entry", to_multifile: bool = True) -> str:
|
def export_entry(cls, entry: "Entry", to_multifile: bool = True) -> str:
|
||||||
"""Returns a markdown representation of a single entry, with YAML front matter."""
|
"""Returns a markdown representation of an entry, with YAML front matter."""
|
||||||
if to_multifile is False:
|
if to_multifile is False:
|
||||||
raise JrnlException(Message(MsgText.YamlMustBeDirectory, MsgStyle.ERROR))
|
raise JrnlException(Message(MsgText.YamlMustBeDirectory, MsgStyle.ERROR))
|
||||||
|
|
||||||
|
@ -117,7 +118,14 @@ class YAMLExporter(TextExporter):
|
||||||
# source directory is entry.journal.config['journal']
|
# source directory is entry.journal.config['journal']
|
||||||
# output directory is...?
|
# output directory is...?
|
||||||
|
|
||||||
return "{start}\ntitle: {title}\ndate: {date}\nstarred: {starred}\ntags: {tags}\n{dayone}body: |{body}{end}".format(
|
return (
|
||||||
|
"{start}\n"
|
||||||
|
"title: {title}\n"
|
||||||
|
"date: {date}\n"
|
||||||
|
"starred: {starred}\n"
|
||||||
|
"tags: {tags}\n"
|
||||||
|
"{dayone}body: |{body}{end}"
|
||||||
|
).format(
|
||||||
start="---",
|
start="---",
|
||||||
date=date_str,
|
date=date_str,
|
||||||
title=entry.title,
|
title=entry.title,
|
||||||
|
|
32
jrnl/time.py
32
jrnl/time.py
|
@ -9,14 +9,11 @@ DEFAULT_PAST = datetime.datetime(FAKE_YEAR, 1, 1, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
def __get_pdt_calendar():
|
def __get_pdt_calendar():
|
||||||
try:
|
|
||||||
import parsedatetime.parsedatetime_consts as pdt
|
|
||||||
except ImportError:
|
|
||||||
import parsedatetime as pdt
|
import parsedatetime as pdt
|
||||||
|
|
||||||
consts = pdt.Constants(usePyICU=False)
|
consts = pdt.Constants(usePyICU=False)
|
||||||
consts.DOWParseStyle = -1 # "Monday" will be either today or the last Monday
|
consts.DOWParseStyle = -1 # "Monday" will be either today or the last Monday
|
||||||
calendar = pdt.Calendar(consts)
|
calendar = pdt.Calendar(consts, version=pdt.VERSION_CONTEXT_STYLE)
|
||||||
|
|
||||||
return calendar
|
return calendar
|
||||||
|
|
||||||
|
@ -34,14 +31,18 @@ def parse(
|
||||||
elif isinstance(date_str, datetime.datetime):
|
elif isinstance(date_str, datetime.datetime):
|
||||||
return date_str
|
return date_str
|
||||||
|
|
||||||
# Don't try to parse anything with 6 or fewer characters and was parsed from the existing journal.
|
# Don't try to parse anything with 6 or fewer characters and was parsed from the
|
||||||
# It's probably a markdown footnote
|
# existing journal. It's probably a markdown footnote
|
||||||
if len(date_str) <= 6 and bracketed:
|
if len(date_str) <= 6 and bracketed:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
default_date = DEFAULT_FUTURE if inclusive else DEFAULT_PAST
|
default_date = DEFAULT_FUTURE if inclusive else DEFAULT_PAST
|
||||||
date = None
|
date = None
|
||||||
year_present = False
|
year_present = False
|
||||||
|
|
||||||
|
hasTime = False
|
||||||
|
hasDate = False
|
||||||
|
|
||||||
while not date:
|
while not date:
|
||||||
try:
|
try:
|
||||||
from dateutil.parser import parse as dateparse
|
from dateutil.parser import parse as dateparse
|
||||||
|
@ -53,7 +54,8 @@ def parse(
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
year_present = True
|
year_present = True
|
||||||
flag = 1 if date.hour == date.minute == 0 else 2
|
hasTime = not (date.hour == date.minute == 0)
|
||||||
|
hasDate = True
|
||||||
date = date.timetuple()
|
date = date.timetuple()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if e.args[0] == "day is out of range for month":
|
if e.args[0] == "day is out of range for month":
|
||||||
|
@ -61,9 +63,11 @@ def parse(
|
||||||
default_date = datetime.datetime(y, m, d - 1, H, M, S)
|
default_date = datetime.datetime(y, m, d - 1, H, M, S)
|
||||||
else:
|
else:
|
||||||
calendar = __get_pdt_calendar()
|
calendar = __get_pdt_calendar()
|
||||||
date, flag = calendar.parse(date_str)
|
date, parse_context = calendar.parse(date_str)
|
||||||
|
hasTime = parse_context.hasTime
|
||||||
|
hasDate = parse_context.hasDate
|
||||||
|
|
||||||
if not flag: # Oops, unparsable.
|
if not hasDate and not hasTime:
|
||||||
try: # Try and parse this as a single year
|
try: # Try and parse this as a single year
|
||||||
year = int(date_str)
|
year = int(date_str)
|
||||||
return datetime.datetime(year, 1, 1)
|
return datetime.datetime(year, 1, 1)
|
||||||
|
@ -72,8 +76,8 @@ def parse(
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if flag == 1: # Date found, but no time. Use the default time.
|
if hasDate and not hasTime:
|
||||||
date = datetime.datetime(
|
date = datetime.datetime( # Use the default time
|
||||||
*date[:3],
|
*date[:3],
|
||||||
hour=23 if inclusive else default_hour or 0,
|
hour=23 if inclusive else default_hour or 0,
|
||||||
minute=59 if inclusive else default_minute or 0,
|
minute=59 if inclusive else default_minute or 0,
|
||||||
|
@ -82,9 +86,9 @@ def parse(
|
||||||
else:
|
else:
|
||||||
date = datetime.datetime(*date[:6])
|
date = datetime.datetime(*date[:6])
|
||||||
|
|
||||||
# Ugly heuristic: if the date is more than 4 weeks in the future, we got the year wrong.
|
# Ugly heuristic: if the date is more than 4 weeks in the future, we got the year
|
||||||
# Rather than this, we would like to see parsedatetime patched so we can tell it to prefer
|
# wrong. Rather than this, we would like to see parsedatetime patched so we can
|
||||||
# past dates
|
# tell it to prefer past dates
|
||||||
dt = datetime.datetime.now() - date
|
dt = datetime.datetime.now() - date
|
||||||
if dt.days < -28 and not year_present:
|
if dt.days < -28 and not year_present:
|
||||||
date = date.replace(date.year - 1)
|
date = date.replace(date.year - 1)
|
||||||
|
|
148
package-lock.json
generated
148
package-lock.json
generated
|
@ -5,7 +5,7 @@
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"pa11y-ci": "3.0.1"
|
"pa11y-ci": "3.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
|
@ -25,12 +25,6 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/abbrev": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/agent-base": {
|
"node_modules/agent-base": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
|
@ -74,9 +68,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axe-core": {
|
"node_modules/axe-core": {
|
||||||
"version": "4.4.3",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.2.4.tgz",
|
||||||
"integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==",
|
"integrity": "sha512-9AiDKFKUCWEQm1Kj4lcq7KFavLqSXdf2m/zJo+NVh4VXlW5iwXRJ6alkKmipCyYorsRnqsICH9XLubP1jBF+Og==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
|
@ -525,19 +519,6 @@
|
||||||
"node": ">= 0.4.0"
|
"node": ">= 0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/hogan.js": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"mkdirp": "0.3.0",
|
|
||||||
"nopt": "1.0.10"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"hulk": "bin/hulk"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/hoopy": {
|
"node_modules/hoopy": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||||
|
@ -684,16 +665,6 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mkdirp": {
|
|
||||||
"version": "0.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz",
|
|
||||||
"integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==",
|
|
||||||
"deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mkdirp-classic": {
|
"node_modules/mkdirp-classic": {
|
||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||||
|
@ -706,6 +677,15 @@
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/mustache": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"mustache": "bin/mustache"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-fetch": {
|
"node_modules/node-fetch": {
|
||||||
"version": "2.6.7",
|
"version": "2.6.7",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||||
|
@ -739,21 +719,6 @@
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nopt": {
|
|
||||||
"version": "1.0.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
|
||||||
"integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"abbrev": "1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"nopt": "bin/nopt.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/nth-check": {
|
"node_modules/nth-check": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||||
|
@ -830,18 +795,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pa11y": {
|
"node_modules/pa11y": {
|
||||||
"version": "6.1.1",
|
"version": "6.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/pa11y/-/pa11y-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/pa11y/-/pa11y-6.2.3.tgz",
|
||||||
"integrity": "sha512-2NzqA3D9CUlDWj8WuOI4fM2P0qM1d/IUxsRRpzCOfDT5eMR1oEgmUwW2TAk+f90ff/GVck0BewdYT4et4BANew==",
|
"integrity": "sha512-69JoUlfW2QVmrgQAm+17XBxIvmd1u0ImFBYIHPyjC61CzAkmxO3kkbqDVxIcl0OKLvAMYSMbvfCH8kMFE9xsbg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axe-core": "^4.0.2",
|
"axe-core": "~4.2.1",
|
||||||
"bfj": "~7.0.2",
|
"bfj": "~7.0.2",
|
||||||
"commander": "~8.0.0",
|
"commander": "~8.0.0",
|
||||||
"envinfo": "~7.8.1",
|
"envinfo": "~7.8.1",
|
||||||
"hogan.js": "^3.0.2",
|
"html_codesniffer": "~2.5.1",
|
||||||
"html_codesniffer": "^2.5.1",
|
|
||||||
"kleur": "~4.1.4",
|
"kleur": "~4.1.4",
|
||||||
|
"mustache": "~4.2.0",
|
||||||
"node.extend": "~2.0.2",
|
"node.extend": "~2.0.2",
|
||||||
"p-timeout": "~4.1.0",
|
"p-timeout": "~4.1.0",
|
||||||
"puppeteer": "~9.1.1",
|
"puppeteer": "~9.1.1",
|
||||||
|
@ -855,19 +820,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pa11y-ci": {
|
"node_modules/pa11y-ci": {
|
||||||
"version": "3.0.1",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/pa11y-ci/-/pa11y-ci-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/pa11y-ci/-/pa11y-ci-3.1.0.tgz",
|
||||||
"integrity": "sha512-DUtEIhEG3Ofds7qRuplq0DdCb9doILRlzcRctFNzo4QUNmVy4iZfM3u51A9cqoPo2irCJZoo5BzfiFrcriY2IQ==",
|
"integrity": "sha512-1WBGBMq0dYtZ+N/SH/AcnFSsT6sZ2w27d8Z/5XHJWSELeX8Qhh4yX5f0drb7crwjt7ugKSo4A7eEF9RbMB0LYg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "~2.6.3",
|
"async": "~2.6.4",
|
||||||
"cheerio": "~1.0.0-rc.10",
|
"cheerio": "~1.0.0-rc.10",
|
||||||
"commander": "~6.2.1",
|
"commander": "~6.2.1",
|
||||||
"globby": "~6.1.0",
|
"globby": "~6.1.0",
|
||||||
"kleur": "~4.1.4",
|
"kleur": "~4.1.4",
|
||||||
"lodash": "~4.17.21",
|
"lodash": "~4.17.21",
|
||||||
"node-fetch": "~2.6.1",
|
"node-fetch": "~2.6.1",
|
||||||
"pa11y": "~6.1.0",
|
"pa11y": "^6.2.3",
|
||||||
"protocolify": "~3.0.0",
|
"protocolify": "~3.0.0",
|
||||||
"puppeteer": "~9.1.1",
|
"puppeteer": "~9.1.1",
|
||||||
"wordwrap": "~1.0.0"
|
"wordwrap": "~1.0.0"
|
||||||
|
@ -1270,12 +1235,6 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"abbrev": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"agent-base": {
|
"agent-base": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
|
@ -1310,9 +1269,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"axe-core": {
|
"axe-core": {
|
||||||
"version": "4.4.3",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.2.4.tgz",
|
||||||
"integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==",
|
"integrity": "sha512-9AiDKFKUCWEQm1Kj4lcq7KFavLqSXdf2m/zJo+NVh4VXlW5iwXRJ6alkKmipCyYorsRnqsICH9XLubP1jBF+Og==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
|
@ -1633,16 +1592,6 @@
|
||||||
"function-bind": "^1.1.1"
|
"function-bind": "^1.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hogan.js": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"mkdirp": "0.3.0",
|
|
||||||
"nopt": "1.0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"hoopy": {
|
"hoopy": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||||
|
@ -1744,12 +1693,6 @@
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
|
||||||
"version": "0.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz",
|
|
||||||
"integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"mkdirp-classic": {
|
"mkdirp-classic": {
|
||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||||
|
@ -1762,6 +1705,12 @@
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"mustache": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node-fetch": {
|
"node-fetch": {
|
||||||
"version": "2.6.7",
|
"version": "2.6.7",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||||
|
@ -1781,15 +1730,6 @@
|
||||||
"is": "^3.2.1"
|
"is": "^3.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nopt": {
|
|
||||||
"version": "1.0.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
|
||||||
"integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"abbrev": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nth-check": {
|
"nth-check": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||||
|
@ -1845,18 +1785,18 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"pa11y": {
|
"pa11y": {
|
||||||
"version": "6.1.1",
|
"version": "6.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/pa11y/-/pa11y-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/pa11y/-/pa11y-6.2.3.tgz",
|
||||||
"integrity": "sha512-2NzqA3D9CUlDWj8WuOI4fM2P0qM1d/IUxsRRpzCOfDT5eMR1oEgmUwW2TAk+f90ff/GVck0BewdYT4et4BANew==",
|
"integrity": "sha512-69JoUlfW2QVmrgQAm+17XBxIvmd1u0ImFBYIHPyjC61CzAkmxO3kkbqDVxIcl0OKLvAMYSMbvfCH8kMFE9xsbg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"axe-core": "^4.0.2",
|
"axe-core": "~4.2.1",
|
||||||
"bfj": "~7.0.2",
|
"bfj": "~7.0.2",
|
||||||
"commander": "~8.0.0",
|
"commander": "~8.0.0",
|
||||||
"envinfo": "~7.8.1",
|
"envinfo": "~7.8.1",
|
||||||
"hogan.js": "^3.0.2",
|
"html_codesniffer": "~2.5.1",
|
||||||
"html_codesniffer": "^2.5.1",
|
|
||||||
"kleur": "~4.1.4",
|
"kleur": "~4.1.4",
|
||||||
|
"mustache": "~4.2.0",
|
||||||
"node.extend": "~2.0.2",
|
"node.extend": "~2.0.2",
|
||||||
"p-timeout": "~4.1.0",
|
"p-timeout": "~4.1.0",
|
||||||
"puppeteer": "~9.1.1",
|
"puppeteer": "~9.1.1",
|
||||||
|
@ -1872,19 +1812,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pa11y-ci": {
|
"pa11y-ci": {
|
||||||
"version": "3.0.1",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/pa11y-ci/-/pa11y-ci-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/pa11y-ci/-/pa11y-ci-3.1.0.tgz",
|
||||||
"integrity": "sha512-DUtEIhEG3Ofds7qRuplq0DdCb9doILRlzcRctFNzo4QUNmVy4iZfM3u51A9cqoPo2irCJZoo5BzfiFrcriY2IQ==",
|
"integrity": "sha512-1WBGBMq0dYtZ+N/SH/AcnFSsT6sZ2w27d8Z/5XHJWSELeX8Qhh4yX5f0drb7crwjt7ugKSo4A7eEF9RbMB0LYg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"async": "~2.6.3",
|
"async": "~2.6.4",
|
||||||
"cheerio": "~1.0.0-rc.10",
|
"cheerio": "~1.0.0-rc.10",
|
||||||
"commander": "~6.2.1",
|
"commander": "~6.2.1",
|
||||||
"globby": "~6.1.0",
|
"globby": "~6.1.0",
|
||||||
"kleur": "~4.1.4",
|
"kleur": "~4.1.4",
|
||||||
"lodash": "~4.17.21",
|
"lodash": "~4.17.21",
|
||||||
"node-fetch": "~2.6.1",
|
"node-fetch": "~2.6.1",
|
||||||
"pa11y": "~6.1.0",
|
"pa11y": "^6.2.3",
|
||||||
"protocolify": "~3.0.0",
|
"protocolify": "~3.0.0",
|
||||||
"puppeteer": "~9.1.1",
|
"puppeteer": "~9.1.1",
|
||||||
"wordwrap": "~1.0.0"
|
"wordwrap": "~1.0.0"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"pa11y-ci": "3.0.1"
|
"pa11y-ci": "3.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2017
poetry.lock
generated
2017
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "jrnl"
|
name = "jrnl"
|
||||||
version = "v4.0"
|
version = "v4.2.1"
|
||||||
description = "Collect your thoughts and notes without leaving the command line."
|
description = "Collect your thoughts and notes without leaving the command line."
|
||||||
authors = [
|
authors = [
|
||||||
"jrnl contributors <maintainers@jrnl.sh>",
|
"jrnl contributors <maintainers@jrnl.sh>",
|
||||||
|
@ -27,38 +27,32 @@ classifiers = [
|
||||||
"Funding" = "https://opencollective.com/jrnl"
|
"Funding" = "https://opencollective.com/jrnl"
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = ">=3.10.0, <3.13"
|
python = ">=3.10.0, <3.14"
|
||||||
|
|
||||||
ansiwrap = "^0.8.4"
|
|
||||||
colorama = ">=0.4" # https://github.com/tartley/colorama/blob/master/CHANGELOG.rst
|
colorama = ">=0.4" # https://github.com/tartley/colorama/blob/master/CHANGELOG.rst
|
||||||
cryptography = ">=3.0" # https://cryptography.io/en/latest/api-stability.html
|
cryptography = ">=3.0" # https://cryptography.io/en/latest/api-stability.html
|
||||||
keyring = ">=21.0" # https://github.com/jaraco/keyring#integration
|
keyring = ">=21.0" # https://github.com/jaraco/keyring#integration
|
||||||
parsedatetime = ">=2.6"
|
parsedatetime = ">=2.6"
|
||||||
python-dateutil = "^2.8" # https://github.com/dateutil/dateutil/blob/master/RELEASING
|
python-dateutil = "^2.8" # https://github.com/dateutil/dateutil/blob/master/RELEASING
|
||||||
pyxdg = ">=0.27.0"
|
pyxdg = ">=0.27.0"
|
||||||
"ruamel.yaml" = "0.17.21" # locked to this version until bug is resolved: https://github.com/jrnl-org/jrnl/issues/1736
|
"ruamel.yaml" = ">=0.17.22"
|
||||||
rich = ">=12.2.0, <14.0.0"
|
rich = ">=14.0.0, <14.1.0"
|
||||||
|
|
||||||
# dayone-only deps
|
# dayone-only deps
|
||||||
tzlocal = ">=4.0" # https://github.com/regebro/tzlocal/blob/master/CHANGES.txt
|
tzlocal = ">=4.0" # https://github.com/regebro/tzlocal/blob/master/CHANGES.txt
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = { version = ">=21.5b2", allow-prereleases = true }
|
black = { version = ">=21.5b2", allow-prereleases = true }
|
||||||
flakeheaven = ">=3.0"
|
|
||||||
flake8-black = ">=0.3.3"
|
|
||||||
flake8-isort = ">=5.0.0"
|
|
||||||
flake8-type-checking = ">=2.2.0"
|
|
||||||
flake8-simplify = ">=0.19"
|
|
||||||
ipdb = "*"
|
ipdb = "*"
|
||||||
isort = ">=5.10"
|
|
||||||
mkdocs = ">=1.4"
|
mkdocs = ">=1.4"
|
||||||
parse-type = ">=0.6.0"
|
parse-type = ">=0.6.0"
|
||||||
poethepoet = "*"
|
poethepoet = "*"
|
||||||
pytest = ">=6.2"
|
pytest = ">=8.1"
|
||||||
pytest-bdd = ">=6.0"
|
pytest-bdd = ">=8.0"
|
||||||
pytest-clarity = "*"
|
pytest-clarity = "*"
|
||||||
pytest-xdist = ">=2.5.0"
|
pytest-xdist = ">=2.5.0"
|
||||||
requests = "*"
|
requests = "*"
|
||||||
|
ruff = ">=0.0.276"
|
||||||
toml = ">=0.10"
|
toml = ">=0.10"
|
||||||
tox = "*"
|
tox = "*"
|
||||||
xmltodict = "*"
|
xmltodict = "*"
|
||||||
|
@ -88,18 +82,18 @@ test-run = [
|
||||||
# Groups of tasks
|
# Groups of tasks
|
||||||
format.default_item_type = "cmd"
|
format.default_item_type = "cmd"
|
||||||
format.sequence = [
|
format.sequence = [
|
||||||
"isort .",
|
"ruff check . --select I --fix", # equivalent to "isort ."
|
||||||
"black .",
|
"black .",
|
||||||
]
|
]
|
||||||
|
|
||||||
lint.env = { FLAKEHEAVEN_CACHE_TIMEOUT = "0" }
|
|
||||||
lint.default_item_type = "cmd"
|
lint.default_item_type = "cmd"
|
||||||
lint.sequence = [
|
lint.sequence = [
|
||||||
"poetry --version",
|
"poetry --version",
|
||||||
"poetry check",
|
"poetry check",
|
||||||
"flakeheaven --version",
|
"ruff --version",
|
||||||
"flakeheaven plugins",
|
"ruff check .",
|
||||||
"flakeheaven lint",
|
"black --version",
|
||||||
|
"black --check ."
|
||||||
]
|
]
|
||||||
|
|
||||||
test = [
|
test = [
|
||||||
|
@ -107,11 +101,6 @@ test = [
|
||||||
"test-run",
|
"test-run",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.isort]
|
|
||||||
profile = "black"
|
|
||||||
force_single_line = true
|
|
||||||
known_first_party = ["jrnl", "tests"]
|
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
minversion = "6.0"
|
minversion = "6.0"
|
||||||
required_plugins = [
|
required_plugins = [
|
||||||
|
@ -132,34 +121,40 @@ addopts = [
|
||||||
|
|
||||||
filterwarnings = [
|
filterwarnings = [
|
||||||
"ignore::DeprecationWarning",
|
"ignore::DeprecationWarning",
|
||||||
"ignore:Flag style will be deprecated in.*",
|
|
||||||
"ignore:[WinError 32].*",
|
"ignore:[WinError 32].*",
|
||||||
"ignore:[WinError 5].*"
|
"ignore:[WinError 5].*"
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.flakeheaven]
|
[tool.ruff]
|
||||||
max_line_length = 88
|
line-length = 88
|
||||||
|
target-version = "py310"
|
||||||
|
|
||||||
|
# https://beta.ruff.rs/docs/rules/
|
||||||
|
lint.select = [
|
||||||
|
'F', # Pyflakes
|
||||||
|
'E', # pycodestyle errors
|
||||||
|
'W', # pycodestyle warnings
|
||||||
|
'I', # isort
|
||||||
|
'ASYNC', # flake8-async
|
||||||
|
'S110', # try-except-pass
|
||||||
|
'S112', # try-except-continue
|
||||||
|
'EM', # flake8-errmsg
|
||||||
|
'ISC', # flake8-implicit-str-concat
|
||||||
|
'Q', # flake8-quotes
|
||||||
|
'RSE', # flake8-raise
|
||||||
|
'TID', # flake8-tidy-imports
|
||||||
|
'TCH', # flake8-type-checking
|
||||||
|
'T100', # debugger, don't allow break points
|
||||||
|
'ICN' # flake8-import-conventions
|
||||||
|
]
|
||||||
exclude = [".git", ".tox", ".venv", "node_modules"]
|
exclude = [".git", ".tox", ".venv", "node_modules"]
|
||||||
|
|
||||||
[tool.flakeheaven.plugins]
|
[tool.ruff.lint.isort]
|
||||||
"py*" = ["+*"]
|
force-single-line = true
|
||||||
pycodestyle = [
|
known-first-party = ["jrnl", "tests"]
|
||||||
"-E101",
|
|
||||||
"-E111", "-E114", "-E115", "-E116", "-E117",
|
|
||||||
"-E12*",
|
|
||||||
"-E13*",
|
|
||||||
"-E2*",
|
|
||||||
"-E3*",
|
|
||||||
"-E401",
|
|
||||||
"-E5*",
|
|
||||||
"-E70",
|
|
||||||
"-W1*", "-W2*", "-W3*", "-W5*",
|
|
||||||
]
|
|
||||||
"flake8-*" = ["+*"]
|
|
||||||
flake8-black = ["-BLK901"]
|
|
||||||
|
|
||||||
[tool.flakeheaven.exceptions."jrnl/journals/__init__.py"]
|
[tool.ruff.lint.per-file-ignores]
|
||||||
pyflakes = ["-F401"]
|
"__init__.py" = ["F401"] # unused imports
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
|
@ -174,8 +169,8 @@ isolated_build = True
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
deps =
|
deps =
|
||||||
pytest >= 6.2
|
pytest >=8.1
|
||||||
pytest-bdd >=6.0
|
pytest-bdd >=8.0
|
||||||
pytest-xdist >=2.5.0
|
pytest-xdist >=2.5.0
|
||||||
parse-type >=0.6.0
|
parse-type >=0.6.0
|
||||||
toml >=0.10
|
toml >=0.10
|
||||||
|
|
9
tasks.py
9
tasks.py
|
@ -41,7 +41,14 @@ def generate_pa11y_config_from_sitemap():
|
||||||
urls += [url["loc"] for url in xml_sitemap["urlset"]["url"]]
|
urls += [url["loc"] for url in xml_sitemap["urlset"]["url"]]
|
||||||
|
|
||||||
with open(CONFIG_FILENAME, "w") as f:
|
with open(CONFIG_FILENAME, "w") as f:
|
||||||
f.write(json.dumps({"urls": urls}))
|
f.write(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"defaults": {"chromeLaunchConfig": {"args": ["--no-sandbox"]}},
|
||||||
|
"urls": urls,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def output_file(file):
|
def output_file(file):
|
||||||
|
|
|
@ -8,16 +8,20 @@ Feature: Test combinations of edit, change-time, and delete
|
||||||
And we write nothing to the editor if opened
|
And we write nothing to the editor if opened
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' --edit" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' --edit" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
N
|
N
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "No text received from editor. Were you trying to delete all the entries?"
|
Then the error output should contain "No text received from editor. Were you trying to delete all the entries?"
|
||||||
And the editor should have been called
|
And the editor should have been called
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2022-04-23 10:30 Entry the first.
|
2022-04-23 10:30 Entry the first.
|
||||||
2022-04-23 10:30 The third entry finally after weeks without writing.
|
2022-04-23 10:30 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -29,12 +33,16 @@ Feature: Test combinations of edit, change-time, and delete
|
||||||
Scenario Outline: --delete with --edit deletes selected entries
|
Scenario Outline: --delete with --edit deletes selected entries
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we append to the editor if opened
|
And we append to the editor if opened
|
||||||
|
"""
|
||||||
[2023-02-21 10:32] Here is a new entry
|
[2023-02-21 10:32] Here is a new entry
|
||||||
|
"""
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --delete --edit" and enter
|
When we run "jrnl --delete --edit" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
N
|
N
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the editor should have been called
|
Then the editor should have been called
|
||||||
And the error output should contain "3 entries found"
|
And the error output should contain "3 entries found"
|
||||||
And the error output should contain "2 entries deleted"
|
And the error output should contain "2 entries deleted"
|
||||||
|
@ -42,8 +50,10 @@ Feature: Test combinations of edit, change-time, and delete
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the error output should contain "2 entries found"
|
Then the error output should contain "2 entries found"
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2023-02-21 10:32 Here is a new entry
|
2023-02-21 10:32 Here is a new entry
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -57,19 +67,23 @@ Feature: Test combinations of edit, change-time, and delete
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
# --change-time is asked first, then --delete
|
# --change-time is asked first, then --delete
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' --delete" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' --delete" and enter
|
||||||
|
"""
|
||||||
N
|
N
|
||||||
N
|
N
|
||||||
Y
|
Y
|
||||||
Y
|
Y
|
||||||
N
|
N
|
||||||
N
|
N
|
||||||
|
"""
|
||||||
Then the error output should contain "3 entries found"
|
Then the error output should contain "3 entries found"
|
||||||
And the error output should contain "1 entry deleted"
|
And the error output should contain "1 entry deleted"
|
||||||
And the error output should contain "1 entry modified"
|
And the error output should contain "1 entry modified"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2022-04-23 10:30 The third entry finally after weeks without writing.
|
2022-04-23 10:30 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -81,24 +95,30 @@ Feature: Test combinations of edit, change-time, and delete
|
||||||
Scenario Outline: Combining --change-time and --delete and --edit affects appropriate entries
|
Scenario Outline: Combining --change-time and --delete and --edit affects appropriate entries
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we append to the editor if opened
|
And we append to the editor if opened
|
||||||
|
"""
|
||||||
[2023-02-21 10:32] Here is a new entry
|
[2023-02-21 10:32] Here is a new entry
|
||||||
|
"""
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
# --change-time is asked first, then --delete, then --edit
|
# --change-time is asked first, then --delete, then --edit
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' --delete --edit" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' --delete --edit" and enter
|
||||||
|
"""
|
||||||
N
|
N
|
||||||
Y
|
Y
|
||||||
Y
|
Y
|
||||||
Y
|
Y
|
||||||
Y
|
Y
|
||||||
N
|
N
|
||||||
|
"""
|
||||||
Then the error output should contain "3 entries found"
|
Then the error output should contain "3 entries found"
|
||||||
And the error output should contain "2 entries deleted"
|
And the error output should contain "2 entries deleted"
|
||||||
And the error output should contain "1 entry modified" # only 1, because the other was deleted
|
And the error output should contain "1 entry modified"
|
||||||
And the error output should contain "1 entry added" # by edit
|
And the error output should contain "1 entry added"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2022-04-23 10:30 The third entry finally after weeks without writing.
|
2022-04-23 10:30 The third entry finally after weeks without writing.
|
||||||
2023-02-21 10:32 Here is a new entry
|
2023-02-21 10:32 Here is a new entry
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
|
|
@ -8,14 +8,18 @@ Feature: Change entry times in journal
|
||||||
When we run "jrnl -1"
|
When we run "jrnl -1"
|
||||||
Then the output should contain "2020-09-24 09:14 The third entry finally"
|
Then the output should contain "2020-09-24 09:14 The third entry finally"
|
||||||
When we run "jrnl -1 --change-time '2022-04-23 10:30'" and enter
|
When we run "jrnl -1 --change-time '2022-04-23 10:30'" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "1 entry modified"
|
Then the error output should contain "1 entry modified"
|
||||||
And the error output should not contain "deleted"
|
And the error output should not contain "deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2022-04-23 10:30 The third entry finally after weeks without writing.
|
2022-04-23 10:30 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -29,20 +33,26 @@ Feature: Change entry times in journal
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --short"
|
When we run "jrnl --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30'" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30'" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
N
|
N
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "3 entries found"
|
Then the error output should contain "3 entries found"
|
||||||
And the error output should contain "2 entries modified"
|
And the error output should contain "2 entries modified"
|
||||||
When we run "jrnl --short"
|
When we run "jrnl --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2022-04-23 10:30 Entry the first.
|
2022-04-23 10:30 Entry the first.
|
||||||
2022-04-23 10:30 The third entry finally after weeks without writing.
|
2022-04-23 10:30 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -58,14 +68,18 @@ Feature: Change entry times in journal
|
||||||
When we run "jrnl -1"
|
When we run "jrnl -1"
|
||||||
Then the output should contain "2020-09-24 09:14 The third entry finally"
|
Then the output should contain "2020-09-24 09:14 The third entry finally"
|
||||||
When we run "jrnl -1 --change-time '2023-02-21 10:30'" and enter
|
When we run "jrnl -1 --change-time '2023-02-21 10:30'" and enter
|
||||||
|
"""
|
||||||
N
|
N
|
||||||
|
"""
|
||||||
Then the error output should not contain "modified"
|
Then the error output should not contain "modified"
|
||||||
And the error output should not contain "deleted"
|
And the error output should not contain "deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -83,9 +97,11 @@ Feature: Change entry times in journal
|
||||||
And the error output should not contain "entries deleted"
|
And the error output should not contain "entries deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -99,14 +115,18 @@ Feature: Change entry times in journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' @ipsum" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' @ipsum" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "1 entry found"
|
Then the error output should contain "1 entry found"
|
||||||
And the error output should contain "1 entry modified"
|
And the error output should contain "1 entry modified"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
2022-04-23 10:30 Entry the first.
|
2022-04-23 10:30 Entry the first.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -120,13 +140,17 @@ Feature: Change entry times in journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' @ipsum @tagthree" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' @ipsum @tagthree" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2022-04-23 10:30 Entry the first.
|
2022-04-23 10:30 Entry the first.
|
||||||
2022-04-23 10:30 The third entry finally after weeks without writing.
|
2022-04-23 10:30 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -140,12 +164,16 @@ Feature: Change entry times in journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' -and @tagone @tagtwo" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' -and @tagone @tagtwo" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
2022-04-23 10:30 Entry the first.
|
2022-04-23 10:30 Entry the first.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -159,12 +187,16 @@ Feature: Change entry times in journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' @tagone -not @ipsum" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' @tagone -not @ipsum" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2022-04-23 10:30 The third entry finally after weeks without writing.
|
2022-04-23 10:30 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -178,12 +210,16 @@ Feature: Change entry times in journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' -from 2020-09-01" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' -from 2020-09-01" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2022-04-23 10:30 The third entry finally after weeks without writing.
|
2022-04-23 10:30 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -197,13 +233,17 @@ Feature: Change entry times in journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' -to 2020-08-31" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' -to 2020-08-31" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
2022-04-23 10:30 Entry the first.
|
2022-04-23 10:30 Entry the first.
|
||||||
2022-04-23 10:30 A second entry in what I hope to be a long series.
|
2022-04-23 10:30 A second entry in what I hope to be a long series.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -217,12 +257,16 @@ Feature: Change entry times in journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' -starred" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' -starred" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
2022-04-23 10:30 A second entry in what I hope to be a long series.
|
2022-04-23 10:30 A second entry in what I hope to be a long series.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -236,13 +280,17 @@ Feature: Change entry times in journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time '2022-04-23 10:30' -contains dignissim" and enter
|
When we run "jrnl --change-time '2022-04-23 10:30' -contains dignissim" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "1 entry modified"
|
Then the error output should contain "1 entry modified"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
2022-04-23 10:30 Entry the first.
|
2022-04-23 10:30 Entry the first.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -256,14 +304,18 @@ Feature: Change entry times in journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --change-time" and enter
|
When we run "jrnl --change-time" and enter
|
||||||
|
"""
|
||||||
N
|
N
|
||||||
N
|
N
|
||||||
N
|
N
|
||||||
|
"""
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
|
|
@ -7,8 +7,8 @@ Feature: Multiple journals
|
||||||
Given the config "basic_onefile.yaml" exists
|
Given the config "basic_onefile.yaml" exists
|
||||||
And we use the config "multiple.yaml"
|
And we use the config "multiple.yaml"
|
||||||
When we run "jrnl --cf basic_onefile.yaml -999"
|
When we run "jrnl --cf basic_onefile.yaml -999"
|
||||||
Then the output should not contain "My first entry" # from multiple.yaml
|
Then the output should not contain "My first entry"
|
||||||
And the output should contain "Lorem ipsum" # from basic_onefile.yaml
|
And the output should contain "Lorem ipsum"
|
||||||
|
|
||||||
Scenario: Write to default journal by default using an alternate config
|
Scenario: Write to default journal by default using an alternate config
|
||||||
Given the config "multiple.yaml" exists
|
Given the config "multiple.yaml" exists
|
||||||
|
@ -73,18 +73,22 @@ Feature: Multiple journals
|
||||||
Given the config "multiple.yaml" exists
|
Given the config "multiple.yaml" exists
|
||||||
And we use the config "basic_onefile.yaml"
|
And we use the config "basic_onefile.yaml"
|
||||||
When we run "jrnl new_encrypted --cf multiple.yaml Adding first entry" and enter
|
When we run "jrnl new_encrypted --cf multiple.yaml Adding first entry" and enter
|
||||||
|
"""
|
||||||
these three eyes
|
these three eyes
|
||||||
these three eyes
|
these three eyes
|
||||||
n
|
n
|
||||||
|
"""
|
||||||
Then the output should contain "Journal 'new_encrypted' created at "
|
Then the output should contain "Journal 'new_encrypted' created at "
|
||||||
|
|
||||||
Scenario: Don't overwrite main config when encrypting a journal in an alternate config
|
Scenario: Don't overwrite main config when encrypting a journal in an alternate config
|
||||||
Given the config "basic_onefile.yaml" exists
|
Given the config "basic_onefile.yaml" exists
|
||||||
And we use the config "multiple.yaml"
|
And we use the config "multiple.yaml"
|
||||||
When we run "jrnl --cf basic_onefile.yaml --encrypt" and enter
|
When we run "jrnl --cf basic_onefile.yaml --encrypt" and enter
|
||||||
|
"""
|
||||||
these three eyes
|
these three eyes
|
||||||
these three eyes
|
these three eyes
|
||||||
n
|
n
|
||||||
|
"""
|
||||||
Then the output should contain "Journal encrypted to features/journals/basic_onefile.journal"
|
Then the output should contain "Journal encrypted to features/journals/basic_onefile.journal"
|
||||||
And the config should contain "encrypt: false"
|
And the config should contain "encrypt: false"
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,13 @@ Feature: Reading and writing to journal with custom date formats
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
When we run "jrnl -n 999"
|
When we run "jrnl -n 999"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
09.06.2013 15:39 My first entry.
|
09.06.2013 15:39 My first entry.
|
||||||
| Everything is alright
|
| Everything is alright
|
||||||
|
|
||||||
10.07.2013 15:40 Life is good.
|
10.07.2013 15:40 Life is good.
|
||||||
| But I'm better.
|
| But I'm better.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario Outline: Writing an entry from command line with custom date
|
Scenario Outline: Writing an entry from command line with custom date
|
||||||
|
@ -142,9 +144,11 @@ Feature: Reading and writing to journal with custom date formats
|
||||||
Given we use the config "mostlyreadabledates.yaml"
|
Given we use the config "mostlyreadabledates.yaml"
|
||||||
When we run "jrnl --short"
|
When we run "jrnl --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2019-07-01 14:23 The third entry
|
2019-07-01 14:23 The third entry
|
||||||
2019-07-18 14:23 The first entry
|
2019-07-18 14:23 The first entry
|
||||||
2019-07-19 14:23 The second entry
|
2019-07-19 14:23 The second entry
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario: Update near-valid dates after journal is edited
|
Scenario: Update near-valid dates after journal is edited
|
||||||
|
@ -175,7 +179,9 @@ Feature: Reading and writing to journal with custom date formats
|
||||||
When we run "jrnl -1"
|
When we run "jrnl -1"
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
2013-10-27 04:27 Some text.
|
2013-10-27 04:27 Some text.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@skip #1422
|
@skip #1422
|
||||||
|
|
|
@ -8,15 +8,19 @@ Feature: Delete entries from journal
|
||||||
When we run "jrnl -1"
|
When we run "jrnl -1"
|
||||||
Then the output should contain "2020-09-24 09:14 The third entry finally"
|
Then the output should contain "2020-09-24 09:14 The third entry finally"
|
||||||
When we run "jrnl --delete" and enter
|
When we run "jrnl --delete" and enter
|
||||||
|
"""
|
||||||
N
|
N
|
||||||
N
|
N
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "3 entries found"
|
Then the error output should contain "3 entries found"
|
||||||
And the error output should contain "1 entry deleted"
|
And the error output should contain "1 entry deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -29,13 +33,17 @@ Feature: Delete entries from journal
|
||||||
Scenario Outline: Backing out of interactive delete does not change journal
|
Scenario Outline: Backing out of interactive delete does not change journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --delete -n 1" and enter
|
When we run "jrnl --delete -n 1" and enter
|
||||||
|
"""
|
||||||
N
|
N
|
||||||
|
"""
|
||||||
Then the error output should not contain "deleted"
|
Then the error output should not contain "deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -50,9 +58,11 @@ Feature: Delete entries from journal
|
||||||
Then the error output should contain "No entries to delete"
|
Then the error output should contain "No entries to delete"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -64,13 +74,17 @@ Feature: Delete entries from journal
|
||||||
Scenario Outline: Delete flag with tag only deletes tagged entries
|
Scenario Outline: Delete flag with tag only deletes tagged entries
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --delete @ipsum" and enter
|
When we run "jrnl --delete @ipsum" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "1 entry found"
|
Then the error output should contain "1 entry found"
|
||||||
Then the error output should contain "1 entry deleted"
|
Then the error output should contain "1 entry deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -82,13 +96,17 @@ Feature: Delete entries from journal
|
||||||
Scenario Outline: Delete flag with multiple tags deletes all entries matching any of the tags
|
Scenario Outline: Delete flag with multiple tags deletes all entries matching any of the tags
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --delete @ipsum @tagthree" and enter
|
When we run "jrnl --delete @ipsum @tagthree" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "2 entries found"
|
Then the error output should contain "2 entries found"
|
||||||
And the error output should contain "2 entries deleted"
|
And the error output should contain "2 entries deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -100,13 +118,17 @@ Feature: Delete entries from journal
|
||||||
Scenario Outline: Delete flag with -and deletes boolean AND of tagged entries
|
Scenario Outline: Delete flag with -and deletes boolean AND of tagged entries
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --delete -and @tagone @tagtwo" and enter
|
When we run "jrnl --delete -and @tagone @tagtwo" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "1 entry found"
|
Then the error output should contain "1 entry found"
|
||||||
And the error output should contain "1 entry deleted"
|
And the error output should contain "1 entry deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -118,13 +140,17 @@ Feature: Delete entries from journal
|
||||||
Scenario Outline: Delete flag with -not does not delete entries from given tag
|
Scenario Outline: Delete flag with -not does not delete entries from given tag
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --delete @tagone -not @ipsum" and enter
|
When we run "jrnl --delete @tagone -not @ipsum" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "1 entry found"
|
Then the error output should contain "1 entry found"
|
||||||
And the error output should contain "1 entry deleted"
|
And the error output should contain "1 entry deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -136,13 +162,17 @@ Feature: Delete entries from journal
|
||||||
Scenario Outline: Delete flag with -from search operator only deletes entries since that date
|
Scenario Outline: Delete flag with -from search operator only deletes entries since that date
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --delete -from 2020-09-01" and enter
|
When we run "jrnl --delete -from 2020-09-01" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "1 entry found"
|
Then the error output should contain "1 entry found"
|
||||||
And the error output should contain "1 entry deleted"
|
And the error output should contain "1 entry deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -154,13 +184,17 @@ Feature: Delete entries from journal
|
||||||
Scenario Outline: Delete flag with -to only deletes entries up to specified date
|
Scenario Outline: Delete flag with -to only deletes entries up to specified date
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --delete -to 2020-08-31" and enter
|
When we run "jrnl --delete -to 2020-08-31" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "2 entries found"
|
Then the error output should contain "2 entries found"
|
||||||
And the error output should contain "2 entries deleted"
|
And the error output should contain "2 entries deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -172,12 +206,16 @@ Feature: Delete entries from journal
|
||||||
Scenario Outline: Delete flag with -starred only deletes starred entries
|
Scenario Outline: Delete flag with -starred only deletes starred entries
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --delete -starred" and enter
|
When we run "jrnl --delete -starred" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "1 entry deleted"
|
Then the error output should contain "1 entry deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -189,13 +227,17 @@ Feature: Delete entries from journal
|
||||||
Scenario Outline: Delete flag with -contains only entries containing expression
|
Scenario Outline: Delete flag with -contains only entries containing expression
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --delete -contains dignissim" and enter
|
When we run "jrnl --delete -contains dignissim" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the error output should contain "1 entry found"
|
Then the error output should contain "1 entry found"
|
||||||
And the error output should contain "1 entry deleted"
|
And the error output should contain "1 entry deleted"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
2020-09-24 09:14 The third entry finally after weeks without writing.
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: Configs
|
Examples: Configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
|
|
@ -11,8 +11,10 @@ Feature: Encrypting and decrypting journals
|
||||||
And the config for journal "default" should contain "encrypt: false"
|
And the config for journal "default" should contain "encrypt: false"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@todo
|
@todo
|
||||||
|
@ -23,8 +25,10 @@ Feature: Encrypting and decrypting journals
|
||||||
Then the config for journal "default" should contain "encrypt: false"
|
Then the config for journal "default" should contain "encrypt: false"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario: Trying to encrypt an already encrypted journal
|
Scenario: Trying to encrypt an already encrypted journal
|
||||||
|
@ -36,9 +40,11 @@ Feature: Encrypting and decrypting journals
|
||||||
Scenario Outline: Encrypting a journal
|
Scenario Outline: Encrypting a journal
|
||||||
Given we use the config "simple.yaml"
|
Given we use the config "simple.yaml"
|
||||||
When we run "jrnl --encrypt" and enter
|
When we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
swordfish
|
swordfish
|
||||||
swordfish
|
swordfish
|
||||||
n
|
n
|
||||||
|
"""
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should contain "Journal encrypted"
|
And the output should contain "Journal encrypted"
|
||||||
And the config for journal "default" should contain "encrypt: true"
|
And the config for journal "default" should contain "encrypt: true"
|
||||||
|
@ -50,16 +56,20 @@ Feature: Encrypting and decrypting journals
|
||||||
Given we use the config "simple.yaml"
|
Given we use the config "simple.yaml"
|
||||||
And we don't have a keyring
|
And we don't have a keyring
|
||||||
When we run "jrnl --encrypt" and enter
|
When we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
swordfish
|
swordfish
|
||||||
swordfish
|
swordfish
|
||||||
y
|
y
|
||||||
|
"""
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should contain "Journal encrypted"
|
And the output should contain "Journal encrypted"
|
||||||
When we run "jrnl --encrypt" and enter
|
When we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
swordfish
|
swordfish
|
||||||
tuna
|
tuna
|
||||||
tuna
|
tuna
|
||||||
y
|
y
|
||||||
|
"""
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should contain "Journal default is already encrypted. Create a new password."
|
And the output should contain "Journal default is already encrypted. Create a new password."
|
||||||
And we should be prompted for a password
|
And we should be prompted for a password
|
||||||
|
@ -69,15 +79,19 @@ Feature: Encrypting and decrypting journals
|
||||||
Given we use the config "simple.yaml"
|
Given we use the config "simple.yaml"
|
||||||
And we have a keyring
|
And we have a keyring
|
||||||
When we run "jrnl --encrypt" and enter
|
When we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
swordfish
|
swordfish
|
||||||
swordfish
|
swordfish
|
||||||
y
|
y
|
||||||
|
"""
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should contain "Journal encrypted"
|
And the output should contain "Journal encrypted"
|
||||||
When we run "jrnl --encrypt" and enter
|
When we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
tuna
|
tuna
|
||||||
tuna
|
tuna
|
||||||
y
|
y
|
||||||
|
"""
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should contain "Journal default is already encrypted. Create a new password."
|
And the output should contain "Journal default is already encrypted. Create a new password."
|
||||||
And we should be prompted for a password
|
And we should be prompted for a password
|
||||||
|
|
|
@ -8,7 +8,9 @@ Feature: Journals iteracting with the file system in a way that users can see
|
||||||
When we run "jrnl 23 July 2013: Testing folder journal."
|
When we run "jrnl 23 July 2013: Testing folder journal."
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the journal directory should contain
|
And the journal directory should contain
|
||||||
|
"""
|
||||||
2013/07/23.txt
|
2013/07/23.txt
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Adding multiple entries to a Folder journal should generate multiple date files
|
Scenario: Adding multiple entries to a Folder journal should generate multiple date files
|
||||||
Given we use the config "empty_folder.yaml"
|
Given we use the config "empty_folder.yaml"
|
||||||
|
@ -16,7 +18,9 @@ Feature: Journals iteracting with the file system in a way that users can see
|
||||||
And we run "jrnl 3/7/2014: Second entry of journal."
|
And we run "jrnl 3/7/2014: Second entry of journal."
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the journal directory should contain
|
And the journal directory should contain
|
||||||
|
"""
|
||||||
2013/07/23.txt
|
2013/07/23.txt
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: If the journal and its parent directory don't exist, they should be created
|
Scenario: If the journal and its parent directory don't exist, they should be created
|
||||||
Given we use the config "missing_directory.yaml"
|
Given we use the config "missing_directory.yaml"
|
||||||
|
@ -55,9 +59,11 @@ Feature: Journals iteracting with the file system in a way that users can see
|
||||||
Scenario: Creating journal with relative path should update to absolute path
|
Scenario: Creating journal with relative path should update to absolute path
|
||||||
Given we use no config
|
Given we use no config
|
||||||
When we run "jrnl hello world" and enter
|
When we run "jrnl hello world" and enter
|
||||||
|
"""
|
||||||
test.txt
|
test.txt
|
||||||
n
|
n
|
||||||
\n
|
\n
|
||||||
|
"""
|
||||||
Then the output should contain "Journal 'default' created"
|
Then the output should contain "Journal 'default' created"
|
||||||
When we change directory to "subfolder"
|
When we change directory to "subfolder"
|
||||||
And we run "jrnl -n 1"
|
And we run "jrnl -n 1"
|
||||||
|
|
|
@ -40,10 +40,12 @@ Feature: Custom formats
|
||||||
Given we parse the output as JSON
|
Given we parse the output as JSON
|
||||||
Then "entries" in the parsed output should have 3 elements
|
Then "entries" in the parsed output should have 3 elements
|
||||||
And "tags" in the parsed output should be
|
And "tags" in the parsed output should be
|
||||||
|
"""
|
||||||
@ipsum
|
@ipsum
|
||||||
@tagone
|
@tagone
|
||||||
@tagtwo
|
@tagtwo
|
||||||
@tagthree
|
@tagthree
|
||||||
|
"""
|
||||||
And "entries.0.tags" in the parsed output should have 3 elements
|
And "entries.0.tags" in the parsed output should have 3 elements
|
||||||
And "entries.1.tags" in the parsed output should have 1 elements
|
And "entries.1.tags" in the parsed output should have 1 elements
|
||||||
And "entries.2.tags" in the parsed output should have 2 elements
|
And "entries.2.tags" in the parsed output should have 2 elements
|
||||||
|
@ -62,7 +64,9 @@ Feature: Custom formats
|
||||||
And the output should be valid JSON
|
And the output should be valid JSON
|
||||||
Given we parse the output as JSON
|
Given we parse the output as JSON
|
||||||
Then "entries.0.uuid" in the parsed output should be
|
Then "entries.0.uuid" in the parsed output should be
|
||||||
|
"""
|
||||||
4BB1F46946AD439996C9B59DE7C4DDC1
|
4BB1F46946AD439996C9B59DE7C4DDC1
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario Outline: Printing a journal that has multiline entries with tags
|
Scenario Outline: Printing a journal that has multiline entries with tags
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
|
@ -70,6 +74,7 @@ Feature: Custom formats
|
||||||
When we run "jrnl -n 1 @ipsum"
|
When we run "jrnl -n 1 @ipsum"
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
| Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada
|
| Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada
|
||||||
| quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus
|
| quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus
|
||||||
|
@ -90,6 +95,7 @@ Feature: Custom formats
|
||||||
| velit scelerisque fringilla. Phasellus pharetra justo et nulla fringilla, ac
|
| velit scelerisque fringilla. Phasellus pharetra justo et nulla fringilla, ac
|
||||||
| porta sapien accumsan. Class aptent taciti sociosqu ad litora torquent per
|
| porta sapien accumsan. Class aptent taciti sociosqu ad litora torquent per
|
||||||
| conubia nostra, per inceptos himenaeos.
|
| conubia nostra, per inceptos himenaeos.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -108,9 +114,11 @@ Feature: Custom formats
|
||||||
Given we parse the output as JSON
|
Given we parse the output as JSON
|
||||||
Then "entries" in the parsed output should have 2 elements
|
Then "entries" in the parsed output should have 2 elements
|
||||||
And "tags" in the parsed output should be
|
And "tags" in the parsed output should be
|
||||||
|
"""
|
||||||
@ipsum
|
@ipsum
|
||||||
@tagone
|
@tagone
|
||||||
@tagtwo
|
@tagtwo
|
||||||
|
"""
|
||||||
And "entries.0.tags" in the parsed output should have 3 elements
|
And "entries.0.tags" in the parsed output should have 3 elements
|
||||||
And "entries.1.tags" in the parsed output should have 1 elements
|
And "entries.1.tags" in the parsed output should have 1 elements
|
||||||
|
|
||||||
|
@ -125,6 +133,7 @@ Feature: Custom formats
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
Given we append to the editor if opened
|
Given we append to the editor if opened
|
||||||
|
"""
|
||||||
[2021-10-14 13:23] Heading Test
|
[2021-10-14 13:23] Heading Test
|
||||||
|
|
||||||
H1-1
|
H1-1
|
||||||
|
@ -167,10 +176,12 @@ Feature: Custom formats
|
||||||
|
|
||||||
More stuff
|
More stuff
|
||||||
more stuff again
|
more stuff again
|
||||||
|
"""
|
||||||
When we run "jrnl --edit -1"
|
When we run "jrnl --edit -1"
|
||||||
Then the editor should have been called
|
Then the editor should have been called
|
||||||
When we run "jrnl -1 --export markdown"
|
When we run "jrnl -1 --export markdown"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
# 2021
|
# 2021
|
||||||
|
|
||||||
## October
|
## October
|
||||||
|
@ -211,6 +222,7 @@ Feature: Custom formats
|
||||||
|
|
||||||
More stuff
|
More stuff
|
||||||
more stuff again
|
more stuff again
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -227,10 +239,12 @@ Feature: Custom formats
|
||||||
Then the output should be a valid XML string
|
Then the output should be a valid XML string
|
||||||
And "entries" in the xml output should have 3 elements
|
And "entries" in the xml output should have 3 elements
|
||||||
And "tags" in the xml output should contain
|
And "tags" in the xml output should contain
|
||||||
|
"""
|
||||||
@ipsum
|
@ipsum
|
||||||
@tagone
|
@tagone
|
||||||
@tagtwo
|
@tagtwo
|
||||||
@tagthree
|
@tagthree
|
||||||
|
"""
|
||||||
And there should be 10 "tag" elements
|
And there should be 10 "tag" elements
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
|
@ -248,9 +262,11 @@ Feature: Custom formats
|
||||||
Given we parse the output as XML
|
Given we parse the output as XML
|
||||||
Then "entries" in the parsed output should have 2 elements
|
Then "entries" in the parsed output should have 2 elements
|
||||||
And "tags" in the parsed output should be
|
And "tags" in the parsed output should be
|
||||||
|
"""
|
||||||
@idea
|
@idea
|
||||||
@journal
|
@journal
|
||||||
@dan
|
@dan
|
||||||
|
"""
|
||||||
And there should be 7 "tag" elements
|
And there should be 7 "tag" elements
|
||||||
|
|
||||||
Scenario Outline: Exporting tags
|
Scenario Outline: Exporting tags
|
||||||
|
@ -258,10 +274,12 @@ Feature: Custom formats
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --export tags"
|
When we run "jrnl --export tags"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
@tagtwo : 2
|
@tagtwo : 2
|
||||||
@tagone : 2
|
@tagone : 2
|
||||||
@tagthree : 1
|
@tagthree : 1
|
||||||
@ipsum : 1
|
@ipsum : 1
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -293,6 +311,7 @@ Feature: Custom formats
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --export fancy"
|
When we run "jrnl --export fancy"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
┎──────────────────────────────────────────────────────────────╮2020-08-29 11:11
|
┎──────────────────────────────────────────────────────────────╮2020-08-29 11:11
|
||||||
┃ Entry the first. ╘═══════════════╕
|
┃ Entry the first. ╘═══════════════╕
|
||||||
┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
|
┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
|
||||||
|
@ -375,6 +394,7 @@ Feature: Custom formats
|
||||||
┃ Phasellus aliquam lacus placerat convallis vestibulum. Curabitur maximus at │
|
┃ Phasellus aliquam lacus placerat convallis vestibulum. Curabitur maximus at │
|
||||||
┃ ante eget fringilla. @tagthree and also @tagone │
|
┃ ante eget fringilla. @tagthree and also @tagone │
|
||||||
┖──────────────────────────────────────────────────────────────────────────────┘
|
┖──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -390,11 +410,14 @@ Feature: Custom formats
|
||||||
And we create a cache directory
|
And we create a cache directory
|
||||||
When we run "jrnl --format yaml --file {cache_dir}"
|
When we run "jrnl --format yaml --file {cache_dir}"
|
||||||
Then the cache directory should contain the files
|
Then the cache directory should contain the files
|
||||||
|
"""
|
||||||
2020-08-29_entry-the-first.md
|
2020-08-29_entry-the-first.md
|
||||||
2020-08-31_a-second-entry-in-what-i-hope-to-be-a-long-series.md
|
2020-08-31_a-second-entry-in-what-i-hope-to-be-a-long-series.md
|
||||||
2020-09-24_the-third-entry-finally-after-weeks-without-writing.md
|
2020-09-24_the-third-entry-finally-after-weeks-without-writing.md
|
||||||
|
"""
|
||||||
|
|
||||||
And the content of file "2020-08-29_entry-the-first.md" in the cache should be
|
And the content of file "2020-08-29_entry-the-first.md" in the cache should be
|
||||||
|
"""
|
||||||
---
|
---
|
||||||
title: Entry the first.
|
title: Entry the first.
|
||||||
date: 2020-08-29 11:11
|
date: 2020-08-29 11:11
|
||||||
|
@ -420,6 +443,7 @@ Feature: Custom formats
|
||||||
porta sapien accumsan. Class aptent taciti sociosqu ad litora torquent per
|
porta sapien accumsan. Class aptent taciti sociosqu ad litora torquent per
|
||||||
conubia nostra, per inceptos himenaeos.
|
conubia nostra, per inceptos himenaeos.
|
||||||
...
|
...
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -451,10 +475,13 @@ Feature: Custom formats
|
||||||
And we create a cache directory
|
And we create a cache directory
|
||||||
When we run "jrnl --export yaml -o {cache_dir}"
|
When we run "jrnl --export yaml -o {cache_dir}"
|
||||||
Then the cache should contain the files
|
Then the cache should contain the files
|
||||||
|
"""
|
||||||
2020-08-29_entry-the-first.md
|
2020-08-29_entry-the-first.md
|
||||||
2020-08-31_a-second-entry-in-what-i-hope-to-be-a-long-series.md
|
2020-08-31_a-second-entry-in-what-i-hope-to-be-a-long-series.md
|
||||||
2020-09-24_the-third-entry-finally-after-weeks-without-writing.md
|
2020-09-24_the-third-entry-finally-after-weeks-without-writing.md
|
||||||
|
"""
|
||||||
And the content of file "2020-09-24_the-third-entry-finally-after-weeks-without-writing.md" in the cache should be
|
And the content of file "2020-09-24_the-third-entry-finally-after-weeks-without-writing.md" in the cache should be
|
||||||
|
"""
|
||||||
---
|
---
|
||||||
title: The third entry finally after weeks without writing.
|
title: The third entry finally after weeks without writing.
|
||||||
date: 2020-09-24 09:14
|
date: 2020-09-24 09:14
|
||||||
|
@ -472,6 +499,7 @@ Feature: Custom formats
|
||||||
Phasellus aliquam lacus placerat convallis vestibulum. Curabitur maximus at
|
Phasellus aliquam lacus placerat convallis vestibulum. Curabitur maximus at
|
||||||
ante eget fringilla. @tagthree and also @tagone
|
ante eget fringilla. @tagthree and also @tagone
|
||||||
...
|
...
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -516,6 +544,7 @@ Feature: Custom formats
|
||||||
Given we use the config "format_md.yaml"
|
Given we use the config "format_md.yaml"
|
||||||
When we run "jrnl -n 1"
|
When we run "jrnl -n 1"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
# 2013
|
# 2013
|
||||||
|
|
||||||
## June
|
## June
|
||||||
|
@ -523,13 +552,16 @@ Feature: Custom formats
|
||||||
### 2013-06-10 15:40 Life is good.
|
### 2013-06-10 15:40 Life is good.
|
||||||
|
|
||||||
But I'm better.
|
But I'm better.
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Text Formatter from config file
|
Scenario: Text Formatter from config file
|
||||||
Given we use the config "format_text.yaml"
|
Given we use the config "format_text.yaml"
|
||||||
When we run "jrnl -n 1"
|
When we run "jrnl -n 1"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
[2013-06-10 15:40] Life is good.
|
[2013-06-10 15:40] Life is good.
|
||||||
But I'm better.
|
But I'm better.
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario Outline: Exporting entries with Cyrillic characters to directory should not fail
|
Scenario Outline: Exporting entries with Cyrillic characters to directory should not fail
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
|
@ -538,7 +570,9 @@ Feature: Custom formats
|
||||||
When we run "jrnl 2020-11-21: Первая"
|
When we run "jrnl 2020-11-21: Первая"
|
||||||
When we run "jrnl --format md --file {cache_dir} -on 2020-11-21"
|
When we run "jrnl --format md --file {cache_dir} -on 2020-11-21"
|
||||||
Then the cache should contain the files
|
Then the cache should contain the files
|
||||||
|
"""
|
||||||
2020-11-21_первая.md
|
2020-11-21_первая.md
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -553,9 +587,11 @@ Feature: Custom formats
|
||||||
When we run "jrnl 2020-08-31 01:01: Hi."
|
When we run "jrnl 2020-08-31 01:01: Hi."
|
||||||
And we run "jrnl --format dates"
|
And we run "jrnl --format dates"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2020-08-29, 1
|
2020-08-29, 1
|
||||||
2020-08-31, 2
|
2020-08-31, 2
|
||||||
2020-09-24, 1
|
2020-09-24, 1
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -602,30 +638,42 @@ Feature: Custom formats
|
||||||
Given we use the config "basic_onefile.yaml"
|
Given we use the config "basic_onefile.yaml"
|
||||||
When we run "jrnl --list"
|
When we run "jrnl --list"
|
||||||
Then the output should match
|
Then the output should match
|
||||||
|
"""
|
||||||
Journals defined in config \(.+basic_onefile\.yaml\)
|
Journals defined in config \(.+basic_onefile\.yaml\)
|
||||||
\* default -> features/journals/basic_onefile\.journal
|
\* default -> features/journals/basic_onefile\.journal
|
||||||
|
"""
|
||||||
When we run "jrnl --list --format json"
|
When we run "jrnl --list --format json"
|
||||||
Then the output should match
|
Then the output should match
|
||||||
|
"""
|
||||||
{"config_path": ".+basic_onefile\.yaml", "journals": {"default": "features/journals/basic_onefile\.journal"}}
|
{"config_path": ".+basic_onefile\.yaml", "journals": {"default": "features/journals/basic_onefile\.journal"}}
|
||||||
|
"""
|
||||||
When we run "jrnl --list --format yaml"
|
When we run "jrnl --list --format yaml"
|
||||||
Then the output should match
|
Then the output should match
|
||||||
|
"""
|
||||||
config_path: .+basic_onefile\.yaml
|
config_path: .+basic_onefile\.yaml
|
||||||
journals:
|
journals:
|
||||||
default: features/journals/basic_onefile\.journal
|
default: features/journals/basic_onefile\.journal
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Export journal list to formats with no default journal
|
Scenario: Export journal list to formats with no default journal
|
||||||
Given we use the config "no_default_journal.yaml"
|
Given we use the config "no_default_journal.yaml"
|
||||||
When we run "jrnl --list"
|
When we run "jrnl --list"
|
||||||
Then the output should match
|
Then the output should match
|
||||||
|
"""
|
||||||
Journals defined in config \(.+no_default_journal\.yaml\)
|
Journals defined in config \(.+no_default_journal\.yaml\)
|
||||||
\* simple -> features/journals/simple\.journal
|
\* simple -> features/journals/simple\.journal
|
||||||
\* work -> features/journals/work\.journal
|
\* work -> features/journals/work\.journal
|
||||||
|
"""
|
||||||
When we run "jrnl --list --format json"
|
When we run "jrnl --list --format json"
|
||||||
Then the output should match
|
Then the output should match
|
||||||
|
"""
|
||||||
{"config_path": ".+no_default_journal\.yaml", "journals": {"simple": "features/journals/simple\.journal", "work": "features/journals/work\.journal"}}
|
{"config_path": ".+no_default_journal\.yaml", "journals": {"simple": "features/journals/simple\.journal", "work": "features/journals/work\.journal"}}
|
||||||
|
"""
|
||||||
When we run "jrnl --list --format yaml"
|
When we run "jrnl --list --format yaml"
|
||||||
Then the output should match
|
Then the output should match
|
||||||
|
"""
|
||||||
config_path: .+no_default_journal\.yaml
|
config_path: .+no_default_journal\.yaml
|
||||||
journals:
|
journals:
|
||||||
simple: features/journals/simple\.journal
|
simple: features/journals/simple\.journal
|
||||||
work: features/journals/work\.journal
|
work: features/journals/work\.journal
|
||||||
|
"""
|
||||||
|
|
|
@ -21,6 +21,7 @@ Feature: Importing data
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --import" and pipe
|
When we run "jrnl --import" and pipe
|
||||||
|
"""
|
||||||
[2020-07-05 15:00] Observe and import.
|
[2020-07-05 15:00] Observe and import.
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada quis
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada quis
|
||||||
est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque augue
|
est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque augue
|
||||||
|
@ -28,6 +29,7 @@ Feature: Importing data
|
||||||
Aenean ante ex, elementum ut interdum et, mattis eget lacus. In commodo nulla nec
|
Aenean ante ex, elementum ut interdum et, mattis eget lacus. In commodo nulla nec
|
||||||
tellus placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at
|
tellus placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at
|
||||||
dolor dui end of entry.
|
dolor dui end of entry.
|
||||||
|
"""
|
||||||
When we run "jrnl -on 2020-07-05"
|
When we run "jrnl -on 2020-07-05"
|
||||||
Then the output should contain "2020-07-05 15:00 Observe and import."
|
Then the output should contain "2020-07-05 15:00 Observe and import."
|
||||||
And the output should contain "Lorem ipsum"
|
And the output should contain "Lorem ipsum"
|
||||||
|
@ -44,11 +46,13 @@ Feature: Importing data
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --import" and pipe
|
When we run "jrnl --import" and pipe
|
||||||
|
"""
|
||||||
[2020-07-05 15:00] Observe and import.
|
[2020-07-05 15:00] Observe and import.
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
[2020-07-05 15:01] Twice as nice.
|
[2020-07-05 15:01] Twice as nice.
|
||||||
Sed dignissim sed nisl eu consequat.
|
Sed dignissim sed nisl eu consequat.
|
||||||
|
"""
|
||||||
When we run "jrnl -on 2020-07-05"
|
When we run "jrnl -on 2020-07-05"
|
||||||
Then the output should contain "2020-07-05 15:00 Observe and import."
|
Then the output should contain "2020-07-05 15:00 Observe and import."
|
||||||
And the output should contain "Lorem ipsum"
|
And the output should contain "Lorem ipsum"
|
||||||
|
@ -83,7 +87,9 @@ Feature: Importing data
|
||||||
But the output should not contain "I have an @idea"
|
But the output should not contain "I have an @idea"
|
||||||
And the output should not contain "I met with"
|
And the output should not contain "I met with"
|
||||||
When we run "jrnl --import --file features/journals/tags.journal" and pipe
|
When we run "jrnl --import --file features/journals/tags.journal" and pipe
|
||||||
|
"""
|
||||||
[2020-07-05 15:00] I should not exist!
|
[2020-07-05 15:00] I should not exist!
|
||||||
|
"""
|
||||||
And we run "jrnl -99"
|
And we run "jrnl -99"
|
||||||
Then the output should contain "My first entry."
|
Then the output should contain "My first entry."
|
||||||
And the output should contain "PROFIT!"
|
And the output should contain "PROFIT!"
|
||||||
|
|
|
@ -3,9 +3,11 @@ Feature: Installing jrnl
|
||||||
Scenario: Install jrnl with default options
|
Scenario: Install jrnl with default options
|
||||||
Given we use no config
|
Given we use no config
|
||||||
When we run "jrnl hello world" and enter
|
When we run "jrnl hello world" and enter
|
||||||
|
"""
|
||||||
\n
|
\n
|
||||||
\n
|
\n
|
||||||
\n
|
\n
|
||||||
|
"""
|
||||||
Then the output should contain "jrnl configuration created at"
|
Then the output should contain "jrnl configuration created at"
|
||||||
And the output should contain "For advanced features, read the docs at https://jrnl.sh"
|
And the output should contain "For advanced features, read the docs at https://jrnl.sh"
|
||||||
And the output should contain "Journal 'default' created"
|
And the output should contain "Journal 'default' created"
|
||||||
|
@ -16,9 +18,11 @@ Feature: Installing jrnl
|
||||||
Scenario: Install jrnl with custom relative default journal path
|
Scenario: Install jrnl with custom relative default journal path
|
||||||
Given we use no config
|
Given we use no config
|
||||||
When we run "jrnl hello world" and enter
|
When we run "jrnl hello world" and enter
|
||||||
|
"""
|
||||||
default/custom.txt
|
default/custom.txt
|
||||||
n
|
n
|
||||||
\n
|
\n
|
||||||
|
"""
|
||||||
Then the output should contain "Journal 'default' created"
|
Then the output should contain "Journal 'default' created"
|
||||||
And the default journal "custom.txt" should be in the "default" directory
|
And the default journal "custom.txt" should be in the "default" directory
|
||||||
And the config should contain "encrypt: false"
|
And the config should contain "encrypt: false"
|
||||||
|
@ -28,9 +32,11 @@ Feature: Installing jrnl
|
||||||
Given we use no config
|
Given we use no config
|
||||||
And the home directory is called "home"
|
And the home directory is called "home"
|
||||||
When we run "jrnl hello world" and enter
|
When we run "jrnl hello world" and enter
|
||||||
|
"""
|
||||||
~/custom.txt
|
~/custom.txt
|
||||||
n
|
n
|
||||||
\n
|
\n
|
||||||
|
"""
|
||||||
Then the output should contain "Journal 'default' created"
|
Then the output should contain "Journal 'default' created"
|
||||||
And the default journal "custom.txt" should be in the "home" directory
|
And the default journal "custom.txt" should be in the "home" directory
|
||||||
And the config should contain "encrypt: false"
|
And the config should contain "encrypt: false"
|
||||||
|
@ -39,9 +45,11 @@ Feature: Installing jrnl
|
||||||
Scenario: Install jrnl with encrypted default journal
|
Scenario: Install jrnl with encrypted default journal
|
||||||
Given we use no config
|
Given we use no config
|
||||||
When we run "jrnl hello world" and enter
|
When we run "jrnl hello world" and enter
|
||||||
|
"""
|
||||||
encrypted.txt
|
encrypted.txt
|
||||||
y
|
y
|
||||||
\n
|
\n
|
||||||
|
"""
|
||||||
Then the output should contain "Journal will be encrypted"
|
Then the output should contain "Journal will be encrypted"
|
||||||
And the default journal "encrypted.txt" should be in the "." directory
|
And the default journal "encrypted.txt" should be in the "." directory
|
||||||
And the config should contain "encrypt: true"
|
And the config should contain "encrypt: true"
|
||||||
|
@ -52,46 +60,58 @@ Feature: Installing jrnl
|
||||||
Scenario: Install jrnl with colors by default
|
Scenario: Install jrnl with colors by default
|
||||||
Given we use no config
|
Given we use no config
|
||||||
When we run "jrnl hello world" and enter
|
When we run "jrnl hello world" and enter
|
||||||
|
"""
|
||||||
\n
|
\n
|
||||||
\n
|
\n
|
||||||
\n
|
\n
|
||||||
|
"""
|
||||||
Then the output should contain "Journal 'default' created"
|
Then the output should contain "Journal 'default' created"
|
||||||
And the config should contain
|
And the config should contain
|
||||||
|
"""
|
||||||
colors:
|
colors:
|
||||||
body: none
|
body: none
|
||||||
date: black
|
date: black
|
||||||
tags: yellow
|
tags: yellow
|
||||||
title: cyan
|
title: cyan
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Install jrnl without colors
|
Scenario: Install jrnl without colors
|
||||||
Given we use no config
|
Given we use no config
|
||||||
When we run "jrnl hello world" and enter
|
When we run "jrnl hello world" and enter
|
||||||
|
"""
|
||||||
\n
|
\n
|
||||||
\n
|
\n
|
||||||
N
|
N
|
||||||
|
"""
|
||||||
Then the output should contain "Journal 'default' created"
|
Then the output should contain "Journal 'default' created"
|
||||||
And the config should contain
|
And the config should contain
|
||||||
|
"""
|
||||||
colors:
|
colors:
|
||||||
body: none
|
body: none
|
||||||
date: none
|
date: none
|
||||||
tags: none
|
tags: none
|
||||||
title: none
|
title: none
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Install jrnl with encrypted default journal with no entries
|
Scenario: Install jrnl with encrypted default journal with no entries
|
||||||
Given we use no config
|
Given we use no config
|
||||||
When we run "jrnl -1" and enter
|
When we run "jrnl -1" and enter
|
||||||
|
"""
|
||||||
encrypted.txt
|
encrypted.txt
|
||||||
y
|
y
|
||||||
n
|
n
|
||||||
test
|
test
|
||||||
test
|
test
|
||||||
n
|
n
|
||||||
|
"""
|
||||||
Then the error output should contain "Journal will be encrypted"
|
Then the error output should contain "Journal will be encrypted"
|
||||||
And the default journal "encrypted.txt" should be in the "." directory
|
And the default journal "encrypted.txt" should be in the "." directory
|
||||||
And the config should contain "encrypt: true"
|
And the config should contain "encrypt: true"
|
||||||
And the version in the config file should be up-to-date
|
And the version in the config file should be up-to-date
|
||||||
When we run "jrnl -1" and enter
|
When we run "jrnl -1" and enter
|
||||||
|
"""
|
||||||
test
|
test
|
||||||
|
"""
|
||||||
Then we should be prompted for a password
|
Then we should be prompted for a password
|
||||||
And the error output should contain "no entries found"
|
And the error output should contain "no entries found"
|
||||||
And the error output should not contain "Wrong password, try again"
|
And the error output should not contain "Wrong password, try again"
|
||||||
|
|
|
@ -7,8 +7,10 @@ Feature: Multiple journals
|
||||||
Given we use the config "multiple.yaml"
|
Given we use the config "multiple.yaml"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
When we run "jrnl work -99 --short"
|
When we run "jrnl work -99 --short"
|
||||||
Then the output should be empty
|
Then the output should be empty
|
||||||
|
|
||||||
|
@ -17,10 +19,14 @@ Feature: Multiple journals
|
||||||
When we run "jrnl this goes to default"
|
When we run "jrnl this goes to default"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should contain
|
Then the output should contain
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
Then the output should contain
|
Then the output should contain
|
||||||
|
"""
|
||||||
this goes to default
|
this goes to default
|
||||||
|
"""
|
||||||
When we run "jrnl work -99 --short"
|
When we run "jrnl work -99 --short"
|
||||||
Then the output should be empty
|
Then the output should be empty
|
||||||
|
|
||||||
|
@ -29,8 +35,10 @@ Feature: Multiple journals
|
||||||
When we run "jrnl work a long day in the office"
|
When we run "jrnl work a long day in the office"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
When we run "jrnl work -99 --short"
|
When we run "jrnl work -99 --short"
|
||||||
Then the output should contain "a long day in the office"
|
Then the output should contain "a long day in the office"
|
||||||
|
|
||||||
|
@ -44,32 +52,44 @@ Feature: Multiple journals
|
||||||
When we run "jrnl work 23 july 2012: a long day in the office"
|
When we run "jrnl work 23 july 2012: a long day in the office"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
When we run "jrnl work -99 --short"
|
When we run "jrnl work -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2012-07-23 09:00 a long day in the office
|
2012-07-23 09:00 a long day in the office
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Write to specified journal without a timestamp but with colon
|
Scenario: Write to specified journal without a timestamp but with colon
|
||||||
Given we use the config "multiple.yaml"
|
Given we use the config "multiple.yaml"
|
||||||
When we run "jrnl work : a long day in the office"
|
When we run "jrnl work : a long day in the office"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
When we run "jrnl work -99 --short"
|
When we run "jrnl work -99 --short"
|
||||||
Then the output should be contain
|
Then the output should be contain
|
||||||
|
"""
|
||||||
a long day in the office
|
a long day in the office
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Write to specified journal without a timestamp but with colon
|
Scenario: Write to specified journal without a timestamp but with colon
|
||||||
Given we use the config "multiple.yaml"
|
Given we use the config "multiple.yaml"
|
||||||
When we run "jrnl work: a long day in the office"
|
When we run "jrnl work: a long day in the office"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
When we run "jrnl work -99 --short"
|
When we run "jrnl work -99 --short"
|
||||||
Then the output should contain
|
Then the output should contain
|
||||||
|
"""
|
||||||
a long day in the office
|
a long day in the office
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Create new journals as required
|
Scenario: Create new journals as required
|
||||||
Given we use the config "multiple.yaml"
|
Given we use the config "multiple.yaml"
|
||||||
|
@ -77,7 +97,9 @@ Feature: Multiple journals
|
||||||
When we run "jrnl ideas 23 july 2012: sell my junk on ebay and make lots of money"
|
When we run "jrnl ideas 23 july 2012: sell my junk on ebay and make lots of money"
|
||||||
When we run "jrnl ideas -99 --short"
|
When we run "jrnl ideas -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2012-07-23 09:00 sell my junk on ebay and make lots of money
|
2012-07-23 09:00 sell my junk on ebay and make lots of money
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Don't crash if no default journal is specified
|
Scenario: Don't crash if no default journal is specified
|
||||||
Given we use the config "no_default_journal.yaml"
|
Given we use the config "no_default_journal.yaml"
|
||||||
|
@ -87,9 +109,11 @@ Feature: Multiple journals
|
||||||
Scenario: Don't crash if no file exists for a configured encrypted journal
|
Scenario: Don't crash if no file exists for a configured encrypted journal
|
||||||
Given we use the config "multiple.yaml"
|
Given we use the config "multiple.yaml"
|
||||||
When we run "jrnl new_encrypted Adding first entry" and enter
|
When we run "jrnl new_encrypted Adding first entry" and enter
|
||||||
|
"""
|
||||||
these three eyes
|
these three eyes
|
||||||
these three eyes
|
these three eyes
|
||||||
n
|
n
|
||||||
|
"""
|
||||||
Then the output should contain "Journal 'new_encrypted' created at"
|
Then the output should contain "Journal 'new_encrypted' created at"
|
||||||
|
|
||||||
Scenario: Read and write to journal with emoji name
|
Scenario: Read and write to journal with emoji name
|
||||||
|
|
|
@ -7,7 +7,9 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys
|
||||||
Given we use the config "basic_encrypted.yaml"
|
Given we use the config "basic_encrypted.yaml"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --config-override editor ''" and type
|
When we run "jrnl --config-override editor ''" and type
|
||||||
|
"""
|
||||||
This is a journal entry
|
This is a journal entry
|
||||||
|
"""
|
||||||
Then the stdin prompt should have been called
|
Then the stdin prompt should have been called
|
||||||
And the editor should not have been called
|
And the editor should not have been called
|
||||||
When we run "jrnl -1"
|
When we run "jrnl -1"
|
||||||
|
@ -27,6 +29,7 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl -2 --config-override linewrap 23 --format fancy"
|
When we run "jrnl -2 --config-override linewrap 23 --format fancy"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
┎─────╮2013-06-09 15:39
|
┎─────╮2013-06-09 15:39
|
||||||
┃ My ╘═══════════════╕
|
┃ My ╘═══════════════╕
|
||||||
┃ fir st ent ry. │
|
┃ fir st ent ry. │
|
||||||
|
@ -40,6 +43,7 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys
|
||||||
┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
|
┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
|
||||||
┃ But I'm better. │
|
┃ But I'm better. │
|
||||||
┖─────────────────────┘
|
┖─────────────────────┘
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario: Override color selections with runtime overrides
|
Scenario: Override color selections with runtime overrides
|
||||||
|
@ -59,12 +63,14 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl -1 --config-override colors.body green --config-override editor 'nano'"
|
When we run "jrnl -1 --config-override colors.body green --config-override editor 'nano'"
|
||||||
Then the config in memory should contain
|
Then the config in memory should contain
|
||||||
|
"""
|
||||||
editor: nano
|
editor: nano
|
||||||
colors:
|
colors:
|
||||||
title: none
|
title: none
|
||||||
body: green
|
body: green
|
||||||
tags: none
|
tags: none
|
||||||
date: none
|
date: none
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario: Override default journal
|
Scenario: Override default journal
|
||||||
|
@ -74,6 +80,7 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
When we run "jrnl -3 --config-override journals.default features/journals/simple.journal"
|
When we run "jrnl -3 --config-override journals.default features/journals/simple.journal"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2000-03-20 09:00 The rain in Spain comes from clouds
|
2000-03-20 09:00 The rain in Spain comes from clouds
|
||||||
|
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
|
@ -81,6 +88,7 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys
|
||||||
|
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
| But I'm better.
|
| But I'm better.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario: Make an entry into an overridden journal
|
Scenario: Make an entry into an overridden journal
|
||||||
|
@ -91,6 +99,7 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys
|
||||||
And the output should contain "Entry added"
|
And the output should contain "Entry added"
|
||||||
When we run "jrnl --config-override journals.temp features/journals/simple.journal temp -3"
|
When we run "jrnl --config-override journals.temp features/journals/simple.journal temp -3"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
1969-09-06 09:00 @say Ni
|
1969-09-06 09:00 @say Ni
|
||||||
|
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
|
@ -98,3 +107,4 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys
|
||||||
|
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
| But I'm better.
|
| But I'm better.
|
||||||
|
"""
|
||||||
|
|
|
@ -7,9 +7,11 @@ Feature: Using the installed keyring
|
||||||
Given we use the config "multiple.yaml"
|
Given we use the config "multiple.yaml"
|
||||||
And we have a keyring
|
And we have a keyring
|
||||||
When we run "jrnl simple --encrypt" and enter
|
When we run "jrnl simple --encrypt" and enter
|
||||||
|
"""
|
||||||
sabertooth
|
sabertooth
|
||||||
sabertooth
|
sabertooth
|
||||||
Y
|
Y
|
||||||
|
"""
|
||||||
Then the config for journal "simple" should contain "encrypt: true"
|
Then the config for journal "simple" should contain "encrypt: true"
|
||||||
When we run "jrnl simple -n 1"
|
When we run "jrnl simple -n 1"
|
||||||
Then the output should contain "2013-06-10 15:40 Life is good"
|
Then the output should contain "2013-06-10 15:40 Life is good"
|
||||||
|
@ -19,9 +21,11 @@ Feature: Using the installed keyring
|
||||||
Given we use the config "simple.yaml"
|
Given we use the config "simple.yaml"
|
||||||
When we run "jrnl test entry"
|
When we run "jrnl test entry"
|
||||||
And we run "jrnl --encrypt" and enter
|
And we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
password
|
password
|
||||||
password
|
password
|
||||||
n
|
n
|
||||||
|
"""
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should not contain "Failed to retrieve keyring"
|
And the output should not contain "Failed to retrieve keyring"
|
||||||
|
|
||||||
|
@ -30,9 +34,11 @@ Feature: Using the installed keyring
|
||||||
Given we use the config "simple.yaml"
|
Given we use the config "simple.yaml"
|
||||||
When we run "jrnl test entry"
|
When we run "jrnl test entry"
|
||||||
And we run "jrnl --encrypt" and enter
|
And we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
password
|
password
|
||||||
password
|
password
|
||||||
y
|
y
|
||||||
|
"""
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should not contain "Failed to retrieve keyring"
|
And the output should not contain "Failed to retrieve keyring"
|
||||||
# @todo add step to check contents of keyring
|
# @todo add step to check contents of keyring
|
||||||
|
@ -55,9 +61,11 @@ Feature: Using the installed keyring
|
||||||
Given we use the config "simple.yaml"
|
Given we use the config "simple.yaml"
|
||||||
And we have a failed keyring
|
And we have a failed keyring
|
||||||
When we run "jrnl --encrypt" and enter
|
When we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
this password will not be saved in keyring
|
this password will not be saved in keyring
|
||||||
this password will not be saved in keyring
|
this password will not be saved in keyring
|
||||||
y
|
y
|
||||||
|
"""
|
||||||
Then the output should contain "Failed to retrieve keyring"
|
Then the output should contain "Failed to retrieve keyring"
|
||||||
And we should get no error
|
And we should get no error
|
||||||
And we should be prompted for a password
|
And we should be prompted for a password
|
||||||
|
@ -77,8 +85,10 @@ Feature: Using the installed keyring
|
||||||
When we run "jrnl --short"
|
When we run "jrnl --short"
|
||||||
Then we should not be prompted for a password
|
Then we should not be prompted for a password
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario: Open encrypted journal when keyring exists but fails
|
Scenario: Open encrypted journal when keyring exists but fails
|
||||||
|
@ -96,25 +106,31 @@ Feature: Using the installed keyring
|
||||||
Scenario: Mistyping your password
|
Scenario: Mistyping your password
|
||||||
Given we use the config "simple.yaml"
|
Given we use the config "simple.yaml"
|
||||||
When we run "jrnl --encrypt" and enter
|
When we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
swordfish
|
swordfish
|
||||||
sordfish
|
sordfish
|
||||||
|
"""
|
||||||
Then we should be prompted for a password
|
Then we should be prompted for a password
|
||||||
And the output should contain "Passwords did not match"
|
And the output should contain "Passwords did not match"
|
||||||
And the config for journal "default" should not contain "encrypt: true"
|
And the config for journal "default" should not contain "encrypt: true"
|
||||||
When we run "jrnl --short"
|
When we run "jrnl --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario: Mistyping your password, then getting it right
|
Scenario: Mistyping your password, then getting it right
|
||||||
Given we use the config "simple.yaml"
|
Given we use the config "simple.yaml"
|
||||||
When we run "jrnl --encrypt" and enter
|
When we run "jrnl --encrypt" and enter
|
||||||
|
"""
|
||||||
swordfish
|
swordfish
|
||||||
sordfish
|
sordfish
|
||||||
swordfish
|
swordfish
|
||||||
swordfish
|
swordfish
|
||||||
n
|
n
|
||||||
|
"""
|
||||||
Then we should be prompted for a password
|
Then we should be prompted for a password
|
||||||
And the output should contain "Passwords did not match"
|
And the output should contain "Passwords did not match"
|
||||||
And the output should contain "Journal encrypted"
|
And the output should contain "Journal encrypted"
|
||||||
|
|
|
@ -65,7 +65,9 @@ Feature: Searching in a journal
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should contain "1 entry found"
|
And the output should contain "1 entry found"
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
2020-08-29 11:11 Entry the first.
|
2020-08-29 11:11 Entry the first.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -86,6 +88,40 @@ Feature: Searching in a journal
|
||||||
| basic_folder.yaml |
|
| basic_folder.yaml |
|
||||||
| basic_dayone.yaml |
|
| basic_dayone.yaml |
|
||||||
|
|
||||||
|
Scenario Outline: Multiple -contains returns entries that match any
|
||||||
|
Given we use the config "<config_file>"
|
||||||
|
When we run "jrnl -contains emojis -contains lorem --short"
|
||||||
|
Then we should get no error
|
||||||
|
And the output should contain "3 entries found"
|
||||||
|
And the output should be
|
||||||
|
"""
|
||||||
|
2020-08-29 11:11 Entry the first.
|
||||||
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
Examples: configs
|
||||||
|
| config_file |
|
||||||
|
| basic_onefile.yaml |
|
||||||
|
| basic_folder.yaml |
|
||||||
|
| basic_dayone.yaml |
|
||||||
|
|
||||||
|
Scenario Outline: Multiple -contains with -and returns only entries that match all
|
||||||
|
Given we use the config "<config_file>"
|
||||||
|
When we run "jrnl -contains emojis -contains nulla -and --short"
|
||||||
|
Then we should get no error
|
||||||
|
And the output should contain "1 entry found"
|
||||||
|
And the output should be
|
||||||
|
"""
|
||||||
|
2020-09-24 09:14 The third entry finally after weeks without writing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
Examples: configs
|
||||||
|
| config_file |
|
||||||
|
| basic_onefile.yaml |
|
||||||
|
| basic_folder.yaml |
|
||||||
|
| basic_dayone.yaml |
|
||||||
|
|
||||||
Scenario Outline: Searching for a string within tag results
|
Scenario Outline: Searching for a string within tag results
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl @tagone -contains maybe"
|
When we run "jrnl @tagone -contains maybe"
|
||||||
|
@ -189,19 +225,23 @@ Feature: Searching in a journal
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
When we run "jrnl -2"
|
When we run "jrnl -2"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2013-07-23 09:00 Testing folder journal.
|
2013-07-23 09:00 Testing folder journal.
|
||||||
|
|
||||||
2014-03-07 16:37 Second entry of journal.
|
2014-03-07 16:37 Second entry of journal.
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario Outline: Searching for all tags should show counts of each tag
|
Scenario Outline: Searching for all tags should show counts of each tag
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --tags"
|
When we run "jrnl --tags"
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
@tagtwo : 2
|
@tagtwo : 2
|
||||||
@tagone : 2
|
@tagone : 2
|
||||||
@tagthree : 1
|
@tagthree : 1
|
||||||
@ipsum : 1
|
@ipsum : 1
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -214,8 +254,10 @@ Feature: Searching in a journal
|
||||||
When we run "jrnl -from 'september 2020' --tags"
|
When we run "jrnl -from 'september 2020' --tags"
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
@tagthree : 1
|
@tagthree : 1
|
||||||
@tagone : 1
|
@tagone : 1
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -227,8 +269,10 @@ Feature: Searching in a journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --tags -not @tagtwo"
|
When we run "jrnl --tags -not @tagtwo"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
@tagthree : 1
|
@tagthree : 1
|
||||||
@tagone : 1
|
@tagone : 1
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -240,7 +284,9 @@ Feature: Searching in a journal
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
When we run "jrnl --tags -not @tagone -not @tagthree"
|
When we run "jrnl --tags -not @tagone -not @tagthree"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
@tagtwo : 1
|
@tagtwo : 1
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -272,11 +318,13 @@ Feature: Searching in a journal
|
||||||
When we run "jrnl -2"
|
When we run "jrnl -2"
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
2013-06-09 15:39 My first entry.
|
2013-06-09 15:39 My first entry.
|
||||||
| Everything is alright
|
| Everything is alright
|
||||||
|
|
||||||
2013-06-10 15:40 Life is good.
|
2013-06-10 15:40 Life is good.
|
||||||
| But I'm better.
|
| But I'm better.
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario Outline: Searching by month
|
Scenario Outline: Searching by month
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
|
@ -351,8 +399,10 @@ Feature: Searching in a journal
|
||||||
And we run "jrnl -today-in-history --short"
|
And we run "jrnl -today-in-history --short"
|
||||||
Then the output should contain "2 entries found"
|
Then the output should contain "2 entries found"
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
2019-08-31 01:01 Hi, from last year.
|
2019-08-31 01:01 Hi, from last year.
|
||||||
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
2020-08-31 14:32 A second entry in what I hope to be a long series.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -367,11 +417,13 @@ Feature: Searching in a journal
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should contain "3 entries found"
|
And the output should contain "3 entries found"
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
2013-05-17 11:39 This entry has tags!
|
2013-05-17 11:39 This entry has tags!
|
||||||
|
|
||||||
2013-06-17 20:38 This entry has a location.
|
2013-06-17 20:38 This entry has a location.
|
||||||
|
|
||||||
2013-07-17 11:38 This entry is starred!
|
2013-07-17 11:38 This entry is starred!
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario Outline: Searching the most recent entry should not show found count
|
Scenario Outline: Searching the most recent entry should not show found count
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
|
|
|
@ -11,9 +11,11 @@ Feature: Tagging
|
||||||
When we run "jrnl --tags -on 2020-09-26"
|
When we run "jrnl --tags -on 2020-09-26"
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the output should be
|
And the output should be
|
||||||
|
"""
|
||||||
@os/2 : 1
|
@os/2 : 1
|
||||||
@c++ : 1
|
@c++ : 1
|
||||||
@c# : 1
|
@c# : 1
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -41,8 +43,10 @@ Feature: Tagging
|
||||||
When we run "jrnl 2020-09-26: @foo came over, we went to a @bar"
|
When we run "jrnl 2020-09-26: @foo came over, we went to a @bar"
|
||||||
When we run "jrnl --tags -on 2020-09-26"
|
When we run "jrnl --tags -on 2020-09-26"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
@foo : 1
|
@foo : 1
|
||||||
@bar : 1
|
@bar : 1
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
Feature: Using templates
|
Feature: Using templates
|
||||||
|
|
||||||
Scenario Outline: Template contents should be used in new entry
|
Scenario Outline: Template contents should be used in new entry
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
And we append to the editor if opened
|
And we append to the editor if opened
|
||||||
|
"""
|
||||||
This is an addition to a templated entry
|
This is an addition to a templated entry
|
||||||
|
"""
|
||||||
When we run "jrnl --config-override template features/templates/basic.template"
|
When we run "jrnl --config-override template features/templates/basic.template"
|
||||||
And we run "jrnl -1"
|
And we run "jrnl -1"
|
||||||
Then the output should contain "This text is in the basic template"
|
Then the output should contain "This text is in the basic template"
|
||||||
|
@ -38,7 +39,7 @@ Feature: Using templates
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --template this_template_does_not_exist.template"
|
When we run "jrnl --template this_template_does_not_exist.template"
|
||||||
Then we should get an error
|
Then we should get an error
|
||||||
Then the error output should contain "Unable to find a template file based on the passed arg"
|
Then the error output should contain "Unable to find a template file"
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
|
|
@ -8,19 +8,27 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
|
||||||
When we run "jrnl -9" and enter "Y"
|
When we run "jrnl -9" and enter "Y"
|
||||||
When we run "jrnl -99 --short"
|
When we run "jrnl -99 --short"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2010-06-10 15:00 A life without chocolate is like a bad analogy.
|
2010-06-10 15:00 A life without chocolate is like a bad analogy.
|
||||||
2013-06-10 15:40 He said "[this] is the best time to be alive".Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada
|
2013-06-10 15:40 He said "[this] is the best time to be alive".Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada
|
||||||
|
"""
|
||||||
And the output should contain
|
And the output should contain
|
||||||
|
"""
|
||||||
2010-06-10 15:00 A life without chocolate is like a bad analogy.
|
2010-06-10 15:00 A life without chocolate is like a bad analogy.
|
||||||
|
"""
|
||||||
And the output should contain
|
And the output should contain
|
||||||
|
"""
|
||||||
2013-06-10 15:40 He said "[this] is the best time to be alive".
|
2013-06-10 15:40 He said "[this] is the best time to be alive".
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Upgrading a journal encrypted with jrnl 1.x
|
Scenario: Upgrading a journal encrypted with jrnl 1.x
|
||||||
Given we use the config "encrypted_old.json"
|
Given we use the config "encrypted_old.json"
|
||||||
When we run "jrnl -n 1" and enter
|
When we run "jrnl -n 1" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
bad doggie no biscuit
|
bad doggie no biscuit
|
||||||
bad doggie no biscuit
|
bad doggie no biscuit
|
||||||
|
"""
|
||||||
Then we should be prompted for a password
|
Then we should be prompted for a password
|
||||||
And the output should contain "2013-06-10 15:40 Life is good"
|
And the output should contain "2013-06-10 15:40 Life is good"
|
||||||
|
|
||||||
|
@ -28,18 +36,22 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
|
||||||
Given we use the config "no_colors.yaml"
|
Given we use the config "no_colors.yaml"
|
||||||
When we run "jrnl -n 1"
|
When we run "jrnl -n 1"
|
||||||
Then the config should contain
|
Then the config should contain
|
||||||
|
"""
|
||||||
colors:
|
colors:
|
||||||
date: none
|
date: none
|
||||||
title: none
|
title: none
|
||||||
body: none
|
body: none
|
||||||
tags: none
|
tags: none
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Upgrade and parse journals with little endian date format
|
Scenario: Upgrade and parse journals with little endian date format
|
||||||
Given we use the config "upgrade_from_195_little_endian_dates.json"
|
Given we use the config "upgrade_from_195_little_endian_dates.json"
|
||||||
When we run "jrnl -9 --short" and enter "Y"
|
When we run "jrnl -9 --short" and enter "Y"
|
||||||
Then the output should contain
|
Then the output should contain
|
||||||
|
"""
|
||||||
10.06.2010 15:00 A life without chocolate is like a bad analogy.
|
10.06.2010 15:00 A life without chocolate is like a bad analogy.
|
||||||
10.06.2013 15:40 He said "[this] is the best time to be alive".
|
10.06.2013 15:40 He said "[this] is the best time to be alive".
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Upgrade with missing journal
|
Scenario: Upgrade with missing journal
|
||||||
Given we use the config "upgrade_from_195_with_missing_journal.json"
|
Given we use the config "upgrade_from_195_with_missing_journal.json"
|
||||||
|
@ -50,8 +62,10 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
|
||||||
Scenario: Upgrade with missing encrypted journal
|
Scenario: Upgrade with missing encrypted journal
|
||||||
Given we use the config "upgrade_from_195_with_missing_encrypted_journal.json"
|
Given we use the config "upgrade_from_195_with_missing_encrypted_journal.json"
|
||||||
When we run "jrnl --list" and enter
|
When we run "jrnl --list" and enter
|
||||||
|
"""
|
||||||
Y
|
Y
|
||||||
bad doggie no biscuit
|
bad doggie no biscuit
|
||||||
|
"""
|
||||||
Then the output should contain "features/journals/missing.journal does not exist"
|
Then the output should contain "features/journals/missing.journal does not exist"
|
||||||
And the output should contain "We're all done"
|
And the output should contain "We're all done"
|
||||||
And we should get no error
|
And we should get no error
|
||||||
|
|
|
@ -67,7 +67,9 @@ Feature: Writing new entries.
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
Then the editor should have been called
|
Then the editor should have been called
|
||||||
And the editor file content should be
|
And the editor file content should be
|
||||||
|
"""
|
||||||
this is a partial
|
this is a partial
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -146,8 +148,10 @@ Feature: Writing new entries.
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
When we run "jrnl -1"
|
When we run "jrnl -1"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2014-04-24 09:00 Created a new website - empty.com.
|
2014-04-24 09:00 Created a new website - empty.com.
|
||||||
| Hope to get a lot of traffic.
|
| Hope to get a lot of traffic.
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
@ -206,13 +210,17 @@ Feature: Writing new entries.
|
||||||
Given we parse the output as JSON
|
Given we parse the output as JSON
|
||||||
Then "entries" in the parsed output should have 5 elements
|
Then "entries" in the parsed output should have 5 elements
|
||||||
And "entries.0.creator" in the parsed output should be
|
And "entries.0.creator" in the parsed output should be
|
||||||
|
"""
|
||||||
software_agent
|
software_agent
|
||||||
os_agent
|
os_agent
|
||||||
host_name
|
host_name
|
||||||
generation_date
|
generation_date
|
||||||
device_agent
|
device_agent
|
||||||
|
"""
|
||||||
And "entries.0.creator.software_agent" in the parsed output should contain
|
And "entries.0.creator.software_agent" in the parsed output should contain
|
||||||
|
"""
|
||||||
jrnl
|
jrnl
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Title with an embedded period on DayOne journal
|
Scenario: Title with an embedded period on DayOne journal
|
||||||
Given we use the config "dayone.yaml"
|
Given we use the config "dayone.yaml"
|
||||||
|
@ -220,8 +228,10 @@ Feature: Writing new entries.
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
When we run "jrnl -1"
|
When we run "jrnl -1"
|
||||||
Then the output should be
|
Then the output should be
|
||||||
|
"""
|
||||||
2014-04-24 09:00 Ran 6.2 miles today in 1:02:03.
|
2014-04-24 09:00 Ran 6.2 miles today in 1:02:03.
|
||||||
| I am feeling sore because I forgot to stretch.
|
| I am feeling sore because I forgot to stretch.
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: Opening an folder that's not a DayOne folder should treat as folder journal
|
Scenario: Opening an folder that's not a DayOne folder should treat as folder journal
|
||||||
Given we use the config "empty_folder.yaml"
|
Given we use the config "empty_folder.yaml"
|
||||||
|
@ -234,7 +244,9 @@ Feature: Writing new entries.
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
And we append to the editor if opened
|
And we append to the editor if opened
|
||||||
|
"""
|
||||||
[2021-11-13] worked on jrnl tests
|
[2021-11-13] worked on jrnl tests
|
||||||
|
"""
|
||||||
When we run "jrnl --edit"
|
When we run "jrnl --edit"
|
||||||
Then the error output should contain "3 entries found"
|
Then the error output should contain "3 entries found"
|
||||||
And the error output should contain "1 entry added"
|
And the error output should contain "1 entry added"
|
||||||
|
@ -252,9 +264,11 @@ Feature: Writing new entries.
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
And we append to the editor if opened
|
And we append to the editor if opened
|
||||||
|
"""
|
||||||
[2021-11-11] worked on jrnl tests
|
[2021-11-11] worked on jrnl tests
|
||||||
[2021-11-12] worked on jrnl tests again
|
[2021-11-12] worked on jrnl tests again
|
||||||
[2021-11-13] worked on jrnl tests a little bit more
|
[2021-11-13] worked on jrnl tests a little bit more
|
||||||
|
"""
|
||||||
When we run "jrnl --edit"
|
When we run "jrnl --edit"
|
||||||
Then the error output should contain "3 entries found"
|
Then the error output should contain "3 entries found"
|
||||||
And the error output should contain "3 entries added"
|
And the error output should contain "3 entries added"
|
||||||
|
@ -271,7 +285,9 @@ Feature: Writing new entries.
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
And we write to the editor if opened
|
And we write to the editor if opened
|
||||||
|
"""
|
||||||
[2021-11-13] I am replacing my whole journal with this entry
|
[2021-11-13] I am replacing my whole journal with this entry
|
||||||
|
"""
|
||||||
When we run "jrnl --edit"
|
When we run "jrnl --edit"
|
||||||
Then the output should contain "2 entries deleted"
|
Then the output should contain "2 entries deleted"
|
||||||
And the output should contain "1 entry modified"
|
And the output should contain "1 entry modified"
|
||||||
|
@ -288,7 +304,9 @@ Feature: Writing new entries.
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
And we write to the editor if opened
|
And we write to the editor if opened
|
||||||
|
"""
|
||||||
[2021-11-13] I am replacing the last entry with this entry
|
[2021-11-13] I am replacing the last entry with this entry
|
||||||
|
"""
|
||||||
When we run "jrnl --edit -1"
|
When we run "jrnl --edit -1"
|
||||||
Then the error output should contain "1 entry modified"
|
Then the error output should contain "1 entry modified"
|
||||||
|
|
||||||
|
@ -304,7 +322,9 @@ Feature: Writing new entries.
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
And we append to the editor if opened
|
And we append to the editor if opened
|
||||||
|
"""
|
||||||
This is a small addendum to my latest entry.
|
This is a small addendum to my latest entry.
|
||||||
|
"""
|
||||||
When we run "jrnl --edit"
|
When we run "jrnl --edit"
|
||||||
Then the error output should contain "3 entries found"
|
Then the error output should contain "3 entries found"
|
||||||
And the error output should contain "1 entry modified"
|
And the error output should contain "1 entry modified"
|
||||||
|
@ -341,12 +361,16 @@ Feature: Writing new entries.
|
||||||
Given we use the config "<config_file>"
|
Given we use the config "<config_file>"
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
And we append to the editor if opened
|
And we append to the editor if opened
|
||||||
|
"""
|
||||||
@newtag
|
@newtag
|
||||||
|
"""
|
||||||
When we run "jrnl --edit -1"
|
When we run "jrnl --edit -1"
|
||||||
Then the error output should contain "1 entry modified"
|
Then the error output should contain "1 entry modified"
|
||||||
When we run "jrnl --tags @newtag"
|
When we run "jrnl --tags @newtag"
|
||||||
Then the output should contain
|
Then the output should contain
|
||||||
|
"""
|
||||||
1 entry found
|
1 entry found
|
||||||
|
"""
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
|
|
@ -183,10 +183,10 @@ def mock_default_journal_path(temp_dir):
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
def mock_default_templates_path(temp_dir):
|
def mock_default_templates_path(temp_dir):
|
||||||
templates_path = Path(temp_dir.name, "templates")
|
templates_path = os.path.join(temp_dir.name, "templates")
|
||||||
return {
|
return {
|
||||||
"get_templates_path": lambda: patch(
|
"get_templates_path": lambda: patch(
|
||||||
"jrnl.controller.get_templates_path", return_value=templates_path
|
"jrnl.editor.get_templates_path", return_value=templates_path
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,11 @@ import string
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree as ET
|
||||||
|
|
||||||
from pytest_bdd import given
|
from pytest_bdd import given
|
||||||
from pytest_bdd.parsers import parse
|
from pytest_bdd.parsers import parse
|
||||||
|
from pytest_bdd.parsers import re
|
||||||
|
|
||||||
from jrnl import __version__
|
from jrnl import __version__
|
||||||
from jrnl.time import __get_pdt_calendar
|
from jrnl.time import __get_pdt_calendar
|
||||||
|
@ -21,7 +22,11 @@ from tests.lib.fixtures import NoKeyring
|
||||||
from tests.lib.fixtures import TestKeyring
|
from tests.lib.fixtures import TestKeyring
|
||||||
|
|
||||||
|
|
||||||
@given(parse("we {editor_method} to the editor if opened\n{editor_input}"))
|
@given(re(r"we (?P<editor_method>\w+) to the editor if opened"))
|
||||||
|
def we_enter_editor_docstring(editor_method, editor_state, docstring):
|
||||||
|
we_enter_editor(editor_method, docstring, editor_state)
|
||||||
|
|
||||||
|
|
||||||
@given(parse("we {editor_method} nothing to the editor if opened"))
|
@given(parse("we {editor_method} nothing to the editor if opened"))
|
||||||
def we_enter_editor(editor_method, editor_input, editor_state):
|
def we_enter_editor(editor_method, editor_input, editor_state):
|
||||||
file_method = editor_state["intent"]["method"]
|
file_method = editor_state["intent"]["method"]
|
||||||
|
@ -168,7 +173,7 @@ def parse_output_as_language(cli_run, language_name):
|
||||||
actual_output = cli_run["stdout"]
|
actual_output = cli_run["stdout"]
|
||||||
|
|
||||||
if language_name == "XML":
|
if language_name == "XML":
|
||||||
parsed_output = ElementTree.fromstring(actual_output)
|
parsed_output = ET.fromstring(actual_output)
|
||||||
elif language_name == "JSON":
|
elif language_name == "JSON":
|
||||||
parsed_output = json.loads(actual_output)
|
parsed_output = json.loads(actual_output)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -4,10 +4,11 @@
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree as ET
|
||||||
|
|
||||||
from pytest_bdd import then
|
from pytest_bdd import then
|
||||||
from pytest_bdd.parsers import parse
|
from pytest_bdd.parsers import parse
|
||||||
|
from pytest_bdd.parsers import re as pytest_bdd_parsers_re
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
from jrnl.config import scope_config
|
from jrnl.config import scope_config
|
||||||
|
@ -30,7 +31,11 @@ def should_get_an_error(cli_run):
|
||||||
assert cli_run["status"] != 0, cli_run["status"]
|
assert cli_run["status"] != 0, cli_run["status"]
|
||||||
|
|
||||||
|
|
||||||
@then(parse("the output should match\n{regex}"))
|
@then(parse("the output should match"))
|
||||||
|
def output_should_match_docstring(cli_run, docstring):
|
||||||
|
output_should_match(docstring, cli_run)
|
||||||
|
|
||||||
|
|
||||||
@then(parse('the output should match "{regex}"'))
|
@then(parse('the output should match "{regex}"'))
|
||||||
def output_should_match(regex, cli_run):
|
def output_should_match(regex, cli_run):
|
||||||
out = cli_run["stdout"]
|
out = cli_run["stdout"]
|
||||||
|
@ -38,47 +43,62 @@ def output_should_match(regex, cli_run):
|
||||||
assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}"
|
assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}"
|
||||||
|
|
||||||
|
|
||||||
@then(parse("the output {it_should:Should} contain\n{expected_output}", SHOULD_DICT))
|
@then(parse("the output {it_should:Should} contain", SHOULD_DICT))
|
||||||
@then(parse('the output {it_should:Should} contain "{expected_output}"', SHOULD_DICT))
|
|
||||||
@then(
|
@then(
|
||||||
parse(
|
parse(
|
||||||
"the {which_output_stream} output {it_should:Should} contain\n{expected_output}",
|
"the {which_output_stream} output {it_should:Should} contain",
|
||||||
SHOULD_DICT,
|
SHOULD_DICT,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
def output_should_contain_docstring(which_output_stream, cli_run, it_should, docstring):
|
||||||
|
output_should_contain(docstring, which_output_stream, cli_run, it_should)
|
||||||
|
|
||||||
|
|
||||||
|
@then(parse('the output {it_should:Should} contain "{expected}"', SHOULD_DICT))
|
||||||
@then(
|
@then(
|
||||||
parse(
|
parse(
|
||||||
'the {which_output_stream} output {it_should:Should} contain "{expected_output}"',
|
'the {which_output_stream} output {it_should:Should} contain "{expected}"',
|
||||||
SHOULD_DICT,
|
SHOULD_DICT,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
def output_should_contain(expected_output, which_output_stream, cli_run, it_should):
|
def output_should_contain(expected, which_output_stream, cli_run, it_should):
|
||||||
output_str = f"\nEXPECTED:\n{expected_output}\n\nACTUAL STDOUT:\n{cli_run['stdout']}\n\nACTUAL STDERR:\n{cli_run['stderr']}"
|
output_str = (
|
||||||
assert expected_output
|
f"\nEXPECTED:\n{expected}\n\n"
|
||||||
|
f"ACTUAL STDOUT:\n{cli_run['stdout']}\n\n"
|
||||||
|
f"ACTUAL STDERR:\n{cli_run['stderr']}"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert expected
|
||||||
if which_output_stream is None:
|
if which_output_stream is None:
|
||||||
assert ((expected_output in cli_run["stdout"]) == it_should) or (
|
assert ((expected in cli_run["stdout"]) == it_should) or (
|
||||||
(expected_output in cli_run["stderr"]) == it_should
|
(expected in cli_run["stderr"]) == it_should
|
||||||
), output_str
|
), output_str
|
||||||
|
|
||||||
elif which_output_stream == "standard":
|
elif which_output_stream == "standard":
|
||||||
assert (expected_output in cli_run["stdout"]) == it_should, output_str
|
assert (expected in cli_run["stdout"]) == it_should, output_str
|
||||||
|
|
||||||
elif which_output_stream == "error":
|
elif which_output_stream == "error":
|
||||||
assert (expected_output in cli_run["stderr"]) == it_should, output_str
|
assert (expected in cli_run["stderr"]) == it_should, output_str
|
||||||
|
|
||||||
else:
|
else:
|
||||||
assert (
|
assert (expected in cli_run[which_output_stream]) == it_should, output_str
|
||||||
expected_output in cli_run[which_output_stream]
|
|
||||||
) == it_should, output_str
|
|
||||||
|
@then(parse("the output should not contain"))
|
||||||
|
def output_should_not_contain_docstring(cli_run, docstring):
|
||||||
|
output_should_not_contain(docstring, cli_run)
|
||||||
|
|
||||||
|
|
||||||
@then(parse("the output should not contain\n{expected_output}"))
|
|
||||||
@then(parse('the output should not contain "{expected_output}"'))
|
@then(parse('the output should not contain "{expected_output}"'))
|
||||||
def output_should_not_contain(expected_output, cli_run):
|
def output_should_not_contain(expected_output, cli_run):
|
||||||
assert expected_output not in cli_run["stdout"]
|
assert expected_output not in cli_run["stdout"]
|
||||||
|
|
||||||
|
|
||||||
@then(parse("the output should be\n{expected_output}"))
|
@then(parse("the output should be"))
|
||||||
|
def output_should_be_docstring(cli_run, docstring):
|
||||||
|
output_should_be(docstring, cli_run)
|
||||||
|
|
||||||
|
|
||||||
@then(parse('the output should be "{expected_output}"'))
|
@then(parse('the output should be "{expected_output}"'))
|
||||||
def output_should_be(expected_output, cli_run):
|
def output_should_be(expected_output, cli_run):
|
||||||
actual = cli_run["stdout"].strip()
|
actual = cli_run["stdout"].strip()
|
||||||
|
@ -119,7 +139,8 @@ def output_should_be_columns_wide(cli_run, width):
|
||||||
|
|
||||||
@then(
|
@then(
|
||||||
parse(
|
parse(
|
||||||
'the default journal "{journal_file}" should be in the "{journal_dir}" directory'
|
'the default journal "{journal_file}" '
|
||||||
|
'should be in the "{journal_dir}" directory'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
def default_journal_location(journal_file, journal_dir, config_on_disk, temp_dir):
|
def default_journal_location(journal_file, journal_dir, config_on_disk, temp_dir):
|
||||||
|
@ -135,18 +156,23 @@ def default_journal_location(journal_file, journal_dir, config_on_disk, temp_dir
|
||||||
|
|
||||||
@then(
|
@then(
|
||||||
parse(
|
parse(
|
||||||
'the config for journal "{journal_name}" {it_should:Should} contain "{some_yaml}"',
|
'the config for journal "{journal_name}" {it_should:Should} contain',
|
||||||
SHOULD_DICT,
|
SHOULD_DICT,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@then(parse("the config {it_should:Should} contain", SHOULD_DICT))
|
||||||
|
def config_var_on_disk_docstring(config_on_disk, journal_name, it_should, docstring):
|
||||||
|
config_var_on_disk(config_on_disk, journal_name, it_should, docstring)
|
||||||
|
|
||||||
|
|
||||||
@then(
|
@then(
|
||||||
parse(
|
parse(
|
||||||
'the config for journal "{journal_name}" {it_should:Should} contain\n{some_yaml}',
|
'the config for journal "{journal_name}" '
|
||||||
|
'{it_should:Should} contain "{some_yaml}"',
|
||||||
SHOULD_DICT,
|
SHOULD_DICT,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@then(parse('the config {it_should:Should} contain "{some_yaml}"', SHOULD_DICT))
|
@then(parse('the config {it_should:Should} contain "{some_yaml}"', SHOULD_DICT))
|
||||||
@then(parse("the config {it_should:Should} contain\n{some_yaml}", SHOULD_DICT))
|
|
||||||
def config_var_on_disk(config_on_disk, journal_name, it_should, some_yaml):
|
def config_var_on_disk(config_on_disk, journal_name, it_should, some_yaml):
|
||||||
actual = config_on_disk
|
actual = config_on_disk
|
||||||
if journal_name:
|
if journal_name:
|
||||||
|
@ -155,31 +181,37 @@ def config_var_on_disk(config_on_disk, journal_name, it_should, some_yaml):
|
||||||
expected = YAML(typ="safe").load(some_yaml)
|
expected = YAML(typ="safe").load(some_yaml)
|
||||||
|
|
||||||
actual_slice = actual
|
actual_slice = actual
|
||||||
if type(actual) is dict:
|
if isinstance(actual, dict):
|
||||||
# `expected` objects formatted in yaml only compare one level deep
|
# `expected` objects formatted in yaml only compare one level deep
|
||||||
actual_slice = {key: actual.get(key, None) for key in expected.keys()}
|
actual_slice = {key: actual.get(key) for key in expected.keys()}
|
||||||
|
|
||||||
assert (expected == actual_slice) == it_should
|
assert (expected == actual_slice) == it_should
|
||||||
|
|
||||||
|
|
||||||
@then(
|
@then(
|
||||||
parse(
|
parse(
|
||||||
'the config in memory for journal "{journal_name}" {it_should:Should} contain "{some_yaml}"',
|
'the config in memory for journal "{journal_name}" '
|
||||||
|
"{it_should:Should} contain",
|
||||||
SHOULD_DICT,
|
SHOULD_DICT,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@then(parse("the config in memory {it_should:Should} contain", SHOULD_DICT))
|
||||||
|
def config_var_in_memory_docstring(
|
||||||
|
config_in_memory, journal_name, it_should, docstring
|
||||||
|
):
|
||||||
|
config_var_in_memory(config_in_memory, journal_name, it_should, docstring)
|
||||||
|
|
||||||
|
|
||||||
@then(
|
@then(
|
||||||
parse(
|
parse(
|
||||||
'the config in memory for journal "{journal_name}" {it_should:Should} contain\n{some_yaml}',
|
'the config in memory for journal "{journal_name}" '
|
||||||
|
'{it_should:Should} contain "{some_yaml}"',
|
||||||
SHOULD_DICT,
|
SHOULD_DICT,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@then(
|
@then(
|
||||||
parse('the config in memory {it_should:Should} contain "{some_yaml}"', SHOULD_DICT)
|
parse('the config in memory {it_should:Should} contain "{some_yaml}"', SHOULD_DICT)
|
||||||
)
|
)
|
||||||
@then(
|
|
||||||
parse("the config in memory {it_should:Should} contain\n{some_yaml}", SHOULD_DICT)
|
|
||||||
)
|
|
||||||
def config_var_in_memory(config_in_memory, journal_name, it_should, some_yaml):
|
def config_var_in_memory(config_in_memory, journal_name, it_should, some_yaml):
|
||||||
actual = config_in_memory["overrides"]
|
actual = config_in_memory["overrides"]
|
||||||
if journal_name:
|
if journal_name:
|
||||||
|
@ -188,7 +220,7 @@ def config_var_in_memory(config_in_memory, journal_name, it_should, some_yaml):
|
||||||
expected = YAML(typ="safe").load(some_yaml)
|
expected = YAML(typ="safe").load(some_yaml)
|
||||||
|
|
||||||
actual_slice = actual
|
actual_slice = actual
|
||||||
if type(actual) is dict:
|
if isinstance(actual, dict):
|
||||||
# `expected` objects formatted in yaml only compare one level deep
|
# `expected` objects formatted in yaml only compare one level deep
|
||||||
actual_slice = {key: get_nested_val(actual, key) for key in expected.keys()}
|
actual_slice = {key: get_nested_val(actual, key) for key in expected.keys()}
|
||||||
|
|
||||||
|
@ -205,21 +237,23 @@ def password_was_not_called(cli_run):
|
||||||
assert not cli_run["mocks"]["user_input"].return_value.input.called
|
assert not cli_run["mocks"]["user_input"].return_value.input.called
|
||||||
|
|
||||||
|
|
||||||
@then(parse("the cache directory should contain the files\n{file_list}"))
|
@then(parse("the cache directory should contain the files"))
|
||||||
def assert_dir_contains_files(file_list, cache_dir):
|
def assert_dir_contains_files(cache_dir, docstring):
|
||||||
assert does_directory_contain_files(file_list, cache_dir["path"])
|
assert does_directory_contain_files(docstring, cache_dir["path"])
|
||||||
|
|
||||||
|
|
||||||
@then(parse("the cache directory should contain {number} files"))
|
@then(
|
||||||
|
pytest_bdd_parsers_re(r"the cache directory should contain (?P<number>\d+) files")
|
||||||
|
)
|
||||||
def assert_dir_contains_n_files(cache_dir, number):
|
def assert_dir_contains_n_files(cache_dir, number):
|
||||||
assert does_directory_contain_n_files(cache_dir["path"], number)
|
assert does_directory_contain_n_files(cache_dir["path"], number)
|
||||||
|
|
||||||
|
|
||||||
@then(parse("the journal directory should contain\n{file_list}"))
|
@then(parse("the journal directory should contain"))
|
||||||
def journal_directory_should_contain(config_on_disk, file_list):
|
def journal_directory_should_contain(config_on_disk, docstring):
|
||||||
scoped_config = scope_config(config_on_disk, "default")
|
scoped_config = scope_config(config_on_disk, "default")
|
||||||
|
|
||||||
assert does_directory_contain_files(file_list, scoped_config["journal"])
|
assert does_directory_contain_files(docstring, scoped_config["journal"])
|
||||||
|
|
||||||
|
|
||||||
@then(parse('journal "{journal_name}" should not exist'))
|
@then(parse('journal "{journal_name}" should not exist'))
|
||||||
|
@ -254,10 +288,10 @@ def directory_should_not_exist(config_on_disk, it_should, journal_name):
|
||||||
assert dir_exists == it_should
|
assert dir_exists == it_should
|
||||||
|
|
||||||
|
|
||||||
@then(parse('the content of file "{file_path}" in the cache should be\n{file_content}'))
|
@then(parse('the content of file "{file_path}" in the cache should be'))
|
||||||
def content_of_file_should_be(file_path, file_content, cache_dir):
|
def content_of_file_should_be(file_path, cache_dir, docstring):
|
||||||
assert cache_dir["exists"]
|
assert cache_dir["exists"]
|
||||||
expected_content = file_content.strip().splitlines()
|
expected_content = docstring.strip().splitlines()
|
||||||
|
|
||||||
with open(os.path.join(cache_dir["path"], file_path), "r") as f:
|
with open(os.path.join(cache_dir["path"], file_path), "r") as f:
|
||||||
actual_content = f.read().strip().splitlines()
|
actual_content = f.read().strip().splitlines()
|
||||||
|
@ -274,12 +308,12 @@ def content_of_file_should_be(file_path, file_content, cache_dir):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@then(parse("the cache should contain the files\n{file_list}"))
|
@then(parse("the cache should contain the files"))
|
||||||
def cache_dir_contains_files(file_list, cache_dir):
|
def cache_dir_contains_files(cache_dir, docstring):
|
||||||
assert cache_dir["exists"]
|
assert cache_dir["exists"]
|
||||||
|
|
||||||
actual_files = os.listdir(cache_dir["path"])
|
actual_files = os.listdir(cache_dir["path"])
|
||||||
expected_files = file_list.split("\n")
|
expected_files = docstring.split("\n")
|
||||||
|
|
||||||
# sort to deal with inconsistent default file ordering on different OS's
|
# sort to deal with inconsistent default file ordering on different OS's
|
||||||
actual_files.sort()
|
actual_files.sort()
|
||||||
|
@ -292,7 +326,7 @@ def cache_dir_contains_files(file_list, cache_dir):
|
||||||
def assert_output_is_valid_language(cli_run, language_name):
|
def assert_output_is_valid_language(cli_run, language_name):
|
||||||
language_name = language_name.upper()
|
language_name = language_name.upper()
|
||||||
if language_name == "XML":
|
if language_name == "XML":
|
||||||
xml_tree = ElementTree.fromstring(cli_run["stdout"])
|
xml_tree = ET.fromstring(cli_run["stdout"])
|
||||||
assert xml_tree, "Invalid XML"
|
assert xml_tree, "Invalid XML"
|
||||||
elif language_name == "JSON":
|
elif language_name == "JSON":
|
||||||
assert json.loads(cli_run["stdout"]), "Invalid JSON"
|
assert json.loads(cli_run["stdout"]), "Invalid JSON"
|
||||||
|
@ -328,11 +362,11 @@ def assert_parsed_output_item_count(node_name, number, parsed_output):
|
||||||
assert False, f"Language name {lang} not recognized"
|
assert False, f"Language name {lang} not recognized"
|
||||||
|
|
||||||
|
|
||||||
@then(parse('"{field_name}" in the parsed output should {comparison}\n{expected_keys}'))
|
@then(parse('"{field_name}" in the parsed output should {comparison}'))
|
||||||
def assert_output_field_content(field_name, comparison, expected_keys, parsed_output):
|
def assert_output_field_content(field_name, comparison, parsed_output, docstring):
|
||||||
lang = parsed_output["lang"]
|
lang = parsed_output["lang"]
|
||||||
obj = parsed_output["obj"]
|
obj = parsed_output["obj"]
|
||||||
expected_keys = expected_keys.split("\n")
|
expected_keys = docstring.split("\n")
|
||||||
if len(expected_keys) == 1:
|
if len(expected_keys) == 1:
|
||||||
expected_keys = expected_keys[0]
|
expected_keys = expected_keys[0]
|
||||||
|
|
||||||
|
@ -360,7 +394,7 @@ def assert_output_field_content(field_name, comparison, expected_keys, parsed_ou
|
||||||
my_obj = my_obj[node]
|
my_obj = my_obj[node]
|
||||||
|
|
||||||
if comparison == "be":
|
if comparison == "be":
|
||||||
if type(my_obj) is str:
|
if isinstance(my_obj, str):
|
||||||
assert expected_keys == my_obj, [my_obj, expected_keys]
|
assert expected_keys == my_obj, [my_obj, expected_keys]
|
||||||
else:
|
else:
|
||||||
assert set(expected_keys) == set(my_obj), [
|
assert set(expected_keys) == set(my_obj), [
|
||||||
|
@ -368,7 +402,7 @@ def assert_output_field_content(field_name, comparison, expected_keys, parsed_ou
|
||||||
set(expected_keys),
|
set(expected_keys),
|
||||||
]
|
]
|
||||||
elif comparison == "contain":
|
elif comparison == "contain":
|
||||||
if type(my_obj) is str:
|
if isinstance(my_obj, str):
|
||||||
assert expected_keys in my_obj, [my_obj, expected_keys]
|
assert expected_keys in my_obj, [my_obj, expected_keys]
|
||||||
else:
|
else:
|
||||||
assert all(elem in my_obj for elem in expected_keys), [
|
assert all(elem in my_obj for elem in expected_keys), [
|
||||||
|
@ -382,7 +416,7 @@ def assert_output_field_content(field_name, comparison, expected_keys, parsed_ou
|
||||||
@then(parse('there should be {number:d} "{item}" elements'))
|
@then(parse('there should be {number:d} "{item}" elements'))
|
||||||
def count_elements(number, item, cli_run):
|
def count_elements(number, item, cli_run):
|
||||||
actual_output = cli_run["stdout"]
|
actual_output = cli_run["stdout"]
|
||||||
xml_tree = ElementTree.fromstring(actual_output)
|
xml_tree = ET.fromstring(actual_output)
|
||||||
assert len(xml_tree.findall(".//" + item)) == number
|
assert len(xml_tree.findall(".//" + item)) == number
|
||||||
|
|
||||||
|
|
||||||
|
@ -412,9 +446,13 @@ def editor_filename_suffix(suffix, editor_state):
|
||||||
assert editor_state["tmpfile"]["name"].endswith(suffix), (editor_filename, suffix)
|
assert editor_state["tmpfile"]["name"].endswith(suffix), (editor_filename, suffix)
|
||||||
|
|
||||||
|
|
||||||
|
@then(parse("the editor file content should {comparison}"))
|
||||||
|
def contains_editor_file_docstring(comparison, editor_state, docstring):
|
||||||
|
contains_editor_file(comparison, docstring, editor_state)
|
||||||
|
|
||||||
|
|
||||||
@then(parse('the editor file content should {comparison} "{str_value}"'))
|
@then(parse('the editor file content should {comparison} "{str_value}"'))
|
||||||
@then(parse("the editor file content should {comparison} empty"))
|
@then(parse("the editor file content should {comparison} empty"))
|
||||||
@then(parse("the editor file content should {comparison}\n{str_value}"))
|
|
||||||
def contains_editor_file(comparison, str_value, editor_state):
|
def contains_editor_file(comparison, str_value, editor_state):
|
||||||
content = editor_state["tmpfile"]["content"]
|
content = editor_state["tmpfile"]["content"]
|
||||||
# content = f'\n"""\n{content}\n"""\n'
|
# content = f'\n"""\n{content}\n"""\n'
|
||||||
|
|
|
@ -7,7 +7,13 @@ from contextlib import ExitStack
|
||||||
from pytest_bdd import when
|
from pytest_bdd import when
|
||||||
from pytest_bdd.parsers import parse
|
from pytest_bdd.parsers import parse
|
||||||
from pytest_bdd.parsers import re
|
from pytest_bdd.parsers import re
|
||||||
from pytest_bdd.steps import inject_fixture
|
|
||||||
|
# This is an undocumented and unsupported function:
|
||||||
|
# https://github.com/pytest-dev/pytest-bdd/issues/684
|
||||||
|
try:
|
||||||
|
from pytest_bdd.compat import inject_fixture # pytest_bdd 7.1.2 and later
|
||||||
|
except ImportError:
|
||||||
|
from pytest_bdd.steps import inject_fixture # pytest_bdd 7.1.1 and earlier
|
||||||
|
|
||||||
from jrnl.main import run
|
from jrnl.main import run
|
||||||
|
|
||||||
|
@ -28,7 +34,11 @@ all_input = '("(?P<all_input>[^"]*)")'
|
||||||
# an empty line of input internally for testing purposes.
|
# an empty line of input internally for testing purposes.
|
||||||
|
|
||||||
|
|
||||||
@when(parse('we run "jrnl {command}" and {input_method}\n{all_input}'))
|
@when(re(f'we run "jrnl {command}" and {input_method}'))
|
||||||
|
def we_run_jrnl_docstring(capsys, keyring, request, command, input_method, docstring):
|
||||||
|
we_run_jrnl(capsys, keyring, request, command, input_method, docstring)
|
||||||
|
|
||||||
|
|
||||||
@when(re(f'we run "jrnl ?{command}" and {input_method} {all_input}'))
|
@when(re(f'we run "jrnl ?{command}" and {input_method} {all_input}'))
|
||||||
@when(re(f'we run "jrnl {command}"(?! and)'))
|
@when(re(f'we run "jrnl {command}"(?! and)'))
|
||||||
@when('we run "jrnl"')
|
@when('we run "jrnl"')
|
||||||
|
|
45
tests/unit/test_editor.py
Normal file
45
tests/unit/test_editor.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
import os
|
||||||
|
from unittest.mock import mock_open
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from jrnl.editor import get_template_path
|
||||||
|
from jrnl.editor import read_template_file
|
||||||
|
from jrnl.exception import JrnlException
|
||||||
|
|
||||||
|
|
||||||
|
@patch(
|
||||||
|
"os.getcwd", side_effect="/"
|
||||||
|
) # prevent failures in CI if current directory has been deleted
|
||||||
|
@patch("builtins.open", side_effect=FileNotFoundError())
|
||||||
|
def test_read_template_file_with_no_file_raises_exception(mock_open, mock_getcwd):
|
||||||
|
with pytest.raises(JrnlException) as ex:
|
||||||
|
read_template_file("invalid_file.txt")
|
||||||
|
assert isinstance(ex.value, JrnlException)
|
||||||
|
|
||||||
|
|
||||||
|
@patch(
|
||||||
|
"os.getcwd", side_effect="/"
|
||||||
|
) # prevent failures in CI if current directory has been deleted
|
||||||
|
@patch("builtins.open", new_callable=mock_open, read_data="template text")
|
||||||
|
def test_read_template_file_with_valid_file_returns_text(mock_file, mock_getcwd):
|
||||||
|
assert read_template_file("valid_file.txt") == "template text"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_template_path_when_exists_returns_correct_path():
|
||||||
|
with patch("os.path.exists", return_value=True):
|
||||||
|
output = get_template_path("template", "templatepath")
|
||||||
|
|
||||||
|
assert output == os.path.join("templatepath", "template")
|
||||||
|
|
||||||
|
|
||||||
|
@patch("jrnl.editor.absolute_path")
|
||||||
|
def test_get_template_path_when_doesnt_exist_returns_correct_path(mock_absolute_paths):
|
||||||
|
with patch("os.path.exists", return_value=False):
|
||||||
|
output = get_template_path("template", "templatepath")
|
||||||
|
|
||||||
|
assert output == mock_absolute_paths.return_value
|
|
@ -6,9 +6,6 @@ from unittest import mock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from jrnl.exception import JrnlException
|
from jrnl.exception import JrnlException
|
||||||
from jrnl.messages import Message
|
|
||||||
from jrnl.messages import MsgStyle
|
|
||||||
from jrnl.messages import MsgText
|
|
||||||
from jrnl.plugins.fancy_exporter import check_provided_linewrap_viability
|
from jrnl.plugins.fancy_exporter import check_provided_linewrap_viability
|
||||||
from jrnl.plugins.yaml_exporter import YAMLExporter
|
from jrnl.plugins.yaml_exporter import YAMLExporter
|
||||||
|
|
||||||
|
@ -36,12 +33,8 @@ class TestFancy:
|
||||||
|
|
||||||
|
|
||||||
class TestYaml:
|
class TestYaml:
|
||||||
@mock.patch("jrnl.plugins.yaml_exporter.YAMLExporter.export_journal")
|
|
||||||
@mock.patch("builtins.open")
|
@mock.patch("builtins.open")
|
||||||
def test_export_to_nonexisting_folder(self, mock_open, mock_export_journal):
|
def test_export_to_nonexisting_folder(self, mock_open):
|
||||||
mock_export_journal.side_effect = JrnlException(
|
|
||||||
Message(MsgText.YamlMustBeDirectory, MsgStyle.ERROR)
|
|
||||||
)
|
|
||||||
with pytest.raises(JrnlException):
|
with pytest.raises(JrnlException):
|
||||||
YAMLExporter.write_file("journal", "non-existing-path")
|
YAMLExporter.write_file("journal", "non-existing-path")
|
||||||
mock_open.assert_not_called()
|
mock_open.assert_not_called()
|
||||||
|
|
|
@ -55,7 +55,7 @@ def test_empty():
|
||||||
|
|
||||||
|
|
||||||
def test_contains_alone():
|
def test_contains_alone():
|
||||||
assert cli_as_dict("-contains whatever") == expected_args(contains="whatever")
|
assert cli_as_dict("-contains whatever") == expected_args(contains=["whatever"])
|
||||||
|
|
||||||
|
|
||||||
def test_debug_alone():
|
def test_debug_alone():
|
||||||
|
@ -242,7 +242,9 @@ def test_color_override():
|
||||||
|
|
||||||
def test_multiple_overrides():
|
def test_multiple_overrides():
|
||||||
parsed_args = cli_as_dict(
|
parsed_args = cli_as_dict(
|
||||||
'--config-override colors.title green --config-override editor "nano" --config-override journal.scratchpad "/tmp/scratchpad"'
|
"--config-override colors.title green "
|
||||||
|
'--config-override editor "nano" '
|
||||||
|
'--config-override journal.scratchpad "/tmp/scratchpad"'
|
||||||
)
|
)
|
||||||
assert parsed_args == expected_args(
|
assert parsed_args == expected_args(
|
||||||
config_override=[
|
config_override=[
|
||||||
|
@ -294,7 +296,7 @@ class TestDeserialization:
|
||||||
)
|
)
|
||||||
def test_deserialize_multiword_strings(self, input_str):
|
def test_deserialize_multiword_strings(self, input_str):
|
||||||
runtime_config = make_yaml_valid_dict(input_str)
|
runtime_config = make_yaml_valid_dict(input_str)
|
||||||
assert runtime_config.__class__ == dict
|
assert runtime_config.__class__ is dict
|
||||||
assert input_str[0] in runtime_config
|
assert input_str[0] in runtime_config
|
||||||
assert runtime_config[input_str[0]] == input_str[1]
|
assert runtime_config[input_str[0]] == input_str[1]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue