Merge branch 'develop' of https://github.com/jrnl-org/jrnl into dayone2

This commit is contained in:
dbxnr 2020-02-11 17:41:03 +00:00
commit d86bbaf861
26 changed files with 439 additions and 200 deletions

View file

@ -1,5 +1,20 @@
#!/usr/bin/env bash
BRANCH=$TRAVIS_BRANCH
if [[ $TRAVIS_BRANCH == $TRAVIS_TAG ]]; then
BRANCH='master'
fi
# Check if branch has been updated since this build started
# This tends to happen if multiple things have been merged in at the same time.
if [[ -z $TRAVIS_TAG ]]; then
git fetch origin
if [[ $(git rev-parse "origin/${BRANCH}") != $TRAVIS_COMMIT ]]; then
echo "${BRANCH} has been updated since build started. Aborting changelog."
exit 0
fi
fi
FILENAME='CHANGELOG.md'
# get the latest git tags
@ -40,11 +55,6 @@ docker run -it --rm -v "$(pwd)":/usr/local/src/your-app ferrarimarco/github-chan
# Put back our link (instead of the broken one)
sed -i 's!https://pypi.org/project/jrnl/HEAD/!https://github.com/jrnl-org/jrnl/!' "$FILENAME"
BRANCH=$TRAVIS_BRANCH
if [[ $TRAVIS_BRANCH == $TRAVIS_TAG ]]; then
BRANCH='master'
fi
git config --global user.email "jrnl.bot@gmail.com"
git config --global user.name "Jrnl Bot"
git checkout $BRANCH

1
.gitignore vendored
View file

@ -52,4 +52,3 @@ exp/
_extras/
*.sublime-*
site/
jrnl/__version__.py

View file

@ -7,12 +7,13 @@ cache:
git:
depth: false
autocrlf: false
before_install:
- date
install:
- pip install poetry~=0.12.17
- pip install poetry
- poetry install
- poetry run python --version
@ -50,7 +51,6 @@ jobs:
fast_finish: true
allow_failures:
- python: nightly
- os: windows
include:
- name: Lint, via Black
@ -73,6 +73,7 @@ jobs:
env:
- JRNL_PYTHON_VERSION=3.6.8
- PATH=/c/Python36:/c/Python36/Scripts:$PATH
- PYTHONIOENCODING=UTF-8
# Python 3.7 Tests
- name: Python 3.7 on Linux
@ -88,6 +89,7 @@ jobs:
env:
- JRNL_PYTHON_VERSION=3.7.5
- PATH=/c/Python37:/c/Python37/Scripts:$PATH
- PYTHONIOENCODING=UTF-8
# Python 3.8 Tests
- name: Python 3.8 on Linux
@ -103,6 +105,7 @@ jobs:
env:
- JRNL_PYTHON_VERSION=3.8.0
- PATH=/c/Python38:/c/Python38/Scripts:$PATH
- PYTHONIOENCODING=UTF-8
# ... and beyond!
- name: Python nightly on Linux
@ -128,6 +131,8 @@ jobs:
- poetry version "$TRAVIS_TAG"
- echo __version__ = \"$TRAVIS_TAG\" > jrnl/__version__.py
- poetry build
script:
- echo "Deployment starting..."
deploy:
- provider: script
script: poetry publish

View file

