Fossil SCM

Add ability to show ticket history from command line. fossil ticket now takes a new history option, which prints the history of a ticket - somewhat like what the history button does on the ticket web GUI.

venkat 2011-08-30 21:50 venks-emacs
Commit 73e363ea96424d3fd036e145bc6cce593621bba5
1 file changed +87 -7
+87 -7
--- src/tkt.c
+++ src/tkt.c
@@ -899,10 +899,14 @@
899899
**
900900
** %fossil ticket add FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote?
901901
**
902902
** like set, but create a new ticket with the given values.
903903
**
904
+** %fossil ticket history TICKETUUID
905
+**
906
+** Show the complete change history for the ticket
907
+**
904908
** The values in set|add are not validated against the definitions
905909
** given in "Ticket Common Script".
906910
*/
907911
void ticket_cmd(void){
908912
int n;
@@ -916,16 +920,16 @@
916920
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
917921
fossil_fatal("no such user: %s", g.zLogin);
918922
}
919923
920924
if( g.argc<3 ){
921
- usage("add|fieldlist|set|show");
925
+ usage("add|fieldlist|set|show|history");
922926
}else{
923927
n = strlen(g.argv[2]);
924928
if( n==1 && g.argv[2][0]=='s' ){
925929
/* set/show cannot be distinguished, so show the usage */
926
- usage("add|fieldlist|set|show");
930
+ usage("add|fieldlist|set|show|history");
927931
}else if( strncmp(g.argv[2],"list",n)==0 ){
928932
if( g.argc==3 ){
929933
usage("list fields|reports");
930934
}else{
931935
n = strlen(g.argv[3]);
@@ -970,19 +974,24 @@
970974
rptshow( zRep, zSep, zFilterUuid, tktEncoding );
971975
972976
}
973977
}else{
974978
/* add a new ticket or update an existing ticket */
975
- enum { set,add,err } eCmd = err;
979
+ enum { set,add,history,err } eCmd = err;
976980
int i = 0;
977981
int rid;
978982
const char *zTktUuid = 0;
979983
Blob tktchng, cksum;
980984
981985
/* get command type (set/add) and get uuid, if needed for set */
982
- if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 ){
983
- eCmd = set;
986
+ if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 ||
987
+ strncmp(g.argv[2],"history",n)==0 ){
988
+ if( strncmp(g.argv[2],"history",n)==0 ){
989
+ eCmd = history;
990
+ }else{
991
+ eCmd = set;
992
+ }
984993
if( g.argc==3 ){
985994
usage("set TICKETUUID");
986995
}
987996
zTktUuid = db_text(0,
988997
"SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3]
@@ -996,13 +1005,84 @@
9961005
i = 3;
9971006
zTktUuid = db_text(0, "SELECT lower(hex(randomblob(20)))");
9981007
}
9991008
/* none of set/add, so show the usage! */
10001009
if( eCmd==err ){
1001
- usage("add|fieldlist|set|show");
1010
+ usage("add|fieldlist|set|show|history");
10021011
}
1003
-
1012
+
1013
+ /* we just handle history separately here, does not get out */
1014
+ if( eCmd==history ){
1015
+ Stmt q;
1016
+ char *zTitle;
1017
+ int tagid;
1018
+
1019
+ if ( i != g.argc ){
1020
+ fossil_fatal("no other parameters expected to %s!",g.argv[2]);
1021
+ }
1022
+ tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zTktUuid);
1023
+ if( tagid==0 ){
1024
+ fossil_fatal("no such ticket %h", zTktUuid);
1025
+ }
1026
+ db_prepare(&q,
1027
+ "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL"
1028
+ " FROM event, blob"
1029
+ " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
1030
+ " AND blob.rid=event.objid"
1031
+ " UNION "
1032
+ "SELECT datetime(mtime,'localtime'), attachid, uuid, src, filename, user"
1033
+ " FROM attachment, blob"
1034
+ " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
1035
+ " AND blob.rid=attachid"
1036
+ " ORDER BY 1 DESC",
1037
+ tagid, tagid
1038
+ );
1039
+ while( db_step(&q)==SQLITE_ROW ){
1040
+ Manifest *pTicket;
1041
+ char zShort[12];
1042
+ const char *zDate = db_column_text(&q, 0);
1043
+ int rid = db_column_int(&q, 1);
1044
+ const char *zChngUuid = db_column_text(&q, 2);
1045
+ const char *zFile = db_column_text(&q, 4);
1046
+ memcpy(zShort, zChngUuid, 10);
1047
+ zShort[10] = 0;
1048
+ if( zFile!=0 ){
1049
+ const char *zSrc = db_column_text(&q, 3);
1050
+ const char *zUser = db_column_text(&q, 5);
1051
+ if( zSrc==0 || zSrc[0]==0 ){
1052
+ fossil_print("Delete attachment %h\n", zFile);
1053
+ }else{
1054
+ fossil_print("Add attachment %h\n", zFile);
1055
+ }
1056
+ fossil_print(" by %h on %h\n", zUser, zDate);
1057
+ }else{
1058
+ pTicket = manifest_get(rid, CFTYPE_TICKET);
1059
+ if( pTicket ){
1060
+ int i;
1061
+
1062
+ fossil_print("Ticket Change by %h on %h:\n", pTicket->zUser, zDate);
1063
+ for(i=0; i<pTicket->nField; i++){
1064
+ Blob val;
1065
+ const char *z;
1066
+ z = pTicket->aField[i].zName;
1067
+ blob_set(&val, pTicket->aField[i].zValue);
1068
+ if( z[0]=='+' ){
1069
+ fossil_print(" Appended to %h:\n ",&z[1]);
1070
+ comment_print(blob_str(&val),7,79);
1071
+ }else{
1072
+ fossil_print(" Change %h to:\n ",z);
1073
+ comment_print(blob_str(&val),7,79);
1074
+ }
1075
+ blob_reset(&val);
1076
+ }
1077
+ }
1078
+ manifest_destroy(pTicket);
1079
+ }
1080
+ }
1081
+ db_finalize(&q);
1082
+ return;
1083
+ }
10041084
/* read all given ticket field/value pairs from command line */
10051085
if( i==g.argc ){
10061086
fossil_fatal("empty %s command aborted!",g.argv[2]);
10071087
}
10081088
getAllTicketFields();
10091089
--- src/tkt.c
+++ src/tkt.c
@@ -899,10 +899,14 @@
899 **
900 ** %fossil ticket add FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote?
901 **
902 ** like set, but create a new ticket with the given values.
903 **
 
 
 
 
904 ** The values in set|add are not validated against the definitions
905 ** given in "Ticket Common Script".
906 */
907 void ticket_cmd(void){
908 int n;
@@ -916,16 +920,16 @@
916 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
917 fossil_fatal("no such user: %s", g.zLogin);
918 }
919
920 if( g.argc<3 ){
921 usage("add|fieldlist|set|show");
922 }else{
923 n = strlen(g.argv[2]);
924 if( n==1 && g.argv[2][0]=='s' ){
925 /* set/show cannot be distinguished, so show the usage */
926 usage("add|fieldlist|set|show");
927 }else if( strncmp(g.argv[2],"list",n)==0 ){
928 if( g.argc==3 ){
929 usage("list fields|reports");
930 }else{
931 n = strlen(g.argv[3]);
@@ -970,19 +974,24 @@
970 rptshow( zRep, zSep, zFilterUuid, tktEncoding );
971
972 }
973 }else{
974 /* add a new ticket or update an existing ticket */
975 enum { set,add,err } eCmd = err;
976 int i = 0;
977 int rid;
978 const char *zTktUuid = 0;
979 Blob tktchng, cksum;
980
981 /* get command type (set/add) and get uuid, if needed for set */
982 if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 ){
983 eCmd = set;
 
 
 
 
 
984 if( g.argc==3 ){
985 usage("set TICKETUUID");
986 }
987 zTktUuid = db_text(0,
988 "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3]
@@ -996,13 +1005,84 @@
996 i = 3;
997 zTktUuid = db_text(0, "SELECT lower(hex(randomblob(20)))");
998 }
999 /* none of set/add, so show the usage! */
1000 if( eCmd==err ){
1001 usage("add|fieldlist|set|show");
1002 }
1003
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1004 /* read all given ticket field/value pairs from command line */
1005 if( i==g.argc ){
1006 fossil_fatal("empty %s command aborted!",g.argv[2]);
1007 }
1008 getAllTicketFields();
1009
--- src/tkt.c
+++ src/tkt.c
@@ -899,10 +899,14 @@
899 **
900 ** %fossil ticket add FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote?
901 **
902 ** like set, but create a new ticket with the given values.
903 **
904 ** %fossil ticket history TICKETUUID
905 **
906 ** Show the complete change history for the ticket
907 **
908 ** The values in set|add are not validated against the definitions
909 ** given in "Ticket Common Script".
910 */
911 void ticket_cmd(void){
912 int n;
@@ -916,16 +920,16 @@
920 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
921 fossil_fatal("no such user: %s", g.zLogin);
922 }
923
924 if( g.argc<3 ){
925 usage("add|fieldlist|set|show|history");
926 }else{
927 n = strlen(g.argv[2]);
928 if( n==1 && g.argv[2][0]=='s' ){
929 /* set/show cannot be distinguished, so show the usage */
930 usage("add|fieldlist|set|show|history");
931 }else if( strncmp(g.argv[2],"list",n)==0 ){
932 if( g.argc==3 ){
933 usage("list fields|reports");
934 }else{
935 n = strlen(g.argv[3]);
@@ -970,19 +974,24 @@
974 rptshow( zRep, zSep, zFilterUuid, tktEncoding );
975
976 }
977 }else{
978 /* add a new ticket or update an existing ticket */
979 enum { set,add,history,err } eCmd = err;
980 int i = 0;
981 int rid;
982 const char *zTktUuid = 0;
983 Blob tktchng, cksum;
984
985 /* get command type (set/add) and get uuid, if needed for set */
986 if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 ||
987 strncmp(g.argv[2],"history",n)==0 ){
988 if( strncmp(g.argv[2],"history",n)==0 ){
989 eCmd = history;
990 }else{
991 eCmd = set;
992 }
993 if( g.argc==3 ){
994 usage("set TICKETUUID");
995 }
996 zTktUuid = db_text(0,
997 "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3]
@@ -996,13 +1005,84 @@
1005 i = 3;
1006 zTktUuid = db_text(0, "SELECT lower(hex(randomblob(20)))");
1007 }
1008 /* none of set/add, so show the usage! */
1009 if( eCmd==err ){
1010 usage("add|fieldlist|set|show|history");
1011 }
1012
1013 /* we just handle history separately here, does not get out */
1014 if( eCmd==history ){
1015 Stmt q;
1016 char *zTitle;
1017 int tagid;
1018
1019 if ( i != g.argc ){
1020 fossil_fatal("no other parameters expected to %s!",g.argv[2]);
1021 }
1022 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zTktUuid);
1023 if( tagid==0 ){
1024 fossil_fatal("no such ticket %h", zTktUuid);
1025 }
1026 db_prepare(&q,
1027 "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL"
1028 " FROM event, blob"
1029 " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
1030 " AND blob.rid=event.objid"
1031 " UNION "
1032 "SELECT datetime(mtime,'localtime'), attachid, uuid, src, filename, user"
1033 " FROM attachment, blob"
1034 " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
1035 " AND blob.rid=attachid"
1036 " ORDER BY 1 DESC",
1037 tagid, tagid
1038 );
1039 while( db_step(&q)==SQLITE_ROW ){
1040 Manifest *pTicket;
1041 char zShort[12];
1042 const char *zDate = db_column_text(&q, 0);
1043 int rid = db_column_int(&q, 1);
1044 const char *zChngUuid = db_column_text(&q, 2);
1045 const char *zFile = db_column_text(&q, 4);
1046 memcpy(zShort, zChngUuid, 10);
1047 zShort[10] = 0;
1048 if( zFile!=0 ){
1049 const char *zSrc = db_column_text(&q, 3);
1050 const char *zUser = db_column_text(&q, 5);
1051 if( zSrc==0 || zSrc[0]==0 ){
1052 fossil_print("Delete attachment %h\n", zFile);
1053 }else{
1054 fossil_print("Add attachment %h\n", zFile);
1055 }
1056 fossil_print(" by %h on %h\n", zUser, zDate);
1057 }else{
1058 pTicket = manifest_get(rid, CFTYPE_TICKET);
1059 if( pTicket ){
1060 int i;
1061
1062 fossil_print("Ticket Change by %h on %h:\n", pTicket->zUser, zDate);
1063 for(i=0; i<pTicket->nField; i++){
1064 Blob val;
1065 const char *z;
1066 z = pTicket->aField[i].zName;
1067 blob_set(&val, pTicket->aField[i].zValue);
1068 if( z[0]=='+' ){
1069 fossil_print(" Appended to %h:\n ",&z[1]);
1070 comment_print(blob_str(&val),7,79);
1071 }else{
1072 fossil_print(" Change %h to:\n ",z);
1073 comment_print(blob_str(&val),7,79);
1074 }
1075 blob_reset(&val);
1076 }
1077 }
1078 manifest_destroy(pTicket);
1079 }
1080 }
1081 db_finalize(&q);
1082 return;
1083 }
1084 /* read all given ticket field/value pairs from command line */
1085 if( i==g.argc ){
1086 fossil_fatal("empty %s command aborted!",g.argv[2]);
1087 }
1088 getAllTicketFields();
1089

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button