Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEW Add merge-ups #2

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(
GuySartorelli marked this conversation as resolved.
Show resolved Hide resolved
// 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()}");
GuySartorelli marked this conversation as resolved.
Show resolved Hide resolved
}
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