TW-303: Make "task import" update existing tasks
This commit is contained in:
2
AUTHORS
2
AUTHORS
@@ -213,7 +213,7 @@ suggestions:
|
|||||||
Dmitriy Matrosov
|
Dmitriy Matrosov
|
||||||
Michele Santullo
|
Michele Santullo
|
||||||
Scott Kroll
|
Scott Kroll
|
||||||
Kosta H
|
Kosta Harlan
|
||||||
Hector Arciga
|
Hector Arciga
|
||||||
Jan Kunder
|
Jan Kunder
|
||||||
jck
|
jck
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
2.4.5 () -
|
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-1440 "task import" from STDIN (thanks to Renato Alves).
|
||||||
- TW-1432 start/stop can be issued on completed tasks (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).
|
- TW-1572 Better urgency inheritance (thanks to Jens Erat).
|
||||||
|
- Prevent potential task duplication during import for non-pending tasks.
|
||||||
|
|
||||||
------ current release ---------------------------
|
------ current release ---------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -346,14 +346,17 @@ provided for exceptional circumstances. Use carefully.
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B task import [<file> ...]
|
.B task import [<file> ...]
|
||||||
Imports tasks in the JSON format. The standard task release comes with a few
|
Imports tasks in the JSON format. Can be used to add new tasks, or update
|
||||||
example scripts, such as:
|
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-todo.sh.pl
|
||||||
import-yaml.pl
|
import-yaml.pl
|
||||||
|
|
||||||
If no file or "-" is specified, import tasks from STDIN.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B task log <mods>
|
.B task log <mods>
|
||||||
Adds a new task that is already completed, to the task list.
|
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.
|
// Parse the whole thing.
|
||||||
Task task (object);
|
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;
|
++count;
|
||||||
std::cout << " "
|
std::cout << task.get ("uuid")
|
||||||
<< task.get ("uuid")
|
|
||||||
<< " "
|
<< " "
|
||||||
<< task.get ("description")
|
<< task.get ("description")
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Test::More tests => 9;
|
use Test::More tests => 8;
|
||||||
|
|
||||||
# Ensure environment has no influence.
|
# Ensure environment has no influence.
|
||||||
delete $ENV{'TASKDATA'};
|
delete $ENV{'TASKDATA'};
|
||||||
@@ -79,10 +79,6 @@ unlike ($output, qr/1.+A.+zero/, 't1 missing');
|
|||||||
unlike ($output, qr/2.+B.+one/, 't2 missing');
|
unlike ($output, qr/2.+B.+one/, 't2 missing');
|
||||||
like ($output, qr/2\/13\/2009.+two/, 't3 present');
|
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.
|
# Create import file.
|
||||||
if (open my $fh, '>', 'import2.txt')
|
if (open my $fh, '>', 'import2.txt')
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Test::More tests => 16;
|
use Test::More tests => 15;
|
||||||
|
|
||||||
# Ensure environment has no influence.
|
# Ensure environment has no influence.
|
||||||
delete $ENV{'TASKDATA'};
|
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/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");
|
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.
|
# Create import file.
|
||||||
if (open my $fh, '>', 'import.txt')
|
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
|
from basetest import Task, TestCase
|
||||||
|
|
||||||
|
|
||||||
class TestImportSTDIN(TestCase):
|
class TestImport(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.t = Task()
|
self.t = Task()
|
||||||
self.t.config("report.foo.description", "foo")
|
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, "2\s+one", "second task present")
|
||||||
self.assertRegexpMatches(out, "-\s+two", "third 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__":
|
if __name__ == "__main__":
|
||||||
from simpletap import TAPTestRunner
|
from simpletap import TAPTestRunner
|
||||||
Reference in New Issue
Block a user