Skip to content

Commit

Permalink
Merge pull request #2 from creative-commoners/pulls/main/merge-ups
Browse files Browse the repository at this point in the history
NEW Add merge-ups
  • Loading branch information
GuySartorelli authored Aug 14, 2023
2 parents 94ace13 + 8ca3e2d commit f70f588
Show file tree
Hide file tree
Showing 12 changed files with 426 additions and 76 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ jobs:
- name: Install PHP
uses: shivammathur/setup-php@1a18b2267f80291a81ca1d33e7c851fe09e7dfc4 # v2.22.0
with:
php-version: 7.4

- name: Install PHPUnit
run: wget https://phar.phpunit.de/phpunit-9.5.phar
php-version: 8.1
- name: Composer install
run: composer install --prefer-dist --no-progress --no-suggest --ansi --no-interaction --no-scripts --no-plugins --optimize-autoloader

- name: PHPUnit
run: php phpunit-9.5.phar --verbose --colors=always
run: vendor/bin/phpunit --verbose --colors=always
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ _tmp
vendor
.phpunit.result.cache
composer.lock
test.php
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ MS_GITHUB_TOKEN=abc123 php run.php update --cms-major=5 --branch=next-minor --dr
| --dry-run | Do not push to github or create pull-requests |
| --account | GitHub account to use for creating pull-requests (default: creative-commoners) |
| --no-delete | Do not delete _data and _modules directories before running |
| --update-prs | Update existing open PRs instead of creating new PRs |

## GitHub API secondary rate limit

Expand Down
7 changes: 4 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"require": {
"php": ">=7.4",
"php": ">=8.1",
"symfony/console": "^6.3",
"symfony/process": "^6.3"
"symfony/process": "^6.3",
"panlatent/cron-expression-descriptor": "^1"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
"phpunit/phpunit": "^9.6"
}
}
92 changes: 87 additions & 5 deletions funcs_scripts.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

use Panlatent\CronExpressionDescriptor\ExpressionDescriptor;

// These functions in scripts can be used in scripts

/**
Expand Down Expand Up @@ -79,6 +81,24 @@ function delete_file_if_exists($filename)
}
}

/**
* Rename a file relative to the root of the module being processed if it exists
*
* Example usage:
* rename_file_if_exists('oldfilename.md', 'newfilename.md')
*/
function rename_file_if_exists($oldFilename, $newFilename)
{
global $MODULE_DIR;
$oldPath = "$MODULE_DIR/$oldFilename";
$newPath = "$MODULE_DIR/$newFilename";
if (file_exists($oldPath)) {
$contents = read_file($oldFilename);
write_file($newPath, $contents);
delete_file_if_exists($oldFilename);
}
}

/**
* Determine if the module being processed is a recipe, including silverstripe-installer
*
Expand All @@ -88,14 +108,30 @@ function delete_file_if_exists($filename)
function module_is_recipe()
{
global $MODULE_DIR;
if (strpos('/recipe-', $MODULE_DIR) !== false
|| strpos('/silverstripe-installer', $MODULE_DIR) !== false
if (strpos($MODULE_DIR, '/recipe-') !== false
|| strpos($MODULE_DIR, '/silverstripe-installer') !== false
) {
return true;
}
return false;
}

/**
* Determine if the module being processed is something installed on a website e.g. silverstripe-admin, not gha-*
*
* Example usage:
* is_module()
*/
function is_module()
{
global $MODULE_DIR;
return strpos($MODULE_DIR, '/gha-') === false
&& strpos($MODULE_DIR, '/developer-docs') === false
&& strpos($MODULE_DIR, '/vendor-plugin') === false
&& strpos($MODULE_DIR, '/eslint-config') === false
&& strpos($MODULE_DIR, '/webpack-config') === false;
}