@ -2,10 +2,41 @@
## [Unreleased](https://github.com/jrnl-org/jrnl/)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.1...HEAD)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.2...HEAD)
**Implemented enhancements:**
- Update YAML exporter to handle Dayone format [\#773](https://github.com/jrnl-org/jrnl/pull/773) ([MinchinWeb](https://github.com/MinchinWeb))
**Fixed bugs:**
- Listing all entries in DayOne Classic journal throws IndexError [\#786](https://github.com/jrnl-org/jrnl/pull/786) ([MinchinWeb](https://github.com/MinchinWeb))
- Add UTC support for failing DayOne tests [\#785](https://github.com/jrnl-org/jrnl/pull/785) ([MinchinWeb](https://github.com/MinchinWeb))
**Build:**
- Stop multipe changelog generators from crashing into each other [\#845](https://github.com/jrnl-org/jrnl/pull/845) ([wren](https://github.com/wren))
- Don't re-run tests on deployment [\#839](https://github.com/jrnl-org/jrnl/pull/839) ([wren](https://github.com/wren))
- Put back build lines in Poetry config [\#838](https://github.com/jrnl-org/jrnl/pull/838) ([wren](https://github.com/wren))
- Restore emoji test [\#837](https://github.com/jrnl-org/jrnl/pull/837) ([micahellison](https://github.com/micahellison))
- Fix crashing unicode Travis tests on Windows and fail build if Windows tests fail [\#836](https://github.com/jrnl-org/jrnl/pull/836) ([micahellison](https://github.com/micahellison))
- Remove poetry from build system in pyproject config to fix `brew install` [\#830](https://github.com/jrnl-org/jrnl/pull/830) ([wren](https://github.com/wren))
- Fix all skipped tests on Travis Windows builds by preserving newlines [\#823](https://github.com/jrnl-org/jrnl/pull/823) ([micahellison](https://github.com/micahellison))
**Updated documentation:**
- Update site description [\#841](https://github.com/jrnl-org/jrnl/pull/841) ([wren](https://github.com/wren))
- Get rid of dumb sex joke [\#840](https://github.com/jrnl-org/jrnl/pull/840) ([wren](https://github.com/wren))
- Updating/clarifying template explanation [\#829](https://github.com/jrnl-org/jrnl/pull/829) ([heymajor](https://github.com/heymajor))
## [v2.2](https://pypi.org/project/jrnl/v2.2/) (2020-02-01)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.1...v2.2)
**Implemented enhancements:**
- Update YAML exporter to handle Dayone format [\#773](https://github.com/jrnl-org/jrnl/pull/773) ([MinchinWeb](https://github.com/MinchinWeb))
- Full text search \(case insensitive\) with "-contains" [\#740](https://github.com/jrnl-org/jrnl/pull/740) ([empireshades](https://github.com/empireshades))
- Reduce startup time by 55% [\#719](https://github.com/jrnl-org/jrnl/pull/719) ([maebert](https://github.com/maebert))
- Refactor password logic to prevent accidental password leakage [\#708](https://github.com/jrnl-org/jrnl/pull/708) ([pspeter](https://github.com/pspeter))
@ -18,6 +49,9 @@
**Build:**
- Fix issue where jrnl would always out 'source' for version, fix Poetry config to build and publish properly [\#820](https://github.com/jrnl-org/jrnl/pull/820) ([wren](https://github.com/wren))
- Unpin poetry [\#808](https://github.com/jrnl-org/jrnl/pull/808) ([wren](https://github.com/wren))
- Fix all skipped tests on Travis Windows builds by preserving newlines [\#823](https://github.com/jrnl-org/jrnl/pull/823) ([micahellison](https://github.com/micahellison))
- Change PyPI auth method in build pipeline [\#807](https://github.com/jrnl-org/jrnl/pull/807) ([wren](https://github.com/wren))
- Automagically update the changelog you see before your very eyes! [\#806](https://github.com/jrnl-org/jrnl/pull/806) ([wren](https://github.com/wren))
- Update Black version and lock file to fix builds on develop branch [\#784](https://github.com/jrnl-org/jrnl/pull/784) ([wren](https://github.com/wren))
@ -30,13 +64,14 @@
**Updated documentation:**
- Explain how fish can be configured to exclude jrnl commands from history by default [\#809](https://github.com/jrnl-org/jrnl/pull/809) ([aureooms](https://github.com/aureooms))
- Remove merge marker in recipes.md [\#782](https://github.com/jrnl-org/jrnl/pull/782) ([markphelps](https://github.com/markphelps))
- Fix merge conflict left-over [\#767](https://github.com/jrnl-org/jrnl/pull/767) ([thejspr](https://github.com/thejspr))
- Display header in docs on mobile devices [\#763](https://github.com/jrnl-org/jrnl/pull/763) ([maebert](https://github.com/maebert))
## [v2.1.1](https://pypi.org/project/jrnl/v2.1.1/) (2019-11-26)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.1-beta...v2.1.1)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.post2...v2.1.1)
**Implemented enhancements:**
@ -59,7 +94,7 @@
## [v2.1.post2](https://pypi.org/project/jrnl/v2.1.post2/) (2019-11-11)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1-beta6...v2.1.post2)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0.1...v2.1.post2)
**Fixed bugs:**
@ -77,7 +112,7 @@
## [v2.0.1](https://pypi.org/project/jrnl/v2.0.1/) (2019-09-26)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0.1-beta...v2.0.1)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0.0...v2.0.1)
**Implemented enhancements:**
@ -95,7 +130,9 @@
## [v2.0.0](https://pypi.org/project/jrnl/v2.0.0/) (2019-08-24)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0-rc4...v2.0.0)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/1.9.8...v2.0.0)
🚨 **BREAKING CHANGES** 🚨
**Implemented enhancements:**
- Change cryptographic backend from PyCrypto to cryptography.io

View file

@ -56,10 +56,14 @@ setopt HIST_IGNORE_SPACE
alias jrnl=" jrnl"
```
The fish shell does not support automatically preventing logging like
this. To prevent `jrnl` commands being logged by fish, you must make
sure to type a space before every `jrnl` command you enter. To delete
existing `jrnl` commands from fishs history, run
If you are using `fish` instead of `bash` or `zsh`, you can get the same behaviour by
adding this to your `fish` configuration:
``` sh
abbr jrnl " jrnl"
```
To delete existing `jrnl` commands from `fish`s history, run
`history delete --prefix 'jrnl '`.
## Manual decryption

View file

@ -70,17 +70,59 @@ jrnlimport () {
### Using templates
Say you always want to use the same template for creating new entries.
If you have an [external editor](../advanced) set up, you can use this:
!!! note
Templates require an [external editor](../advanced) be configured.
A template is a code snippet that makes it easier to enter use repeated text
each time a new journal entry is started. There are two ways you can utilize
templates in your entries.
#### 1. Command line arguments
If you had a `template.txt` file with the following contents:
```sh
jrnl < my_template.txt
jrnl -1 --edit
My Personal Journal
Title:
Body:
```
Another nice solution that allows you to define individual prompts comes
from [Jacobo de
Vera](https://github.com/maebert/jrnl/issues/194#issuecomment-47402869):
The `template.txt` file could be used to create a new entry with these
command line arguements:
```sh
jrnl < template.txt # Imports template.txt as the most recent entry
jrnl -1 --edit # Opens the most recent entry in the editor
```
#### 2. Include the template file in `jrnl.yaml`
A more efficient way to work with a template file is to declare the file
in your config file by changing the `template` setting from `false` to the
template file's path in double quotes:
```sh
...
template: "/path/to/template.txt"
...
```
Changes can be saved as you continue writing the journal entry and will be
logged as a new entry in the journal you specified in the original argument.
!!! tip
To read your journal entry or to verify the entry saved, you can use this
command: `jrnl -n 1` (Check out [Import and Export](../export/#export-to-files) for more export options).
```sh
jrnl -n 1
```
### Prompts on shell reload
If you'd like to be prompted each time you refresh your shell, you can include
this in your `.bash_profile`:
```sh
function log_question()
@ -93,6 +135,11 @@ log_question 'What did I achieve today?'
log_question 'What did I make progress with?'
```
Whenever your shell is reloaded, you will be prompted to answer each of the
questions in the example above. Each answer will be logged as a separate
journal entry at the `default_hour` and `default_minute` listed in your
`jrnl.yaml` [config file](../advanced/#configuration-file).
### Display random entry
You can use this to select one title at random and then display the whole
@ -107,10 +154,11 @@ jrnl -on "$(jrnl --short | shuf -n 1 | cut -d' ' -f1,2)"
## External editors
To use external editors for writing and editing journal entries, set
them up in your `jrnl.yaml` (see `advanced usage <advanced>` for
details). Generally, after writing an entry, you will have to save and
close the file to save the changes to jrnl.
Configure your preferred external editor by updating the `editor` option
in your `jrnl.yaml` file. (See [advanced usage](../advanced) for details).
!!! note
To save and log any entry edits, save and close the file.
### Sublime Text

View file

@ -34,7 +34,7 @@
"operatingSystem": ["macOS", "Windows", "Linux"],
"thumbnailUrl": "https://jrnl.sh/img/banner_og.png",
"installUrl": "https://jrnl.sh/installation",
"softwareVersion": "2.0.0rc2"
"softwareVersion": "2.2"
}
</script>
</head>
@ -42,7 +42,7 @@
<body>
<header>
<aside>
<a id="twitter" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh&via=maebert"><i class="icon twitter"></i>Tell your friends</a>
<a id="twitter" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh"><i class="icon twitter"></i>Tell your friends</a>
</aside>
<div id="title">
<img id="logo" src="img/jrnl_white.svg" width="90px" height="98px" title="jrnl" />
@ -58,7 +58,7 @@
<nav>
<a href="overview">Documentation</a>
<a href="http://github.com/jrnl-org/jrnl" title="View on Github">Fork me on GitHub</a>
<a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh&via=maebert">Tell your friends on twitter</a>
<a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh">Tell your friends on twitter</a>
<a href="installation" class="cta">Download</a>
</nav>
<div class="flex">

View file

@ -119,10 +119,10 @@ Will print all entries in which either `@pinkie` or `@WorldDomination`
occurred.
```sh
jrnl -n 5 -and @pineapple @lubricant
jrnl -n 5 -and @pinkie @WorldDomination
```
the last five entries containing both `@pineapple` **and** `@lubricant`.
the last five entries containing both `@pinkie` **and** `@worldDomination`.
You can change which symbols you'd like to use for tagging in the
configuration.
@ -154,7 +154,7 @@ encrypt) your edited journal after you save and exit the editor.
You can also use this feature for deleting entries from your journal
```sh
jrnl @girlfriend -until 'june 2012' --edit
jrnl @texas -until 'june 2012' --edit
```
Just select all text, press delete, and everything is gone...

View file

@ -41,6 +41,14 @@ Feature: Basic reading and writing to a journal
When we run "jrnl -on 'june 6 2013' --short"
Then the output should be "2013-06-10 15:40 Life is good."
Scenario: Emoji support
Given we use the config "basic.yaml"
When we run "jrnl 23 july 2013: 🌞 sunny day. Saw an 🐘"
Then we should see the message "Entry added"
When we run "jrnl -n 1"
Then the output should contain "🌞"
and the output should contain "🐘"
Scenario: Writing an entry at the prompt
Given we use the config "basic.yaml"
When we run "jrnl" and enter "25 jul 2013: I saw Elvis. He's alive."

View file

@ -0,0 +1,12 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: false
highlight: true
journals:
default: features/journals/bug780.dayone
linewrap: 80
tagsymbols: '@'
template: false
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Activity</key>
<string>Stationary</string>
<key>Creation Date</key>
<date>2019-12-30T21:28:54Z</date>
<key>Entry Text</key>
<string></string>
<key>Starred</key>
<false />
<key>UUID</key>
<string>48A25033B34047C591160A4480197D8B</string>
<key>Creator</key>
<dict>
<key>Device Agent</key>
<string>PC</string>
<key>Generation Date</key>
<date>2019-12-30T21:28:54Z</date>
<key>Host Name</key>
<string>LE-TREPORT</string>
<key>OS Agent</key>
<string>Microsoft Windows/10 Home</string>
<key>Software Agent</key>
<string>Journaley/2.1</string>
</dict>
<key>Tags</key>
<array>
<string>i_have_no_body</string>
</array>
</dict>
</plist>

View file

@ -1,7 +1,5 @@
Feature: Dayone specific implementation details.
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Loading a DayOne Journal
Given we use the config "dayone.yaml"
When we run "jrnl -from 'feb 2013'"
@ -15,7 +13,7 @@ Feature: Dayone specific implementation details.
2013-07-17 11:38 This entry is starred!
"""
# fails when system time is UTC (as on Travis-CI)
# broken still
@skip
Scenario: Entries without timezone information will be interpreted as in the current timezone
Given we use the config "dayone.yaml"
@ -23,7 +21,6 @@ Feature: Dayone specific implementation details.
Then we should get no error
and the output should contain "2013-01-17T18:37Z" in the local time
@skip
Scenario: Writing into Dayone
Given we use the config "dayone.yaml"
When we run "jrnl 01 may 1979: Being born hurts."
@ -33,8 +30,6 @@ Feature: Dayone specific implementation details.
1979-05-01 09:00 Being born hurts.
"""
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Loading tags from a DayOne Journal
Given we use the config "dayone.yaml"
When we run "jrnl --tags"
@ -44,8 +39,6 @@ Feature: Dayone specific implementation details.
@play : 1
"""
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Saving tags from a DayOne Journal
Given we use the config "dayone.yaml"
When we run "jrnl A hard day at @work"
@ -56,8 +49,6 @@ Feature: Dayone specific implementation details.
@play : 1
"""
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Filtering by tags from a DayOne Journal
Given we use the config "dayone.yaml"
When we run "jrnl @work"
@ -66,8 +57,6 @@ Feature: Dayone specific implementation details.
2013-05-17 11:39 This entry has tags!
"""
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Exporting dayone to json
Given we use the config "dayone.yaml"
When we run "jrnl --export json"

View file

@ -24,7 +24,6 @@ Feature: Zapped Dayone bugs stay dead!
| I'm feeling sore because I forgot to stretch.
"""
@skip_win
Scenario: Opening an folder that's not a DayOne folder gives a nice error message
Given we use the config "empty_folder.yaml"
When we run "jrnl Herro"

View file

@ -12,7 +12,6 @@
Then we should see the message "Journal decrypted"
And the journal should have 2 entries
@skip_win
Scenario: Encrypting a journal
Given we use the config "basic.yaml"
When we run "jrnl --encrypt" and enter
@ -27,7 +26,6 @@
Then the output should contain "Password"
And the output should contain "2013-06-10 15:40 Life is good"
@skip_win
Scenario: Mistyping your password
Given we use the config "basic.yaml"
When we run "jrnl --encrypt" and enter
@ -45,7 +43,6 @@
Then the output should contain "Password"
And the output should contain "2013-06-10 15:40 Life is good"
@skip_win
Scenario: Storing a password in Keychain
Given we use the config "multiple.yaml"
When we run "jrnl simple --encrypt" and enter

View file

@ -4,21 +4,20 @@ Feature: Exporting a Journal
Given we use the config "tags.yaml"
When we run "jrnl --export json"
Then we should get no error
and the output should be parsable as json
and "entries" in the json output should have 2 elements
and "tags" in the json output should contain "@idea"
and "tags" in the json output should contain "@journal"
and "tags" in the json output should contain "@dan"
And the output should be parsable as json
And "entries" in the json output should have 2 elements
And "tags" in the json output should contain "@idea"
And "tags" in the json output should contain "@journal"
And "tags" in the json output should contain "@dan"
Scenario: Exporting using filters should only export parts of the journal
Given we use the config "tags.yaml"
When we run "jrnl -until 'may 2013' --export json"
# Then we should get no error
Then the output should be parsable as json
and "entries" in the json output should have 1 element
and "tags" in the json output should contain "@idea"
and "tags" in the json output should contain "@journal"
and "tags" in the json output should not contain "@dan"
And "entries" in the json output should have 1 element
And "tags" in the json output should contain "@idea"
And "tags" in the json output should contain "@journal"
And "tags" in the json output should not contain "@dan"
Scenario: Exporting using custom templates
Given we use the config "basic.yaml"
@ -83,3 +82,57 @@ Feature: Exporting a Journal
More stuff
more stuff again
"""
Scenario: Exporting to XML
Given we use the config "tags.yaml"
When we run "jrnl --export xml"
Then the output should be a valid XML string
And "entries" node in the xml output should have 2 elements
And "tags" in the xml output should contain ["@idea", "@journal", "@dan"]
Scenario: Exporting tags
Given we use the config "tags.yaml"
When we run "jrnl --export tags"
Then the output should be
"""
@idea : 2
@journal : 1
@dan : 1
"""
Scenario: Exporting fancy
Given we use the config "tags.yaml"
When we run "jrnl --export fancy"
Then the output should be
"""
2013-04-09 15:39
I have an @idea:
(1) write a command line @journal software
(2) ???
(3) PROFIT!
2013-06-10 15:40
I met with @dan.
As alway's he shared his latest @idea on how to rule the world with me.
inst
"""
Scenario: Export to yaml
Given we use the config "tags.yaml"
And we created a directory named "exported_journal"
When we run "jrnl --export yaml -o exported_journal"
Then "exported_journal" should contain the files ["2013-04-09_i-have-an-idea.md", "2013-06-10_i-met-with-dan.md"]
And the content of exported yaml "exported_journal/2013-04-09_i-have-an-idea.md" should be
"""
title: I have an @idea:
date: 2013-04-09 15:39
stared: False
tags: idea, journal
(1) write a command line @journal software
(2) ???
(3) PROFIT!
"""

View file

@ -1,7 +1,7 @@
Feature: Zapped bugs should stay dead.
Scenario: Writing an entry does not print the entire journal
# https://github.com/maebert/jrnl/issues/87
# https://github.com/jrnl-org/jrnl/issues/87
Given we use the config "basic.yaml"
When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa."
Then we should see the message "Entry added"
@ -9,21 +9,14 @@ Feature: Zapped bugs should stay dead.
Then the output should not contain "Life is good"
Scenario: Date with time should be parsed correctly
# https://github.com/maebert/jrnl/issues/117
# https://github.com/jrnl-org/jrnl/issues/117
Given we use the config "basic.yaml"
When we run "jrnl 2013-11-30 15:42: Project Started."
Then we should see the message "Entry added"
and the journal should contain "[2013-11-30 15:42] Project Started."
Scenario: Date in the future should be parsed correctly
# https://github.com/maebert/jrnl/issues/185
Given we use the config "basic.yaml"
When we run "jrnl 26/06/2019: Planet? Earth. Year? 2019."
Then we should see the message "Entry added"
and the journal should contain "[2019-06-26 09:00] Planet?"
Scenario: Loading entry with ambiguous time stamp
#https://github.com/maebert/jrnl/issues/153
#https://github.com/jrnl-org/jrnl/issues/153
Given we use the config "bug153.yaml"
When we run "jrnl -1"
Then we should get no error
@ -32,6 +25,19 @@ Feature: Zapped bugs should stay dead.
2013-10-27 03:27 Some text.
"""
Scenario: Date in the future should be parsed correctly
# https://github.com/jrnl-org/jrnl/issues/185
Given we use the config "basic.yaml"
When we run "jrnl 26/06/2019: Planet? Earth. Year? 2019."
Then we should see the message "Entry added"
and the journal should contain "[2019-06-26 09:00] Planet?"
Scenario: Empty DayOne entry bodies should not error
# https://github.com/jrnl-org/jrnl/issues/780
Given we use the config "bug780.yaml"
When we run "jrnl --short"
Then we should get no error
Scenario: Title with an embedded period.
Given we use the config "basic.yaml"
When we run "jrnl 04-24-2014: Created a new website - empty.com. Hope to get a lot of traffic."

View file

@ -3,7 +3,6 @@ from unittest.mock import patch
from behave import given, when, then
from jrnl import cli, install, Journal, util, plugins
from jrnl import __version__
from dateutil import parser as date_parser
from collections import defaultdict
try:
@ -185,53 +184,6 @@ def no_error(context):
assert context.exit_status == 0, context.exit_status
@then("the output should be parsable as json")
def check_output_json(context):
out = context.stdout_capture.getvalue()
assert json.loads(out), out
@then('"{field}" in the json output should have {number:d} elements')
@then('"{field}" in the json output should have 1 element')
def check_output_field(context, field, number=1):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json, [field, out_json]
assert len(out_json[field]) == number, len(out_json[field])
@then('"{field}" in the json output should not contain "{key}"')
def check_output_field_not_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key not in out_json[field]
@then('"{field}" in the json output should contain "{key}"')
def check_output_field_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key in out_json[field]
@then('the json output should contain {path} = "{value}"')
def check_json_output_path(context, path, value):
""" E.g.
the json output should contain entries.0.title = "hello"
"""
out = context.stdout_capture.getvalue()
struct = json.loads(out)
for node in path.split("."):
try:
struct = struct[int(node)]
except ValueError:
struct = struct[node]
assert struct == value, struct
@then("the output should be")
@then('the output should be "{text}"')
def check_output(context, text=None):

View file

@ -0,0 +1,124 @@
import json
import os
import shutil
from xml.etree import ElementTree
from behave import then, given
@then("the output should be parsable as json")
def check_output_json(context):
out = context.stdout_capture.getvalue()
assert json.loads(out), out
@then('"{field}" in the json output should have {number:d} elements')
@then('"{field}" in the json output should have 1 element')
def check_output_field(context, field, number=1):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json, [field, out_json]
assert len(out_json[field]) == number, len(out_json[field])
@then('"{field}" in the json output should not contain "{key}"')
def check_output_field_not_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key not in out_json[field]
@then('"{field}" in the json output should contain "{key}"')
def check_output_field_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key in out_json[field]
@then('the json output should contain {path} = "{value}"')
def check_json_output_path(context, path, value):
""" E.g.
the json output should contain entries.0.title = "hello"
"""
out = context.stdout_capture.getvalue()
struct = json.loads(out)
for node in path.split("."):
try:
struct = struct[int(node)]
except ValueError:
struct = struct[node]
assert struct == value, struct
@then("the output should be a valid XML string")
def assert_valid_xml_string(context):
output = context.stdout_capture.getvalue()
xml_tree = ElementTree.fromstring(output)
assert xml_tree, output
@then('"entries" node in the xml output should have {number:d} elements')
def assert_xml_output_entries_count(context, number):
output = context.stdout_capture.getvalue()
xml_tree = ElementTree.fromstring(output)
xml_tags = (node.tag for node in xml_tree)
assert "entries" in xml_tags, str(list(xml_tags))
actual_entry_count = len(xml_tree.find("entries"))
assert actual_entry_count == number, actual_entry_count
@then('"tags" in the xml output should contain {expected_tags_json_list}')
def assert_xml_output_tags(context, expected_tags_json_list):
output = context.stdout_capture.getvalue()
xml_tree = ElementTree.fromstring(output)
xml_tags = (node.tag for node in xml_tree)
assert "tags" in xml_tags, str(list(xml_tags))
expected_tags = json.loads(expected_tags_json_list)
actual_tags = set(t.attrib["name"] for t in xml_tree.find("tags"))
assert actual_tags == set(expected_tags), [actual_tags, set(expected_tags)]
@given('we created a directory named "{dir_name}"')
def create_directory(context, dir_name):
if os.path.exists(dir_name):
shutil.rmtree(dir_name)
os.mkdir(dir_name)
@then('"{dir_name}" should contain the files {expected_files_json_list}')
def assert_dir_contains_files(context, dir_name, expected_files_json_list):
actual_files = os.listdir(dir_name)
expected_files = json.loads(expected_files_json_list)
assert actual_files == expected_files, [actual_files, expected_files]
@then('the content of exported yaml "{file_path}" should be')
def assert_exported_yaml_file_content(context, file_path):
expected_content = context.text.strip().splitlines()
with open(file_path, "r") as f:
actual_content = f.read().strip().splitlines()
for actual_line, expected_line in zip(actual_content, expected_content):
if actual_line.startswith("tags: ") and expected_line.startswith("tags: "):
assert_equal_tags_ignoring_order(actual_line, expected_line)
else:
assert actual_line.strip() == expected_line.strip(), [
actual_line.strip(),
expected_line.strip(),
]
def assert_equal_tags_ignoring_order(actual_line, expected_line):
actual_tags = set(tag.strip() for tag in actual_line[len("tags: ") :].split(","))
expected_tags = set(
tag.strip() for tag in expected_line[len("tags: ") :].split(",")
)
assert actual_tags == expected_tags, [actual_tags, expected_tags]

View file

@ -1,6 +1,5 @@
Feature: Upgrading Journals from 1.x.x to 2.x.x
@skip_win
Scenario: Upgrade and parse journals with square brackets
Given we use the config "upgrade_from_195.json"
When we run "jrnl -9" and enter "Y"
@ -12,7 +11,6 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
"""
Then the journal should have 2 entries
@skip_win
Scenario: Upgrading a journal encrypted with jrnl 1.x
Given we use the config "encrypted_old.json"
When we run "jrnl -n 1" and enter
@ -24,7 +22,6 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
Then the output should contain "Password"
and the output should contain "2013-06-10 15:40 Life is good"
@skip_win
Scenario: Upgrade and parse journals with little endian date format
Given we use the config "upgrade_from_195_little_endian_dates.json"
When we run "jrnl -9" and enter "Y"

View file

@ -52,7 +52,11 @@ class DayOne(Journal.Journal):
except (KeyError, pytz.exceptions.UnknownTimeZoneError):
timezone = tzlocal.get_localzone()
date = dict_entry["Creation Date"]
date = date + timezone.utcoffset(date, is_dst=False)
# convert the date to UTC rather than keep messing with
# timezones
if timezone.zone != "UTC":
date = date + timezone.utcoffset(date, is_dst=False)
entry = Entry.Entry(
self,
date,

View file

@ -22,7 +22,7 @@ class Entry:
def _parse_text(self):
raw_text = self.text
lines = raw_text.splitlines()
if lines[0].strip().endswith("*"):
if lines and lines[0].strip().endswith("*"):
self.starred = True
raw_text = lines[0].strip("\n *") + "\n" + "\n".join(lines[1:])
self._title, self._body = split_title(raw_text)

1
jrnl/__version__.py Normal file
View file

@ -0,0 +1 @@
__version__ = "v2.2-beta"

View file

@ -1,62 +0,0 @@
#!/usr/bin/env python
from .util import ERROR_COLOR, RESET_COLOR
from .util import slugify
from .plugins.template import Template
import os
class Exporter:
"""This Exporter can convert entries and journals into text files."""
def __init__(self, format):
with open("jrnl/templates/" + format + ".template") as f:
front_matter, body = f.read().strip("-\n").split("---", 2)
self.template = Template(body)
def export_entry(self, entry):
"""Returns a string representation of a single entry."""
return str(entry)
def _get_vars(self, journal):
return {"journal": journal, "entries": journal.entries, "tags": journal.tags}
def export_journal(self, journal):
"""Returns a string representation of an entire journal."""
return self.template.render_block("journal", **self._get_vars(journal))
def write_file(self, journal, path):
"""Exports a journal into a single file."""
try:
with open(path, "w", encoding="utf-8") as f:
f.write(self.export_journal(journal))
return f"[Journal exported to {path}]"
except OSError as e:
return f"[{ERROR_COLOR}ERROR{RESET_COLOR}: {e.filename} {e.strerror}]"
def make_filename(self, entry):
return entry.date.strftime(
"%Y-%m-%d_{}.{}".format(slugify(entry.title), self.extension)
)
def write_files(self, journal, path):
"""Exports a journal into individual files for each entry."""
for entry in journal.entries:
try:
full_path = os.path.join(path, self.make_filename(entry))
with open(full_path, "w", encoding="utf-8") as f:
f.write(self.export_entry(entry))
except OSError as e:
return f"[{ERROR_COLOR}ERROR{RESET_COLOR}: {e.filename} {e.strerror}]"
return f"[Journal exported to {path}]"
def export(self, journal, format="text", output=None):
"""Exports to individual files if output is an existing path, or into
a single file if output is a file name, or returns the exporter's
representation as string if output is None."""
if output and os.path.isdir(output): # multiple files
return self.write_files(journal, output)
elif output: # single file
return self.write_file(journal, output)
else:
return self.export_journal(journal)

View file

@ -19,11 +19,10 @@ class YAMLExporter(TextExporter):
"""Returns a markdown representation of a single entry, with YAML front matter."""
if to_multifile is False:
print(
"{}ERROR{}: YAML export must be to individual files. "
"Please specify a directory to export to.".format(
"\033[31m", "\033[0m"
),
file=sys.stderr,
"{}ERROR{}: YAML export must be to individual files. Please \
specify a directory to export to.".format(
ERROR_COLOR, RESET_COLOR, file=sys.stderr
)
)
return
@ -33,16 +32,14 @@ class YAMLExporter(TextExporter):
tagsymbols = entry.journal.config["tagsymbols"]
# see also Entry.Entry.rag_regex
multi_tag_regex = re.compile(
r"(?u)^\s*([{tags}][-+*#/\w]+\s*)+$".format(tags=tagsymbols)
)
multi_tag_regex = re.compile(fr"(?u)^\s*([{tagsymbols}][-+*#/\w]+\s*)+$")
"""Increase heading levels in body text"""
newbody = ""
heading = "#"
previous_line = ""
warn_on_heading_level = False
for line in entry.body.splitlines(True):
for line in body.splitlines(True):
if re.match(r"^#+ ", line):
"""ATX style headings"""
newbody = newbody + previous_line + heading + line
@ -80,9 +77,32 @@ class YAMLExporter(TextExporter):
dayone_attributes = ""
if hasattr(entry, "uuid"):
dayone_attributes += "uuid: " + entry.uuid + "\n"
# TODO: copy over pictures, if present
# source directory is entry.journal.config['journal']
# output directory is...?
if (
hasattr(entry, "creator_device_agent")
or hasattr(entry, "creator_generation_date")
or hasattr(entry, "creator_host_name")
or hasattr(entry, "creator_os_agent")
or hasattr(entry, "creator_software_agent")
):
dayone_attributes += "creator:\n"
if hasattr(entry, "creator_device_agent"):
dayone_attributes += f" device agent: {entry.creator_device_agent}\n"
if hasattr(entry, "creator_generation_date"):
dayone_attributes += " generation date: {}\n".format(
str(entry.creator_generation_date)
)
if hasattr(entry, "creator_host_name"):
dayone_attributes += f" host name: {entry.creator_host_name}\n"
if hasattr(entry, "creator_os_agent"):
dayone_attributes += f" os agent: {entry.creator_os_agent}\n"
if hasattr(entry, "creator_software_agent"):
dayone_attributes += (
f" software agent: {entry.creator_software_agent}\n"
)
# TODO: copy over pictures, if present
# source directory is entry.journal.config['journal']
# output directory is...?
return "title: {title}\ndate: {date}\nstared: {stared}\ntags: {tags}\n{dayone} {body} {space}".format(
date=date_str,

View file

@ -12,7 +12,7 @@ markdown_extensions:
- admonition
repo_url: https://github.com/jrnl-org/jrnl/
site_author: Manuel Ebert
site_description: Never Worry about Money Again.
site_description: Collect your thoughts and notes without leaving the command line.
nav:
- Overview: overview.md
- Quickstart: installation.md

View file

@ -1,12 +1,15 @@
[tool.poetry]
name = "jrnl"
version = "v2.1.1"
version = "v2.2.1-beta2"
description = "Collect your thoughts and notes without leaving the command line."
authors = [
"Manuel Ebert <manuel@1450.me>",
"Jonathan Wren <jonathan@nowandwren.com>",
"Micah Ellison <micahellison@gmail.com>"
]
maintainers = [
"Jonathan Wren and Micah Ellison <jrnl-sh@googlegroups.com>",
]
license = "MIT"
readme = "README.md"
homepage = "https://jrnl.sh"
@ -30,7 +33,7 @@ pyyaml = "^5.1"
behave = "^1.2"
mkdocs = "^1.0"
flake8 = "^3.7"
black = {version = "^19.10b0",allows-prereleases = true}
black = {version = "^19.10b0",allow-prereleases = true}
[tool.poetry.scripts]
jrnl = 'jrnl.cli:run'