TW-303: Make "task import" update existing tasks
This commit is contained in:
2
AUTHORS
2
AUTHORS
@@ -213,7 +213,7 @@ suggestions:
|
||||
Dmitriy Matrosov
|
||||
Michele Santullo
|
||||
Scott Kroll
|
||||
Kosta H
|
||||
Kosta Harlan
|
||||
Hector Arciga
|
||||
Jan Kunder
|
||||
jck
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
2.4.5 () -
|
||||
|
||||
- TW-303 Ability for "import" to update existing tasks (thanks to Kosta
|
||||
Harlan).
|
||||
- TW-1440 "task import" from STDIN (thanks to Renato Alves).
|
||||
- TW-1432 start/stop can be issued on completed tasks (thanks to Renato Alves).
|
||||
- TW-1572 Better urgency inheritance (thanks to Jens Erat).
|
||||
- Prevent potential task duplication during import for non-pending tasks.
|
||||
|
||||
------ current release ---------------------------
|
||||
|
||||
|
||||
@@ -346,14 +346,17 @@ provided for exceptional circumstances. Use carefully.
|
||||
|
||||
.TP
|
||||
.B task import [<file> ...]
|
||||
Imports tasks in the JSON format. The standard task release comes with a few
|
||||
example scripts, such as:
|
||||
Imports tasks in the JSON format. Can be used to add new tasks, or update
|
||||
existing ones. Tasks are identified by their UUID.
|
||||
|
||||
If no file or "-" is specified, import tasks from STDIN.
|
||||
|
||||
For importing other file formats, the standard task release comes with a
|
||||
few example scripts, such as:
|
||||
|
||||
import-todo.sh.pl
|
||||
import-yaml.pl
|
||||
|
||||
If no file or "-" is specified, import tasks from STDIN.
|
||||
|
||||
.TP
|
||||
.B task log <mods>
|
||||
Adds a new task that is already completed, to the task list.
|
||||
|
||||
@@ -110,11 +110,22 @@ int CmdImport::import (std::vector <std::string>& lines)
|
||||
|
||||
// Parse the whole thing.
|
||||
Task task (object);
|
||||
context.tdb2.add (task);
|
||||
|
||||
// Check whether the imported task is new or a modified existing task.
|
||||
Task dummy;
|
||||
if (context.tdb2.get (task.get ("uuid"), dummy))
|
||||
{
|
||||
context.tdb2.modify (task);
|
||||
std::cout << " mod ";
|
||||
}
|
||||
else
|
||||
{
|
||||
context.tdb2.add (task);
|
||||
std::cout << " add ";
|
||||
}
|
||||
|
||||
++count;
|
||||
std::cout << " "
|
||||
<< task.get ("uuid")
|
||||
std::cout << task.get ("uuid")
|
||||
<< " "
|
||||
<< task.get ("description")
|
||||
<< "\n";
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 9;
|
||||
use Test::More tests => 8;
|
||||
|
||||
# Ensure environment has no influence.
|
||||
delete $ENV{'TASKDATA'};
|
||||
@@ -79,10 +79,6 @@ unlike ($output, qr/1.+A.+zero/, 't1 missing');
|
||||
unlike ($output, qr/2.+B.+one/, 't2 missing');
|
||||
like ($output, qr/2\/13\/2009.+two/, 't3 present');
|
||||
|
||||
# Make sure that a duplicate task cannot be imported.
|
||||
$output = qx{../src/task rc:import.rc import import.txt 2>&1 >/dev/null};
|
||||
like ($output, qr/Cannot add task because the uuid .+ is not unique\./, 'error on duplicate uuid');
|
||||
|
||||
# Create import file.
|
||||
if (open my $fh, '>', 'import2.txt')
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 16;
|
||||
use Test::More tests => 15;
|
||||
|
||||
# Ensure environment has no influence.
|
||||
delete $ENV{'TASKDATA'};
|
||||
@@ -136,10 +136,6 @@ like ($output, qr/1.+A.+zero.*\n.+ONE/, "$ut: t1 selected by tag, has
|
||||
like ($output, qr/2.+B.+one.*\n.+TWO.*\n.+THREE/, "$ut: t2 selected by tag, has two annotations");
|
||||
like ($output, qr/\n2 tasks\n/, "$ut: tag selected two tasks");
|
||||
|
||||
# Make sure that a duplicate task cannot be imported.
|
||||
$output = qx{../src/task rc:$rc import import.json 2>&1 >/dev/null};
|
||||
like ($output, qr/Cannot add task because the uuid '.{36}' is not unique\./, "$ut: error on duplicate uuid");
|
||||
|
||||
# Create import file.
|
||||
if (open my $fh, '>', 'import.txt')
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
from basetest import Task, TestCase
|
||||
|
||||
|
||||
class TestImportSTDIN(TestCase):
|
||||
class TestImport(TestCase):
|
||||
def setUp(self):
|
||||
self.t = Task()
|
||||
self.t.config("report.foo.description", "foo")
|
||||
@@ -55,6 +55,28 @@ class TestImportSTDIN(TestCase):
|
||||
self.assertRegexpMatches(out, "2\s+one", "second task present")
|
||||
self.assertRegexpMatches(out, "-\s+two", "third task present")
|
||||
|
||||
def test_import_update(self):
|
||||
"""Update existing tasks"""
|
||||
json_data = """
|
||||
{"uuid":"00000000-0000-0000-0000-000000000000","description":"zero","project":"A","status":"pending","entry":"1234567889"}
|
||||
{"uuid":"11111111-1111-1111-1111-111111111111","description":"one","project":"B","status":"deleted","entry":"1234567889"}
|
||||
{"uuid":"22222222-2222-2222-2222-222222222222","description":"two","status":"completed","entry":"1234524689","end":"1234524690"}"""
|
||||
self.t("import", input=json_data)
|
||||
|
||||
self.t("next") # Run GC
|
||||
|
||||
json_data = """
|
||||
{"uuid":"00000000-0000-0000-0000-000000000000","description":"zero","project":"C","status":"pending","entry":"1234567889"}
|
||||
{"uuid":"11111111-1111-1111-1111-111111111111","description":"one","project":"B","status":"pending","entry":"1234567889"}
|
||||
{"uuid":"22222222-2222-2222-2222-222222222222","description":"two","status":"pending","entry":"1234524689","end":"1234524690"}"""
|
||||
self.t("import", input=json_data)
|
||||
|
||||
zero, one, two = sorted(self.t.export(), key=lambda t: t["uuid"])
|
||||
self.assertEqual(zero["status"], "pending", "status for 'zero' unchanged")
|
||||
self.assertEqual(zero["project"], "C", "project for 'zero' changed to 'C'")
|
||||
self.assertEqual(one["status"], "pending", "status for 'one' changed to pending")
|
||||
self.assertEqual(two["status"], "pending", "status for 'two' changed to pending")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from simpletap import TAPTestRunner
|
||||
Reference in New Issue
Block a user