Fossil SCM

fossil-scm / src / warnpolicy.c
Blame History Raw 245 lines
1
/*
2
** Copyright (c) 2023 Preben Guldberg
3
**
4
** This program is free software; you can redistribute it and/or
5
** modify it under the terms of the Simplified BSD License (also
6
** known as the "2-Clause License" or "FreeBSD License".)
7
8
** This program is distributed in the hope that it will be useful,
9
** but without any warranty; without even the implied warranty of
10
** merchantability or fitness for a particular purpose.
11
**
12
** Author contact information:
13
** [email protected]
14
** http://www.hwaci.com/drh/
15
**
16
*******************************************************************************
17
**
18
** This file contains code implementing a warning policy for different events.
19
*/
20
#include "config.h"
21
#include "warnpolicy.h"
22
23
/*
24
** SETTING: warning-policy width=40 block-text propagating default={}
25
** Policy for showing warnings under certain conditions.
26
**
27
** The policy is a JSON object where the following names are recognised:
28
**
29
** commit: Used when committing. A list of objects with names in
30
** (message, branch, except-branch, users, except-users).
31
** merge: Used when merging. A List of objects with names in
32
** (message, branch, except-branch, from, except-from,
33
** users, except-users, unpublished).
34
** match-style: If "regexp", patterns use REGEXP, otherwise GLOB.
35
**
36
** Meaning of names used in lists above:
37
**
38
** message: MESSAGE Required: Message to show.
39
** branch: PATTERN Apply branch match PATTERN (default any).
40
** except-branch: PATTERN Exclude when in a branch matching PATTERN.
41
** from: PATTERN Apply if merging from PATTERN (default any).
42
** except-from: PATTERN Exclude when merging from PATTERN.
43
** unpublished: true If true, only show when merging from a private
44
** branch into a public branch.
45
** users: LIST Show only for users in LIST (default any).
46
** except-users: LIST Users in LIST will not be shown the messages.
47
**
48
** Example:
49
**
50
** {
51
** "commit": [
52
** { "message": "Release pending, proceed with caution.",
53
** "branch": "trunk",
54
** "except-users": [ "owner", "admin" ] }
55
** ],
56
** "merge": [
57
** { "message": "Please use 'fossil publish' before merging private to public",
58
** "except-branch": "rebased-branch-*",
59
** "unpublished": true },
60
** { "message": "Updates to release branches should be merged from rc.",
61
** "branch": "release-*",
62
** "except-from": "rc-*" }
63
** ]
64
** }
65
*/
66
67
/*
68
** Fetch the match-style for warning-policy.
69
*/
70
static const char *warning_policy_match_style(void){
71
int isRegexp = db_int(0,
72
"SELECT 1"
73
" FROM config"
74
" WHERE name='warning-policy'"
75
" AND json_error_position(value)=0"
76
" AND value->>'match-style'='regexp'");
77
return isRegexp ? "REGEXP" : "GLOB";
78
}
79
80
/*
81
** Common part of issuing warnings.
82
*/
83
static int print_policy_warnings(Blob *pSql){
84
Stmt q;
85
int nWarnings = 0;
86
87
db_prepare(&q, "%s)", blob_sql_text(pSql));
88
while( db_step(&q)==SQLITE_ROW ){
89
if( nWarnings==0 ) fossil_warning("Policy warnings:");
90
fossil_warning(" %s", db_column_text(&q, 0));
91
nWarnings++;
92
}
93
db_finalize(&q);
94
return nWarnings;
95
}
96
97
/*
98
** Print commit specific warnings from the warning-policy.
99
*/
100
int issue_commit_warnings(
101
const char *zBranch /* The branch we are committing to */
102
){
103
Blob sql = empty_blob;
104
const char *zMatch;
105
int nWarnings = 0;
106
107
assert(zBranch!=0);
108
if( g.zLogin==0) user_select();
109
zMatch = warning_policy_match_style();
110
blob_append_sql(&sql,
111
"WITH list AS ("
112
" SELECT value AS elm"
113
" FROM json_each(("
114
" SELECT json_extract(value, '$.commit')"
115
" FROM config"
116
" WHERE name='warning-policy' AND json_error_position(value)=0)))"
117
" SELECT elm->>'message' FROM list"
118
" WHERE ("
119
" (elm->>'branch' IS NULL"
120
" OR %Q %S elm->>'branch')"
121
" AND (elm->>'except-branch' IS NULL"
122
" OR NOT %Q %S elm->>'except-branch')"
123
" AND (elm->>'users' IS NULL"
124
" OR %Q IN (SELECT value FROM json_each(elm->>'users')))"
125
" AND NOT %Q IN (SELECT value FROM json_each(elm->>'except-users')"
126
" )",
127
zBranch, zMatch, zBranch, zMatch, g.zLogin, g.zLogin
128
);
129
nWarnings = print_policy_warnings(&sql);
130
blob_reset(&sql);
131
return nWarnings;
132
}
133
134
/*
135
** Print merge specific warnings from the warning-policy.
136
*/
137
int issue_merge_warnings(
138
const char *zBranch, /* The branch we are merging into */
139
const char *zFrom, /* The branch we are merging from */
140
int historyLoss /* Merging a private branch into a public branch */
141
){
142
Blob sql = empty_blob;
143
const char *zMatch;
144
int nWarnings = 0;
145
146
assert(zBranch!=0);
147
assert(zFrom!=0);
148
if( g.zLogin==0) user_select();
149
zMatch = warning_policy_match_style();
150
blob_append_sql(&sql,
151
"WITH list AS ("
152
" SELECT value AS elm"
153
" FROM json_each(("
154
" SELECT json_extract(value, '$.merge')"
155
" FROM config"
156
" WHERE name='warning-policy' AND json_error_position(value)=0)))"
157
" SELECT elm->>'message' FROM list"
158
" WHERE ("
159
" (elm->>'branch' IS NULL"
160
" OR %Q %S elm->>'branch')"
161
" AND (elm->>'except-branch' IS NULL"
162
" OR NOT %Q %S elm->>'except-branch')"
163
" AND (elm->>'from' IS NULL"
164
" OR %Q %S elm->>'from')"
165
" AND (elm->>'except-from' IS NULL"
166
" OR NOT %Q %S elm->>'except-from')"
167
" AND (elm->>'users' IS NULL"
168
" OR %Q IN (SELECT value FROM json_each(elm->>'users')))"
169
" AND NOT %Q IN (SELECT value FROM json_each(elm->>'except-users'))",
170
zBranch, zMatch, zBranch, zMatch,
171
zFrom, zMatch, zFrom, zMatch,
172
g.zLogin, g.zLogin
173
);
174
if( !historyLoss ){
175
blob_append_sql(&sql,
176
" AND (elm->>'unpublished' IS NULL"
177
" OR NOT elm->>'unpublished')"
178
);
179
}
180
nWarnings = print_policy_warnings(&sql);
181
blob_reset(&sql);
182
return nWarnings;
183
}
184
185
/*
186
** COMMAND: test-warning-policy
187
** Usage: %fossil test-warning-policy EVENT ?OPTIONS?
188
**
189
** Test what messages would be shown for a specific scenario.
190
** Use the global -U|--user option to test for a specific user.
191
**
192
** Options:
193
** --json JSON
194
**
195
** Options for "commit" event:
196
** -b|--branch BRANCH Test commit to BRANCH.
197
**
198
** Options for "merge" event:
199
** -b|--branch BRANCH Test merge to BRANCH.
200
** -f|--from BRANCH Test merge from BRANCH.
201
** -u|--unpublished Test merging from a private to a public branch.
202
*/
203
void test_warning_policy_cmd(void){
204
const char *zEvent;
205
const char *zJSON;
206
207
if( g.argc<3 ) fossil_fatal("EVENT is required");
208
zEvent = g.argv[2];
209
db_must_be_within_tree();
210
211
zJSON = find_option("json", 0, 1);
212
if( zJSON ){
213
db_begin_transaction();
214
db_set("warning-policy", zJSON, 0);
215
}
216
217
switch( db_int(-1,
218
"SELECT json_error_position(value)=0 FROM config WHERE name='warning-policy'")
219
){
220
case -1: fossil_fatal("The warning-policy setting is not set");
221
case 0: fossil_fatal("The warning-policy setting is not valid JSON");
222
default: break;
223
}
224
225
if( fossil_strcmp(zEvent, "commit")==0 ){
226
const char *zBranch = find_option("branch", "b", 1);
227
if( zBranch==0 ) fossil_fatal("%s: missing --branch option", zEvent);
228
verify_all_options();
229
issue_commit_warnings(zBranch);
230
}else if( fossil_strcmp(zEvent, "merge")==0 ){
231
const char *zBranch = find_option("branch", "b", 1);
232
const char *zFrom = find_option("from", "f", 1);
233
int historyLoss = find_option("unpublished", "u", 0)!=0;
234
if( zBranch==0 ) fossil_fatal("%s: missing --branch option", zEvent);
235
if( zFrom==0 ) fossil_fatal("%s: missing --from option", zEvent);
236
verify_all_options();
237
issue_merge_warnings(zBranch, zFrom, historyLoss);
238
}else{
239
fossil_fatal("Unknown POLICY: %s", g.argv[2]);
240
}
241
242
if( zJSON ) db_end_transaction(1);
243
}
244
245

Keyboard Shortcuts

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