release 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #!/usr/bin/env php
  2. <?php
  3. /**
  4. * Usage:
  5. *
  6. * ./vendor/bin/release VERSION
  7. */
  8. $semverRegEx = '(?<version>[0-9]+\.[0-9]+\.[0-9]+)(?<prerelease>-[0-9a-zA-Z.]+)?(?<build>\+[0-9a-zA-Z.]*)?';
  9. $optind = null;
  10. $options = getopt ("dvy", [
  11. 'pattern:',
  12. 'simulate',
  13. 'yes',
  14. ], $optind) + [
  15. 'pattern' => "^SEMVER$",
  16. ];
  17. $simulate = array_key_exists('simulate', $options);
  18. $yes = array_key_exists('yes', $options) || array_key_exists('y', $options);
  19. $pos_args = array_slice($argv, $optind);
  20. $path = array_shift($pos_args);
  21. if (empty($path)) {
  22. print "Path to version file must be specified as a commandline argument\n";
  23. exit(1);
  24. }
  25. if (!file_exists($path)) {
  26. print "Version file not found at $path\n";
  27. exit(1);
  28. }
  29. // The --pattern option is expected to contain the string SEMVER
  30. $regex = str_replace('SEMVER', "$semverRegEx", $options['pattern']);
  31. if ($regex == $options['pattern']) {
  32. print "Pattern '$regex' must contain the string 'SEMVER'.\n";
  33. exit(1);
  34. }
  35. // Read the contents of the version file and find the version string
  36. $contents = file_get_contents($path);
  37. if (!preg_match("#$regex#m", $contents, $matches)) {
  38. print "A semver version not found in $path\n";
  39. exit(1);
  40. }
  41. $matches += ['prerelease' => '', 'build' => ''];
  42. // Calculate the stable and next version strings
  43. $original_version_match = $matches[0];
  44. $original_version = $matches['version'] . $matches['prerelease'] . $matches['build'];
  45. $stable_version = $matches['version'] . (has_prerelease($matches) ? $matches['prerelease'] : '');
  46. $next_version = next_version($matches);
  47. $stable_version_replacement = str_replace($original_version, $stable_version, $original_version_match);
  48. $next_version_replacement = str_replace($original_version, $next_version, $original_version_match);
  49. $stable_version_contents = str_replace($original_version_match, $stable_version_replacement, $contents);
  50. $next_version_contents = str_replace($original_version_match, $next_version_replacement, $contents);
  51. $composerContents = file_get_contents('composer.json');
  52. $composerData = json_decode($composerContents, true);
  53. $project = $composerData['name'];
  54. $msg = "Release $project version $stable_version";
  55. $dashes = str_pad('', strlen($msg) + 8, '-', STR_PAD_LEFT);
  56. print "\n$dashes\n\n";
  57. print " $msg\n";
  58. print "\n$dashes\n\n";
  59. // Write the stable version into the version file, tag and push the release
  60. if (!$simulate) {
  61. file_put_contents($path, $stable_version_contents);
  62. }
  63. else {
  64. print "Replace stable version in $path:\n> $stable_version_replacement\n";
  65. }
  66. run('git add {path}', ['{path}' => $path], $simulate);
  67. run('git commit -m "Version {version}"', ['{version}' => $stable_version], $simulate);
  68. run('git tag {version}', ['{version}' => $stable_version], $simulate);
  69. run('git push origin {version}', ['{version}' => $stable_version], $simulate);
  70. // Put the next version into the version file and push the result back to master
  71. if (!$simulate) {
  72. file_put_contents($path, $next_version_contents);
  73. }
  74. else {
  75. print "Replace next version in $path:\n> $next_version_replacement\n";
  76. }
  77. run('git add {path}', ['{path}' => $path], $simulate);
  78. run('git commit -m "[ci skip] Back to {version}"', ['{version}' => $next_version], $simulate);
  79. run('git push origin master', [], $simulate);
  80. exit(0);
  81. /**
  82. * inflect replaces the placeholders in the command with the provided parameter values
  83. * @param string $cmd
  84. * @param array $parameters
  85. * @return string
  86. */
  87. function inflect($cmd, $parameters = [])
  88. {
  89. if (!empty($parameters)) {
  90. return str_replace(array_keys($parameters), array_values($parameters), $cmd);
  91. }
  92. return $cmd;
  93. }
  94. /**
  95. * Run the specified command. Abort most rudely if an error is encountered
  96. */
  97. function run($cmd, $parameters = [], $simulate = false)
  98. {
  99. $cmd = inflect($cmd, $parameters);
  100. if ($simulate) {
  101. print "$cmd\n";
  102. return;
  103. }
  104. passthru($cmd, $status);
  105. if ($status) {
  106. exit($status);
  107. }
  108. }
  109. /**
  110. * Determine the next version after the current release
  111. */
  112. function next_version($matches)
  113. {
  114. $version = $matches['version'];
  115. $next_version = next_version_prerelease($matches);
  116. if ($next_version !== false) {
  117. return $next_version;
  118. }
  119. return next_version_stable($matches);
  120. }
  121. /**
  122. * Determine the next version given that the current version is stable
  123. */
  124. function next_version_stable($matches)
  125. {
  126. $version_parts = explode('.', $matches['version']);
  127. $last_version = array_pop($version_parts);
  128. $last_version++;
  129. $version_parts[] = $last_version;
  130. return implode('.', $version_parts) . (empty($matches['prerelease']) ? '-dev' : $matches['prerelease']);
  131. }
  132. function has_prerelease($matches)
  133. {
  134. if (empty($matches['prerelease'])) {
  135. return false;
  136. }
  137. return is_numeric(substr($matches['prerelease'], -1));
  138. }
  139. /**
  140. * Determine the next version given that the current version has a pre-release
  141. * (e.g. '-alpha5').
  142. */
  143. function next_version_prerelease($version_parts)
  144. {
  145. if (!preg_match('#(.*?)([0-9]+)$#', $version_parts['prerelease'], $matches)) {
  146. return false;
  147. }
  148. $next = $matches[2] + 1;
  149. return $version_parts['version'] . $matches[1] . $next . '+dev';
  150. }