From dbdd1737dac5c657c6d20980862e3123f3e51ff6 Mon Sep 17 00:00:00 2001 From: Esteban Cairol Date: Wed, 20 Apr 2022 10:32:52 -0600 Subject: [PATCH 1/7] Initial migration of bulk-add-outside-collaborator tool from stand-alone repo to a CLI tool command --- README.md | 4 ++ config__partial.json | 12 ++++ load-application.php | 2 +- src/commands/onboard-collaborator.php | 80 +++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 config__partial.json create mode 100644 src/commands/onboard-collaborator.php diff --git a/README.md b/README.md index 640dc2f2..1b221efa 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@ It's the nickname for our Special Projects team at Automattic. Be well, be kind, make things and set them free. +## Dependencies +- Composer (instructions below) +- GitHub CLI (`gh`) for certaing user related tasks + ## Installation 1. Open the Terminal on your Mac and clone this repository by running: - `git clone git@github.com:Automattic/team51-cli.git` diff --git a/config__partial.json b/config__partial.json new file mode 100644 index 00000000..80f1bc0e --- /dev/null +++ b/config__partial.json @@ -0,0 +1,12 @@ +{ + "***REMOVED***": "***REMOVED***", + "***REMOVED***": "***REMOVED***", + + "***REMOVED***":"***REMOVED***", + "***REMOVED***":"***REMOVED***", + "***REMOVED***":"gYtmrAYGS_3OtwYlQdYPif1B4aFLnE_-8v81MGiIlcw", + + "***REMOVED***": "***REMOVED***", + "***REMOVED***": "***REMOVED***", + "ASCII_WELCOME_ART": "\n ______ ______ _\n/\\__ _\\ /\\ ___\\ /' \\\n\\/_/\\ \\/ __ __ ___ ___ \\ \\ \\__/ /\\_, \\\n \\ \\ \\ /'__`\\ /'__`\\ /' __` __`\\ \\ \\___``\\/_/\\ \\\n \\ \\ \\/\\ __//\\ \\L\\.\\_/\\ \\/\\ \\/\\ \\ \\/\\ \\L\\ \\ \\ \\ \\\n \\ \\_\\ \\____\\ \\__/.\\_\\ \\_\\ \\_\\ \\_\\ \\ \\____/ \\ \\_\\\n \\/_/\\/____/\\/__/\\/_/\\/_/\\/_/\\/_/ \\/___/ \\/_/\n\n\n" +} \ No newline at end of file diff --git a/load-application.php b/load-application.php index 960c4eb5..f33d67f7 100644 --- a/load-application.php +++ b/load-application.php @@ -31,6 +31,6 @@ $application->add( new Team51\Command\Plugin_List() ); $application->add( new Team51\Command\Pressable_Generate_Token() ); $application->add( new Team51\Command\Pressable_Grant_Access() ); - +$application->add( new Team51\Command\Onboard_Collaborator() ); $application->run(); diff --git a/src/commands/onboard-collaborator.php b/src/commands/onboard-collaborator.php new file mode 100644 index 00000000..82587758 --- /dev/null +++ b/src/commands/onboard-collaborator.php @@ -0,0 +1,80 @@ +setDescription( 'Adds collaborator to all Github repos and Pressable sites. Collaborator can be either a11n or contractor' ) + ->setHelp( 'This command allows you to bulk add a collabortor to all Pressable sites and Github repos.' ) + ->addOption( 'type', null, InputOption::VALUE_REQUIRED, 'Type of collaborator. Either a11n or contractor.' ) + ->addOption( 'email', null, InputOption::VALUE_REQUIRED, "Collaborator's email." ) + ->addOption( 'github', null, InputOption::VALUE_REQUIRED, "Collaborator's Github username." ) + ->addOption( 'github_team', null, InputOption::VALUE_NONE, 'Optional Github team for this collaborator.' ); + } + + protected function execute( InputInterface $input, OutputInterface $output ) { + $this->api_helper = new API_Helper(); + $this->output = $output; + + $type = $input->getOption( 'type' ); + if ( empty( $type ) ) { + $type = trim( readline( 'Please provide the type of collaborator. Enter "a11n" or "contractor": ' ) ); + if ( empty( $type ) ) { + $output->writeln( 'Missing collaborator type (eg: --type=contractor).' ); + exit; + } + } + + $email = $input->getOption( 'email' ); + if ( empty( $email ) ) { + $email = trim( readline( 'Please provide the email of the collaborator: ' ) ); + if ( empty( $email ) ) { + $output->writeln( "Missing collaborator's email (eg: --email=user@domain.com)." ); + exit; + } + } + + $github_user = $input->getOption( 'github' ); + if ( empty( $github_user ) ) { + $github_user = trim( readline( 'Please provide the Github username of the collaborator: ' ) ); + if ( empty( $github_user ) ) { + $github_user->writeln( "Missing collaborator's Github username (eg: --github=their_username)." ); + exit; + } + } + + $github_team = $input->getOption( 'github_team' ); + + // Start process + $this->onboard_github( $output, $github_user, $github_team ); + + + $output->writeln( 'All done!' ); + } + + + private function onboard_github( $output, $gh_username ) { + $output->writeln( 'Adding collaborator to a8cteam51 Github repos...' ); + $repo_names = exec( 'gh repo list a8cteam51 --no-archived --limit 1000 --json name' ); + $repo_names = json_decode( $repo_names ); + + foreach( $repo_names as $repo_name ) { + $repo_name = $repo_name->name; + $output->writeln( ''.$repo_name.'' ); + $command = "gh api repos/a8cteam51/$repo_name/collaborators/$gh_username -X PUT -f permission='push'"; + passthru( $command ); + } + $output->writeln( 'All set for our Github repos.' ); + } +} From 76708c63fdba45ff9bbb72d64b578de236cd720b Mon Sep 17 00:00:00 2001 From: Esteban Cairol Date: Thu, 21 Apr 2022 15:01:19 -0600 Subject: [PATCH 2/7] Onboard Github function changed to use REST API instead of gh cli, to avoid extra dependencies. Subscribes a given username to one of 3 Team access levels Remove type parameter and replaced it with github_team --- README.md | 4 +- src/commands/onboard-collaborator.php | 83 +++++++++++++++++++-------- 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 1b221efa..27fcedff 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ Be well, be kind, make things and set them free. ## Dependencies - Composer (instructions below) -- GitHub CLI (`gh`) for certaing user related tasks ## Installation 1. Open the Terminal on your Mac and clone this repository by running: @@ -63,6 +62,9 @@ If you get the error `./install-osx: line 2: composer: command not found`, you c ### `brew: command not found` If you don't have [brew](https://brew.sh/) yet, install it by executing this from your Terminal: `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` — Tip: you can use brew to install all sort of apps on your Mac. Give it [a try](https://formulae.brew.sh/cask/zoom) +### `gh: command not found` +If you're onboarding/offboarding users, you will need access to Github CLI. Please refer to the [installation instructions](https://cli.github.com/), and then follow the instructions on the Terminal for authentication. + ### `Warning: file_get_contents: failed to open stream` ``` Warning: file_get_contents(/Users/.../team51-cli/config.json): failed to open stream: No such file or directory in /Users/.../team51-cli/src/helpers/config-loader.php on line 5 diff --git a/src/commands/onboard-collaborator.php b/src/commands/onboard-collaborator.php index 82587758..4654982c 100644 --- a/src/commands/onboard-collaborator.php +++ b/src/commands/onboard-collaborator.php @@ -13,32 +13,27 @@ class Onboard_Collaborator extends Command { private $api_helper; private $output; + const ACCESS_1 = 'access-level-1'; + const ACCESS_2 = 'access-level-2'; + const ACCESS_3 = 'access-level-3'; + + protected function configure() { $this ->setDescription( 'Adds collaborator to all Github repos and Pressable sites. Collaborator can be either a11n or contractor' ) ->setHelp( 'This command allows you to bulk add a collabortor to all Pressable sites and Github repos.' ) - ->addOption( 'type', null, InputOption::VALUE_REQUIRED, 'Type of collaborator. Either a11n or contractor.' ) ->addOption( 'email', null, InputOption::VALUE_REQUIRED, "Collaborator's email." ) ->addOption( 'github', null, InputOption::VALUE_REQUIRED, "Collaborator's Github username." ) - ->addOption( 'github_team', null, InputOption::VALUE_NONE, 'Optional Github team for this collaborator.' ); + ->addOption( 'github_team', null, InputOption::VALUE_REQUIRED, sprintf('Github team can be: %s, %s, or %s. Following this order, level 1 has less privileges than level 3', self::ACCESS_1, self::ACCESS_2, self::ACCESS_3) ); } protected function execute( InputInterface $input, OutputInterface $output ) { $this->api_helper = new API_Helper(); $this->output = $output; - $type = $input->getOption( 'type' ); - if ( empty( $type ) ) { - $type = trim( readline( 'Please provide the type of collaborator. Enter "a11n" or "contractor": ' ) ); - if ( empty( $type ) ) { - $output->writeln( 'Missing collaborator type (eg: --type=contractor).' ); - exit; - } - } - $email = $input->getOption( 'email' ); if ( empty( $email ) ) { - $email = trim( readline( 'Please provide the email of the collaborator: ' ) ); + $email = trim( readline( "Please provide the collaborator's email: " ) ); if ( empty( $email ) ) { $output->writeln( "Missing collaborator's email (eg: --email=user@domain.com)." ); exit; @@ -47,7 +42,7 @@ protected function execute( InputInterface $input, OutputInterface $output ) { $github_user = $input->getOption( 'github' ); if ( empty( $github_user ) ) { - $github_user = trim( readline( 'Please provide the Github username of the collaborator: ' ) ); + $github_user = trim( readline( "Please provide the collaborator's Github username : " ) ); if ( empty( $github_user ) ) { $github_user->writeln( "Missing collaborator's Github username (eg: --github=their_username)." ); exit; @@ -55,26 +50,68 @@ protected function execute( InputInterface $input, OutputInterface $output ) { } $github_team = $input->getOption( 'github_team' ); + if ( empty( $github_team ) || ! in_array($github_team, [self::ACCESS_1, self::ACCESS_2, self::ACCESS_3]) ) { + $github_team = trim( readline( sprintf("Please provide the collaborator's Github team. Values can be: %s, %s, or %s: ", self::ACCESS_1, self::ACCESS_2, self::ACCESS_3) ) ); + if ( empty( $github_team ) || ! in_array($github_team, [self::ACCESS_1, self::ACCESS_2, self::ACCESS_3]) ) { + $output->writeln( 'Missing collaborator github_team (eg: --github_team='.self::ACCESS_1.').' ); + exit; + } + } // Start process - $this->onboard_github( $output, $github_user, $github_team ); + $this->onboard_github( $github_user, $github_team ); $output->writeln( 'All done!' ); } - private function onboard_github( $output, $gh_username ) { - $output->writeln( 'Adding collaborator to a8cteam51 Github repos...' ); - $repo_names = exec( 'gh repo list a8cteam51 --no-archived --limit 1000 --json name' ); - $repo_names = json_decode( $repo_names ); + private function onboard_github( $gh_username, $gh_team ) { + $this->output->writeln( 'Pulling list of Github repos for organzation a8cteam51...' ); + + $page = 1; + $load_more = 1; + $repo_names = array(); + + // Load all Github repositories + while ($load_more > 0) { + $tmp_repos = $this->api_helper->call_github_api( + sprintf( 'orgs/%s/repos?per_page=100&page=%s', GITHUB_API_OWNER, $page ), + '', + 'GET' + ); + $this->output->writeln( '...' ); + $tmp_repo_names = array_map( function( $row ) { + return $row->name; + }, $tmp_repos); + + $repo_names = array_merge( $repo_names, $tmp_repo_names ); + $load_more = count( $tmp_repos ); + $page++; + } + + $this->output->writeln( 'Found ' . count($repo_names) . ' repositories.' ); + + // Associate Github username with Github Team + $team_put = $this->api_helper->call_github_api( + sprintf( 'orgs/%s/teams/%s/memberships/%s', GITHUB_API_OWNER, $gh_team, $gh_username ), + array( + 'role' => 'member' + ), + 'PUT' + ); + // TODO: Do we still need this loop to grant access per-repo? foreach( $repo_names as $repo_name ) { - $repo_name = $repo_name->name; - $output->writeln( ''.$repo_name.'' ); - $command = "gh api repos/a8cteam51/$repo_name/collaborators/$gh_username -X PUT -f permission='push'"; - passthru( $command ); + // $output->writeln( ''.$repo_name.'' ); + // $tmp_repos = $this->api_helper->call_github_api( + // sprintf( 'orgs/%s/repos?per_page=100&page=%s', GITHUB_API_OWNER, $page ), + // array( + // 'permission': 'push' + // ), + // 'PUT' + // ); } - $output->writeln( 'All set for our Github repos.' ); + $this->output->writeln( 'All set for our Github repos.' ); } } From 434a316c19e064844f868dccae3d63ea1c1e60d0 Mon Sep 17 00:00:00 2001 From: Esteban Cairol Date: Wed, 27 Apr 2022 15:36:55 -0600 Subject: [PATCH 3/7] Changed teams name to be Triage, Deploy and Admin. Clean-up code related to calling all repos and giving individual access to each repo. This is all now managed at Team level --- src/commands/onboard-collaborator.php | 72 ++++++++------------------- 1 file changed, 22 insertions(+), 50 deletions(-) diff --git a/src/commands/onboard-collaborator.php b/src/commands/onboard-collaborator.php index 4654982c..311ef6ca 100644 --- a/src/commands/onboard-collaborator.php +++ b/src/commands/onboard-collaborator.php @@ -13,17 +13,17 @@ class Onboard_Collaborator extends Command { private $api_helper; private $output; - const ACCESS_1 = 'access-level-1'; - const ACCESS_2 = 'access-level-2'; - const ACCESS_3 = 'access-level-3'; + const ACCESS_1 = 'triage'; + const ACCESS_2 = 'deploy'; + const ACCESS_3 = 'admin'; protected function configure() { $this - ->setDescription( 'Adds collaborator to all Github repos and Pressable sites. Collaborator can be either a11n or contractor' ) - ->setHelp( 'This command allows you to bulk add a collabortor to all Pressable sites and Github repos.' ) + ->setDescription( 'Adds collaborator to Github Team and Pressable sites. Collaborator can be either a11n or contractor' ) + ->setHelp( 'This command allows you to bulk add a collaborator to all Pressable sites and a Github team.' ) ->addOption( 'email', null, InputOption::VALUE_REQUIRED, "Collaborator's email." ) - ->addOption( 'github', null, InputOption::VALUE_REQUIRED, "Collaborator's Github username." ) + ->addOption( 'github_username', null, InputOption::VALUE_REQUIRED, "Collaborator's Github username." ) ->addOption( 'github_team', null, InputOption::VALUE_REQUIRED, sprintf('Github team can be: %s, %s, or %s. Following this order, level 1 has less privileges than level 3', self::ACCESS_1, self::ACCESS_2, self::ACCESS_3) ); } @@ -31,16 +31,16 @@ protected function execute( InputInterface $input, OutputInterface $output ) { $this->api_helper = new API_Helper(); $this->output = $output; - $email = $input->getOption( 'email' ); - if ( empty( $email ) ) { - $email = trim( readline( "Please provide the collaborator's email: " ) ); - if ( empty( $email ) ) { - $output->writeln( "Missing collaborator's email (eg: --email=user@domain.com)." ); - exit; - } - } + // $email = $input->getOption( 'email' ); + // if ( empty( $email ) ) { + // $email = trim( readline( "Please provide the collaborator's email: " ) ); + // if ( empty( $email ) ) { + // $output->writeln( "Missing collaborator's email (eg: --email=user@domain.com)." ); + // exit; + // } + // } - $github_user = $input->getOption( 'github' ); + $github_user = $input->getOption( 'github_username' ); if ( empty( $github_user ) ) { $github_user = trim( readline( "Please provide the collaborator's Github username : " ) ); if ( empty( $github_user ) ) { @@ -61,36 +61,15 @@ protected function execute( InputInterface $input, OutputInterface $output ) { // Start process $this->onboard_github( $github_user, $github_team ); + // TODO: onboard_pressable() + $output->writeln( 'All done!' ); } private function onboard_github( $gh_username, $gh_team ) { - $this->output->writeln( 'Pulling list of Github repos for organzation a8cteam51...' ); - - $page = 1; - $load_more = 1; - $repo_names = array(); - - // Load all Github repositories - while ($load_more > 0) { - $tmp_repos = $this->api_helper->call_github_api( - sprintf( 'orgs/%s/repos?per_page=100&page=%s', GITHUB_API_OWNER, $page ), - '', - 'GET' - ); - $this->output->writeln( '...' ); - $tmp_repo_names = array_map( function( $row ) { - return $row->name; - }, $tmp_repos); - - $repo_names = array_merge( $repo_names, $tmp_repo_names ); - $load_more = count( $tmp_repos ); - $page++; - } - - $this->output->writeln( 'Found ' . count($repo_names) . ' repositories.' ); + $this->output->writeln( "Granting access to our a8cteam51 organization..." ); // Associate Github username with Github Team $team_put = $this->api_helper->call_github_api( @@ -101,17 +80,10 @@ private function onboard_github( $gh_username, $gh_team ) { 'PUT' ); - // TODO: Do we still need this loop to grant access per-repo? - foreach( $repo_names as $repo_name ) { - // $output->writeln( ''.$repo_name.'' ); - // $tmp_repos = $this->api_helper->call_github_api( - // sprintf( 'orgs/%s/repos?per_page=100&page=%s', GITHUB_API_OWNER, $page ), - // array( - // 'permission': 'push' - // ), - // 'PUT' - // ); + if ( ! empty( $team_put->message ) ) { + $this->output->writeln( "Something went wrong. Github says: {$team_put->message}" ); + } else { + $this->output->writeln( "The user '{$gh_username}' has been added to Team '{$gh_team}'!" ); } - $this->output->writeln( 'All set for our Github repos.' ); } } From 2ced186b29d0fa01cb947d263cc27a95d788d265 Mon Sep 17 00:00:00 2001 From: Esteban Cairol Date: Fri, 29 Apr 2022 09:35:48 -0600 Subject: [PATCH 4/7] Command that adds all 400+ Github repos to our 3 access teams: triage, deploy, admin --- load-application.php | 1 + src/commands/github-repos-to-teams.php | 88 ++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/commands/github-repos-to-teams.php diff --git a/load-application.php b/load-application.php index f33d67f7..1c7752c0 100644 --- a/load-application.php +++ b/load-application.php @@ -32,5 +32,6 @@ $application->add( new Team51\Command\Pressable_Generate_Token() ); $application->add( new Team51\Command\Pressable_Grant_Access() ); $application->add( new Team51\Command\Onboard_Collaborator() ); +$application->add( new Team51\Command\Github_Repos_To_Teams() ); $application->run(); diff --git a/src/commands/github-repos-to-teams.php b/src/commands/github-repos-to-teams.php new file mode 100644 index 00000000..dce61913 --- /dev/null +++ b/src/commands/github-repos-to-teams.php @@ -0,0 +1,88 @@ + 'triage', + 'team_permission' => 'triage', + ); + private $ACCESS_2 = array( + 'team_slug' => 'deploy', + 'team_permission' => 'push', + ); + private $ACCESS_3 = array( + 'team_slug' => 'admin', + 'team_permission' => 'admin', + ); + + protected function configure() { + $this + ->setDescription( 'Add all Repositories to all GitHub Teams in the organization, with the respective repo permission.' ) + ->setHelp( 'Add all repos to our Github teams. Most-likely to be run only once, for the creation of the teams' ); + } + + protected function execute( InputInterface $input, OutputInterface $output ) { + $this->api_helper = new API_Helper(); + $this->output = $output; + + $output->writeln( "Pulling all repositories from our Github organization." ); + $repos = array(); + $repos_page = 1; + $more_repos = true; + + while( $more_repos ) { + $this->output->writeln( "..." ); + $tmp_repos = $this->api_helper->call_github_api( + sprintf( 'orgs/%s/repos?type=private&per_page=100&page=%s', GITHUB_API_OWNER, $repos_page ), + '', + 'GET' + ); + + if ( empty($tmp_repos) ) { + $more_repos = false; + break; + } + + $repos = array_merge($repos, $tmp_repos); + $repos_page++; + } + + $repo_names = array_column( $repos, 'name' ); + $total_repos = count($repo_names); + $output->writeln( "{$total_repos} repositories will be added to each of our Github Teams." ); + + // Populate Teams with Repositories + $this->populate_team_with_repos( $repo_names, $this->ACCESS_1['team_slug'], $this->ACCESS_1['team_permission'] ); + $this->populate_team_with_repos( $repo_names, $this->ACCESS_2['team_slug'], $this->ACCESS_2['team_permission'] ); + $this->populate_team_with_repos( $repo_names, $this->ACCESS_3['team_slug'], $this->ACCESS_3['team_permission'] ); + + $output->writeln( "All done." ); + } + + private function populate_team_with_repos($repo_names, $team_slug, $team_permission) { + $this->output->writeln( "Adding repos to team '{$team_slug}'. This might take a while..." ); + foreach( $repo_names as $repo_name ) { + $github_response = $this->api_helper->call_github_api( + sprintf( 'orgs/%s/teams/%s/repos/%s/%s', GITHUB_API_OWNER, $team_slug, GITHUB_API_OWNER, $repo_name ), + array( + 'permission' => $team_permission + ), + 'PUT' + ); + if ( ! empty($github_response->message) ) { + $this->output->writeln( "Something went wrong when adding the repo '{$repo_name}' to the team '{$team_slug}'. Message: {$github_response->message}" ); + } + } + } +} From ad6aee6adffba45260181ff7c0b02e36ed5f8f0f Mon Sep 17 00:00:00 2001 From: Esteban Cairol Date: Fri, 29 Apr 2022 15:48:55 -0600 Subject: [PATCH 5/7] Remove accidentally submitted config file. --- config__partial.json | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 config__partial.json diff --git a/config__partial.json b/config__partial.json deleted file mode 100644 index 80f1bc0e..00000000 --- a/config__partial.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "***REMOVED***": "***REMOVED***", - "***REMOVED***": "***REMOVED***", - - "***REMOVED***":"***REMOVED***", - "***REMOVED***":"***REMOVED***", - "***REMOVED***":"gYtmrAYGS_3OtwYlQdYPif1B4aFLnE_-8v81MGiIlcw", - - "***REMOVED***": "***REMOVED***", - "***REMOVED***": "***REMOVED***", - "ASCII_WELCOME_ART": "\n ______ ______ _\n/\\__ _\\ /\\ ___\\ /' \\\n\\/_/\\ \\/ __ __ ___ ___ \\ \\ \\__/ /\\_, \\\n \\ \\ \\ /'__`\\ /'__`\\ /' __` __`\\ \\ \\___``\\/_/\\ \\\n \\ \\ \\/\\ __//\\ \\L\\.\\_/\\ \\/\\ \\/\\ \\ \\/\\ \\L\\ \\ \\ \\ \\\n \\ \\_\\ \\____\\ \\__/.\\_\\ \\_\\ \\_\\ \\_\\ \\ \\____/ \\ \\_\\\n \\/_/\\/____/\\/__/\\/_/\\/_/\\/_/\\/_/ \\/___/ \\/_/\n\n\n" -} \ No newline at end of file From bade39a6982a74c83600a880d5ab1e51348d1ad3 Mon Sep 17 00:00:00 2001 From: Esteban Cairol Date: Fri, 29 Apr 2022 17:03:30 -0600 Subject: [PATCH 6/7] Moved populate_team_with_repos to a re-usable function. Created DRY utils module --- src/commands/github-repos-to-teams.php | 24 +++++----------------- src/helpers/dry-helper.php | 28 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 19 deletions(-) create mode 100644 src/helpers/dry-helper.php diff --git a/src/commands/github-repos-to-teams.php b/src/commands/github-repos-to-teams.php index dce61913..fbac0ce2 100644 --- a/src/commands/github-repos-to-teams.php +++ b/src/commands/github-repos-to-teams.php @@ -3,6 +3,7 @@ namespace Team51\Command; use Team51\Helper\API_Helper; +use Team51\Helper\DRY_Helper; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -34,6 +35,7 @@ protected function configure() { protected function execute( InputInterface $input, OutputInterface $output ) { $this->api_helper = new API_Helper(); + $this->dry_helper = new DRY_Helper(); $this->output = $output; $output->writeln( "Pulling all repositories from our Github organization." ); @@ -63,26 +65,10 @@ protected function execute( InputInterface $input, OutputInterface $output ) { $output->writeln( "{$total_repos} repositories will be added to each of our Github Teams." ); // Populate Teams with Repositories - $this->populate_team_with_repos( $repo_names, $this->ACCESS_1['team_slug'], $this->ACCESS_1['team_permission'] ); - $this->populate_team_with_repos( $repo_names, $this->ACCESS_2['team_slug'], $this->ACCESS_2['team_permission'] ); - $this->populate_team_with_repos( $repo_names, $this->ACCESS_3['team_slug'], $this->ACCESS_3['team_permission'] ); + $this->dry_helper->populate_team_with_repos( $repo_names, $this->ACCESS_1['team_slug'], $this->ACCESS_1['team_permission'] ); + $this->dry_helper->populate_team_with_repos( $repo_names, $this->ACCESS_2['team_slug'], $this->ACCESS_2['team_permission'] ); + $this->dry_helper->populate_team_with_repos( $repo_names, $this->ACCESS_3['team_slug'], $this->ACCESS_3['team_permission'] ); $output->writeln( "All done." ); } - - private function populate_team_with_repos($repo_names, $team_slug, $team_permission) { - $this->output->writeln( "Adding repos to team '{$team_slug}'. This might take a while..." ); - foreach( $repo_names as $repo_name ) { - $github_response = $this->api_helper->call_github_api( - sprintf( 'orgs/%s/teams/%s/repos/%s/%s', GITHUB_API_OWNER, $team_slug, GITHUB_API_OWNER, $repo_name ), - array( - 'permission' => $team_permission - ), - 'PUT' - ); - if ( ! empty($github_response->message) ) { - $this->output->writeln( "Something went wrong when adding the repo '{$repo_name}' to the team '{$team_slug}'. Message: {$github_response->message}" ); - } - } - } } diff --git a/src/helpers/dry-helper.php b/src/helpers/dry-helper.php new file mode 100644 index 00000000..561b73b8 --- /dev/null +++ b/src/helpers/dry-helper.php @@ -0,0 +1,28 @@ +api_helper = new API_Helper(); + } + + public function populate_team_with_repos( $repo_names, $team_slug, $team_permission ) { + echo "Adding repos to team '{$team_slug}'. This might take a while...\n"; + foreach( $repo_names as $repo_name ) { + $github_response = $this->api_helper->call_github_api( + sprintf( 'orgs/%s/teams/%s/repos/%s/%s', GITHUB_API_OWNER, $team_slug, GITHUB_API_OWNER, $repo_name ), + array( + 'permission' => $team_permission + ), + 'PUT' + ); + if ( ! empty($github_response->message) ) { + echo "Something went wrong when adding the repo '{$repo_name}' to the team '{$team_slug}'. Message: {$github_response->message}\n"; + } + } + } + +} From 145b474f7bb9ce911989de25a02618d67da8fad1 Mon Sep 17 00:00:00 2001 From: Esteban Cairol Date: Mon, 2 May 2022 12:36:06 -0600 Subject: [PATCH 7/7] Create repository now uses populate_team_with_repos to assign new repo to each Github Team Abstract Github access levels to the DRY helper class, and renamed a few commands and parameters --- load-application.php | 4 +-- src/commands/create-repository.php | 10 +++++++ src/commands/github-repos-to-teams.php | 23 ++++------------ ...laborator.php => github-team-add-user.php} | 27 +++++-------------- src/helpers/dry-helper.php | 14 ++++++++++ 5 files changed, 38 insertions(+), 40 deletions(-) rename src/commands/{onboard-collaborator.php => github-team-add-user.php} (70%) diff --git a/load-application.php b/load-application.php index 1c7752c0..76a9d48e 100644 --- a/load-application.php +++ b/load-application.php @@ -31,7 +31,7 @@ $application->add( new Team51\Command\Plugin_List() ); $application->add( new Team51\Command\Pressable_Generate_Token() ); $application->add( new Team51\Command\Pressable_Grant_Access() ); -$application->add( new Team51\Command\Onboard_Collaborator() ); -$application->add( new Team51\Command\Github_Repos_To_Teams() ); +$application->add( new Team51\Command\Github_Team_Add_User() ); +$application->add( new Team51\Command\Github_Team_Add_Repos() ); $application->run(); diff --git a/src/commands/create-repository.php b/src/commands/create-repository.php index 46bd19bd..5ff53112 100644 --- a/src/commands/create-repository.php +++ b/src/commands/create-repository.php @@ -3,6 +3,7 @@ namespace Team51\Command; use Team51\Helper\API_Helper; +use Team51\Helper\DRY_Helper; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputOption; @@ -35,6 +36,7 @@ protected function execute( InputInterface $input, OutputInterface $output ) { $filesystem = new Filesystem(); $api_helper = new API_Helper(); + $dry_helper = new DRY_Helper(); if ( empty( $input->getOption( 'repo-slug' ) ) ) { $output->writeln( 'You must pass a repository slug with --repo-slug.' ); @@ -167,6 +169,14 @@ protected function execute( InputInterface $input, OutputInterface $output ) { //exit; } + // Adding repo to all required teams + // TODO: TEST + $output->writeln( "Adding '{$slug}' to the corresponding Github Teams." ); + $repo_names = array( $slug ); + $dry_helper->populate_team_with_repos( $repo_names, $dry_helper->GH_ACCESS_1['team_slug'], $dry_helper->GH_ACCESS_1['team_permission'] ); + $dry_helper->populate_team_with_repos( $repo_names, $dry_helper->GH_ACCESS_2['team_slug'], $dry_helper->GH_ACCESS_2['team_permission'] ); + $dry_helper->populate_team_with_repos( $repo_names, $dry_helper->GH_ACCESS_3['team_slug'], $dry_helper->GH_ACCESS_3['team_permission'] ); + $ssh_url = $response->ssh_url; $html_url = $response->html_url; diff --git a/src/commands/github-repos-to-teams.php b/src/commands/github-repos-to-teams.php index fbac0ce2..44abfd3f 100644 --- a/src/commands/github-repos-to-teams.php +++ b/src/commands/github-repos-to-teams.php @@ -9,24 +9,11 @@ use Symfony\Component\Console\Output\OutputInterface; -class Github_Repos_To_Teams extends Command { - protected static $defaultName = 'github-repos-to-teams'; +class Github_Team_Add_Repos extends Command { + protected static $defaultName = 'github-team-add-repos'; private $api_helper; private $output; - private $ACCESS_1 = array( - 'team_slug' => 'triage', - 'team_permission' => 'triage', - ); - private $ACCESS_2 = array( - 'team_slug' => 'deploy', - 'team_permission' => 'push', - ); - private $ACCESS_3 = array( - 'team_slug' => 'admin', - 'team_permission' => 'admin', - ); - protected function configure() { $this ->setDescription( 'Add all Repositories to all GitHub Teams in the organization, with the respective repo permission.' ) @@ -65,9 +52,9 @@ protected function execute( InputInterface $input, OutputInterface $output ) { $output->writeln( "{$total_repos} repositories will be added to each of our Github Teams." ); // Populate Teams with Repositories - $this->dry_helper->populate_team_with_repos( $repo_names, $this->ACCESS_1['team_slug'], $this->ACCESS_1['team_permission'] ); - $this->dry_helper->populate_team_with_repos( $repo_names, $this->ACCESS_2['team_slug'], $this->ACCESS_2['team_permission'] ); - $this->dry_helper->populate_team_with_repos( $repo_names, $this->ACCESS_3['team_slug'], $this->ACCESS_3['team_permission'] ); + $this->dry_helper->populate_team_with_repos( $repo_names, $this->dry_helper->GH_ACCESS_1['team_slug'], $this->dry_helper->GH_ACCESS_1['team_permission'] ); + $this->dry_helper->populate_team_with_repos( $repo_names, $this->dry_helper->GH_ACCESS_2['team_slug'], $this->dry_helper->GH_ACCESS_2['team_permission'] ); + $this->dry_helper->populate_team_with_repos( $repo_names, $this->dry_helper->GH_ACCESS_3['team_slug'], $this->dry_helper->GH_ACCESS_3['team_permission'] ); $output->writeln( "All done." ); } diff --git a/src/commands/onboard-collaborator.php b/src/commands/github-team-add-user.php similarity index 70% rename from src/commands/onboard-collaborator.php rename to src/commands/github-team-add-user.php index 311ef6ca..a4c47860 100644 --- a/src/commands/onboard-collaborator.php +++ b/src/commands/github-team-add-user.php @@ -8,8 +8,8 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -class Onboard_Collaborator extends Command { - protected static $defaultName = 'onboard-collaborator'; +class Github_Team_Add_User extends Command { + protected static $defaultName = 'github-team-add-user'; private $api_helper; private $output; @@ -22,29 +22,19 @@ protected function configure() { $this ->setDescription( 'Adds collaborator to Github Team and Pressable sites. Collaborator can be either a11n or contractor' ) ->setHelp( 'This command allows you to bulk add a collaborator to all Pressable sites and a Github team.' ) - ->addOption( 'email', null, InputOption::VALUE_REQUIRED, "Collaborator's email." ) - ->addOption( 'github_username', null, InputOption::VALUE_REQUIRED, "Collaborator's Github username." ) - ->addOption( 'github_team', null, InputOption::VALUE_REQUIRED, sprintf('Github team can be: %s, %s, or %s. Following this order, level 1 has less privileges than level 3', self::ACCESS_1, self::ACCESS_2, self::ACCESS_3) ); + ->addOption( 'username', null, InputOption::VALUE_REQUIRED, "Collaborator's Github username." ) + ->addOption( 'team', null, InputOption::VALUE_REQUIRED, sprintf('Github Team can be: %s, %s, or %s.', self::ACCESS_1, self::ACCESS_2, self::ACCESS_3) ); } protected function execute( InputInterface $input, OutputInterface $output ) { $this->api_helper = new API_Helper(); $this->output = $output; - // $email = $input->getOption( 'email' ); - // if ( empty( $email ) ) { - // $email = trim( readline( "Please provide the collaborator's email: " ) ); - // if ( empty( $email ) ) { - // $output->writeln( "Missing collaborator's email (eg: --email=user@domain.com)." ); - // exit; - // } - // } - $github_user = $input->getOption( 'github_username' ); if ( empty( $github_user ) ) { - $github_user = trim( readline( "Please provide the collaborator's Github username : " ) ); + $github_user = trim( readline( "Please provide the collaborator's Github username: " ) ); if ( empty( $github_user ) ) { - $github_user->writeln( "Missing collaborator's Github username (eg: --github=their_username)." ); + $github_user->writeln( "Missing collaborator's Github username (eg: --username=their_username)." ); exit; } } @@ -53,7 +43,7 @@ protected function execute( InputInterface $input, OutputInterface $output ) { if ( empty( $github_team ) || ! in_array($github_team, [self::ACCESS_1, self::ACCESS_2, self::ACCESS_3]) ) { $github_team = trim( readline( sprintf("Please provide the collaborator's Github team. Values can be: %s, %s, or %s: ", self::ACCESS_1, self::ACCESS_2, self::ACCESS_3) ) ); if ( empty( $github_team ) || ! in_array($github_team, [self::ACCESS_1, self::ACCESS_2, self::ACCESS_3]) ) { - $output->writeln( 'Missing collaborator github_team (eg: --github_team='.self::ACCESS_1.').' ); + $output->writeln( 'Missing collaborator github_team (eg: --team='.self::ACCESS_1.').' ); exit; } } @@ -61,9 +51,6 @@ protected function execute( InputInterface $input, OutputInterface $output ) { // Start process $this->onboard_github( $github_user, $github_team ); - // TODO: onboard_pressable() - - $output->writeln( 'All done!' ); } diff --git a/src/helpers/dry-helper.php b/src/helpers/dry-helper.php index 561b73b8..299c8a59 100644 --- a/src/helpers/dry-helper.php +++ b/src/helpers/dry-helper.php @@ -5,6 +5,20 @@ class DRY_Helper { private $api_helper; + // Github Access Levels + public $GH_ACCESS_1 = array( + 'team_slug' => 'triage', + 'team_permission' => 'triage', + ); + public $GH_ACCESS_2 = array( + 'team_slug' => 'deploy', + 'team_permission' => 'push', + ); + public $GH_ACCESS_3 = array( + 'team_slug' => 'admin', + 'team_permission' => 'admin', + ); + function __construct() { $this->api_helper = new API_Helper(); }