Commit | Line | Data |
---|---|---|
545fc9df TO |
1 | #!/usr/bin/env php |
2 | <?php | |
3 | ||
4 | // Update the data-files within this repo to reflect a new version number. | |
5 | // Example usage: | |
6 | // git checkout origin/master -b master-4.7.29 | |
7 | // ./tools/bin/scripts/set-version.php 4.7.29 --commit | |
8 | // git commit -m "Update to version 4.7.29" | |
9 | // git push origin master | |
10 | ||
11 | /* *********************************************************************** */ | |
12 | /* Boot */ | |
5c5ed6db | 13 | if (!(php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0))) { |
a9f3bf65 SL |
14 | header("HTTP/1.0 404 Not Found"); |
15 | return; | |
16 | } | |
545fc9df TO |
17 | $civicrm_root = dirname(dirname(dirname(__DIR__))); |
18 | chdir($civicrm_root); | |
19 | ||
20 | /* *********************************************************************** */ | |
21 | /* Parse inputs -- $oldVersion, $newVersion, $doCommit */ | |
22 | ||
23 | $oldVersion = (string) simplexml_load_file("xml/version.xml")->version_no; | |
24 | if (!isVersionValid($oldVersion)) { | |
25 | fatal("failed to read old version from \"xml/version.xml\"\n"); | |
26 | } | |
27 | ||
b43bfb44 TO |
28 | /** @var string $newVersion */ |
29 | /** @var bool $doCommit */ | |
bd9556c5 | 30 | /** @var bool $doSql */ |
b43bfb44 TO |
31 | extract(parseArgs($argv)); |
32 | ||
545fc9df TO |
33 | if (!isVersionValid($newVersion)) { |
34 | fatal("failed to read new version\n"); | |
35 | } | |
36 | ||
545fc9df TO |
37 | /* *********************************************************************** */ |
38 | /* Main */ | |
39 | ||
337dc87a TO |
40 | echo "Changing version from $oldVersion to $newVersion...\n"; |
41 | ||
42 | $verName = makeVerName($newVersion); | |
b7c0a88f | 43 | $phpFile = initFile("CRM/Upgrade/Incremental/php/{$verName}.php", function () use ($verName) { |
337dc87a TO |
44 | ob_start(); |
45 | global $camelNumber; | |
46 | $camelNumber = $verName; | |
47 | require 'CRM/Upgrade/Incremental/php/Template.php'; | |
48 | unset($camelNumber); | |
49 | return ob_get_clean(); | |
50 | }); | |
51 | ||
bd9556c5 TO |
52 | // It is typical for `*.alpha` to need SQL file -- and for `*.beta1` and `*.0` to NOT need a SQL file. |
53 | if ($doSql === TRUE || ($doSql === 'auto' && preg_match(';alpha;', $newVersion))) { | |
54 | $sqlFile = initFile("CRM/Upgrade/Incremental/sql/{$newVersion}.mysql.tpl", function () use ($newVersion) { | |
55 | return "{* file to handle db changes in $newVersion during upgrade *}\n"; | |
56 | }); | |
57 | } | |
545fc9df TO |
58 | |
59 | updateFile("xml/version.xml", function ($content) use ($newVersion, $oldVersion) { | |
60 | return str_replace($oldVersion, $newVersion, $content); | |
61 | }); | |
62 | ||
653b713e C |
63 | if (file_exists("civicrm-version.php")) { |
64 | updateFile("civicrm-version.php", function ($content) use ($newVersion, $oldVersion) { | |
65 | return str_replace($oldVersion, $newVersion, $content); | |
66 | }); | |
67 | } | |
4d4f529c | 68 | |
545fc9df TO |
69 | updateFile("sql/civicrm_generated.mysql", function ($content) use ($newVersion, $oldVersion) { |
70 | return str_replace($oldVersion, $newVersion, $content); | |
71 | }); | |
72 | ||
d071a643 SL |
73 | updateFile("sql/test_data_second_domain.mysql", function ($content) use ($newVersion, $oldVersion) { |
74 | return str_replace($oldVersion, $newVersion, $content); | |
75 | }); | |
76 | ||
a9b847ea TO |
77 | $infoXmls = findCoreInfoXml(); |
78 | foreach ($infoXmls as $infoXml) { | |
68122019 TO |
79 | updateXmlFile($infoXml, function (DOMDocument $dom) use ($newVersion) { |
80 | foreach ($dom->getElementsByTagName('version') as $tag) { | |
81 | /** @var \DOMNode $tag */ | |
82 | $tag->textContent = $newVersion; | |
83 | } | |
84 | }); | |
85 | } | |
86 | ||
545fc9df | 87 | if ($doCommit) { |
bd9556c5 | 88 | $files = array_filter( |
a9b847ea | 89 | array_merge(['xml/version.xml', 'sql/civicrm_generated.mysql', 'sql/test_data_second_domain.mysql', $phpFile, @$sqlFile], $infoXmls), |
bd9556c5 TO |
90 | 'file_exists' |
91 | ); | |
92 | $filesEsc = implode(' ', array_map('escapeshellarg', $files)); | |
93 | passthru("git add $filesEsc"); | |
94 | passthru("git commit $filesEsc -m " . escapeshellarg("Set version to $newVersion")); | |
545fc9df TO |
95 | } |
96 | ||
97 | /* *********************************************************************** */ | |
98 | /* Helper functions */ | |
99 | ||
337dc87a TO |
100 | /** |
101 | * Update the content of a file. | |
102 | * | |
103 | * @param string $file | |
104 | * @param callable $callback | |
105 | * Function(string $originalContent) => string $newContent. | |
106 | */ | |
545fc9df TO |
107 | function updateFile($file, $callback) { |
108 | if (!file_exists($file)) { | |
109 | die("File does not exist: $file\n"); | |
110 | } | |
111 | echo "Update \"$file\"\n"; | |
112 | $content = file_get_contents($file); | |
113 | $content = $callback($content); | |
114 | file_put_contents($file, $content); | |
115 | } | |
116 | ||
68122019 TO |
117 | /** |
118 | * Update the content of an XML file | |
119 | * | |
120 | * @param string $file | |
121 | * @param callable $callback | |
122 | * Function(DOMDocument $dom) | |
123 | */ | |
124 | function updateXmlFile($file, $callback) { | |
125 | updateFile($file, function ($content) use ($callback) { | |
126 | $dom = new DomDocument(); | |
127 | $dom->loadXML($content); | |
128 | $dom->preserveWhiteSpace = FALSE; | |
129 | $dom->formatOutput = TRUE; | |
130 | $callback($dom); | |
131 | return $dom->saveXML(); | |
132 | }); | |
133 | } | |
134 | ||
337dc87a TO |
135 | /** |
136 | * Initialize a file (if it doesn't already exist). | |
137 | * @param string $file | |
138 | * @param callable $callback | |
139 | * Function() => string $newContent. | |
140 | */ | |
141 | function initFile($file, $callback) { | |
142 | if (file_exists($file)) { | |
143 | echo "File \"$file\" already exists.\n"; | |
144 | } | |
145 | else { | |
146 | echo "Initialize \"$file\"\n"; | |
147 | $content = $callback(); | |
148 | file_put_contents($file, $content); | |
149 | } | |
150 | return $file; | |
151 | } | |
152 | ||
153 | /** | |
154 | * Render a pretty string for a major/minor version number. | |
155 | * | |
156 | * @param string $version | |
157 | * Ex: '5.10.alpha1' | |
158 | * @return string | |
159 | * Ex: 'FiveTen'. | |
160 | */ | |
161 | function makeVerName($version) { | |
b43bfb44 | 162 | [$a, $b] = explode('.', $version); |
337dc87a TO |
163 | require_once 'CRM/Utils/EnglishNumber.php'; |
164 | return CRM_Utils_EnglishNumber::toCamelCase($a) . CRM_Utils_EnglishNumber::toCamelCase($b); | |
165 | } | |
166 | ||
545fc9df TO |
167 | function isVersionValid($v) { |
168 | return $v && preg_match('/^[0-9a-z\.\-]+$/', $v); | |
169 | } | |
170 | ||
171 | /** | |
172 | * @param $error | |
173 | */ | |
174 | function fatal($error) { | |
175 | echo $error; | |
bd9556c5 TO |
176 | echo "usage: set-version.php <new-version> [--sql|--no-sql] [--commit|--no-commit]\n"; |
177 | echo " --sql A placeholder *.sql file will be created.\n"; | |
178 | echo " --no-sql A placeholder *.sql file will not be created.\n"; | |
179 | echo " --commit Any changes will be committed automatically the current git branch.\n"; | |
180 | echo " --no-commit Any changes will be left uncommitted.\n"; | |
181 | echo "\n"; | |
182 | echo "If the SQL style is not specified, it will decide automatically. (Alpha versions get SQL files.)\n"; | |
183 | echo "\n"; | |
184 | echo "You MUST indicate whether to commit.\n"; | |
545fc9df TO |
185 | exit(1); |
186 | } | |
b43bfb44 TO |
187 | |
188 | /** | |
189 | * @param array $argv | |
190 | * Ex: ['myscript.php', '--no-commit', '5.6.7'] | |
191 | * @return array | |
192 | * Ex: ['scriptFile' => 'myscript.php', 'doCommit' => FALSE, 'newVersion' => '5.6.7'] | |
193 | */ | |
194 | function parseArgs($argv) { | |
195 | $parsed = []; | |
bd9556c5 | 196 | $parsed['doSql'] = 'auto'; |
b43bfb44 TO |
197 | $positions = ['scriptFile', 'newVersion']; |
198 | $positional = []; | |
199 | ||
200 | foreach ($argv as $arg) { | |
201 | switch ($arg) { | |
202 | case '--commit': | |
203 | $parsed['doCommit'] = TRUE; | |
204 | break; | |
205 | ||
206 | case '--no-commit': | |
207 | $parsed['doCommit'] = FALSE; | |
208 | break; | |
209 | ||
bd9556c5 TO |
210 | case '--sql': |
211 | $parsed['doSql'] = TRUE; | |
212 | break; | |
213 | ||
214 | case '--no-sql': | |
215 | $parsed['doSql'] = FALSE; | |
216 | break; | |
217 | ||
b43bfb44 TO |
218 | default: |
219 | if ($arg[0] !== '-') { | |
220 | $positional[] = $arg; | |
221 | } | |
222 | else { | |
223 | fatal("Unrecognized argument: $arg\n"); | |
224 | } | |
225 | break; | |
226 | } | |
227 | } | |
228 | ||
229 | foreach ($positional as $offset => $value) { | |
230 | $name = $positions[$offset] ?? "unknown_$offset"; | |
231 | $parsed[$name] = $value; | |
232 | } | |
233 | ||
234 | if (!isset($parsed['doCommit'])) { | |
235 | fatal("Must specify --commit or --no-commit\n"); | |
236 | } | |
237 | ||
238 | return $parsed; | |
239 | } | |
68122019 TO |
240 | |
241 | /** | |
242 | * @return array | |
243 | * Ex: ['ext/afform/html/info.xml', 'ext/search_kit/info.xml'] | |
244 | */ | |
245 | function findCoreInfoXml() { | |
246 | $lines = explode("\n", file_get_contents('distmaker/core-ext.txt')); | |
247 | $exts = preg_grep(";^#;", $lines, PREG_GREP_INVERT); | |
248 | $exts = preg_grep(';[a-z-A-Z];', $exts); | |
249 | ||
250 | $infoXmls = []; | |
251 | foreach ($exts as $coreExtDir) { | |
252 | $infoXmls = array_merge($infoXmls, (array) glob("ext/$coreExtDir/*/info.xml")); | |
253 | if (file_exists("ext/$coreExtDir/info.xml")) { | |
254 | $infoXmls[] = "ext/$coreExtDir/info.xml"; | |
255 | } | |
256 | } | |
257 | ||
258 | return $infoXmls; | |
259 | } |