Skip to content

Commit

Permalink
NEW Update rulesets
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed May 22, 2024
1 parent b8961f2 commit dedb140
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 1 deletion.
41 changes: 40 additions & 1 deletion funcs_utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ function github_api($url, $data = [], $httpMethod = '')
{
// silverstripe-themes has a kind of weird redirect only for api requests
$url = str_replace('/silverstripe-themes/silverstripe-simple', '/silverstripe/silverstripe-simple', $url);
info("Making curl request to $url");
$method = $httpMethod ? strtoupper($httpMethod) : 'GET';
info("Making $method curl request to $url");
$token = github_token();
$jsonStr = empty($data) ? '' : json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
$ch = curl_init($url);
Expand Down Expand Up @@ -244,6 +245,44 @@ function output_repos_with_labels_updated()
$io->writeln('');
}

/**
* Outputs a list of repos that that had rulesets updated
* If there was an error with a run (probably a secondary rate limit), this can be
* copy pasted into the --exclude option for the next run to continue from where you left off
*/
function output_repos_with_rulesets_created_or_updated()
{
if (running_unit_tests()) {
return;
}
global $REPOS_WITH_RULESETS_UPDATED;
$io = io();
$io->writeln('');
$io->writeln('Repos with rulesets created/updated (add to --exclude if you need to re-run):');
$io->writeln(implode(',', $REPOS_WITH_RULESETS_UPDATED));
$io->writeln('');
}

function create_ruleset($type, $additionalBranchConditions = [])
{
$ruleset = file_get_contents("rulesets/$type-ruleset.json");
if (!$ruleset) {
error("Could not read ruleset for $type");
}
$json = json_decode($ruleset, true);
if ($type == 'branch') {
$json['name'] = BRANCH_RULESET_NAME;
} elseif ($type === 'tag') {
$json['name'] = TAG_RULESET_NAME;
} else {
error("Invalid ruleset type: $type");
}
foreach ($additionalBranchConditions as $value) {
$json['conditions']['ref_name']['include'][] = $value;
}
return $json;
}

