diff --git a/README.md b/README.md index ea3ffc495..f026755bb 100644 --- a/README.md +++ b/README.md @@ -383,35 +383,37 @@ assembles it from the Git log. ## Automatic Deployment to Pantheon -In order to deploy upon every merge automatically using GitHub Actions, you shall: +### Prerequisites -1. Initiate QA (`qa` branch) multidev environment for the given project. +The GitHub Actions workflows for automatic deployment are already configured in the repository. You just need to set up the necessary credentials. + +### Setup Steps + +In order to deploy upon every merge automatically using GitHub Actions: + +1. Ensure QA (`qa` branch) multidev environment exists for the given project. This is automatically created during bootstrap, or can be created manually. 1. Double-check if `./.ddev/providers/pantheon.yaml` contains the proper Pantheon project name. 1. Get a [Pantheon machine token](https://pantheon.io/docs/machine-tokens) (using a dummy new Pantheon user ideally, one user per project for the sake of security) 1. Get a GitHub Personal access token. It will be used to post a comment to GitHub to the relevant issue when a merged PR is deployed, so set the expiry date far in the future enough for this. -1. `ddev robo deploy:config-autodeploy [your terminus token] [your github token]` -1. `git commit -m "Deployment secrets and configuration"` -1. Add the public key in `pantheon-key.pub` to the newly created dummy [Pantheon user](https://pantheon.io/docs/ssh-keys) -1. Set up the following in your GitHub repository settings: - - **GitHub Secrets** (Settings → Secrets and variables → Actions → Secrets): - - `TERMINUS_TOKEN`: Your Pantheon machine token - - `PANTHEON_DEPLOY_KEY`: The SSH private key for deployment - - `GH_TOKEN`: GitHub personal access token for posting deployment comments +1. Run the autodeploy configuration command: + ```bash + ddev robo deploy:config-autodeploy [your terminus token] [your github token] + ``` - **GitHub Variables** (Settings → Secrets and variables → Actions → Variables): - - `PANTHEON_GIT_URL`: The Pantheon Git URL for your project - - `ROLLBAR_SERVER_TOKEN`: Your Rollbar server token (optional) - - `DEPLOY_EXCLUDE_WARNING`: Warnings to exclude from deployment notifications (optional) - -1. Actualize `public static string $githubProject = 'Gizra/the-client';` in the `RoboFile.php`. + This will generate an SSH key pair. The command will automatically install the [GitHub CLI](https://cli.github.com/) (`gh`) if it's not already available in your DDEV environment, then offer to automatically set up GitHub Secrets and Variables. If installation fails, it will provide manual instructions. + +1. Follow the instructions provided by the command to: + - Add the SSH public key (`pantheon-key.pub`) to your [Pantheon account](https://pantheon.io/docs/ssh-keys) + - If using automated setup: Confirm when prompted to automatically configure GitHub Secrets and Variables + - If setting up manually: Configure GitHub Secrets (TERMINUS_TOKEN, PANTHEON_DEPLOY_KEY, GH_TOKEN) and Variables (PANTHEON_GIT_URL, ROLLBAR_SERVER_TOKEN, DEPLOY_EXCLUDE_WARNING) as instructed + +**Note**: If you used the `bootstrap:project` command to create your project, the `$githubProject` variable in `DeploymentTrait.php` is automatically updated with your organization and project name. Otherwise, you'll need to manually update `public static string $githubProject = 'YourOrg/your-project';` in `robo-components/DeploymentTrait.php`. -Optionally you can specify which target branch you'd like to push on Pantheon, by default it's `master`, so the target is the DEV environment, but alternatively you can issue: -`ddev robo deploy:config-autodeploy [your terminus token] [your github token] [pantheon project name] [gh_branch] [pantheon_branch]` +### Tag-based Deployments After you have automatic deployment for a project, you are able to deploy to Pantheon `test` and `live` using Git tags. -`git tag 0.1.2` will imply a deployment to the `test` environment (and `dev` - as enforced by Pantheon). -`git tag 0.1.2_live` will imply a deployment to `live`. In order to make it fast, you need to first create the tag that deploy to `test`, then you need to tag the same commit with a tag suffixed with `_live`. +- `git tag 0.1.2` will imply a deployment to the `test` environment (and `dev` - as enforced by Pantheon). +- `git tag 0.1.2_live` will imply a deployment to `live`. In order to make it fast, you need to first create the tag that deploy to `test`, then you need to tag the same commit with a tag suffixed with `_live`. ### Excluding Warnings in Deployment diff --git a/robo-components/BootstrapTrait.php b/robo-components/BootstrapTrait.php index 4565c1019..16f5f3ca3 100644 --- a/robo-components/BootstrapTrait.php +++ b/robo-components/BootstrapTrait.php @@ -13,7 +13,7 @@ trait BootstrapTrait { * Bootstrap a new client project on Pantheon.io. * * @param string $project_name - * The project name. + * The Pantheon project name. * @param string $github_repository_url * The clone URL of the GitHub repository. * @param string $terminus_token @@ -27,52 +27,63 @@ trait BootstrapTrait { * The HTTP basic auth password. Optional. */ public function bootstrapProject(string $project_name, string $github_repository_url, string $terminus_token, string $github_token, string $http_basic_auth_user = '', string $http_basic_auth_password = '') { - // Extract project name from $github_repository_url. - // The syntax is like: git@github.com:Organization/projectname.git . + // Extract organization and repo name from GitHub URL. preg_match('/github.com[:\/](.*)\/(.*)\.git/', $github_repository_url, $matches); $github_organization = $matches[1]; - $project_machine_name = $matches[2]; + $github_repo_name = $matches[2]; - $this->verifyRequirements($project_name, $github_organization, $project_machine_name, $terminus_token, $github_token, $http_basic_auth_user, $http_basic_auth_password); + $this->verifyRequirements($project_name, $github_organization, $github_repo_name, $terminus_token, $github_token, $http_basic_auth_user, $http_basic_auth_password); - $this->prepareGithubRepository($project_name, $github_organization, $project_machine_name, $github_repository_url); + $this->prepareGithubRepository($project_name, $github_organization, $github_repo_name, $github_repository_url); - $this->createPantheonProject($terminus_token, $project_name, $project_machine_name); + $this->createPantheonProject($terminus_token, $project_name); - $this->deployPantheonInstallEnv('dev', $project_machine_name); - $this->deployPantheonInstallEnv('qa', $project_machine_name); + $this->deployPantheonInstallEnv('dev', $project_name); + $this->deployPantheonInstallEnv('qa', $project_name); - $this->lockPantheonEnvironments($project_machine_name, $http_basic_auth_user, $http_basic_auth_password); + $this->lockPantheonEnvironments($project_name, $http_basic_auth_user, $http_basic_auth_password); $tfa_secret = $this->taskExec("openssl rand -base64 32") ->printOutput(FALSE) ->run() ->getMessage(); $this->taskExec('terminus self:plugin:install pantheon-systems/terminus-secrets-plugin')->run(); - $this->taskExec("terminus secrets:set $project_machine_name.qa tfa $tfa_secret")->run(); - $this->taskExec("terminus secrets:set $project_machine_name.dev tfa $tfa_secret")->run(); + $this->taskExec("terminus secrets:set $project_name.qa tfa $tfa_secret")->run(); + $this->taskExec("terminus secrets:set $project_name.dev tfa $tfa_secret")->run(); $this->say("Bootstrap completed successfully."); - $this->say("You might want to run the following commands to properly place the project:"); - $this->say("mv .bootstrap ../$project_machine_name"); - $this->say("mv .pantheon ../$project_machine_name/.pantheon"); - $this->say("To configure autodeployment to Pantheon run:"); - $this->say("ddev robo deploy:config-autodeploy $terminus_token $github_token"); + $this->say(""); + $this->say("Next steps:"); + $this->say("1. Move the project to its final location:"); + $this->say(" mv .bootstrap ../$github_repo_name"); + $this->say(" mv .pantheon ../$github_repo_name/.pantheon"); + $this->say(""); + $this->say("2. Configure automatic deployment to Pantheon with GitHub Actions:"); + $this->say(" cd ../$github_repo_name"); + $this->say(" ddev robo deploy:config-autodeploy $terminus_token $github_token"); + $this->say(""); + $this->say(" This will generate SSH keys and provide instructions for:"); + $this->say(" - Setting up GitHub Secrets (TERMINUS_TOKEN, PANTHEON_DEPLOY_KEY, GH_TOKEN)"); + $this->say(" - Setting up GitHub Variables (PANTHEON_GIT_URL, ROLLBAR_SERVER_TOKEN)"); + $this->say(" - Adding the SSH public key to your Pantheon account"); + $this->say(""); + $this->say("For full deployment setup details, see:"); + $this->say("https://github.com/$github_organization/$github_repo_name#automatic-deployment-to-pantheon"); } /** * Prepares the new GitHub repository for the project. * * @param string $project_name - * The project name. - * @param string $organization + * The Pantheon site name. + * @param string $github_organization * The GitHub organization. - * @param string $project_machine_name - * The project machine name in GH slug. + * @param string $github_repo_name + * The GitHub repository name. * @param string $github_repository_url * The clone URL of the GitHub repository. */ - protected function prepareGithubRepository(string $project_name, string $organization, string $project_machine_name, string $github_repository_url) { + protected function prepareGithubRepository(string $project_name, string $github_organization, string $github_repo_name, string $github_repository_url) { $temp_remote = 'bootstrap_' . time(); $this->taskExec("git remote add $temp_remote $github_repository_url") ->run(); @@ -94,12 +105,12 @@ protected function prepareGithubRepository(string $project_name, string $organiz $this->taskReplaceInFile('.bootstrap/robo-components/DeploymentTrait.php') ->from('Gizra/drupal-starter') - ->to("$organization/$project_machine_name") + ->to("$github_organization/$github_repo_name") ->run(); $this->taskReplaceInFile('.bootstrap/.ddev/config.yaml') ->from('drupal-starter') - ->to($project_machine_name) + ->to($github_repo_name) ->run(); $this->taskReplaceInFile('.bootstrap/.ddev/config.yaml') @@ -124,12 +135,12 @@ protected function prepareGithubRepository(string $project_name, string $organiz $this->taskReplaceInFile('.bootstrap/README.md') ->from('Gizra') - ->to($organization) + ->to($github_organization) ->run(); $this->taskReplaceInFile('.bootstrap/README.md') ->from('drupal-starter') - ->to($project_machine_name) + ->to($github_repo_name) ->run(); $this->taskReplaceInFile('.bootstrap/.ddev/providers/pantheon.yaml') @@ -139,18 +150,28 @@ protected function prepareGithubRepository(string $project_name, string $organiz $this->taskReplaceInFile('.bootstrap/composer.json') ->from('drupal-starter') - ->to(strtolower($project_machine_name)) + ->to(strtolower($github_repo_name)) ->run(); $this->taskReplaceInFile('.bootstrap/composer.json') ->from('gizra') - ->to(strtolower($organization)) + ->to(strtolower($github_organization)) ->run(); $this->taskReplaceInFile('.bootstrap/web/sites/default/settings.pantheon.php') ->from('drupal_starter') - ->to(str_replace('-', '_', $project_machine_name)) + ->to(str_replace('-', '_', $github_repo_name)) ->run(); + // Run composer install first to get contrib modules (needed for + // merge-plugin to find webform's composer.libraries.json). + $result = $this->taskExec("cd .bootstrap && composer install --no-interaction") + ->run() + ->getExitCode(); + if ($result !== 0) { + throw new \Exception("Failed to run composer install in GH repository."); + } + + // Now update the lock file hash after the project name replacements. $result = $this->taskExec("cd .bootstrap && composer update --lock") ->run() ->getExitCode(); @@ -178,11 +199,9 @@ protected function prepareGithubRepository(string $project_name, string $organiz * @param string $terminus_token * The Pantheon machine token. * @param string $project_name - * The project name. - * @param string $project_machine_name - * The project machine name in GH slug. + * The Pantheon site name. */ - public function createPantheonProject(string $terminus_token, string $project_name, string $project_machine_name) { + public function createPantheonProject(string $terminus_token, string $project_name) { $result = $this->taskExec("terminus auth:login --machine-token=\"$terminus_token\"") ->run() ->getExitCode(); @@ -213,7 +232,7 @@ public function createPantheonProject(string $terminus_token, string $project_na // matches Drupal Starter. $upstream_id = "bde48795-b16d-443f-af01-8b1790caa1af"; - $result = $this->taskExec("terminus site:create $project_machine_name \"$project_name\" \"$upstream_id\" --org=\"$selected_organization_id\"") + $result = $this->taskExec("terminus site:create $project_name \"$project_name\" \"$upstream_id\" --org=\"$selected_organization_id\"") ->run() ->getExitCode(); @@ -221,7 +240,7 @@ public function createPantheonProject(string $terminus_token, string $project_na throw new \Exception("Failed to create the Pantheon project."); } - $result = $this->taskExec("terminus connection:set $project_machine_name.dev git") + $result = $this->taskExec("terminus connection:set $project_name.dev git") ->run() ->getExitCode(); @@ -231,7 +250,7 @@ public function createPantheonProject(string $terminus_token, string $project_na // Retrieve Git repository from Pantheon, then clone the artifact repository // to .pantheon directory. - $pantheon_repository_url = $this->taskExec("terminus connection:info $project_machine_name.dev --field=git_url") + $pantheon_repository_url = $this->taskExec("terminus connection:info $project_name.dev --field=git_url") ->printOutput(FALSE) ->run() ->getMessage(); @@ -297,7 +316,7 @@ public function createPantheonProject(string $terminus_token, string $project_na } // Create QA environment on Pantheon. - $result = $this->taskExec("terminus multidev:create $project_machine_name.dev qa") + $result = $this->taskExec("terminus multidev:create $project_name.dev qa") ->run() ->getExitCode(); @@ -305,7 +324,7 @@ public function createPantheonProject(string $terminus_token, string $project_na throw new \Exception('Failed to create the Pantheon QA environment.'); } - $result = $this->taskExec("terminus connection:set $project_machine_name.qa git") + $result = $this->taskExec("terminus connection:set $project_name.qa git") ->run() ->getExitCode(); @@ -317,33 +336,33 @@ public function createPantheonProject(string $terminus_token, string $project_na /** * Lock all Pantheon environments for the given site. * - * @param string $project_machine_name - * The machine name of the project. + * @param string $project_name + * The Pantheon site name. * @param string $http_basic_auth_user * The HTTP basic auth user. * @param string $http_basic_auth_password * The HTTP basic auth password. */ - public function lockPantheonEnvironments(string $project_machine_name, string $http_basic_auth_user, string $http_basic_auth_password) { + public function lockPantheonEnvironments(string $project_name, string $http_basic_auth_user, string $http_basic_auth_password) { if (empty($http_basic_auth_user) || empty($http_basic_auth_password)) { $this->say("No HTTP basic auth credentials were provided. Pantheon environments will not be locked."); return; } - $pantheon_environments = $this->taskExec("terminus env:list $project_machine_name --field=ID --format=list") + $pantheon_environments = $this->taskExec("terminus env:list $project_name --field=ID --format=list") ->printOutput(FALSE) ->run() ->getMessage(); $pantheon_environments = explode(PHP_EOL, $pantheon_environments); foreach ($pantheon_environments as $pantheon_environment) { - $result = $this->taskExec("terminus env:wake $project_machine_name.$pantheon_environment") + $result = $this->taskExec("terminus env:wake $project_name.$pantheon_environment") ->run() ->getExitCode(); if ($result !== 0) { $this->say("Failed to wake up the Pantheon $pantheon_environment environment."); continue; } - $result = $this->taskExec("terminus lock:enable $project_machine_name.$pantheon_environment $http_basic_auth_user $http_basic_auth_password") + $result = $this->taskExec("terminus lock:enable $project_name.$pantheon_environment $http_basic_auth_user $http_basic_auth_password") ->run() ->getExitCode(); if ($result !== 0) { @@ -357,10 +376,10 @@ public function lockPantheonEnvironments(string $project_machine_name, string $h * * @param string $project_name * The project name. - * @param string $organization + * @param string $github_organization * The GitHub organization. - * @param string $project_machine_name - * The project machine name in GH slug. + * @param string $github_repo_name + * The GitHub repository name. * @param string $terminus_token * The Pantheon machine token. * @param string $github_token @@ -370,7 +389,7 @@ public function lockPantheonEnvironments(string $project_machine_name, string $h * @param string $http_basic_auth_password * The HTTP basic auth password. */ - protected function verifyRequirements(string $project_name, string $organization, string $project_machine_name, string $terminus_token, string $github_token, $http_basic_auth_user, $http_basic_auth_password) { + protected function verifyRequirements(string $project_name, string $github_organization, string $github_repo_name, string $terminus_token, string $github_token, $http_basic_auth_user, $http_basic_auth_password) { if (is_dir('.bootstrap')) { throw new \Exception('The .bootstrap directory already exists. Please remove / move it and try again.'); } @@ -380,14 +399,13 @@ protected function verifyRequirements(string $project_name, string $organization if (empty(trim($project_name))) { throw new \Exception('The project name is empty.'); } - if (empty(trim($organization))) { - throw new \Exception('The organization is empty.'); - } - if (empty(trim($project_machine_name))) { - throw new \Exception('The project machine name is empty.'); + $this->validatePantheonSiteName($project_name); + + if (empty(trim($github_organization))) { + throw new \Exception('The GitHub organization is empty.'); } - if (str_contains($project_machine_name, ' ')) { - throw new \Exception('The project machine name contains spaces.'); + if (empty(trim($github_repo_name))) { + throw new \Exception('The GitHub repository name is empty.'); } if (empty(trim($terminus_token))) { throw new \Exception('The Pantheon machine token is empty.'); @@ -397,4 +415,22 @@ protected function verifyRequirements(string $project_name, string $organization } } + /** + * Validates a Pantheon site name. + * + * @param string $site_name + * The site name to validate. + * + * @throws \Exception + * If the site name is invalid. + */ + protected function validatePantheonSiteName(string $site_name): void { + if (strlen($site_name) >= 52) { + throw new \Exception("The site name '$site_name' must be fewer than 52 characters."); + } + if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$/', $site_name)) { + throw new \Exception("The site name '$site_name' can only contain a-z, A-Z, 0-9, and dashes, and cannot begin or end with a dash."); + } + } + } diff --git a/robo-components/DeploymentTrait.php b/robo-components/DeploymentTrait.php index 00e7435d1..00f06b366 100644 --- a/robo-components/DeploymentTrait.php +++ b/robo-components/DeploymentTrait.php @@ -2,6 +2,7 @@ namespace RoboComponents; +use Robo\Symfony\ConsoleIO; use Symfony\Component\Yaml\Yaml; /** @@ -693,24 +694,21 @@ public function deployPantheonInstallEnv(string $env = 'qa', ?string $pantheon_n } /** - * Prepares the repository to perform automatic deployment to Pantheon. + * Configures automatic deployment to Pantheon using GitHub Actions. + * + * This command generates an SSH key pair and provides instructions for + * setting up the necessary GitHub Secrets and Variables for automatic + * deployment. * * @param string $token * Terminus machine token: https://pantheon.io/docs/machine-tokens. * @param string $github_token * Personal GitHub token: * https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token. - * @param string $github_deploy_branch - * The branch that should be pushed automatically to Pantheon. By default, - * it's 'main', the default GitHub branch for any new project. - * @param string $pantheon_deploy_branch - * The branch at the artifact repo that should be the target of the - * deployment. As we typically deploy to QA, the default value here is 'qa', - * that multi-dev environment should be created by hand beforehand. * * @throws \Exception */ - public function deployConfigAutodeploy(string $token, string $github_token, string $github_deploy_branch = 'main', string $pantheon_deploy_branch = 'qa'): void { + public function deployConfigAutodeploy(string $token, string $github_token): void { $pantheon_info = $this->getPantheonNameAndEnv(); $project_name = $pantheon_info['name']; @@ -720,63 +718,137 @@ public function deployConfigAutodeploy(string $token, string $github_token, stri throw new \Exception('The key generation failed.'); } - // Encrypt the SSH key for use in GitHub Actions. - $result = $this->taskExec('openssl rand -hex 32')->printOutput(FALSE)->run(); - if ($result->getExitCode() !== 0) { - throw new \Exception('Failed to generate encryption key.'); - } - $encryption_key = trim($result->getMessage()); - - $result = $this->taskExec('openssl rand -hex 16')->printOutput(FALSE)->run(); - if ($result->getExitCode() !== 0) { - throw new \Exception('Failed to generate encryption IV.'); - } - $encryption_iv = trim($result->getMessage()); - - $result = $this->taskExec("openssl aes-256-cbc -K $encryption_key -iv $encryption_iv -in pantheon-key -out pantheon-key.enc")->run(); - if ($result->getExitCode() !== 0) { - throw new \Exception('The encryption of the private key failed.'); - } - $result = $this->taskExec("terminus connection:info $project_name.dev --fields='Git Command' --format=string | awk '{print $3}'") ->printOutput(FALSE) ->run(); $pantheon_git_url = trim($result->getMessage()); - // Update GitHub Actions workflows if they exist. - if (file_exists('.github/workflows/lint.template.yml')) { - $this->_exec("cp .github/workflows/lint.template.yml .github/workflows/lint.yml"); - $this->taskReplaceInFile('.github/workflows/lint.yml') - ->from('{{ GITHUB_DEPLOY_BRANCH }}') - ->to($github_deploy_branch) - ->run(); + $this->say("The project was prepared for automatic deployment to Pantheon using GitHub Actions"); + $this->say(""); + + // Check if gh CLI is available. + $gh_available = $this->taskExec('which gh') + ->printOutput(FALSE) + ->run() + ->wasSuccessful(); + + // If gh CLI is not available, try to install it. + if (!$gh_available) { + $this->say("GitHub CLI (gh) is not installed. Installing it now..."); + + // Install gh CLI on Ubuntu/Debian. + $install_commands = [ + 'sudo apt-get update -qq', + 'sudo apt-get install -y -qq curl', + 'curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 2>/dev/null', + 'sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg', + 'echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null', + 'sudo apt-get update -qq', + 'sudo apt-get install -y -qq gh', + ]; + + $install_failed = FALSE; + foreach ($install_commands as $cmd) { + $result = $this->taskExec($cmd)->run(); + if (!$result->wasSuccessful()) { + $this->say("Warning: Failed to install gh CLI automatically."); + $install_failed = TRUE; + break; + } + } + + if (!$install_failed) { + $this->say("✓ GitHub CLI installed successfully!"); + $this->say(""); + $gh_available = TRUE; + } } - $result = $this->taskExec('git add pantheon-key.enc')->run(); - if ($result->getExitCode() !== 0) { - throw new \Exception("git add failed."); + if ($gh_available) { + $this->say("GitHub Secrets and Variables can be set automatically using gh CLI."); + $io = new ConsoleIO($this->input(), $this->output()); + $automate = $io->confirm('Would you like to automatically set up GitHub Secrets and Variables now?', TRUE); + + if ($automate) { + $this->say(""); + $this->say("Setting up GitHub Secrets and Variables..."); + + // Set secrets. + $result = $this->taskExec("gh secret set TERMINUS_TOKEN --body '$token' --repo " . self::$githubProject)->run(); + if ($result->wasSuccessful()) { + $this->say("✓ Set TERMINUS_TOKEN secret"); + } + + $result = $this->taskExec("gh secret set PANTHEON_DEPLOY_KEY < pantheon-key --repo " . self::$githubProject)->run(); + if ($result->wasSuccessful()) { + $this->say("✓ Set PANTHEON_DEPLOY_KEY secret"); + } + + $result = $this->taskExec("gh secret set GH_TOKEN --body '$github_token' --repo " . self::$githubProject)->run(); + if ($result->wasSuccessful()) { + $this->say("✓ Set GH_TOKEN secret"); + } + + // Set variables. + $result = $this->taskExec("gh variable set PANTHEON_GIT_URL --body '$pantheon_git_url' --repo " . self::$githubProject)->run(); + if ($result->wasSuccessful()) { + $this->say("✓ Set PANTHEON_GIT_URL variable"); + } + + $this->say(""); + $this->say("GitHub Secrets and Variables have been configured!"); + $this->say(""); + $this->say("Optional: You can also set ROLLBAR_SERVER_TOKEN and DEPLOY_EXCLUDE_WARNING variables if needed:"); + $this->say(" gh variable set ROLLBAR_SERVER_TOKEN --body 'your-token' --repo " . self::$githubProject); + $this->say(" gh variable set DEPLOY_EXCLUDE_WARNING --body 'warning1|warning2' --repo " . self::$githubProject); + } + else { + $this->printManualInstructions($token, $github_token, $pantheon_git_url); + } + } + else { + $this->say(""); + $this->printManualInstructions($token, $github_token, $pantheon_git_url); } - $this->say("The project was prepared for automatic deployment to Pantheon using GitHub Actions"); - $this->say(""); - $this->say("Please complete the following steps:"); - $this->say(""); - $this->say("1. Add the following secrets to your GitHub repository:"); - $this->say(" - Go to: Settings → Secrets and variables → Actions → New repository secret"); - $this->say(" - PANTHEON_GIT_URL: " . $pantheon_git_url); - $this->say(" - TERMINUS_TOKEN: " . $token); - $this->say(" - ENCRYPTED_KEY: " . $encryption_key); - $this->say(" - ENCRYPTED_IV: " . $encryption_iv); - $this->say(" - GITHUB_TOKEN: (use the automatically provided token or your personal token)"); - $this->say(" - ROLLBAR_SERVER_TOKEN: (your Rollbar token if applicable)"); $this->say(""); - $this->say("2. Add the SSH public key to the Pantheon account:"); + $this->say("Remaining steps:"); + $this->say("1. Add the SSH public key to the Pantheon account:"); $this->say(" - Key location: pantheon-key.pub"); $this->say(" - Instructions: https://pantheon.io/docs/ssh-keys"); $this->say(""); - $this->say("3. Review and commit the encrypted key file (pantheon-key.enc)"); + $this->say("2. IMPORTANT: Keep the pantheon-key file secure and DO NOT commit it to the repository."); + $this->say(" After adding the public key to Pantheon, you can delete the pantheon-key files locally."); + $this->say(""); + $this->say("3. Ensure nested docroot is configured: https://pantheon.io/docs/nested-docroot"); $this->say(""); - $this->say("4. Ensure nested docroot is configured: https://pantheon.io/docs/nested-docroot"); + $this->say("For more details, see the 'Automatic Deployment to Pantheon' section in README.md"); + } + + /** + * Prints manual instructions for setting up GitHub Secrets and Variables. + * + * @param string $token + * The Terminus token. + * @param string $github_token + * The GitHub token. + * @param string $pantheon_git_url + * The Pantheon Git URL. + */ + protected function printManualInstructions(string $token, string $github_token, string $pantheon_git_url): void { + $this->say("Please complete the following steps manually:"); + $this->say(""); + $this->say("1. Set up the following GitHub Secrets:"); + $this->say(" - Go to: Settings → Secrets and variables → Actions → Secrets → New repository secret"); + $this->say(" - TERMINUS_TOKEN: " . $token); + $this->say(" - PANTHEON_DEPLOY_KEY: (paste the contents of pantheon-key file)"); + $this->say(" - GH_TOKEN: " . $github_token); + $this->say(""); + $this->say("2. Set up the following GitHub Variables:"); + $this->say(" - Go to: Settings → Secrets and variables → Actions → Variables → New repository variable"); + $this->say(" - PANTHEON_GIT_URL: " . $pantheon_git_url); + $this->say(" - ROLLBAR_SERVER_TOKEN: (your Rollbar token, optional)"); + $this->say(" - DEPLOY_EXCLUDE_WARNING: (warnings to exclude, optional)"); } /**