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

Various fixes required to get supported modules data to be correctly utilised #51

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
89 changes: 74 additions & 15 deletions funcs_scripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ function is_module()
return false;
}

if (is_gha_repository()) {
return false;
}

$contents = read_file('composer.json');
$json = json_decode($contents);
if (is_null($json)) {
Expand All @@ -158,7 +162,7 @@ function is_module()
}

// config isn't technically a Silverstripe CMS module, but we treat it like one.
if ($json->name === 'silverstripe/config') {
if (($json->name ?? '') === 'silverstripe/config') {
return true;
}

Expand Down Expand Up @@ -238,6 +242,7 @@ function is_docs()

/**
* Determine if the module being processed is a gha-* repository e.g. gha-ci
* aka "WORKFLOW"
*
* Example usage:
* is_gha_repository()
Expand All @@ -254,6 +259,56 @@ function is_gha_repository()
);
}

/**
* Determine if the module being processed is "TOOLING"
*
* Example usage:
* is_gha_repository()
*/
function is_tooling()
{
global $GITHUB_REF;
return in_array(
$GITHUB_REF,
array_column(
MetaData::getAllRepositoryMetaData()[MetaData::CATEGORY_TOOLING],
'github'
)
);
}

/**
* Determine if the module being processed is "MISC"
*
* Example usage:
* is_gha_repository()
*/
function is_misc()
{
global $GITHUB_REF;
return in_array(
$GITHUB_REF,
array_column(
MetaData::getAllRepositoryMetaData()[MetaData::CATEGORY_MISC],
'github'
)
);
}

/**
* Determine if the module being processed has a wildcard major version mapping
* in silverstripe/supported-modules repositories.json
*
* Example usage:
* has_wildcard_major_version_mapping()
*/
function has_wildcard_major_version_mapping()
{
global $GITHUB_REF;
$repoData = MetaData::getMetaDataForRepository($GITHUB_REF);
return array_key_exists('*', $repoData['majorVersionMapping']);
GuySartorelli marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Return the module name without the account e.g. silverstripe/silverstripe-admin with return silverstripe-admin
*
Expand Down Expand Up @@ -350,21 +405,25 @@ function human_cron(string $cron): string
* between 1 and 28
* Note that this will return the exact same value every time it is called for a given filename in a given module
*/
function predictable_random_int($max, $offset = 0): int
function predictable_random_int($scriptName, $max, $offset = 0): int
{
$chars = str_split(module_name() . $scriptName);
$codes = array_map(fn($c) => ord($c), $chars);
$sum = array_sum($codes);
$remainder = $sum % ($max + 1);
return $remainder + $offset;
}

/**
* Determine if the current branch is either 1 or 1.2 numeric style
* Can also be pulls/<number>/... style
*/
function current_branch_name_is_numeric_style()
{
global $MODULE_DIR;
$callingFile = debug_backtrace()[0]['file'];
// remove absolute path e.g. /home/myuser/...
$moduleStandardiserDir = basename(__DIR__);
$dirQuoted = preg_quote($moduleStandardiserDir);
// double $dirQuoted is for github actions CI where there which will have a directory strcture
// with /module-standardiser/module-standardiser/...
if (!preg_match("#/$dirQuoted/$dirQuoted/(.+)$#", $callingFile, $matches)) {
preg_match("#/$dirQuoted/(.+)$#", $callingFile, $matches);
$currentBranch = cmd('git rev-parse --abbrev-ref HEAD', $MODULE_DIR);
if (preg_match('#^(pulls/)?([0-9]+)(\.[0-9]+)?(/|$)#', $currentBranch)) {
return true;
}
GuySartorelli marked this conversation as resolved.
Show resolved Hide resolved
$relativePath = $matches[1];
$chars = str_split("$MODULE_DIR-$relativePath");
$codes = array_map(fn($c) => ord($c), $chars);
mt_srand(array_sum($codes));
return mt_rand(0, $max) + $offset;
return false;
}
3 changes: 2 additions & 1 deletion funcs_utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,13 +287,14 @@ function current_branch_cms_major(
return MetaData::HIGHEST_STABLE_CMS_MAJOR;
}

$contents = '';
if ($composerJson) {
$contents = $composerJson;
} elseif (check_file_exists('composer.json')) {
$contents = read_file('composer.json');
}
$composerJson = json_decode($contents);
if (is_null($composerJson)) {
if (is_null($composerJson) && check_file_exists('composer.json')) {
$lastError = json_last_error();
error("Could not parse from composer.json - last error was $lastError");
}
Expand Down
10 changes: 7 additions & 3 deletions scripts/cms-any/dispatch-ci.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?php

// run on two consecutive days of the week
$dayOfWeek = predictable_random_int(6);
$dayOfWeek = predictable_random_int('dispatch-ci', 6);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use basename(__FILE__) instead, saves having the same magic string multiple times. Change all of these if you change any.
Doesn't ultimately matter though so I won't hold up merging if you leave these as they are.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already tried that, it doesn't work due to the use of eval()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yikes.... we should probably not be using eval but I guess that's something for a separate card.
I guess we just have to hope we don't forget and add code relying on basename in another script or during refactoring in the future.

Copy link
Member Author

@emteknetnz emteknetnz May 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basname() isn't the problem, the problem is __FILE__ will be the file with eval() in it, rather than the script file

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, pretend I said __FILE__ then, my remark still stands. :p
Nothing to change in this PR, just something we'll have to watch out for in the future.

$nextDayOfWeek = $dayOfWeek === 6 ? 0 : $dayOfWeek + 1;
$runsOnDaysOfWeek = sprintf('%s,%s', $dayOfWeek, $nextDayOfWeek);
// run at a random hour of the day
$runOnHour = predictable_random_int(23);
$runOnHour = predictable_random_int('dispatch-ci', 23);
// run at a random minute of the hour rounded to 5 minutes
$runOnMinute = predictable_random_int(11) * 5;
$runOnMinute = predictable_random_int('dispatch-ci', 11) * 5;

$cron = "$runOnMinute $runOnHour * * $runsOnDaysOfWeek";
$humanCron = human_cron($cron);
Expand Down Expand Up @@ -40,6 +40,10 @@
$dispatchCiPath = '.github/workflows/dispatch-ci.yml';
$ciPath = '.github/workflows/ci.yml';
$shouldHaveDispatchCi = (is_module() || is_composer_plugin()) && !is_docs() && !is_gha_repository();
// If module non has_wildcard_major_version_mapping then dispatch-ci.yml should always be present
if (!has_wildcard_major_version_mapping()) {
$shouldHaveDispatchCi = true;
}

if ($shouldHaveDispatchCi) {
if (check_file_exists($ciPath)) {
Expand Down
6 changes: 3 additions & 3 deletions scripts/cms-any/keepalive.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?php

// run on a day of the month up to the 28th
$runOnDay = predictable_random_int(27, 1);
$runOnDay = predictable_random_int('keepalive', 27, 1);
// run at a random hour of the day
$runOnHour = predictable_random_int(23);
$runOnHour = predictable_random_int('keepalive', 23);
// run at a random minute of the hour rounded to 5 minutes
$runOnMinute = predictable_random_int(11) * 5;
$runOnMinute = predictable_random_int('keepalive', 11) * 5;

$cron = "$runOnMinute $runOnHour $runOnDay * *";
$humanCron = human_cron($cron);
Expand Down
13 changes: 8 additions & 5 deletions scripts/cms-any/merge-ups.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?php

// run on a random day of the week
$runOnDay = predictable_random_int(6);
$runOnDay = predictable_random_int('merge-ups', 6);
// run at a random hour of the day
$runOnHour = predictable_random_int(23);
$runOnHour = predictable_random_int('merge-ups', 23);
// run at a random minute of the hour rounded to 5 minutes
$runOnMinute = predictable_random_int(11) * 5;
$runOnMinute = predictable_random_int('merge-ups', 11) * 5;

// If there's a CI workflow, offset mergeups from the CI run by 3 days
if (check_file_exists('.github/workflows/dispatch-ci.yml')) {
Expand Down Expand Up @@ -59,6 +59,9 @@
rename_file_if_exists('.github/workflows/merge-ups.yml', '.github/workflows/merge-up.yml');
}

if (!module_is_recipe() && !is_meta_repo()) {
write_file_even_if_exists('.github/workflows/merge-up.yml', $content);
if (current_branch_name_is_numeric_style() && !module_is_recipe()) {
write_file_even_if_exists('.github/workflows/merge-up.yml', $content);
} else {
// remove any merge-up.yml that was previously added though shouldn't be there
delete_file_if_exists('.github/workflows/merge-up.yml');
}
6 changes: 3 additions & 3 deletions scripts/cms-any/update-js.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
$account = module_account();

// run at a random hour of the day
$runOnHour = predictable_random_int(23);
$runOnHour = predictable_random_int('update-js', 23);
// run at a random minute of the hour rounded to 5 minutes
$runOnMinute = predictable_random_int(11) * 5;
$runOnMinute = predictable_random_int('update-js', 11) * 5;
// run on a 1st of the month
$runOnDay = 1;

Expand Down Expand Up @@ -34,6 +34,6 @@
uses: silverstripe/gha-update-js@v1
EOT;

if (check_file_exists('package.json')) {
if (check_file_exists('package.json') && check_file_exists('yarn.lock')) {
write_file_even_if_exists('.github/workflows/update-js.yml', $content);
}
2 changes: 1 addition & 1 deletion scripts/cms5/phpstan.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

// Only valid for non-theme modules
if (!is_module() || is_theme() || module_is_recipe()) {
if (!is_module() || is_theme() || module_is_recipe() || is_tooling()) {
GuySartorelli marked this conversation as resolved.
Show resolved Hide resolved
return;
}

Expand Down
25 changes: 13 additions & 12 deletions tests/FuncsScriptsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ class FuncsScriptsTest extends TestCase
{
public function testPredictableRandomInt()
{
global $MODULE_DIR;
$MODULE_DIR = 'lorem';
$this->assertSame(0, predictable_random_int(15));
$this->assertSame(25, predictable_random_int(30));
$this->assertSame(45, predictable_random_int(30, 20));
$MODULE_DIR = 'donuts';
$this->assertSame(13, predictable_random_int(15));
// use eval to simulate calling from a different file
// it will suffix "(19) : eval()'d code" to the calling file in debug_backtrace()
$ret = null;
eval('$ret = predictable_random_int(15);');
$this->assertSame(2, $ret);
global $GITHUB_REF;
// set $GITHUB_REF because by module_name() which is used by predictable_random_int()
$GITHUB_REF = 'myaccount/lorem';
$this->assertSame(1, predictable_random_int('test-script', 15));
// Setting a higher max does more than just add to the result, it's somewhat random
$this->assertSame(23, predictable_random_int('test-script', 30));
// Setting an offset simply adds to the result of the same max as above
$this->assertSame(43, predictable_random_int('test-script', 30, 20));
// Changing $GITHUB_REF will change the result
$GITHUB_REF = 'myaccount/donuts';
$this->assertSame(15, predictable_random_int('test-script', 15));
// Changing the script name will change the result
$this->assertSame(6, predictable_random_int('different-script', 15));
}
}
16 changes: 10 additions & 6 deletions update_command.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
$cloneUrl = $module['cloneUrl'];
$MODULE_DIR = MODULES_DIR . "/$repo";
$GITHUB_REF = "$account/$repo";

// clone repo
// always clone the actual remote even when doing update-prs even though this is slower
// reason is because we read origin in .git/config to workout the actual $account in
Expand All @@ -65,14 +66,16 @@
}
cmd("git remote add pr-remote $prOrigin", $MODULE_DIR);

$useDefaultBranch = has_wildcard_major_version_mapping();

if ($input->getOption('update-prs')) {
// checkout latest existing pr branch
cmd('git fetch pr-remote', $MODULE_DIR);
$allBranches = explode("\n", cmd('git branch -r', $MODULE_DIR));
// example branch name: pulls/5/module-standardiser-1691550112
$allBranches = array_map('trim', $allBranches);
$allBranches = array_filter($allBranches, function($branch) {
return preg_match('#^pr\-remote/pulls/[0-9\.]+/module\-standardiser\-[0-9]{10}$#', $branch);
return preg_match('#^pr\-remote/pulls/.+?/module\-standardiser\-[0-9]{10}$#', $branch);
});
if (empty($allBranches)) {
warning("Could not find an existing PR branch for $repo - skipping");
Expand Down Expand Up @@ -107,11 +110,12 @@
$defaultBranch = cmd($cmd, $MODULE_DIR);
cmd("git checkout $defaultBranch", $MODULE_DIR);

if (is_meta_repo()) {
$branchToCheckout = $allBranches[0];
$currentBranch = cmd('git rev-parse --abbrev-ref HEAD', $MODULE_DIR);

// checkout the branch to run scripts over
if ($useDefaultBranch) {
$branchToCheckout = $currentBranch;
} else {
// checkout the branch to run scripts over
$currentBranch = cmd('git rev-parse --abbrev-ref HEAD', $MODULE_DIR);
// ensure that we're on a standard next-minor style branch
if (!ctype_digit($currentBranch)) {
$tmp = array_filter($allBranches, fn($branch) => ctype_digit($branch));
Expand All @@ -138,7 +142,7 @@
cmd("git checkout $branchToCheckout", $MODULE_DIR);

// ensure that this branch actually supports the cmsMajor we're targetting
if ($branchOption !== 'github-default' && current_branch_cms_major() !== $cmsMajor) {
if (!$useDefaultBranch && $branchOption !== 'github-default' && current_branch_cms_major() !== $cmsMajor) {
error("Branch $branchToCheckout does not support CMS major version $cmsMajor");
}

Expand Down
Loading