/**
* Determine if the module being processed is one of the modules in a list
*
Expand All @@ -112,16 +148,31 @@ function module_is_one_of($repos)
if (!is_string($repo)) {
error('repo is not a string');
}
if (strpos("/$repo", $MODULE_DIR) !== false) {
if (strpos($MODULE_DIR, "/$repo") !== false) {
return true;
}
}
return false;
}

/**
* Return the github account of the module being processed
*
* Example usage:
* module_account()
*/
function module_account()
{
$s = read_file('.git/config');
if (!preg_match('#github.com:([^/]+)/#', $s, $matches)) {
error('Could not determine github account');
}
return $matches[1];
}

/**
* Output an info message to the console
*
*
* Example usage:
* info('This is a mildly interesting message')
*/
Expand All @@ -133,11 +184,42 @@ function info($message)

/**
* Output a warning message to the console
*
*
* Example usage:
* warning('This is something you might want to pay attention to')
*/
function warning($message)
{
io()->warning($message);
}

/**
* Converts a cron expression to a human readable string
* Says UTC because that's what GitHub Actions uses
*
* Example usage:
* human_cron('5 4 * * 0')
* => 'At 4:05 AM UTC, only on Sunday'
*/
function human_cron(string $cron): string
{
$str = (new ExpressionDescriptor($cron))->getDescription();
$str = preg_replace('#0([1-9]):#', '$1:', $str);
$str = preg_replace('# (AM|PM),#', ' $1 UTC,', $str);
return $str;
}

/**
* Creates a predicatable random int between 0 and $max based on the module name to be used with the % mod operator.
* $offset variable will offset both the min (0) and $max. e.g. $offset of 1 with a max of 27 will return an int
* between 1 and 28
* Note that this will return the exact same value every time it is called for a given module.
*/
function predictable_random_int($max, $offset = 0): int
{
global $MODULE_DIR;
$chars = str_split($MODULE_DIR);
$codes = array_map(fn($c) => ord($c), $chars);
mt_srand(array_sum($codes));
return mt_rand(0, $max) + $offset;
}
77 changes: 72 additions & 5 deletions funcs_utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function write_file($path, $contents)
}
$dirname = dirname($path);
if (!file_exists($dirname)) {
error("Directory $dirname does not exist");
mkdir($dirname, 0775, true);
}
$contents = trim($contents) . "\n";
file_put_contents($path, $contents);
Expand Down Expand Up @@ -67,12 +67,43 @@ function supported_modules($cmsMajor)
'account' => explode('/', $ghrepo)[0],
'repo' => explode('/', $ghrepo)[1],
'cloneUrl' => "[email protected]:$ghrepo.git",
'branch' => max($module['branches'] ?: [-1])
];
}
return $modules;
}

/**
* Hardcoded list of additional repositories to standardise (e.g. silverstripe/gha-*)
*
* Repositories in this list should only have a single supported major version
* This will only be included if the $cmsMajor is the CURRENT_CMS_MAJOR
*/
function extra_repositories()
{
$modules = [];
// iterating to page 7 should be enough to get all the repos well into the future
for ($i = 0; $i < 7; $i++) {
$json = github_api("https://api.github.com/orgs/silverstripe/repos?per_page=100&page=$i");
foreach ($json as $repo) {
if ($repo['archived']) {
continue;
}
$ghrepo = $repo['full_name'];
// exclude non gha-* repos
if (strpos($ghrepo, '/gha-') === false) {
continue;
}
$modules[] = [
'ghrepo' => $ghrepo,
'account' => explode('/', $ghrepo)[0],
'repo' => explode('/', $ghrepo)[1],
'cloneUrl' => "[email protected]:$ghrepo.git",
];
}
}
return $modules;
}

