Rename 'expiration.on-sync' to 'purge.on-sync' (#3556)

Taskwarrior uses "expire" to refer to deletion of tasks past their
"until" date, so let's use `purge` to link this semantically to the
`task purge` command.
This commit is contained in:
Dustin J. Mitchell 2024-07-14 15:45:26 -04:00 committed by GitHub
parent 1304d6361c
commit 7d79b9e516
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 57 additions and 99 deletions

View file

@ -217,8 +217,8 @@ rc.gc=0 ...), and not permanently used in the .taskrc file, as this
significantly affects performance in the long term. significantly affects performance in the long term.
.TP .TP
.B expiration.on-sync=0 .B purge.on-sync=0
If set, old tasks will be deleted automatically after each synchronization. If set, old tasks will be purged automatically after each synchronization.
Tasks are identified as "old" when they have status "Deleted" and have not Tasks are identified as "old" when they have status "Deleted" and have not
been modified for 180 days. been modified for 180 days.

View file

@ -132,7 +132,7 @@ syn match taskrcGoodKey '^\s*\Vexpressions='he=e-1
syn match taskrcGoodKey '^\s*\Vextensions='he=e-1 syn match taskrcGoodKey '^\s*\Vextensions='he=e-1
syn match taskrcGoodKey '^\s*\Vfontunderline='he=e-1 syn match taskrcGoodKey '^\s*\Vfontunderline='he=e-1
syn match taskrcGoodKey '^\s*\Vgc='he=e-1 syn match taskrcGoodKey '^\s*\Vgc='he=e-1
syn match taskrcGoodKey '^\s*\Vexpiration.on-sync='he=e-1 syn match taskrcGoodKey '^\s*\Vpurge.on-sync='he=e-1
syn match taskrcGoodKey '^\s*\Vhooks='he=e-1 syn match taskrcGoodKey '^\s*\Vhooks='he=e-1
syn match taskrcGoodKey '^\s*\Vhooks.location='he=e-1 syn match taskrcGoodKey '^\s*\Vhooks.location='he=e-1
syn match taskrcGoodKey '^\s*\Vhyphenate='he=e-1 syn match taskrcGoodKey '^\s*\Vhyphenate='he=e-1

View file

@ -118,7 +118,7 @@ std::string configurationDefaults =
"json.array=1 # Enclose JSON output in [ ]\n" "json.array=1 # Enclose JSON output in [ ]\n"
"abbreviation.minimum=2 # Shortest allowed abbreviation\n" "abbreviation.minimum=2 # Shortest allowed abbreviation\n"
"news.version= # Latest version highlights read by the user\n" "news.version= # Latest version highlights read by the user\n"
"expiration.on-sync=0 # Expire old tasks on sync\n" "purge.on-sync=0 # Purge old tasks on sync\n"
"\n" "\n"
"# Dates\n" "# Dates\n"
"dateformat=Y-M-D # Preferred input and display date format\n" "dateformat=Y-M-D # Preferred input and display date format\n"

View file

