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 | ||
68122019 TO |
77 | foreach (findCoreInfoXml() as $infoXml) { |
78 | updateXmlFile($infoXml, function (DOMDocument $dom) use ($newVersion) { | |
79 | foreach ($dom->getElementsByTagName('version') as $tag) { | |
80 | /** @var \DOMNode $tag */ | |
81 | $tag->textContent = $newVersion; | |
82 | } | |
83 | }); | |
84 | } | |
85 | ||
545fc9df | 86 | if ($doCommit) { |
bd9556c5 TO |
87 | $files = array_filter( |
88 | ['xml/version.xml', 'sql/civicrm_generated.mysql', 'sql/test_data_second_domain.mysql', $phpFile, @$sqlFile], | |
89 | 'file_exists' | |
90 | ); | |
91 | $filesEsc = implode(' ', array_map('escapeshellarg', $files)); | |
92 | passthru("git add $filesEsc"); | |
93 | passthru("git commit $filesEsc -m " . escapeshellarg("Set version to $newVersion")); | |
545fc9df TO |
94 | } |
95 | ||
96 | /* *********************************************************************** */ | |
97 | /* Helper functions */ | |
98 | ||
337dc87a TO |
99 | /** |
100 | * Update the content of a file. | |
101 | * | |
102 | * @param string $file | |
103 | * @param callable $callback | |
104 | * Function(string $originalContent) => string $newContent. | |
105 | */ | |
545fc9df TO |
106 | function updateFile($file, $callback) { |
107 | if (!file_exists($file)) { | |
108 | die("File does not exist: $file\n"); | |
109 | } | |
110 | echo "Update \"$file\"\n"; | |
111 | $content = file_get_contents($file); | |
112 | $content = $callback($content); | |
113 | file_put_contents($file, $content); | |
114 | } | |
115 | ||
68122019 TO |
116 | /** |
117 | * Update the content of an XML file | |
118 | * | |
119 | * @param string $file | |
120 | * @param callable $callback | |
121 | * Function(DOMDocument $dom) | |
122 | */ | |
123 | function updateXmlFile($file, $callback) { | |
124 | updateFile($file, function ($content) use ($callback) { | |
125 | $dom = new DomDocument(); | |
126 | $dom->loadXML($content); | |
127 | $dom->preserveWhiteSpace = FALSE; | |
128 | $dom->formatOutput = TRUE; | |
129 | $callback($dom); | |
130 | return $dom->saveXML(); | |
131 | }); | |
132 | } | |
133 | ||
337dc87a TO |
134 | /** |
135 | * Initialize a file (if it doesn't already exist). | |
136 | * @param string $file | |
137 | * @param callable $callback | |
138 | * Function() => string $newContent. | |
139 | */ | |
140 | function initFile($file, $callback) { | |
141 | if (file_exists($file)) { | |
142 | echo "File \"$file\" already exists.\n"; | |
143 | } | |
144 | else { | |
145 | echo "Initialize \"$file\"\n"; | |
146 | $content = $callback(); | |
147 | file_put_contents($file, $content); | |
148 | } | |
149 | return $file; | |
150 | } | |
151 | ||
152 | /** | |
153 | * Render a pretty string for a major/minor version number. | |
154 | * | |
155 | * @param string $version | |
156 | * Ex: '5.10.alpha1' | |
157 | * @return string | |
158 | * Ex: 'FiveTen'. | |
159 | */ | |
160 | function makeVerName($version) { | |
b43bfb44 | 161 | [$a, $b] = explode('.', $version); |
337dc87a TO |
162 | require_once 'CRM/Utils/EnglishNumber.php'; |
163 | return CRM_Utils_EnglishNumber::toCamelCase($a) . CRM_Utils_EnglishNumber::toCamelCase($b); | |
164 | } | |
165 | ||
545fc9df TO |
166 | function isVersionValid($v) { |
167 | return $v && preg_match('/^[0-9a-z\.\-]+$/', $v); | |
168 | } | |
169 | ||
170 | /** | |
171 | * @param $error | |
172 | */ | |
173 | function fatal($error) { | |
174 | echo $error; | |
bd9556c5 TO |
175 | echo "usage: set-version.php <new-version> [--sql|--no-sql] [--commit|--no-commit]\n"; |
176 | echo " --sql A placeholder *.sql file will be created.\n"; | |
177 | echo " --no-sql A placeholder *.sql file will not be created.\n"; | |
178 | echo " --commit Any changes will be committed automatically the current git branch.\n"; | |
179 | echo " --no-commit Any changes will be left uncommitted.\n"; | |
180 | echo "\n"; | |
181 | echo "If the SQL style is not specified, it will decide automatically. (Alpha versions get SQL files.)\n"; | |
182 | echo "\n"; | |
183 | echo "You MUST indicate whether to commit.\n"; | |
545fc9df TO |
184 | exit(1); |
185 | } | |
b43bfb44 TO |
186 | |
187 | /** | |
188 | * @param array $argv | |
189 | * Ex: ['myscript.php', '--no-commit', '5.6.7'] | |
190 | * @return array | |
191 | * Ex: ['scriptFile' => 'myscript.php', 'doCommit' => FALSE, 'newVersion' => '5.6.7'] | |
192 | */ | |
193 | function parseArgs($argv) { | |
194 | $parsed = []; | |
bd9556c5 | 195 | $parsed['doSql'] = 'auto'; |
b43bfb44 TO |
196 | $positions = ['scriptFile', 'newVersion']; |
197 | $positional = []; | |
198 | ||
199 | foreach ($argv as $arg) { | |
200 | switch ($arg) { | |
201 | case '--commit': | |
202 | $parsed['doCommit'] = TRUE; | |
203 | break; | |
204 | ||
205 | case '--no-commit': | |
206 | $parsed['doCommit'] = FALSE; | |
207 | break; | |
208 | ||
bd9556c5 TO |
209 | case '--sql': |
210 | $parsed['doSql'] = TRUE; | |
211 | break; | |
212 | ||
213 | case '--no-sql': | |
214 | $parsed['doSql'] = FALSE; | |
215 | break; | |
216 | ||
b43bfb44 TO |
217 | default: |
218 | if ($arg[0] !== '-') { | |
219 | $positional[] = $arg; | |
220 | } | |
221 | else { | |
222 | fatal("Unrecognized argument: $arg\n"); | |
223 | } | |
224 | break; | |
225 | } | |
226 | } | |
227 | ||
228 | foreach ($positional as $offset => $value) { | |
229 | $name = $positions[$offset] ?? "unknown_$offset"; | |
230 | $parsed[$name] = $value; | |
231 | } | |
232 | ||
233 | if (!isset($parsed['doCommit'])) { | |
234 | fatal("Must specify --commit or --no-commit\n"); | |
235 | } | |
236 | ||
237 | return $parsed; | |
238 | } | |
68122019 TO |
239 | |
240 | /** | |
241 | * @return array | |
242 | * Ex: ['ext/afform/html/info.xml', 'ext/search_kit/info.xml'] | |
243 | */ | |
244 | function findCoreInfoXml() { | |
245 | $lines = explode("\n", file_get_contents('distmaker/core-ext.txt')); | |
246 | $exts = preg_grep(";^#;", $lines, PREG_GREP_INVERT); | |
247 | $exts = preg_grep(';[a-z-A-Z];', $exts); | |
248 | ||
249 | $infoXmls = []; | |
250 | foreach ($exts as $coreExtDir) { | |
251 | $infoXmls = array_merge($infoXmls, (array) glob("ext/$coreExtDir/*/info.xml")); | |
252 | if (file_exists("ext/$coreExtDir/info.xml")) { | |
253 | $infoXmls[] = "ext/$coreExtDir/info.xml"; | |
254 | } | |
255 | } | |
256 | ||
257 | return $infoXmls; | |
258 | } |