/**
* Returns a list of all scripts files to run against a particular cms major version
*/
Expand Down Expand Up @@ -169,6 +200,8 @@ function github_token()
*/
function github_api($url, $data = [])
{
// silverstripe-themes has a kind of weird redirect only for api requests
$url = str_replace('/silverstripe-themes/silverstripe-simple', '/silverstripe/silverstripe-simple', $url);
$token = github_token();
$jsonStr = empty($data) ? '' : json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
$ch = curl_init($url);
Expand Down Expand Up @@ -265,12 +298,38 @@ function branch_to_checkout($branches, $currentBranch, $currentBranchCmsMajor, $
return (string) $branchToCheckout;
}

/**
* Uses composer.json to workout the current branch cms major version
*
* If composer.json does not exist then it's assumed to be CURRENT_CMS_MAJOR
*/
function current_branch_cms_major(
// this param is only used for unit testing
string $composerJson = ''
) {
// read __composer.json of the current branch
$contents = $composerJson ?: read_file('composer.json');
global $MODULE_DIR;

if ($composerJson) {
$contents = $composerJson;
} elseif (check_file_exists('composer.json')) {
$contents = read_file('composer.json');
} else {
return CURRENT_CMS_MAJOR;
}

// special logic for developer-docs
if (strpos($MODULE_DIR, '/developer-docs') !== false) {
$currentBranch = cmd('git rev-parse --abbrev-ref HEAD', $MODULE_DIR);
if (!preg_match('#^(pulls/)?([0-9]+)(\.[0-9]+)?(/|$)#', $currentBranch, $matches)) {
error("Could work out current major for developer-docs from branch $currentBranch");
}
return $matches[2];
}

// special logic for silverstripe-themes/silverstripe-simple
if (strpos($MODULE_DIR, '/silverstripe-simple') !== false) {
return CURRENT_CMS_MAJOR;
}

$json = json_decode($contents);
if (is_null($json)) {
Expand All @@ -287,7 +346,15 @@ function current_branch_cms_major(
}
if (!$version) {
$version = preg_replace('#[^0-9\.]#', '', $json->require->{'silverstripe/assets'} ?? '');
$matchedOnBranchThreeLess = true;
if ($version) {
$matchedOnBranchThreeLess = true;
}
}
if (!$version) {
$version = preg_replace('#[^0-9\.]#', '', $json->require->{'cwp/starter-theme'} ?? '');
if ($version) {
$version += 1;
}
}
$cmsMajor = '';
if (preg_match('#^([0-9]+)+\.?[0-9]*$#', $version, $matches)) {
Expand Down
14 changes: 13 additions & 1 deletion run.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,17 @@
InputOption::VALUE_NONE,
'Do not delete _data and _modules directories before running'
)
->addOption(
'update-prs',
null,
InputOption::VALUE_NONE,
'Checkout out and update the latest open PR instead of creating a new one'
)
->setCode($updateCommand);
$app->run();

try {
$app->run();
} catch (Error|Exception $e) {
// Make sure we output and information about PRs which were raised before killing the process.
error("file: {$e->getFile()}\nline: {$e->getLine()}\nmessage: {$e->getMessage()}");
}
4 changes: 3 additions & 1 deletion scripts/cms-any/editorconfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@
insert_final_newline = false
EOT;

write_file_if_not_exist('.editorconfig', $contents);
if (is_module()) {
write_file_if_not_exist('.editorconfig', $contents);
}
23 changes: 21 additions & 2 deletions scripts/cms-any/license.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
$contents = <<<EOT
BSD 3-Clause License
Copyright (c) $year, SilverStripe Limited - www.silverstripe.com
Copyright (c) $year, Silverstripe Limited - www.silverstripe.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -34,4 +34,23 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
EOT;

write_file_if_not_exist('LICENSE', $contents);
// standard filename used on framework, admin, cms, etc
$licenseFilename = 'LICENSE';

// can rename the licence filename on any account
foreach (['LICENSE.md', 'license.md', 'license'] as $filename) {
rename_file_if_exists($filename, $licenseFilename);
}

// only update licence contents if module is on silverstripe account
if (module_account() === 'silverstripe') {
if (file_exists('LICENSE')) {
$oldContents = read_file($licenseFilename);
$newContents = str_replace('SilverStripe', 'Silverstripe', $oldContents);
if ($newContents !== $oldContents) {
write_file_even_if_exists($licenseFilename, $newContents);
}
} else {
write_file_if_not_exist($licenseFilename, $contents);
}
}
Loading

0 comments on commit f70f588

Please sign in to comment.