Feature #457
- Tasks may now be given an 'until' date, after which they expire and are deleted.
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
2.0.1 ()
|
2.0.1 ()
|
||||||
|
|
||||||
Features
|
Features
|
||||||
|
+ Feature #457, tasks may now be given an 'until' date, after which they expire
|
||||||
|
and are deleted.
|
||||||
+ Feature #516, which allows the duplication of completed tasks (thanks to
|
+ Feature #516, which allows the duplication of completed tasks (thanks to
|
||||||
Peter De Poorter, Ethan Schoonover).
|
Peter De Poorter, Ethan Schoonover).
|
||||||
+ Applied patch for feature #1005, which prevents the update-holidays.pl script
|
+ Applied patch for feature #1005, which prevents the update-holidays.pl script
|
||||||
|
|||||||
4
NEWS
4
NEWS
@@ -5,13 +5,15 @@ New Features in taskwarrior 2.0.1
|
|||||||
and 'summary' commands.
|
and 'summary' commands.
|
||||||
- Support for the 'scheduled' date for a task, which represent the earliest
|
- Support for the 'scheduled' date for a task, which represent the earliest
|
||||||
opportunity to work on a task.
|
opportunity to work on a task.
|
||||||
|
- All tasks may now be given an 'until' date, after which they will expire
|
||||||
|
and are deleted.
|
||||||
|
|
||||||
Please refer to the ChangeLog file for full details. There are too many to
|
Please refer to the ChangeLog file for full details. There are too many to
|
||||||
list here.
|
list here.
|
||||||
|
|
||||||
New commands in taskwarrior 2.0.1
|
New commands in taskwarrior 2.0.1
|
||||||
|
|
||||||
- None
|
- New 'ready' report that lists tasks ready for work, sorted by urgency.
|
||||||
|
|
||||||
New configuration options in taskwarrior 2.0.1
|
New configuration options in taskwarrior 2.0.1
|
||||||
|
|
||||||
|
|||||||
@@ -546,8 +546,8 @@ Specifies the due-date of a task.
|
|||||||
Specifies the frequency of a recurrence of a task.
|
Specifies the frequency of a recurrence of a task.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B until:<end-date-of-recurrence>
|
.B until:<expiration date of task>
|
||||||
Specifies the Recurrence end-date of a task.
|
Specifies the expiration date of a task, after which it will be deleted.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B fg:<color-spec>
|
.B fg:<color-spec>
|
||||||
|
|||||||
@@ -1154,10 +1154,6 @@ void Task::validate ()
|
|||||||
if (! has ("due") && has ("recur"))
|
if (! has ("due") && has ("recur"))
|
||||||
throw std::string (STRING_TASK_VALID_REC_DUE);
|
throw std::string (STRING_TASK_VALID_REC_DUE);
|
||||||
|
|
||||||
// Cannot have an until date no recurrence frequency.
|
|
||||||
if (has ("until") && !has ("recur"))
|
|
||||||
throw std::string (STRING_TASK_VALID_UNTIL);
|
|
||||||
|
|
||||||
// Recur durations must be valid.
|
// Recur durations must be valid.
|
||||||
if (has ("recur"))
|
if (has ("recur"))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ int CmdInfo::execute (std::string& output)
|
|||||||
if (task->has ("until"))
|
if (task->has ("until"))
|
||||||
{
|
{
|
||||||
row = view.addRow ();
|
row = view.addRow ();
|
||||||
view.set (row, 0, STRING_CMD_INFO_RECUR_UNTIL);
|
view.set (row, 0, STRING_CMD_INFO_UNTIL);
|
||||||
view.set (row, 1, Date (task->get_date ("until")).toString (dateformat));
|
view.set (row, 1, Date (task->get_date ("until")).toString (dateformat));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,7 @@
|
|||||||
#define STRING_CMD_INFO_USAGE "Shows all data and metadata"
|
#define STRING_CMD_INFO_USAGE "Shows all data and metadata"
|
||||||
#define STRING_CMD_INFO_BLOCKED "This task blocked by"
|
#define STRING_CMD_INFO_BLOCKED "This task blocked by"
|
||||||
#define STRING_CMD_INFO_BLOCKING "This task is blocking"
|
#define STRING_CMD_INFO_BLOCKING "This task is blocking"
|
||||||
#define STRING_CMD_INFO_RECUR_UNTIL "Recur until"
|
#define STRING_CMD_INFO_UNTIL "Until"
|
||||||
#define STRING_CMD_INFO_MODIFICATION "Modification"
|
#define STRING_CMD_INFO_MODIFICATION "Modification"
|
||||||
#define STRING_CMD_INFO_TOTAL_ACTIVE "Total active time"
|
#define STRING_CMD_INFO_TOTAL_ACTIVE "Total active time"
|
||||||
#define STRING_CMD_UNDO_USAGE "Reverts the most recent change to a task"
|
#define STRING_CMD_UNDO_USAGE "Reverts the most recent change to a task"
|
||||||
@@ -698,6 +698,7 @@
|
|||||||
#define STRING_FEEDBACK_TAG_NOCAL "The 'nocal' special tag will keep this task off the calendar report."
|
#define STRING_FEEDBACK_TAG_NOCAL "The 'nocal' special tag will keep this task off the calendar report."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "The 'next' special tag will boost the urgency of this task so it appears on the 'next' report."
|
#define STRING_FEEDBACK_TAG_NEXT "The 'next' special tag will boost the urgency of this task so it appears on the 'next' report."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Unblocked {1} '{2}'."
|
#define STRING_FEEDBACK_UNBLOCKED "Unblocked {1} '{2}'."
|
||||||
|
#define STRING_FEEDBACK_EXPIRED "Task {1} '{2}' expired and was deleted."
|
||||||
|
|
||||||
// File
|
// File
|
||||||
#define STRING_FILE_PERMS "Task does not have the correct permissions for '{1}'."
|
#define STRING_FILE_PERMS "Task does not have the correct permissions for '{1}'."
|
||||||
@@ -732,9 +733,6 @@
|
|||||||
#define STRING_RECORD_JUNK_AT_EOL "Unrecognized characters at end of line."
|
#define STRING_RECORD_JUNK_AT_EOL "Unrecognized characters at end of line."
|
||||||
#define STRING_RECORD_NOT_FF4 "Record not recognized as format 4."
|
#define STRING_RECORD_NOT_FF4 "Record not recognized as format 4."
|
||||||
|
|
||||||
// recur
|
|
||||||
#define STRING_RECUR_PAST_UNTIL "Task ({1}) has past its 'until' date, and has been deleted."
|
|
||||||
|
|
||||||
// 'show' command
|
// 'show' command
|
||||||
#define STRING_CMD_SHOW "Shows all configuration variables or subset"
|
#define STRING_CMD_SHOW "Shows all configuration variables or subset"
|
||||||
#define STRING_CMD_SHOW_ARGS "You can only specify 'all' or a search string."
|
#define STRING_CMD_SHOW_ARGS "You can only specify 'all' or a search string."
|
||||||
|
|||||||
@@ -468,6 +468,18 @@ std::string onProjectChange (Task& task1, Task& task2)
|
|||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
std::string onExpiration (Task& task)
|
||||||
|
{
|
||||||
|
std::stringstream msg;
|
||||||
|
|
||||||
|
if (context.verbose ("affected"))
|
||||||
|
msg << format (STRING_FEEDBACK_EXPIRED, task.id, task.get ("description"))
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
|
return msg.str ();
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
static void countTasks (
|
static void countTasks (
|
||||||
const std::vector <Task>& all,
|
const std::vector <Task>& all,
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ void feedback_special_tags (const Task&, const std::string&);
|
|||||||
void feedback_unblocked (const Task&);
|
void feedback_unblocked (const Task&);
|
||||||
std::string onProjectChange (Task&, bool scope = true);
|
std::string onProjectChange (Task&, bool scope = true);
|
||||||
std::string onProjectChange (Task&, Task&);
|
std::string onProjectChange (Task&, Task&);
|
||||||
|
std::string onExpiration (Task&);
|
||||||
|
|
||||||
// sort.cpp
|
// sort.cpp
|
||||||
void sort_tasks (std::vector <Task>&, std::vector <int>&, const std::string&);
|
void sort_tasks (std::vector <Task>&, std::vector <int>&, const std::string&);
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ extern Context context;
|
|||||||
void handleRecurrence ()
|
void handleRecurrence ()
|
||||||
{
|
{
|
||||||
std::vector <Task> tasks = context.tdb2.pending.get_tasks ();
|
std::vector <Task> tasks = context.tdb2.pending.get_tasks ();
|
||||||
|
Date now;
|
||||||
|
|
||||||
// Look at all tasks and find any recurring ones.
|
// Look at all tasks and find any recurring ones.
|
||||||
std::vector <Task>::iterator t;
|
std::vector <Task>::iterator t;
|
||||||
@@ -68,12 +69,10 @@ void handleRecurrence ()
|
|||||||
std::vector <Date> due;
|
std::vector <Date> due;
|
||||||
if (!generateDueDates (*t, due))
|
if (!generateDueDates (*t, due))
|
||||||
{
|
{
|
||||||
std::cout << format (STRING_RECUR_PAST_UNTIL, trim (t->get ("description")))
|
|
||||||
<< "\n";
|
|
||||||
|
|
||||||
// Determine the end date.
|
// Determine the end date.
|
||||||
t->setStatus (Task::deleted);
|
t->setStatus (Task::deleted);
|
||||||
context.tdb2.modify (*t);
|
context.tdb2.modify (*t);
|
||||||
|
context.footnote (onExpiration (*t));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +136,18 @@ void handleRecurrence ()
|
|||||||
context.tdb2.modify (*t);
|
context.tdb2.modify (*t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Non-recurring tasks expire too.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (t->has ("until") &&
|
||||||
|
Date (t->get_date ("until")) < now)
|
||||||
|
{
|
||||||
|
t->setStatus (Task::deleted);
|
||||||
|
context.tdb2.modify(*t);
|
||||||
|
context.footnote (onExpiration (*t));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ qx{../src/task rc:bug.rc add foo due:today recur:daily until:eom};
|
|||||||
my $output = qx{../src/task rc:bug.rc info 1};
|
my $output = qx{../src/task rc:bug.rc info 1};
|
||||||
|
|
||||||
# Result: Make sure the 'until' date is rendered as a date, not an epoch.
|
# Result: Make sure the 'until' date is rendered as a date, not an epoch.
|
||||||
unlike ($output, qr/Recur until\s+\d{10}/, 'until is not shown as an epoch');
|
unlike ($output, qr/Until\s+\d{10}/, 'until is not shown as an epoch');
|
||||||
like ($output, qr/Recur until\s+\d+\/\d+\/\d{4}/, 'until is shown as a date');
|
like ($output, qr/Until\s+\d+\/\d+\/\d{4}/, 'until is shown as a date');
|
||||||
|
|
||||||
# Cleanup.
|
# Cleanup.
|
||||||
unlink qw(pending.data completed.data undo.data backlog.data synch.key bug.rc);
|
unlink qw(pending.data completed.data undo.data backlog.data synch.key bug.rc);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ qx{../src/task rc:recur.rc 3 do};
|
|||||||
qx{../src/task rc:recur.rc 4 do};
|
qx{../src/task rc:recur.rc 4 do};
|
||||||
qx{../src/task rc:recur.rc 5 do};
|
qx{../src/task rc:recur.rc 5 do};
|
||||||
$output = qx{../src/task rc:recur.rc list};
|
$output = qx{../src/task rc:recur.rc list};
|
||||||
like ($output, qr/and has been deleted/, 'Parent task deleted');
|
like ($output, qr/and was deleted/, 'Parent task deleted');
|
||||||
|
|
||||||
$output = qx{../src/task rc:recur.rc diag};
|
$output = qx{../src/task rc:recur.rc diag};
|
||||||
like ($output, qr/No duplicates found/, 'No duplicate UUIDs detected');
|
like ($output, qr/No duplicates found/, 'No duplicate UUIDs detected');
|
||||||
|
|||||||
Reference in New Issue
Block a user