/**
* Works out which branch in a module to checkout before running scripts on it
*
Expand Down
44 changes: 44 additions & 0 deletions rulesets/branch-ruleset.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "<RULESET_NAME>",
"target": "branch",
"enforcement": "active",
"conditions": {
"ref_name": {
"exclude": [],
"include": [
"refs/heads/[0-9]*"
]
}
},
"rules": [
{
"type": "deletion"
},
{
"type": "non_fast_forward"
},
{
"type": "creation"
},
{
"type": "update"
},
{
"type": "pull_request",
"parameters": {
"required_approving_review_count": 2,
"dismiss_stale_reviews_on_push": true,
"require_code_owner_review": false,
"require_last_push_approval": true,
"required_review_thread_resolution": false
}
}
],
"bypass_actors": [
{
"actor_id": 5,
"actor_type": "RepositoryRole",
"bypass_mode": "always"
}
]
}
34 changes: 34 additions & 0 deletions rulesets/tag-ruleset.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "<RULESET_NAME>",
"target": "tag",
"enforcement": "active",
"conditions": {
"ref_name": {
"exclude": [],
"include": [
"~ALL"
]
}
},
"rules": [
{
"type": "deletion"
},
{
"type": "non_fast_forward"
},
{
"type": "creation"
},
{
"type": "update"
}
],
"bypass_actors": [
{
"actor_id": 5,
"actor_type": "RepositoryRole",
"bypass_mode": "always"
}
]
}
104 changes: 104 additions & 0 deletions rulesets_command.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

use SilverStripe\SupportedModules\MetaData;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command;

$rulesetsCommand = function(InputInterface $input, OutputInterface $output): int {
// This is the code that is executed when running the 'rulesets' command

// Variables
global $OUT, $REPOS_WITH_RULESETS_UPDATED;
$OUT = $output;

// Validate system is ready
validate_system();

// Modules
$modules = [];
$repos = [];
$modulesCurrentMajor = filtered_modules(MetaData::HIGHEST_STABLE_CMS_MAJOR, $input);
$modulesPreviousMajor = filtered_modules(MetaData::HIGHEST_STABLE_CMS_MAJOR - 1, $input);
foreach ([$modulesCurrentMajor, $modulesPreviousMajor] as $modulesList) {
foreach ($modulesList as $module) {
$repo = $module['repo'];
$ghrepo = $module['ghrepo'];
if (in_array($repo, $repos) || in_array($ghrepo, LABELS_EXCLUDE_GHREPOS)) {
continue;
}
// Important! Only include modules on the "silverstripe" account
if (!preg_match('#^silverstripe/#', $repo)) {
continue;
}
$modules[] = $module;
$repos[] = $repo;
}
}

// Update rulesets
foreach ($modules as $module) {
$account = $module['account'];
$repo = $module['repo'];

// Fetch existing rulesets
$rulesets = github_api("https://api.github.com/repos/$account/$repo/rulesets");
$branchRulesetID = 0;
$tagRulesetID = 0;
foreach ($rulesets as $ruleset) {
$id = $ruleset['id'];
$name = $ruleset['name'];
if ($name === BRANCH_RULESET_NAME) {
$branchRulesetID = $id;
}
if ($name === TAG_RULESET_NAME) {
$tagRulesetID = $id;
}
}

// Get any additional branches to add
// Assumption is that if the default branch is main/master, then the repo uses
// a non-numeric style branching system (e.g. main, master) and that needs to be protected
// [0-9]* branch protection will still be applied, on the chance that the repo is converted
// to uses a numeric style branch system in the future and we would want branch protection
// to start immediately on the new branches
$additionalBranchConditions = [];
$defaultBranch = github_api("https://api.github.com/repos/$account/$repo")['default_branch'];
if (in_array($defaultBranch, ['main', 'master'])) {
$additionalBranchConditions[] = "refs/heads/$defaultBranch";
}

// Create rulesets
// Note: This will read from the "rulsets" directory
// In each of those json rulesets there is "bypass_actors"."actor_id" = 5
// This translates to the "Repository admin" role
$branchRuleset = create_ruleset('branch', $additionalBranchConditions);
$tagRuleset = create_ruleset('tag');

// Create new rulesets
if (!$branchRulesetID) {
$url = "https://api.github.com/repos/$account/$repo/rulesets";
github_api($url, $branchRuleset, 'POST');
}
if (!$tagRulesetID) {
$url = "https://api.github.com/repos/$account/$repo/rulesets";
github_api($url, $tagRuleset, 'POST');
}

// Update existing rulesets
// Don't bother to check if the ruleset is already correct
// This is a very quick update so no need to optimise this
if ($branchRulesetID) {
$url = "https://api.github.com/repos/$account/$repo/rulesets/$branchRulesetID";
github_api($url, $branchRuleset, 'PUT');
}
if ($tagRulesetID) {
$url = "https://api.github.com/repos/$account/$repo/rulesets/$tagRulesetID";
github_api($url, $tagRuleset, 'PUT');
}
$REPOS_WITH_RULESETS_UPDATED[] = $repo;
}

output_repos_with_rulesets_created_or_updated();
return Command::SUCCESS;
};
12 changes: 12 additions & 0 deletions run.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
include 'funcs_utils.php';
include 'update_command.php';
include 'labels_command.php';
include 'rulesets_command.php';

use SilverStripe\SupportedModules\MetaData;
use Symfony\Component\Console\Application;
Expand All @@ -19,13 +20,16 @@
const TOOL_URL = 'https://github.com/silverstripe/module-standardiser';
const PR_TITLE = 'MNT Run module-standardiser';
const PR_DESCRIPTION = 'This pull-request was created automatically by [module-standardiser](' . TOOL_URL . ')';
const BRANCH_RULESET_NAME = 'Silverstripe branch ruleset';
const TAG_RULESET_NAME = 'Silverstripe tag ruleset';

// global variables
$MODULE_DIR = '';
$GITHUB_REF = '';
$PRS_CREATED = [];
$REPOS_WITH_PRS_CREATED = [];
$REPOS_WITH_LABELS_UPDATED = [];
$REPOS_WITH_RULESETS_UPDATED = [];
$OUT = null;

// options
Expand Down Expand Up @@ -102,6 +106,14 @@
->addOption(...$optionNoDelete)
->setCode($labelsCommand);

$app->register('rulesets')
->setDescription('Script to set rulesets on all repos only on the silverstripe account')
->addOption(...$optionOnly)
->addOption(...$optionExclude)
->addOption(...$optionDryRun)
->addOption(...$optionNoDelete)
->setCode($rulesetsCommand);

try {
$app->run();
} catch (Error|Exception $e) {
Expand Down

0 comments on commit dedb140

Please sign in to comment.