4 // Update the data-files within this repo to reflect a new version number.
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
11 /* *********************************************************************** */
13 if (!(php_sapi_name() == 'cli' ||
(is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0))) {
14 header("HTTP/1.0 404 Not Found");
17 $civicrm_root = dirname(dirname(dirname(__DIR__
)));
20 /* *********************************************************************** */
21 /* Parse inputs -- $oldVersion, $newVersion, $doCommit */
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");
28 /** @var string $newVersion */
29 /** @var bool $doCommit */
30 /** @var bool $doSql */
31 extract(parseArgs($argv));
33 if (!isVersionValid($newVersion)) {
34 fatal("failed to read new version\n");
37 /* *********************************************************************** */
40 echo "Changing version from $oldVersion to $newVersion...\n";
42 $verName = makeVerName($newVersion);
43 $phpFile = initFile("CRM/Upgrade/Incremental/php/{$verName}.php", function () use ($verName) {
46 $camelNumber = $verName;
47 require 'CRM/Upgrade/Incremental/php/Template.php';
49 return ob_get_clean();
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";
59 updateFile("xml/version.xml", function ($content) use ($newVersion, $oldVersion) {
60 return str_replace($oldVersion, $newVersion, $content);
63 if (file_exists("civicrm-version.php")) {
64 updateFile("civicrm-version.php", function ($content) use ($newVersion, $oldVersion) {
65 return str_replace($oldVersion, $newVersion, $content);
69 updateFile("sql/civicrm_generated.mysql", function ($content) use ($newVersion, $oldVersion) {
70 return str_replace($oldVersion, $newVersion, $content);
73 updateFile("sql/test_data_second_domain.mysql", function ($content) use ($newVersion, $oldVersion) {
74 return str_replace($oldVersion, $newVersion, $content);
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;
87 $files = array_filter(
88 ['xml/version.xml', 'sql/civicrm_generated.mysql', 'sql/test_data_second_domain.mysql', $phpFile, @$sqlFile],
91 $filesEsc = implode(' ', array_map('escapeshellarg', $files));
92 passthru("git add $filesEsc");
93 passthru("git commit $filesEsc -m " . escapeshellarg("Set version to $newVersion"));
96 /* *********************************************************************** */
97 /* Helper functions */
100 * Update the content of a file.
102 * @param string $file
103 * @param callable $callback
104 * Function(string $originalContent) => string $newContent.
106 function updateFile($file, $callback) {
107 if (!file_exists($file)) {
108 die("File does not exist: $file\n");
110 echo "Update \"$file\"\n";
111 $content = file_get_contents($file);
112 $content = $callback($content);
113 file_put_contents($file, $content);
117 * Update the content of an XML file
119 * @param string $file
120 * @param callable $callback
121 * Function(DOMDocument $dom)
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;
130 return $dom->saveXML();
135 * Initialize a file (if it doesn't already exist).
136 * @param string $file
137 * @param callable $callback
138 * Function() => string $newContent.
140 function initFile($file, $callback) {
141 if (file_exists($file)) {
142 echo "File \"$file\" already exists.\n";
145 echo "Initialize \"$file\"\n";
146 $content = $callback();
147 file_put_contents($file, $content);
153 * Render a pretty string for a major/minor version number.
155 * @param string $version
160 function makeVerName($version) {
161 [$a, $b] = explode('.', $version);
162 require_once 'CRM/Utils/EnglishNumber.php';
163 return CRM_Utils_EnglishNumber
::toCamelCase($a) . CRM_Utils_EnglishNumber
::toCamelCase($b);
166 function isVersionValid($v) {
167 return $v && preg_match('/^[0-9a-z\.\-]+$/', $v);
173 function fatal($error) {
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";
181 echo "If the SQL style is not specified, it will decide automatically. (Alpha versions get SQL files.)\n";
183 echo "You MUST indicate whether to commit.\n";
189 * Ex: ['myscript.php', '--no-commit', '5.6.7']
191 * Ex: ['scriptFile' => 'myscript.php', 'doCommit' => FALSE, 'newVersion' => '5.6.7']
193 function parseArgs($argv) {
195 $parsed['doSql'] = 'auto';
196 $positions = ['scriptFile', 'newVersion'];
199 foreach ($argv as $arg) {
202 $parsed['doCommit'] = TRUE;
206 $parsed['doCommit'] = FALSE;
210 $parsed['doSql'] = TRUE;
214 $parsed['doSql'] = FALSE;
218 if ($arg[0] !== '-') {
219 $positional[] = $arg;
222 fatal("Unrecognized argument: $arg\n");
228 foreach ($positional as $offset => $value) {
229 $name = $positions[$offset] ??
"unknown_$offset";
230 $parsed[$name] = $value;
233 if (!isset($parsed['doCommit'])) {
234 fatal("Must specify --commit or --no-commit\n");
242 * Ex: ['ext/afform/html/info.xml', 'ext/search_kit/info.xml']
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);
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";