Fossil SCM

Improvements to verify-comments: (1) the verify-comments setting is now text that can take four different values for different levels of verification. (2) Recent changes work better with -M and -m. (3) Improved user interaction.

drh 2025-03-18 19:16 trunk
Commit 798b232ce729f9ce1b7e9f27f278f32167d7a8d24e770d0dbd6d65edfea5af1a
1 file changed +152 -91
+152 -91
--- src/checkin.c
+++ src/checkin.c
@@ -2283,97 +2283,139 @@
22832283
char **pB = (char**)b;
22842284
return fossil_strcmp(pA[0], pB[0]);
22852285
}
22862286
22872287
/*
2288
-** SETTING: verify-comments boolean default=on show-only-if-changed
2288
+** SETTING: verify-comments width=8 default=on show-only-if-changed
2289
+**
2290
+** This setting determines much sanity checking, if any, the
2291
+** "fossil commit" and "fossil amend" commands do against check-in
2292
+** comments. Recognized values:
2293
+**
2294
+** on (Default) Check for bad syntax in check-in comments
2295
+** and offer the user a chance to continue editing for
2296
+** interactive sessions, or simply abort the commit if
2297
+** commit was entered using using -m or -M
2298
+**
2299
+** off Do not syntax checking of any kind
2300
+**
2301
+** links Similar to "on", except only check for bad hyperlinks
22892302
**
2290
-** If enabled (the default) then the "fossil commit" command does sanity
2291
-** checking on the checkin comment. The sanity checks can be overridden
2292
-** on a case by case basis using the --allow-suspect-comment option to
2293
-** the "fossil commit" command. If disabled, this setting makes every
2294
-** "fossil commit" behave as if the --allow-suspect-comment option were
2295
-** provided.
2303
+** preview Do all the same checks as "on" but also preview the
2304
+** checkin comment to the user during interactive sessions
2305
+** and provide an opportunity to accept or re-edit
22962306
*/
22972307
2308
+#if INTERFACE
2309
+#define COMCK_LINKS 0x01 /* Check for back hyperlinks */
2310
+#define COMCK_MARKUP 0x02 /* Check markup */
2311
+#define COMCK_PREVIEW 0x04 /* Always preview even if no issues found */
2312
+#define COMCK_NOPREVIEW 0x08 /* Never preview, even for other errors */
2313
+#endif /* INTERFACE */
2314
+
22982315
/*
22992316
** Check for possible formatting errors in the comment string pComment.
2300
-** If found, write a description of the problem(s) into pSus and return
2301
-** true. If everything looks ok, return false.
2317
+**
2318
+** If concerns are found, write a description of the problem(s) to
2319
+** stdout return non-zero. The return value is some combination of
2320
+** of the COMCK_* flags depending on what went wrong.
2321
+**
2322
+** If no issues are seen, do not output anything and return zero.
23022323
*/
2303
-static int suspicious_comment(Blob *pComment, Blob *pSus){
2324
+static int suspicious_comment(Blob *pComment, int mFlags){
23042325
char *zStart = blob_str(pComment);
23052326
char *z;
23062327
char *zEnd, *zEnd2;
23072328
char *zSep;
23082329
char cSave1;
23092330
int nIssue = 0;
2331
+ int rc = mFlags & COMCK_PREVIEW;
2332
+ Blob out;
23102333
static const char zSpecial[] = "\\&<*_`[";
23112334
2312
- if( !db_get_boolean("verify-comments",1) ) return 0;
2335
+ if( mFlags==0 ) return 0;
23132336
z = zStart;
2314
- blob_init(pSus, 0, 0);
2315
- while( (z = strchr(z,'['))!=0 ){
2316
- zEnd = strchr(z,']');
2317
- if( zEnd==0 ){
2318
- blob_appendf(pSus,"\n (%d) ", ++nIssue);
2319
- blob_appendf(pSus, "Unterminated hyperlink \"%.12s...\"", z);
2320
- break;
2321
- }
2322
- if( zEnd[1]=='(' && (zEnd2 = strchr(zEnd,')'))!=0 ){
2323
- blob_appendf(pSus,"\n (%d) ", ++nIssue);
2324
- blob_appendf(pSus, "Markdown hyperlink syntax: %.*s",
2325
- (int)(zEnd2+1-z), z);
2326
- z = zEnd2;
2327
- continue;
2328
- }
2329
- zSep = strchr(z+1,'|');
2330
- if( zSep==0 || zSep>zEnd ) zSep = zEnd;
2331
- while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--;
2332
- cSave1 = zSep[0];
2333
- zSep[0] = 0;
2334
- if( !wiki_valid_link_target(z+1) ){
2335
- blob_appendf(pSus,"\n (%d) ", ++nIssue);
2336
- blob_appendf(pSus, "Broken hyperlink: [%s]", z+1);
2337
- }
2338
- zSep[0] = cSave1;
2339
- z = zEnd;
2340
- }
2341
- if( nIssue ){
2342
- Blob tmp = *pSus;
2343
- blob_init(pSus, 0, 0);
2344
- blob_appendf(pSus,
2345
- "Possible comment formatting error%s:%b\n",
2346
- nIssue>1 ? "s" : "", &tmp);
2347
- blob_reset(&tmp);
2348
- return 1;
2349
- }else if( strcspn(zStart,zSpecial)<strlen(zStart) ){
2350
- Blob in, html, txt;
2337
+ blob_init(&out, 0, 0);
2338
+ if( mFlags & COMCK_LINKS ){
2339
+ while( (z = strchr(z,'['))!=0 ){
2340
+ zEnd = strchr(z,']');
2341
+ if( zEnd==0 ){
2342
+ blob_appendf(&out,"\n (%d) ", ++nIssue);
2343
+ blob_appendf(&out, "Unterminated hyperlink \"%.12s...\"", z);
2344
+ break;
2345
+ }
2346
+ if( zEnd[1]=='(' && (zEnd2 = strchr(zEnd,')'))!=0 ){
2347
+ blob_appendf(&out,"\n (%d) ", ++nIssue);
2348
+ blob_appendf(&out, "Markdown hyperlink syntax: %.*s",
2349
+ (int)(zEnd2+1-z), z);
2350
+ z = zEnd2;
2351
+ continue;
2352
+ }
2353
+ zSep = strchr(z+1,'|');
2354
+ if( zSep==0 || zSep>zEnd ) zSep = zEnd;
2355
+ while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--;
2356
+ cSave1 = zSep[0];
2357
+ zSep[0] = 0;
2358
+ if( !wiki_valid_link_target(z+1) ){
2359
+ blob_appendf(&out,"\n (%d) ", ++nIssue);
2360
+ blob_appendf(&out, "Broken hyperlink: [%s]", z+1);
2361
+ }
2362
+ zSep[0] = cSave1;
2363
+ z = zEnd;
2364
+ }
2365
+ }
2366
+
2367
+ if( nIssue>0
2368
+ || (mFlags & COMCK_PREVIEW)!=0
2369
+ || ((mFlags & COMCK_MARKUP)!=0 && strcspn(zStart,zSpecial)<strlen(zStart))
2370
+ ){
23512371
char zGot[16];
23522372
int nGot = 0;
23532373
int i;
2354
- for(i=0; zSpecial[i]; i++){
2355
- if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i];
2374
+ if( (mFlags & COMCK_MARKUP)!=0 ){
2375
+ for(i=0; zSpecial[i]; i++){
2376
+ if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i];
2377
+ }
23562378
}
23572379
zGot[nGot] = 0;
2358
- blob_init(&in, blob_str(pComment), -1);
2359
- blob_init(&html, 0, 0);
2360
- wiki_convert(&in, &html, WIKI_INLINE);
2361
- blob_reset(&in);
2362
- blob_init(&txt, 0, 0);
2363
- html_to_plaintext(blob_str(&html), &txt);
2364
- blob_reset(&html);
2365
- fossil_print("The comment uses special character%s \"%s\". "
2366
- "Does it render as you expect?\n\n ",
2367
- nGot>1 ? "s" : "", zGot);
2368
- comment_print(blob_str(&txt), 0, 3, -1, get_comment_format());
2369
- blob_init(pSus, 0, 0);
2370
- blob_appendf(pSus, "\n");
2371
- return 1;
2372
- }else{
2373
- return 0;
2374
- }
2380
+ if( nGot>0 ) rc |= COMCK_MARKUP;
2381
+ if( nGot>0 && nIssue>0 ){
2382
+ blob_appendf(&out,"\n (%d) Comment uses special character%s \"%s\"",
2383
+ ++nIssue, (nGot>1 ? "s" : ""), zGot);
2384
+ nGot = 0;
2385
+ }
2386
+ if( nIssue ){
2387
+ rc |= COMCK_LINKS;
2388
+ fossil_print(
2389
+ "Possible comment formatting error%s:%b\n",
2390
+ nIssue>1 ? "s" : "", &out
2391
+ );
2392
+ }
2393
+ if( (mFlags & COMCK_NOPREVIEW)==0 ){
2394
+ Blob in, html, txt;
2395
+ blob_init(&in, blob_str(pComment), -1);
2396
+ blob_init(&html, 0, 0);
2397
+ blob_init(&txt, 0, 0);
2398
+ wiki_convert(&in, &html, WIKI_INLINE);
2399
+ html_to_plaintext(blob_str(&html), &txt);
2400
+ if( nGot>0 ){
2401
+ fossil_print(
2402
+ "The comment uses special character%s \"%s\". "
2403
+ "Does it render as you expect?\n\n ",
2404
+ (nGot>1 ? "s" : ""), zGot
2405
+ );
2406
+ }else{
2407
+ fossil_print("Preview of the check-in comment:\n\n ");
2408
+ }
2409
+ comment_print(blob_str(&txt), 0, 3, -1, get_comment_format());
2410
+ blob_reset(&in);
2411
+ blob_reset(&html);
2412
+ blob_reset(&txt);
2413
+ }
2414
+ }
2415
+ blob_reset(&out);
2416
+ return rc;
23752417
}
23762418
23772419
/*
23782420
** COMMAND: ci#
23792421
** COMMAND: commit
@@ -2389,11 +2431,11 @@
23892431
** You will be prompted to enter a check-in comment unless the comment
23902432
** has been specified on the command-line using "-m" or "-M". The
23912433
** text editor used is determined by the "editor" setting, or by the
23922434
** "VISUAL" or "EDITOR" environment variables. Commit message text is
23932435
** interpreted as fossil-wiki format. Potentially misformatted check-in
2394
-** comment text is detected and reported unless the --allow-suspect-comment
2436
+** comment text is detected and reported unless the --no-verify-comment
23952437
** option is used.
23962438
**
23972439
** The --branch option followed by a branch name causes the new
23982440
** check-in to be placed in a newly-created branch with name specified.
23992441
**
@@ -2421,11 +2463,10 @@
24212463
** Options:
24222464
** --allow-conflict Allow unresolved merge conflicts
24232465
** --allow-empty Allow a commit with no changes
24242466
** --allow-fork Allow the commit to fork
24252467
** --allow-older Allow a commit older than its ancestor
2426
-** --allow-suspect-comment Allow check-in comments that might be misformed
24272468
** --baseline Use a baseline manifest in the commit process
24282469
** --branch NEW-BRANCH-NAME Check in to this new branch
24292470
** --close Close the branch being committed
24302471
** --date-override DATETIME Make DATETIME the time of the check-in.
24312472
** Useful when importing historical check-ins
@@ -2449,10 +2490,11 @@
24492490
** --no-prompt This option disables prompting the user for
24502491
** input and assumes an answer of 'No' for every
24512492
** question.
24522493
** --no-warnings Omit all warnings about file contents
24532494
** --no-verify Do not run before-commit hooks
2495
+** --no-verify-comment Do not validate the check-in comment
24542496
** --nosign Do not attempt to sign this commit with gpg
24552497
** --nosync Do not auto-sync prior to committing
24562498
** --override-lock Allow a check-in even though parent is locked
24572499
** --private Never sync the resulting check-in and make
24582500
** all descendants private too.
@@ -2488,11 +2530,11 @@
24882530
int allowConflict = 0; /* Allow unresolve merge conflicts */
24892531
int allowEmpty = 0; /* Allow a commit with no changes */
24902532
int onlyIfChanges = 0; /* No-op if there are no changes */
24912533
int allowFork = 0; /* Allow the commit to fork */
24922534
int allowOlder = 0; /* Allow a commit older than its ancestor */
2493
- int allowSusCom = 0; /* Allow suspicious check-in comments */
2535
+ int noVerifyCom = 0; /* Allow suspicious check-in comments */
24942536
char *zManifestFile; /* Name of the manifest file */
24952537
int useCksum; /* True if checksums should be computed and verified */
24962538
int outputManifest; /* True to output "manifest" and "manifest.uuid" */
24972539
int dryRunFlag; /* True for a test run. Debugging only */
24982540
CheckinInfo sCiInfo; /* Information about this check-in */
@@ -2514,10 +2556,11 @@
25142556
int bRecheck = 0; /* Repeat fork and closed-branch checks*/
25152557
int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
25162558
int mxSize;
25172559
char *zCurBranch = 0; /* The current branch name of checkout */
25182560
char *zNewBranch = 0; /* The branch name after update */
2561
+ int ckComFlgs; /* Flags passed to suspicious_comment() */
25192562
25202563
memset(&sCiInfo, 0, sizeof(sCiInfo));
25212564
url_proxy_options();
25222565
/* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
25232566
useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
@@ -2544,11 +2587,11 @@
25442587
}
25452588
zComment = find_option("comment","m",1);
25462589
forceFlag = find_option("force", "f", 0)!=0;
25472590
allowConflict = find_option("allow-conflict",0,0)!=0;
25482591
allowEmpty = find_option("allow-empty",0,0)!=0;
2549
- allowSusCom = find_option("allow-suspect-comment",0,0)!=0;
2592
+ noVerifyCom = find_option("no-verify-comment",0,0)!=0;
25502593
onlyIfChanges = find_option("if-changes",0,0)!=0;
25512594
allowFork = find_option("allow-fork",0,0)!=0;
25522595
if( find_option("override-lock",0,0)!=0 ) allowFork = 1;
25532596
allowOlder = find_option("allow-older",0,0)!=0;
25542597
noPrompt = find_option("no-prompt", 0, 0)!=0;
@@ -2585,13 +2628,13 @@
25852628
mxSize = db_large_file_size();
25862629
if( find_option("ignore-oversize",0,0)!=0 ) mxSize = 0;
25872630
verify_all_options();
25882631
25892632
/* The --no-warnings flag and the --force flag each imply
2590
- ** the --allow-suspect-comment flag */
2633
+ ** the --no-verify-comment flag */
25912634
if( noWarningFlag || forceFlag ){
2592
- allowSusCom = 1;
2635
+ noVerifyCom = 1;
25932636
}
25942637
25952638
/* Get the ID of the parent manifest artifact */
25962639
vid = db_lget_int("checkout", 0);
25972640
if( vid==0 ){
@@ -2876,52 +2919,70 @@
28762919
fossil_free(zNewBranch);
28772920
28782921
/* Always exit the loop on the second pass */
28792922
if( bRecheck ) break;
28802923
2924
+
2925
+ /* Figure out how much comment verification is requested */
2926
+ if( noVerifyCom ){
2927
+ ckComFlgs = 0;
2928
+ }else{
2929
+ const char *zVerComs = db_get("verify-comments","on");
2930
+ if( is_false(zVerComs) ){
2931
+ ckComFlgs = 0;
2932
+ }else if( strcmp(zVerComs,"preview")==0 ){
2933
+ ckComFlgs = COMCK_PREVIEW | COMCK_LINKS | COMCK_MARKUP;
2934
+ }else if( strcmp(zVerComs,"links")==0 ){
2935
+ ckComFlgs = COMCK_LINKS;
2936
+ }else{
2937
+ ckComFlgs = COMCK_LINKS | COMCK_MARKUP;
2938
+ }
2939
+ }
28812940
28822941
/* Get the check-in comment. This might involve prompting the
28832942
** user for the check-in comment, in which case we should resync
28842943
** to renew the check-in lock and repeat the checks for conflicts.
28852944
*/
28862945
if( zComment ){
2887
- Blob sus;
28882946
blob_zero(&comment);
28892947
blob_append(&comment, zComment, -1);
2890
- if( !allowSusCom && suspicious_comment(&comment, &sus) ){
2891
- fossil_fatal("%bCommit aborted; "
2892
- "use --allow-suspect-comment to override", &sus);
2948
+ ckComFlgs &= ~(COMCK_PREVIEW|COMCK_MARKUP);
2949
+ ckComFlgs |= COMCK_NOPREVIEW;
2950
+ if( suspicious_comment(&comment, ckComFlgs) ){
2951
+ fossil_fatal("Commit aborted; "
2952
+ "use --no-verify-comment to override");
28932953
}
28942954
}else if( zComFile ){
2895
- Blob sus;
28962955
blob_zero(&comment);
28972956
blob_read_from_file(&comment, zComFile, ExtFILE);
28982957
blob_to_utf8_no_bom(&comment, 1);
2899
- if( !allowSusCom && suspicious_comment(&comment, &sus) ){
2900
- fossil_fatal("%bCommit aborted; "
2901
- "use --allow-suspect-comment to override", &sus);
2958
+ ckComFlgs &= ~(COMCK_PREVIEW|COMCK_MARKUP);
2959
+ ckComFlgs |= COMCK_NOPREVIEW;
2960
+ if( suspicious_comment(&comment, ckComFlgs) ){
2961
+ fossil_fatal("Commit aborted; "
2962
+ "use --no-verify-comment to override");
29022963
}
29032964
}else if( !noPrompt ){
29042965
while( 1/*exit-by-break*/ ){
2966
+ int rc;
29052967
char *zInit;
2906
- Blob sus;
2907
-
29082968
zInit = db_text(0,"SELECT value FROM vvar WHERE name='ci-comment'");
29092969
prepare_commit_comment(&comment, zInit, &sCiInfo, vid, dryRunFlag);
29102970
db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment);
2911
- if( !allowSusCom && suspicious_comment(&comment,&sus) ){
2912
- blob_appendf(&sus, "Continue (y/n/E=edit)? ");
2913
- prompt_user(blob_str(&sus), &ans);
2971
+ if( (rc = suspicious_comment(&comment, ckComFlgs))!=0 ){
2972
+ if( rc==COMCK_PREVIEW ){
2973
+ prompt_user("\nContinue (Y/n/e=edit)? ", &ans);
2974
+ }else{
2975
+ prompt_user("\nContinue (y/n/E=edit)? ", &ans);
2976
+ }
29142977
cReply = blob_str(&ans)[0];
2978
+ cReply = fossil_tolower(cReply);
29152979
blob_reset(&ans);
2916
- blob_reset(&sus);
2917
- if( cReply=='n' || cReply=='N' ){
2980
+ if( cReply=='n' ){
29182981
fossil_fatal("Commit aborted.");
29192982
}
2920
- if( cReply!='y' && cReply!='Y' ){
2921
- /* "Edit" is the default in case the user enters anything that
2922
- ** does not start with Y or N - including just hitting return. */
2983
+ if( cReply=='e' || (cReply!='y' && rc!=COMCK_PREVIEW) ){
29232984
fossil_free(zInit);
29242985
continue;
29252986
}
29262987
}
29272988
if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
29282989
--- src/checkin.c
+++ src/checkin.c
@@ -2283,97 +2283,139 @@
2283 char **pB = (char**)b;
2284 return fossil_strcmp(pA[0], pB[0]);
2285 }
2286
2287 /*
2288 ** SETTING: verify-comments boolean default=on show-only-if-changed
 
 
 
 
 
 
 
 
 
 
 
 
 
2289 **
2290 ** If enabled (the default) then the "fossil commit" command does sanity
2291 ** checking on the checkin comment. The sanity checks can be overridden
2292 ** on a case by case basis using the --allow-suspect-comment option to
2293 ** the "fossil commit" command. If disabled, this setting makes every
2294 ** "fossil commit" behave as if the --allow-suspect-comment option were
2295 ** provided.
2296 */
2297
 
 
 
 
 
 
 
2298 /*
2299 ** Check for possible formatting errors in the comment string pComment.
2300 ** If found, write a description of the problem(s) into pSus and return
2301 ** true. If everything looks ok, return false.
 
 
 
 
2302 */
2303 static int suspicious_comment(Blob *pComment, Blob *pSus){
2304 char *zStart = blob_str(pComment);
2305 char *z;
2306 char *zEnd, *zEnd2;
2307 char *zSep;
2308 char cSave1;
2309 int nIssue = 0;
 
 
2310 static const char zSpecial[] = "\\&<*_`[";
2311
2312 if( !db_get_boolean("verify-comments",1) ) return 0;
2313 z = zStart;
2314 blob_init(pSus, 0, 0);
2315 while( (z = strchr(z,'['))!=0 ){
2316 zEnd = strchr(z,']');
2317 if( zEnd==0 ){
2318 blob_appendf(pSus,"\n (%d) ", ++nIssue);
2319 blob_appendf(pSus, "Unterminated hyperlink \"%.12s...\"", z);
2320 break;
2321 }
2322 if( zEnd[1]=='(' && (zEnd2 = strchr(zEnd,')'))!=0 ){
2323 blob_appendf(pSus,"\n (%d) ", ++nIssue);
2324 blob_appendf(pSus, "Markdown hyperlink syntax: %.*s",
2325 (int)(zEnd2+1-z), z);
2326 z = zEnd2;
2327 continue;
2328 }
2329 zSep = strchr(z+1,'|');
2330 if( zSep==0 || zSep>zEnd ) zSep = zEnd;
2331 while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--;
2332 cSave1 = zSep[0];
2333 zSep[0] = 0;
2334 if( !wiki_valid_link_target(z+1) ){
2335 blob_appendf(pSus,"\n (%d) ", ++nIssue);
2336 blob_appendf(pSus, "Broken hyperlink: [%s]", z+1);
2337 }
2338 zSep[0] = cSave1;
2339 z = zEnd;
2340 }
2341 if( nIssue ){
2342 Blob tmp = *pSus;
2343 blob_init(pSus, 0, 0);
2344 blob_appendf(pSus,
2345 "Possible comment formatting error%s:%b\n",
2346 nIssue>1 ? "s" : "", &tmp);
2347 blob_reset(&tmp);
2348 return 1;
2349 }else if( strcspn(zStart,zSpecial)<strlen(zStart) ){
2350 Blob in, html, txt;
2351 char zGot[16];
2352 int nGot = 0;
2353 int i;
2354 for(i=0; zSpecial[i]; i++){
2355 if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i];
 
 
2356 }
2357 zGot[nGot] = 0;
2358 blob_init(&in, blob_str(pComment), -1);
2359 blob_init(&html, 0, 0);
2360 wiki_convert(&in, &html, WIKI_INLINE);
2361 blob_reset(&in);
2362 blob_init(&txt, 0, 0);
2363 html_to_plaintext(blob_str(&html), &txt);
2364 blob_reset(&html);
2365 fossil_print("The comment uses special character%s \"%s\". "
2366 "Does it render as you expect?\n\n ",
2367 nGot>1 ? "s" : "", zGot);
2368 comment_print(blob_str(&txt), 0, 3, -1, get_comment_format());
2369 blob_init(pSus, 0, 0);
2370 blob_appendf(pSus, "\n");
2371 return 1;
2372 }else{
2373 return 0;
2374 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2375 }
2376
2377 /*
2378 ** COMMAND: ci#
2379 ** COMMAND: commit
@@ -2389,11 +2431,11 @@
2389 ** You will be prompted to enter a check-in comment unless the comment
2390 ** has been specified on the command-line using "-m" or "-M". The
2391 ** text editor used is determined by the "editor" setting, or by the
2392 ** "VISUAL" or "EDITOR" environment variables. Commit message text is
2393 ** interpreted as fossil-wiki format. Potentially misformatted check-in
2394 ** comment text is detected and reported unless the --allow-suspect-comment
2395 ** option is used.
2396 **
2397 ** The --branch option followed by a branch name causes the new
2398 ** check-in to be placed in a newly-created branch with name specified.
2399 **
@@ -2421,11 +2463,10 @@
2421 ** Options:
2422 ** --allow-conflict Allow unresolved merge conflicts
2423 ** --allow-empty Allow a commit with no changes
2424 ** --allow-fork Allow the commit to fork
2425 ** --allow-older Allow a commit older than its ancestor
2426 ** --allow-suspect-comment Allow check-in comments that might be misformed
2427 ** --baseline Use a baseline manifest in the commit process
2428 ** --branch NEW-BRANCH-NAME Check in to this new branch
2429 ** --close Close the branch being committed
2430 ** --date-override DATETIME Make DATETIME the time of the check-in.
2431 ** Useful when importing historical check-ins
@@ -2449,10 +2490,11 @@
2449 ** --no-prompt This option disables prompting the user for
2450 ** input and assumes an answer of 'No' for every
2451 ** question.
2452 ** --no-warnings Omit all warnings about file contents
2453 ** --no-verify Do not run before-commit hooks
 
2454 ** --nosign Do not attempt to sign this commit with gpg
2455 ** --nosync Do not auto-sync prior to committing
2456 ** --override-lock Allow a check-in even though parent is locked
2457 ** --private Never sync the resulting check-in and make
2458 ** all descendants private too.
@@ -2488,11 +2530,11 @@
2488 int allowConflict = 0; /* Allow unresolve merge conflicts */
2489 int allowEmpty = 0; /* Allow a commit with no changes */
2490 int onlyIfChanges = 0; /* No-op if there are no changes */
2491 int allowFork = 0; /* Allow the commit to fork */
2492 int allowOlder = 0; /* Allow a commit older than its ancestor */
2493 int allowSusCom = 0; /* Allow suspicious check-in comments */
2494 char *zManifestFile; /* Name of the manifest file */
2495 int useCksum; /* True if checksums should be computed and verified */
2496 int outputManifest; /* True to output "manifest" and "manifest.uuid" */
2497 int dryRunFlag; /* True for a test run. Debugging only */
2498 CheckinInfo sCiInfo; /* Information about this check-in */
@@ -2514,10 +2556,11 @@
2514 int bRecheck = 0; /* Repeat fork and closed-branch checks*/
2515 int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
2516 int mxSize;
2517 char *zCurBranch = 0; /* The current branch name of checkout */
2518 char *zNewBranch = 0; /* The branch name after update */
 
2519
2520 memset(&sCiInfo, 0, sizeof(sCiInfo));
2521 url_proxy_options();
2522 /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
2523 useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
@@ -2544,11 +2587,11 @@
2544 }
2545 zComment = find_option("comment","m",1);
2546 forceFlag = find_option("force", "f", 0)!=0;
2547 allowConflict = find_option("allow-conflict",0,0)!=0;
2548 allowEmpty = find_option("allow-empty",0,0)!=0;
2549 allowSusCom = find_option("allow-suspect-comment",0,0)!=0;
2550 onlyIfChanges = find_option("if-changes",0,0)!=0;
2551 allowFork = find_option("allow-fork",0,0)!=0;
2552 if( find_option("override-lock",0,0)!=0 ) allowFork = 1;
2553 allowOlder = find_option("allow-older",0,0)!=0;
2554 noPrompt = find_option("no-prompt", 0, 0)!=0;
@@ -2585,13 +2628,13 @@
2585 mxSize = db_large_file_size();
2586 if( find_option("ignore-oversize",0,0)!=0 ) mxSize = 0;
2587 verify_all_options();
2588
2589 /* The --no-warnings flag and the --force flag each imply
2590 ** the --allow-suspect-comment flag */
2591 if( noWarningFlag || forceFlag ){
2592 allowSusCom = 1;
2593 }
2594
2595 /* Get the ID of the parent manifest artifact */
2596 vid = db_lget_int("checkout", 0);
2597 if( vid==0 ){
@@ -2876,52 +2919,70 @@
2876 fossil_free(zNewBranch);
2877
2878 /* Always exit the loop on the second pass */
2879 if( bRecheck ) break;
2880
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2881
2882 /* Get the check-in comment. This might involve prompting the
2883 ** user for the check-in comment, in which case we should resync
2884 ** to renew the check-in lock and repeat the checks for conflicts.
2885 */
2886 if( zComment ){
2887 Blob sus;
2888 blob_zero(&comment);
2889 blob_append(&comment, zComment, -1);
2890 if( !allowSusCom && suspicious_comment(&comment, &sus) ){
2891 fossil_fatal("%bCommit aborted; "
2892 "use --allow-suspect-comment to override", &sus);
 
 
2893 }
2894 }else if( zComFile ){
2895 Blob sus;
2896 blob_zero(&comment);
2897 blob_read_from_file(&comment, zComFile, ExtFILE);
2898 blob_to_utf8_no_bom(&comment, 1);
2899 if( !allowSusCom && suspicious_comment(&comment, &sus) ){
2900 fossil_fatal("%bCommit aborted; "
2901 "use --allow-suspect-comment to override", &sus);
 
 
2902 }
2903 }else if( !noPrompt ){
2904 while( 1/*exit-by-break*/ ){
 
2905 char *zInit;
2906 Blob sus;
2907
2908 zInit = db_text(0,"SELECT value FROM vvar WHERE name='ci-comment'");
2909 prepare_commit_comment(&comment, zInit, &sCiInfo, vid, dryRunFlag);
2910 db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment);
2911 if( !allowSusCom && suspicious_comment(&comment,&sus) ){
2912 blob_appendf(&sus, "Continue (y/n/E=edit)? ");
2913 prompt_user(blob_str(&sus), &ans);
 
 
 
2914 cReply = blob_str(&ans)[0];
 
2915 blob_reset(&ans);
2916 blob_reset(&sus);
2917 if( cReply=='n' || cReply=='N' ){
2918 fossil_fatal("Commit aborted.");
2919 }
2920 if( cReply!='y' && cReply!='Y' ){
2921 /* "Edit" is the default in case the user enters anything that
2922 ** does not start with Y or N - including just hitting return. */
2923 fossil_free(zInit);
2924 continue;
2925 }
2926 }
2927 if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
2928
--- src/checkin.c
+++ src/checkin.c
@@ -2283,97 +2283,139 @@
2283 char **pB = (char**)b;
2284 return fossil_strcmp(pA[0], pB[0]);
2285 }
2286
2287 /*
2288 ** SETTING: verify-comments width=8 default=on show-only-if-changed
2289 **
2290 ** This setting determines much sanity checking, if any, the
2291 ** "fossil commit" and "fossil amend" commands do against check-in
2292 ** comments. Recognized values:
2293 **
2294 ** on (Default) Check for bad syntax in check-in comments
2295 ** and offer the user a chance to continue editing for
2296 ** interactive sessions, or simply abort the commit if
2297 ** commit was entered using using -m or -M
2298 **
2299 ** off Do not syntax checking of any kind
2300 **
2301 ** links Similar to "on", except only check for bad hyperlinks
2302 **
2303 ** preview Do all the same checks as "on" but also preview the
2304 ** checkin comment to the user during interactive sessions
2305 ** and provide an opportunity to accept or re-edit
 
 
 
2306 */
2307
2308 #if INTERFACE
2309 #define COMCK_LINKS 0x01 /* Check for back hyperlinks */
2310 #define COMCK_MARKUP 0x02 /* Check markup */
2311 #define COMCK_PREVIEW 0x04 /* Always preview even if no issues found */
2312 #define COMCK_NOPREVIEW 0x08 /* Never preview, even for other errors */
2313 #endif /* INTERFACE */
2314
2315 /*
2316 ** Check for possible formatting errors in the comment string pComment.
2317 **
2318 ** If concerns are found, write a description of the problem(s) to
2319 ** stdout return non-zero. The return value is some combination of
2320 ** of the COMCK_* flags depending on what went wrong.
2321 **
2322 ** If no issues are seen, do not output anything and return zero.
2323 */
2324 static int suspicious_comment(Blob *pComment, int mFlags){
2325 char *zStart = blob_str(pComment);
2326 char *z;
2327 char *zEnd, *zEnd2;
2328 char *zSep;
2329 char cSave1;
2330 int nIssue = 0;
2331 int rc = mFlags & COMCK_PREVIEW;
2332 Blob out;
2333 static const char zSpecial[] = "\\&<*_`[";
2334
2335 if( mFlags==0 ) return 0;
2336 z = zStart;
2337 blob_init(&out, 0, 0);
2338 if( mFlags & COMCK_LINKS ){
2339 while( (z = strchr(z,'['))!=0 ){
2340 zEnd = strchr(z,']');
2341 if( zEnd==0 ){
2342 blob_appendf(&out,"\n (%d) ", ++nIssue);
2343 blob_appendf(&out, "Unterminated hyperlink \"%.12s...\"", z);
2344 break;
2345 }
2346 if( zEnd[1]=='(' && (zEnd2 = strchr(zEnd,')'))!=0 ){
2347 blob_appendf(&out,"\n (%d) ", ++nIssue);
2348 blob_appendf(&out, "Markdown hyperlink syntax: %.*s",
2349 (int)(zEnd2+1-z), z);
2350 z = zEnd2;
2351 continue;
2352 }
2353 zSep = strchr(z+1,'|');
2354 if( zSep==0 || zSep>zEnd ) zSep = zEnd;
2355 while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--;
2356 cSave1 = zSep[0];
2357 zSep[0] = 0;
2358 if( !wiki_valid_link_target(z+1) ){
2359 blob_appendf(&out,"\n (%d) ", ++nIssue);
2360 blob_appendf(&out, "Broken hyperlink: [%s]", z+1);
2361 }
2362 zSep[0] = cSave1;
2363 z = zEnd;
2364 }
2365 }
2366
2367 if( nIssue>0
2368 || (mFlags & COMCK_PREVIEW)!=0
2369 || ((mFlags & COMCK_MARKUP)!=0 && strcspn(zStart,zSpecial)<strlen(zStart))
2370 ){
 
 
 
2371 char zGot[16];
2372 int nGot = 0;
2373 int i;
2374 if( (mFlags & COMCK_MARKUP)!=0 ){
2375 for(i=0; zSpecial[i]; i++){
2376 if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i];
2377 }
2378 }
2379 zGot[nGot] = 0;
2380 if( nGot>0 ) rc |= COMCK_MARKUP;
2381 if( nGot>0 && nIssue>0 ){
2382 blob_appendf(&out,"\n (%d) Comment uses special character%s \"%s\"",
2383 ++nIssue, (nGot>1 ? "s" : ""), zGot);
2384 nGot = 0;
2385 }
2386 if( nIssue ){
2387 rc |= COMCK_LINKS;
2388 fossil_print(
2389 "Possible comment formatting error%s:%b\n",
2390 nIssue>1 ? "s" : "", &out
2391 );
2392 }
2393 if( (mFlags & COMCK_NOPREVIEW)==0 ){
2394 Blob in, html, txt;
2395 blob_init(&in, blob_str(pComment), -1);
2396 blob_init(&html, 0, 0);
2397 blob_init(&txt, 0, 0);
2398 wiki_convert(&in, &html, WIKI_INLINE);
2399 html_to_plaintext(blob_str(&html), &txt);
2400 if( nGot>0 ){
2401 fossil_print(
2402 "The comment uses special character%s \"%s\". "
2403 "Does it render as you expect?\n\n ",
2404 (nGot>1 ? "s" : ""), zGot
2405 );
2406 }else{
2407 fossil_print("Preview of the check-in comment:\n\n ");
2408 }
2409 comment_print(blob_str(&txt), 0, 3, -1, get_comment_format());
2410 blob_reset(&in);
2411 blob_reset(&html);
2412 blob_reset(&txt);
2413 }
2414 }
2415 blob_reset(&out);
2416 return rc;
2417 }
2418
2419 /*
2420 ** COMMAND: ci#
2421 ** COMMAND: commit
@@ -2389,11 +2431,11 @@
2431 ** You will be prompted to enter a check-in comment unless the comment
2432 ** has been specified on the command-line using "-m" or "-M". The
2433 ** text editor used is determined by the "editor" setting, or by the
2434 ** "VISUAL" or "EDITOR" environment variables. Commit message text is
2435 ** interpreted as fossil-wiki format. Potentially misformatted check-in
2436 ** comment text is detected and reported unless the --no-verify-comment
2437 ** option is used.
2438 **
2439 ** The --branch option followed by a branch name causes the new
2440 ** check-in to be placed in a newly-created branch with name specified.
2441 **
@@ -2421,11 +2463,10 @@
2463 ** Options:
2464 ** --allow-conflict Allow unresolved merge conflicts
2465 ** --allow-empty Allow a commit with no changes
2466 ** --allow-fork Allow the commit to fork
2467 ** --allow-older Allow a commit older than its ancestor
 
2468 ** --baseline Use a baseline manifest in the commit process
2469 ** --branch NEW-BRANCH-NAME Check in to this new branch
2470 ** --close Close the branch being committed
2471 ** --date-override DATETIME Make DATETIME the time of the check-in.
2472 ** Useful when importing historical check-ins
@@ -2449,10 +2490,11 @@
2490 ** --no-prompt This option disables prompting the user for
2491 ** input and assumes an answer of 'No' for every
2492 ** question.
2493 ** --no-warnings Omit all warnings about file contents
2494 ** --no-verify Do not run before-commit hooks
2495 ** --no-verify-comment Do not validate the check-in comment
2496 ** --nosign Do not attempt to sign this commit with gpg
2497 ** --nosync Do not auto-sync prior to committing
2498 ** --override-lock Allow a check-in even though parent is locked
2499 ** --private Never sync the resulting check-in and make
2500 ** all descendants private too.
@@ -2488,11 +2530,11 @@
2530 int allowConflict = 0; /* Allow unresolve merge conflicts */
2531 int allowEmpty = 0; /* Allow a commit with no changes */
2532 int onlyIfChanges = 0; /* No-op if there are no changes */
2533 int allowFork = 0; /* Allow the commit to fork */
2534 int allowOlder = 0; /* Allow a commit older than its ancestor */
2535 int noVerifyCom = 0; /* Allow suspicious check-in comments */
2536 char *zManifestFile; /* Name of the manifest file */
2537 int useCksum; /* True if checksums should be computed and verified */
2538 int outputManifest; /* True to output "manifest" and "manifest.uuid" */
2539 int dryRunFlag; /* True for a test run. Debugging only */
2540 CheckinInfo sCiInfo; /* Information about this check-in */
@@ -2514,10 +2556,11 @@
2556 int bRecheck = 0; /* Repeat fork and closed-branch checks*/
2557 int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
2558 int mxSize;
2559 char *zCurBranch = 0; /* The current branch name of checkout */
2560 char *zNewBranch = 0; /* The branch name after update */
2561 int ckComFlgs; /* Flags passed to suspicious_comment() */
2562
2563 memset(&sCiInfo, 0, sizeof(sCiInfo));
2564 url_proxy_options();
2565 /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
2566 useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
@@ -2544,11 +2587,11 @@
2587 }
2588 zComment = find_option("comment","m",1);
2589 forceFlag = find_option("force", "f", 0)!=0;
2590 allowConflict = find_option("allow-conflict",0,0)!=0;
2591 allowEmpty = find_option("allow-empty",0,0)!=0;
2592 noVerifyCom = find_option("no-verify-comment",0,0)!=0;
2593 onlyIfChanges = find_option("if-changes",0,0)!=0;
2594 allowFork = find_option("allow-fork",0,0)!=0;
2595 if( find_option("override-lock",0,0)!=0 ) allowFork = 1;
2596 allowOlder = find_option("allow-older",0,0)!=0;
2597 noPrompt = find_option("no-prompt", 0, 0)!=0;
@@ -2585,13 +2628,13 @@
2628 mxSize = db_large_file_size();
2629 if( find_option("ignore-oversize",0,0)!=0 ) mxSize = 0;
2630 verify_all_options();
2631
2632 /* The --no-warnings flag and the --force flag each imply
2633 ** the --no-verify-comment flag */
2634 if( noWarningFlag || forceFlag ){
2635 noVerifyCom = 1;
2636 }
2637
2638 /* Get the ID of the parent manifest artifact */
2639 vid = db_lget_int("checkout", 0);
2640 if( vid==0 ){
@@ -2876,52 +2919,70 @@
2919 fossil_free(zNewBranch);
2920
2921 /* Always exit the loop on the second pass */
2922 if( bRecheck ) break;
2923
2924
2925 /* Figure out how much comment verification is requested */
2926 if( noVerifyCom ){
2927 ckComFlgs = 0;
2928 }else{
2929 const char *zVerComs = db_get("verify-comments","on");
2930 if( is_false(zVerComs) ){
2931 ckComFlgs = 0;
2932 }else if( strcmp(zVerComs,"preview")==0 ){
2933 ckComFlgs = COMCK_PREVIEW | COMCK_LINKS | COMCK_MARKUP;
2934 }else if( strcmp(zVerComs,"links")==0 ){
2935 ckComFlgs = COMCK_LINKS;
2936 }else{
2937 ckComFlgs = COMCK_LINKS | COMCK_MARKUP;
2938 }
2939 }
2940
2941 /* Get the check-in comment. This might involve prompting the
2942 ** user for the check-in comment, in which case we should resync
2943 ** to renew the check-in lock and repeat the checks for conflicts.
2944 */
2945 if( zComment ){
 
2946 blob_zero(&comment);
2947 blob_append(&comment, zComment, -1);
2948 ckComFlgs &= ~(COMCK_PREVIEW|COMCK_MARKUP);
2949 ckComFlgs |= COMCK_NOPREVIEW;
2950 if( suspicious_comment(&comment, ckComFlgs) ){
2951 fossil_fatal("Commit aborted; "
2952 "use --no-verify-comment to override");
2953 }
2954 }else if( zComFile ){
 
2955 blob_zero(&comment);
2956 blob_read_from_file(&comment, zComFile, ExtFILE);
2957 blob_to_utf8_no_bom(&comment, 1);
2958 ckComFlgs &= ~(COMCK_PREVIEW|COMCK_MARKUP);
2959 ckComFlgs |= COMCK_NOPREVIEW;
2960 if( suspicious_comment(&comment, ckComFlgs) ){
2961 fossil_fatal("Commit aborted; "
2962 "use --no-verify-comment to override");
2963 }
2964 }else if( !noPrompt ){
2965 while( 1/*exit-by-break*/ ){
2966 int rc;
2967 char *zInit;
 
 
2968 zInit = db_text(0,"SELECT value FROM vvar WHERE name='ci-comment'");
2969 prepare_commit_comment(&comment, zInit, &sCiInfo, vid, dryRunFlag);
2970 db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment);
2971 if( (rc = suspicious_comment(&comment, ckComFlgs))!=0 ){
2972 if( rc==COMCK_PREVIEW ){
2973 prompt_user("\nContinue (Y/n/e=edit)? ", &ans);
2974 }else{
2975 prompt_user("\nContinue (y/n/E=edit)? ", &ans);
2976 }
2977 cReply = blob_str(&ans)[0];
2978 cReply = fossil_tolower(cReply);
2979 blob_reset(&ans);
2980 if( cReply=='n' ){
 
2981 fossil_fatal("Commit aborted.");
2982 }
2983 if( cReply=='e' || (cReply!='y' && rc!=COMCK_PREVIEW) ){
 
 
2984 fossil_free(zInit);
2985 continue;
2986 }
2987 }
2988 if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
2989

Keyboard Shortcuts

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