@ -542,7 +542,7 @@ void NewsItem::version3_1_0 (std::vector<NewsItem>& items) {
Version version("3.1.0"); Version version("3.1.0");
NewsItem sync { NewsItem sync {
version, version,
/*title=*/"Purging and Expiring Tasks", /*title=*/"Purging Tasks, Manually or Automatically",
/*bg_title=*/"", /*bg_title=*/"",
/*background=*/"", /*background=*/"",
/*punchline=*/ /*punchline=*/
@ -552,7 +552,7 @@ void NewsItem::version3_1_0 (std::vector<NewsItem>& items) {
"The `task purge` command removes tasks entirely, in contrast to `task delete` which merely sets\n" "The `task purge` command removes tasks entirely, in contrast to `task delete` which merely sets\n"
"the task status to 'Deleted'. This functionality existed in versions 2.x but was temporarily\n" "the task status to 'Deleted'. This functionality existed in versions 2.x but was temporarily\n"
"removed in 3.0.\n\n" "removed in 3.0.\n\n"
"The new `expiration.on-sync` configuration parameter controls automatic expiration of old tasks.\n" "The new `purge.on-sync` configuration parameter controls automatic purging of old tasks.\n"
"An old task is one with status 'Deleted' that has not been modified in 180 days. This\n" "An old task is one with status 'Deleted' that has not been modified in 180 days. This\n"
"functionality is optional and not enabled by default." "functionality is optional and not enabled by default."
}; };

View file

@ -160,7 +160,7 @@ int CmdShow::execute (std::string& output)
" due" " due"
" editor" " editor"
" exit.on.missing.db" " exit.on.missing.db"
" expiration.on-sync" " purge.on-sync"
" expressions" " expressions"
" fontunderline" " fontunderline"
" gc" " gc"

View file

@ -109,7 +109,7 @@ int CmdSync::execute (std::string& output)
Context &context = Context::getContext (); Context &context = Context::getContext ();
context.tdb2.sync(std::move(server), false); context.tdb2.sync(std::move(server), false);
if (context.config.getBoolean ("expiration.on-sync")) { if (context.config.getBoolean ("purge.on-sync")) {
context.tdb2.expire_tasks (); context.tdb2.expire_tasks ();
} }

View file

@ -111,7 +111,6 @@ set (pythonTests
encoding.test.py encoding.test.py
enpassant.test.py enpassant.test.py
exec.test.py exec.test.py
expiration.test.py
export.test.py export.test.py
feature.559.test.py feature.559.test.py
feature.default.project.test.py feature.default.project.test.py

View file

@ -1,89 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright 2006 - 2024, Tomas Babej, Paul Beckingham, Federico Hernandez.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# https://www.opensource.org/licenses/mit-license.php
#
###############################################################################
import sys
import os
import unittest
import time
# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from basetest import Task, TestCase
from basetest.utils import mkstemp
class TestImport(TestCase):
def setUp(self):
self.t = Task()
# Set up local sync within the TASKDATA directory, so that it will be
# deleted properly.
self.t.config("sync.local.server_dir", self.t.datadir)
def exists(self, uuid):
code, out, err = self.t(f"_get {uuid}.status")
return out.strip() != ""
def test_expiration(self):
"""Only tasks that are deleted and have a modification in the past are expired."""
yesterday = int(time.time()) - 3600 * 24
last_year = int(time.time()) - 265 * 3600 * 24
old_pending = "a1111111-a111-a111-a111-a11111111111"
old_completed = "a2222222-a222-a222-a222-a22222222222"
new_deleted = "a3333333-a333-a333-a333-a33333333333"
old_deleted = "a4444444-a444-a444-a444-a44444444444"
task_data = f"""[
{{"uuid":"{old_pending}","status":"pending","modified":"{last_year}","description":"x"}},
{{"uuid":"{old_completed}","status":"completed","modified":"{last_year}","description":"x"}},
{{"uuid":"{new_deleted}","status":"deleted","modified":"{yesterday}","description":"x"}},
{{"uuid":"{old_deleted}","status":"deleted","modified":"{last_year}","description":"x"}}
]
"""
code, out, err = self.t("import -", input=task_data)
self.assertIn("Imported 4 tasks", err)
# By default, expiration does not occur.
code, out, err = self.t("sync")
self.assertTrue(self.exists(old_pending))
self.assertTrue(self.exists(old_completed))
self.assertTrue(self.exists(new_deleted))
self.assertTrue(self.exists(old_deleted))
# Configure expiration on sync. The old_deleted task
# should be removed.
self.t.config("expiration.on-sync", "1")
code, out, err = self.t("sync")
self.assertTrue(self.exists(old_pending))
self.assertTrue(self.exists(old_completed))
self.assertTrue(self.exists(new_deleted))
self.assertFalse(self.exists(old_deleted))
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4 ft=python

View file

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
############################################################################### ###############################################################################
# #
# Copyright 2006 - 2021, Tomas Babej, Paul Beckingham, Federico Hernandez. # Copyright 2006 - 2024, Tomas Babej, Paul Beckingham, Federico Hernandez.
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
@ -29,10 +29,58 @@
import sys import sys
import os import os
import unittest import unittest
import time
# Ensure python finds the local simpletap module # Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__))) sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from basetest import Task, TestCase from basetest import Task, TestCase
from basetest.utils import mkstemp
class TestAutoPurge(TestCase):
def setUp(self):
self.t = Task()
# Set up local sync within the TASKDATA directory, so that it will be
# deleted properly.
self.t.config("sync.local.server_dir", self.t.datadir)
def exists(self, uuid):
code, out, err = self.t(f"_get {uuid}.status")
return out.strip() != ""
def test_auto_purge(self):
"""Only tasks that are deleted and have a modification in the past are purged."""
yesterday = int(time.time()) - 3600 * 24
last_year = int(time.time()) - 265 * 3600 * 24
old_pending = "a1111111-a111-a111-a111-a11111111111"
old_completed = "a2222222-a222-a222-a222-a22222222222"
new_deleted = "a3333333-a333-a333-a333-a33333333333"
old_deleted = "a4444444-a444-a444-a444-a44444444444"
task_data = f"""[
{{"uuid":"{old_pending}","status":"pending","modified":"{last_year}","description":"x"}},
{{"uuid":"{old_completed}","status":"completed","modified":"{last_year}","description":"x"}},
{{"uuid":"{new_deleted}","status":"deleted","modified":"{yesterday}","description":"x"}},
{{"uuid":"{old_deleted}","status":"deleted","modified":"{last_year}","description":"x"}}
]
"""
code, out, err = self.t("import -", input=task_data)
self.assertIn("Imported 4 tasks", err)
# By default, purge does not occur.
code, out, err = self.t("sync")
self.assertTrue(self.exists(old_pending))
self.assertTrue(self.exists(old_completed))
self.assertTrue(self.exists(new_deleted))
self.assertTrue(self.exists(old_deleted))
# Configure purge on sync. The old_deleted task
# should be removed.
self.t.config("purge.on-sync", "1")
code, out, err = self.t("sync")
self.assertTrue(self.exists(old_pending))
self.assertTrue(self.exists(old_completed))
self.assertTrue(self.exists(new_deleted))
self.assertFalse(self.exists(old_deleted))
class TestDelete(TestCase): class TestDelete(TestCase):