1 | <?php |
---|
2 | |
---|
3 | define( 'DEBUG_LEVEL', 1 ); |
---|
4 | define( 'UPLOAD_PATCH', false ); |
---|
5 | |
---|
6 | define( 'WPORG_USER', '' ); |
---|
7 | define( 'WPORG_PASSWORD', '' ); |
---|
8 | |
---|
9 | // The massive first auto-fixer commit. |
---|
10 | $firstFixerCommit = '8f95800d52c1736d651ae6e259f90ad4a0db2c3f'; |
---|
11 | |
---|
12 | // Subsequent fixer commits. |
---|
13 | $fixerCommits = array( |
---|
14 | // Upgrade WPCS to 1.0.0. |
---|
15 | 'a75d153eeeac9154c2576697adf721027e1d073e', |
---|
16 | ); |
---|
17 | |
---|
18 | /* |
---|
19 | * When applying patches, certain strings in the patch will cause the value of the -p option |
---|
20 | * to change. As most patches are made with SVN, we default to 0, and change for other patch styles. |
---|
21 | */ |
---|
22 | $pLevels = array( |
---|
23 | 1 => array( |
---|
24 | 'diff --git a/', |
---|
25 | '--- /www/wp-', |
---|
26 | ), |
---|
27 | ); |
---|
28 | |
---|
29 | /* |
---|
30 | * Sometimes patches are uploaded that don't apply to the base directory, so we need to change |
---|
31 | * the --directory option to a new target. |
---|
32 | */ |
---|
33 | $targets = array( |
---|
34 | 'src' => array( |
---|
35 | 'Index: wp-', |
---|
36 | 'diff --git wp-', |
---|
37 | 'diff --git a/wp-', |
---|
38 | '--- /www/wp-', |
---|
39 | ), |
---|
40 | 'src/wp-includes' => array( |
---|
41 | 'Index: feed', |
---|
42 | ), |
---|
43 | ); |
---|
44 | |
---|
45 | if ( ! file_exists( '../working/ticket-data.csv' ) ) { |
---|
46 | echo "Downloading ticket data...\n"; |
---|
47 | |
---|
48 | shell_exec( 'curl https://core.trac.wordpress.org/report/1?sort=ticket&asc=1&format=csv > ../working/ticket-data.csv' ); |
---|
49 | } |
---|
50 | |
---|
51 | // Make sure master is up to date |
---|
52 | $output = shell_exec( 'git checkout -f master' ); |
---|
53 | if ( DEBUG_LEVEL ) { |
---|
54 | echo $output; |
---|
55 | } |
---|
56 | $output = shell_exec( 'git pull origin master' ); |
---|
57 | if ( DEBUG_LEVEL ) { |
---|
58 | echo $output; |
---|
59 | } |
---|
60 | |
---|
61 | $ticketHandle = fopen( '../working/ticket-data.csv', 'r' ); |
---|
62 | |
---|
63 | while ( ( $ticketData = fgetcsv( $ticketHandle ) ) !== FALSE ) { |
---|
64 | $ticket = $ticketData[0]; |
---|
65 | if ( ! is_numeric( $ticket ) ) { |
---|
66 | continue; |
---|
67 | } |
---|
68 | |
---|
69 | $output = shell_exec( 'git checkout -f master' ); |
---|
70 | if ( DEBUG_LEVEL ) { |
---|
71 | echo $output; |
---|
72 | } |
---|
73 | |
---|
74 | $output = shell_exec( 'git clean -fd' ); |
---|
75 | if ( DEBUG_LEVEL ) { |
---|
76 | echo $output; |
---|
77 | } |
---|
78 | |
---|
79 | $output = shell_exec( 'git reset --hard origin/master' ); |
---|
80 | if ( DEBUG_LEVEL ) { |
---|
81 | echo $output; |
---|
82 | } |
---|
83 | |
---|
84 | if ( file_exists( "../working/$ticket-automerged.diff" ) ) { |
---|
85 | continue; |
---|
86 | } |
---|
87 | |
---|
88 | if ( ! file_exists( "../working/$ticket.diff" ) ) { |
---|
89 | $ticketHtml = file_get_contents( "https://core.trac.wordpress.org/ticket/$ticket" ); |
---|
90 | |
---|
91 | $matches = array(); |
---|
92 | preg_match_all( "|<a href=\"/(attachment/ticket/$ticket/[^\"]*)\" title=\"View attachment\">.*from=([^&]*)|", $ticketHtml, $matches ); |
---|
93 | |
---|
94 | $newestDiff = ''; |
---|
95 | $newestDiffTime = 0; |
---|
96 | for ( $ii = 0; $ii < count( $matches[0] ); $ii++ ) { |
---|
97 | if ( ! preg_match( '/.(diff|patch)$/', $matches[1][ $ii ] ) ) { |
---|
98 | continue; |
---|
99 | } |
---|
100 | |
---|
101 | $time = strtotime( urldecode( $matches[2][ $ii ] ) ); |
---|
102 | if ( $time > $newestDiffTime ) { |
---|
103 | $newestDiff = $matches[1][ $ii ]; |
---|
104 | $newestDiffTime = $time; |
---|
105 | } |
---|
106 | } |
---|
107 | |
---|
108 | if ( ! $newestDiffTime || $newestDiffTime >= strtotime( '2017-12-01 00:00:00' ) ) { |
---|
109 | continue; |
---|
110 | } |
---|
111 | |
---|
112 | shell_exec( "curl https://core.trac.wordpress.org/raw-$newestDiff > ../working/$ticket.diff" ); |
---|
113 | } |
---|
114 | |
---|
115 | // git branch at the auto-fixer commit. |
---|
116 | echo "Creating branch for Ticket #$ticket\n"; |
---|
117 | $output = shell_exec( "git branch -f $ticket $firstFixerCommit" ); |
---|
118 | if ( DEBUG_LEVEL ) { |
---|
119 | echo $output; |
---|
120 | } |
---|
121 | $output = shell_exec( "git checkout $ticket" ); |
---|
122 | if ( DEBUG_LEVEL ) { |
---|
123 | echo $output; |
---|
124 | } |
---|
125 | |
---|
126 | $diff = file_get_contents( "../working/$ticket.diff" ); |
---|
127 | $pLevel = 0; |
---|
128 | foreach ( $pLevels as $level => $testStrings ) { |
---|
129 | foreach ( $testStrings as $testString ) { |
---|
130 | if ( strpos( $diff, $testString ) !== false ) { |
---|
131 | $pLevel = $level; |
---|
132 | break 2; |
---|
133 | } |
---|
134 | } |
---|
135 | } |
---|
136 | |
---|
137 | $target = ''; |
---|
138 | foreach ( $targets as $dir => $testStrings ) { |
---|
139 | foreach ( $testStrings as $testString ) { |
---|
140 | if ( strpos( $diff, $testString ) !== false ) { |
---|
141 | $target = "--directory $dir"; |
---|
142 | break 2; |
---|
143 | } |
---|
144 | } |
---|
145 | } |
---|
146 | |
---|
147 | // Find files changed in the patch. |
---|
148 | echo "Finding files that will be changed by this patch:\n"; |
---|
149 | $fileString = shell_exec( "git apply --numstat -p$pLevel ../working/$ticket.diff $target | awk '{print $3}'" ); |
---|
150 | echo $fileString; |
---|
151 | |
---|
152 | $files = explode( "\n", $fileString ); |
---|
153 | $fileParams = implode( ' ', $files ); |
---|
154 | |
---|
155 | // Undo changed files to the change before the auto-fixer commit, if those files exist. |
---|
156 | $existingFiles = array_filter( $files, 'file_exists' ); |
---|
157 | if ( $existingFiles ) { |
---|
158 | echo "Reverting patch files to previous commit.\n"; |
---|
159 | $output = shell_exec( "git checkout $firstFixerCommit~1 -- " . implode( ' ', $existingFiles ) ); |
---|
160 | if ( DEBUG_LEVEL ) { |
---|
161 | echo $output; |
---|
162 | } |
---|
163 | } |
---|
164 | |
---|
165 | // Apply the patch file. |
---|
166 | echo "Applying patch.\n"; |
---|
167 | $output = shell_exec( "git apply -p$pLevel ../working/$ticket.diff $target 2>&1" ); |
---|
168 | if ( DEBUG_LEVEL ) { |
---|
169 | echo $output; |
---|
170 | } |
---|
171 | |
---|
172 | if ( strpos( $output, 'error: ' ) !== false ) { |
---|
173 | continue; |
---|
174 | } |
---|
175 | |
---|
176 | // Install original WPCS/PHPCS versions (source: https://github.com/WordPress/wordpress-develop/pull/8/files#diff-1da2c7edc898c70e5a79a9997c98cecc). |
---|
177 | echo "Installing composer dependences.\n"; |
---|
178 | shell_exec( 'rm -rf vendor' ); |
---|
179 | $originalDependences = array( |
---|
180 | 'squizlabs/PHP_CodeSniffer:dev-master#506feeeb6753b9904a165366dd78077b2879adb7', |
---|
181 | 'wp-coding-standards/wpcs:dev-feature/new-multi-line-comment-formatting-sniffs#ce4d719296ebbecd01f57bc3729833e89b39ad99', |
---|
182 | 'dealerdirect/phpcodesniffer-composer-installer:0.4.3', |
---|
183 | ); |
---|
184 | $output = shell_exec( 'composer require ' . implode( ' ', $originalDependences ) ); |
---|
185 | if ( DEBUG_LEVEL ) { |
---|
186 | echo $output; |
---|
187 | } |
---|
188 | |
---|
189 | // Grab the original phpcs.xml.dist, which wasn't included in the firt auto-fixer commit. |
---|
190 | $output = shell_exec( 'git checkout 81a48c2924bb1c1cd8ae5752397766f133950e18 -- phpcs.xml.dist' ); |
---|
191 | if ( DEBUG_LEVEL ) { |
---|
192 | echo $output; |
---|
193 | } |
---|
194 | |
---|
195 | // Run phpcbf on patch files. |
---|
196 | echo "Running code formatter on the patch files.\n"; |
---|
197 | $output = shell_exec( "vendor/bin/phpcbf $fileParams" ); |
---|
198 | if ( DEBUG_LEVEL ) { |
---|
199 | echo $output; |
---|
200 | } |
---|
201 | |
---|
202 | // Remove the PHPCS/composer files that we had to add. |
---|
203 | echo shell_exec( 'git rm -f phpcs.xml.dist' ); |
---|
204 | $output = shell_exec( 'rm composer.json composer.lock' ); |
---|
205 | if ( DEBUG_LEVEL ) { |
---|
206 | echo $output; |
---|
207 | } |
---|
208 | |
---|
209 | // Commit the changed files. |
---|
210 | echo "Committing formatted patch files.\n"; |
---|
211 | $output = shell_exec( "git add $fileParams" ); |
---|
212 | if ( DEBUG_LEVEL ) { |
---|
213 | echo $output; |
---|
214 | } |
---|
215 | $output = shell_exec( 'git commit -m "Apply phpcbf to patch files"' ); |
---|
216 | if ( DEBUG_LEVEL ) { |
---|
217 | echo $output; |
---|
218 | } |
---|
219 | |
---|
220 | foreach ( $fixerCommits as $commit ) { |
---|
221 | // Merge up to the commit before the next fixer commit |
---|
222 | // For merge conflicts, assume ours (with the patch) is correct |
---|
223 | echo "Merging up to the commit before $commit\n"; |
---|
224 | $output = shell_exec( "git merge --strategy-option ours $commit~1 -m 'Merge changes before fixer commit $commit'" ); |
---|
225 | if ( DEBUG_LEVEL > 1 ) { |
---|
226 | echo $output; |
---|
227 | } |
---|
228 | |
---|
229 | $mergeCommit = trim( shell_exec( 'git rev-parse HEAD' ) ); |
---|
230 | |
---|
231 | // Merge the next fixer commit. Assume that we're correct for merge conflicts. |
---|
232 | echo "Merging fixer commit $commit\n"; |
---|
233 | $output = shell_exec( "git merge --strategy-option ours $commit -m 'Merge fixer commit git merge $commit'" ); |
---|
234 | if ( DEBUG_LEVEL > 1 ) { |
---|
235 | echo $output; |
---|
236 | } |
---|
237 | |
---|
238 | // Upgrade composer dependences. |
---|
239 | echo "Upgrading composer dependences\n"; |
---|
240 | shell_exec( 'rm -rf vendor' ); |
---|
241 | $output = shell_exec( 'composer install' ); |
---|
242 | if ( DEBUG_LEVEL ) { |
---|
243 | echo $output; |
---|
244 | } |
---|
245 | |
---|
246 | // Revert the patched files to the previous commit. |
---|
247 | echo "Reverting patch files to previous commit.\n"; |
---|
248 | $output = shell_exec( "git checkout $mergeCommit -- $fileParams" ); |
---|
249 | if ( DEBUG_LEVEL ) { |
---|
250 | echo $output; |
---|
251 | } |
---|
252 | |
---|
253 | // Run phpcbf on patch files. |
---|
254 | echo "Running code formatter on the patch files.\n"; |
---|
255 | $output = shell_exec( "vendor/bin/phpcbf $fileParams" ); |
---|
256 | if ( DEBUG_LEVEL ) { |
---|
257 | echo $output; |
---|
258 | } |
---|
259 | |
---|
260 | // Commit the changed files. |
---|
261 | echo "Committing formatted patch files.\n"; |
---|
262 | $output = shell_exec( "git add $fileParams" ); |
---|
263 | if ( DEBUG_LEVEL ) { |
---|
264 | echo $output; |
---|
265 | } |
---|
266 | $output = shell_exec( 'git commit -m "Apply phpcbf to patch files"' ); |
---|
267 | if ( DEBUG_LEVEL ) { |
---|
268 | echo $output; |
---|
269 | } |
---|
270 | } |
---|
271 | |
---|
272 | // Merge the rest of master. |
---|
273 | echo "Merging the rest of master.\n"; |
---|
274 | $output = shell_exec( 'git merge --strategy-option ours master -m "Merge the rest of master"' ); |
---|
275 | if ( DEBUG_LEVEL > 1 ) { |
---|
276 | echo $output; |
---|
277 | } |
---|
278 | |
---|
279 | // Create patch. |
---|
280 | $output = shell_exec( "git diff master..$ticket > ../working/$ticket-automerged.diff" ); |
---|
281 | if ( DEBUG_LEVEL ) { |
---|
282 | echo $output; |
---|
283 | } |
---|
284 | |
---|
285 | // Delete branch |
---|
286 | if ( ! DEBUG_LEVEL ) { |
---|
287 | shell_exec( 'git checkout master' ); |
---|
288 | shell_exec( "git branch -D $ticket" ); |
---|
289 | } |
---|
290 | |
---|
291 | if ( UPLOAD_PATCH ) { |
---|
292 | $diffContent = base64_encode( file_get_contents( "../working/$ticket-automerged.diff" ) ); |
---|
293 | |
---|
294 | $attachmentRequest = "<?xml version=\"1.0\"? > |
---|
295 | <methodCall> |
---|
296 | <methodName>ticket.putAttachment</methodName> |
---|
297 | <params> |
---|
298 | <param><int>$ticket</int></param> |
---|
299 | <param><string>$ticket.diff</string></param> |
---|
300 | <param><string>Auto-refreshed patch</string></param> |
---|
301 | <param><base64>$diffContent</base64></param> |
---|
302 | <param><boolean>0</boolean></param> |
---|
303 | </params> |
---|
304 | </methodCall>"; |
---|
305 | |
---|
306 | $conn = curl_init( 'https://core.trac.wordpress.org/login/xmlrpc' ); |
---|
307 | |
---|
308 | if ( DEBUG_LEVEL ) { |
---|
309 | curl_setopt( $conn, CURLOPT_VERBOSE, 1 ); |
---|
310 | } |
---|
311 | |
---|
312 | curl_setopt( $conn, CURLOPT_RETURNTRANSFER, 1 ); |
---|
313 | curl_setopt( $conn, CURLOPT_USERAGENT, 'Patch Auto Refresher' ); |
---|
314 | curl_setopt( $conn, CURLOPT_HTTPHEADER, array( 'Content-Type: application/xml; charset=utf-8' ) ); |
---|
315 | curl_setopt( $conn, CURLOPT_POST, 1 ); |
---|
316 | curl_setopt( $conn, CURLOPT_POSTFIELDS, $attachmentRequest ); |
---|
317 | |
---|
318 | curl_setopt( $conn, CURLOPT_USERPWD, WPORG_USER . ':' . WPORG_PASSWORD ); |
---|
319 | |
---|
320 | $response = curl_exec( $conn ); |
---|
321 | if ( DEBUG_LEVEL ) { |
---|
322 | echo $response; |
---|
323 | } |
---|
324 | } |
---|
325 | } |
---|