From cc2d8378acf6f97ec5850062b42b99c9bc702470 Mon Sep 17 00:00:00 2001 From: John Spellman Date: Mon, 5 Dec 2022 16:05:26 -0700 Subject: [PATCH 01/16] [CMS-1149] Remove dependabot (#58) --- .github/dependabot.yml | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index d0ab34c2..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,10 +0,0 @@ -version: 2 -updates: -- package-ecosystem: composer - directory: "/" - schedule: - interval: daily - time: "08:00" - timezone: US/Central - open-pull-requests-limit: 10 - versioning-strategy: increase From cb557259ee29269e89ee2dbddcd4351826792a1d Mon Sep 17 00:00:00 2001 From: J Ryan Wagner Date: Tue, 3 Jan 2023 12:41:51 -0500 Subject: [PATCH 02/16] =?UTF-8?q?CMS-1112:=20Resolves=20issue=20where=20an?= =?UTF-8?q?=20unnecessary=20commit=20was=20being=20includ=E2=80=A6=20(#60)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CMS-1112: Resolves issue where updates to commit choosing logic were causing a merge conflict. --- devops/scripts/deploy-decoupled-upstream.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/devops/scripts/deploy-decoupled-upstream.sh b/devops/scripts/deploy-decoupled-upstream.sh index 1ff34ae6..8d816257 100755 --- a/devops/scripts/deploy-decoupled-upstream.sh +++ b/devops/scripts/deploy-decoupled-upstream.sh @@ -29,8 +29,24 @@ echo newcommits=$(git log decoupled-release-pointer..HEAD --reverse --pretty=format:"%h") commits=() +# There are a small number of commits which must be manually excluded, usually +# due to changes in the commit type rules which would retroactively include commits +# which were not initially included, causing merge conflicts. Commits which should +# be excluded can be added to this array and will not be cherry picked. +exclude_list=(0099a8b) + # Identify commits that should be released for commit in $newcommits; do + # Exclude commits which have been manually rejected + skip=false + for item in "${exclude_list[@]}"; do + [[ $item == $commit ]] && echo "Commit ${commit} has been manually excluded."; skip=true + done + + if [[ $skip==true ]] ; then + continue + fi + commit_type=$(identify_commit_type "$commit") if [[ $commit_type == "normal" ]] ; then commits+=($commit) From 2185459192faeb399283ae915b508bfc4ee0e4c8 Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Tue, 10 Jan 2023 10:19:57 -0700 Subject: [PATCH 03/16] Update to resolve repository maintenance issues This update to the WordPress (Composer Managed) upstream disables Dependabot dependency management notifications (we do not want to change the versions of dependencies in our composer.json file for risk of merge conflicts). This update also resolves an issue that was causing releases to not deploy to the Decoupled WordPress (Composer Managed) upstream. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b3033e3..8ac1e10d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 2023-01-10 +* Remove Dependabot ([#58](https://github.com/pantheon-systems/wordpress-composer-managed/pull/58)) +* Resolves issue where updates to commit choosing logic were causing a merge conflict. ([#60](https://github.com/pantheon-systems/wordpress-composer-managed/pull/60)) + ### 2022-11-30 * Set minimum-stability to "stable" in `composer.json` ([#55](https://github.com/pantheon-systems/wordpress-composer-managed/pull/55)) * Add Composer `post-install-cmd` to create symlinks to the `web/wp` directory (for better multisite support) ([#56](https://github.com/pantheon-systems/wordpress-composer-managed/pull/56)) From b2b383b51dd9c39a506002b1c6629f1570c6703f Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Tue, 10 Jan 2023 12:46:08 -0700 Subject: [PATCH 04/16] [BUGS-5228] Sage install script (#61) * add final-ish sage install script * make the script executable * add the install sage script * document how to install sage this just gives the script and links to the installing sage doc * add base install doc * set process timeout to 0 so our script can complete * remove sort packages that might change things and cause merge conflicts * update docs * add final note about multiple sage themes * also add note about symlinks * fix link to screenshot * Capitalize Composer Co-authored-by: John Spellman Co-authored-by: John Spellman --- README.md | 8 + composer.json | 4 + docs/Installing-Sage.md | 181 ++++++++++++++ docs/images/sage-theme-screenshot.png | Bin 0 -> 60886 bytes private/scripts/sage-theme-install.sh | 325 ++++++++++++++++++++++++++ 5 files changed, 518 insertions(+) create mode 100644 docs/Installing-Sage.md create mode 100644 docs/images/sage-theme-screenshot.png create mode 100755 private/scripts/sage-theme-install.sh diff --git a/README.md b/README.md index ba43129f..b7306876 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,14 @@ composer upstream-require wpackagist-theme/twentytwentytwo composer upstream-require wpackagist-plugin/advanced-custom-fields ``` +### Using Roots Sage starter theme + +We've included a Sage Install script that can be run via Composer. This will install the Sage starter theme from Roots, ensure all dependencies are installed, and adds a `post-install-cmd` hook to the `composer.json`. For more information see [Installing Sage](docs/Installing-Sage.md). The command to run the script is below. + +``` +composer install-sage +``` + ## Contributing Contributions are welcome in the form of GitHub pull requests. However, the `pantheon-upstreams/wordpress-composer-managed` repository is a mirror that does not directly accept pull requests. diff --git a/composer.json b/composer.json index 5a2276f5..c2f66b2a 100644 --- a/composer.json +++ b/composer.json @@ -73,6 +73,7 @@ "config": { "optimize-autoloader": true, "preferred-install": "dist", + "process-timeout": 0, "allow-plugins": { "composer/installers": true, "roots/wordpress-core-installer": true @@ -115,6 +116,9 @@ "pre-update-cmd": [ "WordPressComposerManaged\\ComposerScripts::preUpdate" ], + "install-sage": [ + "bash ./private/scripts/sage-theme-install.sh" + ], "test": [ "phpcs" ], diff --git a/docs/Installing-Sage.md b/docs/Installing-Sage.md new file mode 100644 index 00000000..46f7d8fd --- /dev/null +++ b/docs/Installing-Sage.md @@ -0,0 +1,181 @@ +# Installing Roots Sage + +## Introduction +Roots Sage is an advanced WordPress starter theme with a modern development workflow. It's built with Laravel Blade, Tailwind CSS and bud.js and is available on the [Roots website](https://roots.io/sage/). + +## Requirements +Before running the Sage installation script, you must have the following: + +* A fully installed WordPress website on Pantheon. A site that has been deployed but not set up will fail during the installation process. +* [Git](https://git-scm.com/) +* [Composer](https://getcomposer.org/) +* [Terminus](https://pantheon.io/docs/terminus/install/) +* [Terminus Build Tools Plugin](https://github.com/pantheon-systems/terminus-build-tools-plugin) +* [Homebrew](https://brew.sh/) +* [Node.js](https://nodejs.org/en/) +* [jq](https://stedolan.github.io/jq/) (optional, will be installed with Brew if it does not alredy exist) + +Note: The script assumes a Mac OS X environment. If you are using a different operating system, you will need to install Sage manually, skip to [How it Works](#how-it-works) to understand what the script is doing so you can recreate the process. + +You will also need a copy of the site cloned to your local environment as the script will be run locally. You may use `git clone` or `terminus local:clone site-name` to clone the site. + +## Running the Script + +If you have all the above requirements, including a copy of the site locally, `cd` into the root directory of the project and run: + +``` +composer install-sage +``` + +## How it Works +The script does a lot of things and each step builds onto the last. You can look at the script in [`private/scripts/sage-theme-install.sh`](../private/scripts/sage-theme-install.sh) if you're interested in the precise commands that are being run. This overview will walk through each step. + +### Check Login +The first thing the script will do is check to see if you are logged into Terminus with a `terminus whoami` command. If you are not logged in, the script will end and you will be prompted to log in first. + +### Get Site Info +Once we know you are logged into Terminus, the script can run a `terminus site:info` command. From this, the script is able to extract the site name and ID and stores them in variables that we can use in the next step. + +### Prompt for Information +If the script was able to identify the site ID and Name, the only thing the script will prompt you for is the name of the theme that you want to create. If it was not able to identify that information, the prompt will ask for Site Name, SFTP username and hostname, and the theme name. Once this information is entered, a confirmation prompt is displayed to ensure that the information is correct. You can type `y` to accept the information or `n` to start the prompts over. If the defaults were used, they will be cleared on a `n` entry, but they will be displayed in their respective prompts. + +It's important at this step, when choosing a theme name, to use a name that does **not** include spaces. This name will be used as the directory name and slug for the theme and will be used in bash commands which could error or fail if spaces were entered that it was not expecting. + +### Update PHP +The first change the script actually makes is updating the PHP version in the `pantheon.upstream.yml` file to 8.0 as required by Sage. This is done with a `sed` command and immediately pushed on completion. + +```yml +php_version: 8.0 +``` + +### Install Sage +The next step is to install Sage. Before this is done, the script will check to see if a directory already exists in `web/app/themes` that matches the name of the theme you entered. If it does, the script will end immediately with a `Directory not empty` error. Otherwise, the script will continue by running the following composer commands: + + ```bash + # Create the new Sage theme + composer create-project roots/sage $sagedir + + # Require Roots/acorn + composer require roots/acorn --working-dir=$sagedir + + # Install all the Sage dependencies + composer install --no-dev --prefer-dist --working-dir=$sagedir + ``` + + Note: In the code snippet above, `$sagedir` refers to the full path of the Sage theme that you are creating. If you are performing the steps manually, you can save that variable name by entering `sagedir=web/app/themes/` before running the commands. + +Once the Composer processes are done, the NPM processes kick in, The script will run the following to build and install all the Sage NPM dependencies. + +```bash +npm install --prefix $sagedir +npm run build --prefix $sagedir +``` + +When this completes, the `.gitignore` file inside the new Sage theme is modified to remove the line ignoring the `/public/` directory, which should exist on the Pantheon environment. + +Then, the newly created theme is added to Git and committed. + +```bash + git add $sagedir + git commit -m "[Sage Install] Add the Sage theme ${sagename}." + git push origin master +``` + +### Adding the Symlink +The next part of the script adds a symlink to point `web/app/cache` to `web/app/uploads/cache`. Sage assumes the `web/app/` directory is writeable, but on Pantheon it is not. However, we can get around this by creating a symbolic link so `web/app/cache` points to `web/app/uploads/cache`. + +First, the script switches to the Pantheon site to SFTP mode, which we will need to make changes to the filesystem before creating the symlink. + +```bash + terminus connection:set $sitename.dev sftp +``` + + Then, it checks the existance of and creates the `web/app/uploads` and `web/app/uploads/cache` directories if they do not exist. Then, it connects to the site over SFTP to create the `/files/cache` directory with the following command: + +```bash +sftp -P 2222 $sftpuser@$sftphost < composer.new.json + sed -i '' "s,%sagedir%,$sagedir," composer.new.json + rm composer.json + mv composer.new.json composer.json +``` + +If you are doing this manually, you can add the following to your `composer.json` in the `scripts` section: + +```json + "post-install-cmd": [ + "@composer install --no-dev --prefer-dist --ignore-platform-reqs --working-dir=web/app/themes/" + ] +``` + +Once the change is made, it's committed and pushed to the site. + +### Final Steps +The last steps are to activate the theme and verify that it displays as expected. + +For WordPress multisites, we need to first Network Enable the theme before it can be activated, so the script runs the following command: + +```bash + terminus wp $sitename.dev -- theme enable $sagename --network +``` + +Then, the theme is activated: + +```bash + terminus wp $sitename.dev -- theme activate $sagename +``` + +Finally, the script will open the site in your default browser to verify that the theme is displaying as expected. + +```bash +terminus wp -- $sitename.dev theme enable $sagename +``` + +For single sites, this will produce an error, but it will not exit the script. This is normal and expected. Once we know that the theme is enabled (if applicable), the script will run a `wp theme list` to ensure it appears in the list of themes: + +```bash + terminus wp -- $sitename.dev theme list +``` + +If you are performing these steps manually, take time to make sure that your new theme shows up in the theme list. If it does not, you may want to retrace your steps. + +Assuming it shows up, the next step is to activate the theme. This is also done via WP-CLI. + +```bash + terminus wp -- $sitename.dev theme activate $sagename +``` + +Once it's activated, the script will attempt to open your site in your default browser. If you are performing these steps manually, you can open the site in your browser and verify that the theme is displaying as expected. It's possible here that you may need to flush your browser cache or use a different browser if you did not see the new sage theme show up. If you continue to see a different default theme, ensure the theme is activated by going to your `wp-admin/themes.php` page. Otherwise, you should see something like this: + +![Newly-installed Sage theme screenshot](./images/sage-theme-screenshot.png) + +If you see a fresh Sage starter theme, the setup worked and you're ready to start building! Refer to the [Sage documentation](https://docs.roots.io/sage/10.x/configuration/) for more information on how to use Sage now that it's been installed. + +## Final Thoughts +This script was written with the assumption that you are only using a single Sage theme. If you install multiple Sage themes, you will need to manually update the `composer.json` file to include the `post-install-cmd` for each theme as the script will update the existing entry if one exists already. Additionally, some steps (like creating directories and symlinks) will naturally fail if those things have been done already. diff --git a/docs/images/sage-theme-screenshot.png b/docs/images/sage-theme-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..d989d68017acfaaba54125be96f1be7ea2fe452a GIT binary patch literal 60886 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%0A+Ur$$Pe0(8`()8i| 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 literal 0 HcmV?d00001 diff --git a/private/scripts/sage-theme-install.sh b/private/scripts/sage-theme-install.sh new file mode 100755 index 00000000..77426b10 --- /dev/null +++ b/private/scripts/sage-theme-install.sh @@ -0,0 +1,325 @@ + +#!/usr/bin/env bash + +# Get the site name, theme name, and SFTP credentials from the user. +function get_info() { + # If is_restarted is unset, set it to 0. + if [ -z "$is_restarted" ]; then + is_restarted=0 + fi + + dashboard_link="https://dashboard.pantheon.io/sites/${id}#dev/code" + + # Unset the variables if we're doing this a second time. + if [ $is_restarted == 1 ]; then + unset sitename + unset sagename + unset sftpuser + unset sftphost + fi + + if [ $is_restarted == 0 ]; then + echo -e "${yellow}Finding site information...${normal}\n" + fi + + # Set up some defaults. These should evaluate to false if you go through + # the prompts once but say no to the confirmation because at that point we + # set them to empty strings. + # There's some discussion about the brackets distinction in this + # StackOverflow: https://stackoverflow.com/a/13864829/1351526 + if [ $is_restarted == 0 ] && [ -z "$sitename" ]; then + echo "Found site name! Using ${name}." + sitename=$name + fi + + if [ $is_restarted == 0 ] && [ -z "$sftpuser" ]; then + echo "Found SFTP username! Using dev.${id}." + sftpuser=dev.$id + fi + + if [ $is_restarted == 0 ] && [ -z "$sftphost" ]; then + echo "Found SFTP host name! Using appserver.dev.${id}.drush.in." + sftphost=appserver.dev.$id.drush.in + fi + + if [ $is_restarted == 0 ]; then + echo -e "\n--------------------------------------------------------------------------" + fi + # We want these to evaluate to false if they're empty strings so they can be + # set manually. + if [ -z "$sitename" ]; then + echo -e "${yellow}Enter the site name.${normal}\nThis will be used to interact with your site. The default is ${green}${name}${normal}." + read -p "Site name: " -r sitename + else + echo -e "${green}Site name: ${normal}${sitename}" + fi + + if [ -z "$sftpuser" ]; then + echo -e "${yellow}Enter your SFTP username.${normal}\nThis will only be stored in this terminal session. This can be found in your site dashboard. The default is ${green}dev.${id}${normal}. \nDashboard link: ${dashboard_link}" + read -p "SFTP username: " -r sftpuser + else + echo -e "${green}SFTP username: ${normal}${sftpuser}" + fi + + if [ -z "$sftphost" ]; then + echo -e "${yellow}Enter your SFTP hostname.${normal}\nThis will only be stored in this terminal session. This can be found in your site dashboard. The default is ${green}appserver.dev.${id}.drush.in${normal}. \nDashboard link: ${dashboard_link}" + read -p "SFTP hostname: " -r sftphost + else + echo -e "${green}SFTP hostname: ${normal}${sftphost}" + fi + + if [ $is_restarted == 0 ]; then + echo -e "--------------------------------------------------------------------------\n" + fi + + # This is the first input that doesn't have a default. We'll do the line break above this. + if [ -z "$sagename" ]; then + echo -e "${yellow}Enter your theme name.${normal}\nThis is used to create the theme directory. As such, it should ideally be all lowercase with no spaces (hyphens or underscores recommended)\n" + read -p "Theme name: " -r sagename + else + echo -e "${green}Theme name: ${sagename}${normal}" + fi + + echo "You've entered: + Site name: ${sitename} + Theme name: ${sagename} + SFTP username: ${sftpuser} + SFTP hostname: ${sftphost}" + read -p "Is this correct? (y/n) " -n 1 -r + # If the user enters n, redo the prompts. + if [[ $REPLY =~ ^[Nn]$ ]]; then + echo -e "\nRestarting...\n" + + # Toggle the restarted state. + is_restarted=1 + + get_info + fi + + if [ -z "$sitename" ] || [ -z "$sagename" ] || [ -z "$sftpuser" ] || [ -z "$sftphost" ]; then + echo -e "\n${red}Missing information!${normal} Make sure you've everything for all the prompts.\n" + get_info + fi + + # Set the theme directory. Do this at the end, after we know what everything should be. + sagedir=$themedir/$sagename +} + +# Use terminus whoami to check if the user is logged in and exit the script if they are not. +function check_login() { + echo -e "${yellow}Checking if you are logged in to Terminus...${normal}" + # Read the response from terminus whoami into the REPLY variable. + REPLY=$(terminus whoami) + + # If the response does not include a @, you're not logged in. + # Ask the user to log in and exit. + if [[ $REPLY != *"@"* ]]; then + echo -e "${red}You are not logged in to Terminus.${normal}\nPlease authenticate with terminus first using ${bold}terminus auth:login${normal}" + exit 1; + fi +} + +# Get a field from the output of terminus site:info. +get_field() { + local input="$1" + # Remove leading and trailing whitespace from each line + input="$(echo "$input" | sed -e 's/^[ \t]*//')" + + # Remove the first and last lines that are entirely dashes + input="$(echo "$input" | sed -e '1d' -e '$d')" + # $1: field name + # $2: input string + echo "$2" | awk -v field="$1" '$1 == field { print $2 }' +} + +# Update to PHP 8.0 +function update_php() { + echo -e "\n\n${yellow}Updating PHP version to 8.0.${normal}" + sed -i '' "s/php_version: 7.4/php_version: 8.0/" pantheon.upstream.yml + git commit -am "[Sage Install] Update PHP version to 8.0" + git push origin master +} + +# Install sage and related dependencies. +function install_sage() { + # Check if the directory $sagedir is empty. If it's not, bail. + echo -e "Checking if ${sagedir} is exists and if it's empty.\n" + + if [ "$(ls -A $sagedir)" ]; then + echo -e "${red}Directory not empty!${normal}\n Trying to install into ${sagedir}. Exiting." + exit 1; + fi + + echo -e "${yellow}Installing Sage.${normal}" + # Create the new Sage theme + composer create-project roots/sage $sagedir + + # Require Roots/acorn + composer require roots/acorn --working-dir=$sagedir + + # Install all the Sage dependencies + composer install --no-dev --prefer-dist --working-dir=$sagedir + + # NPM the things + npm install --prefix $sagedir + npm run build --prefix $sagedir + + # Remove /public from .gitignore + sed -i '' "s/\/public//" $sagedir/.gitignore + + # Commit the theme + git add $sagedir + git commit -m "[Sage Install] Add the Sage theme ${sagename}." + git push origin master + echo -e "${green}Sage installed!${normal}\n" +} + +# Create the symlink to the cache directory. +function add_symlink() { + # Switch to SFTP mode + terminus connection:set $sitename.dev sftp + + if [ ! -d "web/app/uploads" ]; then + echo -e "${yellow}Creating the uploads directory.${normal}" + mkdir web/app/uploads + fi + + if [ ! -d "web/app/uploads/cache" ]; then + echo -e "${yellow}Creating the cache directory.${normal}" + mkdir web/app/uploads/cache + fi + + # Create a files/cache directory on the host. + sftp -P 2222 $sftpuser@$sftphost < /dev/null ]; then + if [ ! command -v brew & /dev/null ]; then + echo "${yellow}Brew was not found. Exiting here. You'll need to add the following lines to your `composer.json`:${normal}" + echo ' "scripts": {' + echo ' "post-install-cmd": [' + echo " \"@composer install --no-dev --prefer-dist --ignore-platform-reqs --working-dir=web/app/themes/$sagename\"" + echo ' ],' + exit + fi + brew install jq + fi + + # Add a post-install hook to the composer.json. + echo -e "${yellow}Adding a post-install hook to composer.json.${normal}" + jq -r '.scripts += { "post-install-cmd": [ "@composer install --no-dev --prefer-dist --ignore-platform-reqs --working-dir=%sagedir%" ] }' composer.json > composer.new.json + sed -i '' "s,%sagedir%,$sagedir," composer.new.json + rm composer.json + mv composer.new.json composer.json + + # Commit the change to composer.json + git add composer.json + git commit -m "[Sage Install] Add post-install-cmd hook to also run install on ${sagename}" + + git pull --ff --commit + git push origin master + if [ $? -ne 0 ]; then + echo -e "\n${red}Push failed. Stopping here.${normal}\nNext steps are to push the changes to the repo and then set the connection mode back to Git." + exit 1; + fi + + # Wait for the build to finish. + echo -e "${yellow}Waiting for the deploy to finish.${normal}" + terminus workflow:wait --max=30 $sitename.dev + if [ $? -ne 0 ]; then + echo -e "\n${red}terminus workflow:wait command not found. Stopping here.${normal}\nYou will need to install the terminus-build-tools-plugin.\nterminus self:plugin:install terminus-build-tools-plugin" + exit 1; + fi + + # Check for long-running workflows. + if [[ "$(terminus workflow:wait --max=1 ${sitename}.dev)" == *"running"* ]]; then + echo -e "${yellow}Workflow still running, waiting another 30 seconds.${normal}" + terminus workflow:wait --max=30 $sitename.dev + fi +} + +# Finish up the Sage install process. +function clean_up() { + # If the site is multisite, we'll need to enable the theme so we can activate it. + terminus wp -- $sitename.dev theme enable $sagename + # List the themes. + terminus wp -- $sitename.dev theme list + + # Activate the new theme + echo -e "${yellow}Activating the ${sagename} theme.${normal}" + terminus wp -- $sitename.dev theme activate $sagename + if [ $? -ne 0 ]; then + echo -e "${red}Theme activation failed. Exiting here.${normal}\nCheck the theme list above. If the theme you created is not listed, it's possible that the deploy has not completed. You can try again in a few minutes using the following command:\nterminus wp -- $sitename.dev theme activate $sagename\nOnce you do this, you will need to open the site to generate the requisite files and then commit them in SFTP mode.\n5. You're ready to go! Set the connection mode back to Git." + exit 1; + fi + + # Switch back to SFTP so files can be written. + terminus connection:set $sitename.dev sftp + + # Open the site. This should generate requisite files on page load. + echo -e "${yellow}Opening the dev-${sitename}.pantheonsite.io to generate requisite files.${normal}" + open https://dev-$sitename.pantheonsite.io + + # Commit any additions found in SFTP mode. + echo -e "${yellow}Committing any files found in SFTP mode that were created by Sage.${normal}" + terminus env:commit $sitename.dev --message="[Sage Install] Add any leftover files found in SFTP mode." + + # Switch back to Git. + terminus connection:set $sitename.dev git + git pull --ff --commit +} + +# Defines some global variables for colors. +normal=$(tput sgr0) +bold=$(tput bold) +italic=$(tput sitm) +red=$(tput setaf 1) +green=$(tput setaf 2) +yellow=$(tput setaf 3) +blue=$(tput setaf 4) +magenta=$(tput setaf 5) +cyan=$(tput setaf 6) + +# Check if the user is logged into Terminus before trying to run other Terminus commands. +check_login + +themedir="web/app/themes" +siteinfo=$(terminus site:info) +id=$(get_field "ID" "$siteinfo") +name=$(get_field "Name" "$siteinfo") + +get_info +update_php +install_sage +add_symlink +update_composer +clean_up From 3cf658d738ea8c830dd9db00ce4a76a336127d7e Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Tue, 10 Jan 2023 12:53:12 -0700 Subject: [PATCH 05/16] Roots Sage install script and repository maintenance This update adds an install script (located in /private/scripts and accessible via Composer) that can assist in installing the Roots Sage theme on new WordPress (Composer Managed) sites. Documentation can be found in the README.md file and in the Installing Sage doc in /docs. This update also disables the Dependabot dependency management notifications (we do not want to change the versions of dependencies in our composer.json file for risk of merge conflicts). Finally, this update resolves an issue that was causing releases to not deploy to the Decoupled WordPress (Composer Managed) upstream. --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ac1e10d..1b6b373a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ -### 2023-01-10 +### 2023-01-11 * Remove Dependabot ([#58](https://github.com/pantheon-systems/wordpress-composer-managed/pull/58)) * Resolves issue where updates to commit choosing logic were causing a merge conflict. ([#60](https://github.com/pantheon-systems/wordpress-composer-managed/pull/60)) +* Adds a Roots Sage install script. See [docs/Installing-Sage.md](docs/Installing-Sage.md) ([#61](https://github.com/pantheon-systems/wordpress-composer-managed/pull/61)) ### 2022-11-30 * Set minimum-stability to "stable" in `composer.json` ([#55](https://github.com/pantheon-systems/wordpress-composer-managed/pull/55)) From 0efbd3993ebeaaac7986663f5699a110a69deb7f Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Wed, 11 Jan 2023 10:23:19 -0700 Subject: [PATCH 06/16] Update the SSH key fingerprint (#63) --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1fa372db..94b3d8d2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,7 +31,7 @@ jobs: # ssh-keygen -l -E md5 -f ed25519 - add_ssh_keys: fingerprints: - - "d6:6c:3e:b6:92:36:04:fc:5a:23:1f:e2:9d:87:00:ef" + - "f0:fb:bb:86:5c:da:1a:7e:77:02:f8:21:ba:bf:81:79" - run: name: Copy commits to destination repo command: devops/scripts/deploy-public-upstream.sh From 3d27b365295b812d35bed87ec7527331e4d55fef Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Wed, 11 Jan 2023 10:23:19 -0700 Subject: [PATCH 07/16] Roots Sage install script & repository maintenance This update adds an install script (located in /private/scripts and accessible via Composer) that can assist in installing the Roots Sage theme on new WordPress (Composer Managed) sites. Documentation can be found in the README.md file and in the Installing Sage doc in /docs. This update also disables the Dependabot dependency management notifications (we do not want to change the versions of dependencies in our composer.json file for risk of merge conflicts). Finally, this update resolves an issue that was causing releases to not deploy to the Decoupled WordPress (Composer Managed) upstream. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1fa372db..94b3d8d2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,7 +31,7 @@ jobs: # ssh-keygen -l -E md5 -f ed25519 - add_ssh_keys: fingerprints: - - "d6:6c:3e:b6:92:36:04:fc:5a:23:1f:e2:9d:87:00:ef" + - "f0:fb:bb:86:5c:da:1a:7e:77:02:f8:21:ba:bf:81:79" - run: name: Copy commits to destination repo command: devops/scripts/deploy-public-upstream.sh From b79f19a97a6c0e159c6a74001b73baf081a9df7d Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Wed, 11 Jan 2023 10:49:22 -0700 Subject: [PATCH 08/16] update ssh key fingerprint (#65) again --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 94b3d8d2..deffbc37 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,7 +31,7 @@ jobs: # ssh-keygen -l -E md5 -f ed25519 - add_ssh_keys: fingerprints: - - "f0:fb:bb:86:5c:da:1a:7e:77:02:f8:21:ba:bf:81:79" + - "50:72:cc:79:5d:fa:9d:b9:83:40:af:e9:4a:37:4f:4b" - run: name: Copy commits to destination repo command: devops/scripts/deploy-public-upstream.sh From 55b804d4222c41f5e6cc0cf1abbe65cb9c7e42a8 Mon Sep 17 00:00:00 2001 From: Brian Perry Date: Wed, 1 Feb 2023 15:55:11 -0600 Subject: [PATCH 09/16] DB-5248: add composer patches plugin (#66) * DB-5248: add composer patches plugin * DB-5248: exit on patch failure --- composer.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index c2f66b2a..6b6646a7 100644 --- a/composer.json +++ b/composer.json @@ -64,7 +64,8 @@ "pantheon-upstreams/upstream-configuration": "dev-main", "wpackagist-plugin/lh-hsts": "^1.25", "wpackagist-plugin/pantheon-advanced-page-cache": "*", - "wpackagist-plugin/wp-native-php-sessions": "*" + "wpackagist-plugin/wp-native-php-sessions": "*", + "cweagans/composer-patches": "^1.7" }, "require-dev": { "squizlabs/php_codesniffer": "^3.6.2", @@ -76,7 +77,8 @@ "process-timeout": 0, "allow-plugins": { "composer/installers": true, - "roots/wordpress-core-installer": true + "roots/wordpress-core-installer": true, + "cweagans/composer-patches": true } }, "minimum-stability": "stable", @@ -98,7 +100,9 @@ "locations": { "web-root": "./" } - } + }, + "composer-exit-on-patch-failure": true, + "enable-patching": true }, "autoload": { "classmap": [ From 7637e103fe833a0dd4de96415968431c2ef6f109 Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Thu, 2 Feb 2023 14:31:32 -0700 Subject: [PATCH 10/16] Adds Composer Patches plugin The Composer Patches plugin provides a way to patch any required Composer package from a local or remote file. This brings the WordPress (Composer Managed) upstream in line with the existing Drupal (Composer Managed) upstream which also supports Composer Patches. You can learn more about Composer Patches here: https://github.com/cweagans/composer-patches --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b6b373a..b3352dfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 2023-02-02 +* Adds Composer Patches plugin ([#66](https://github.com/pantheon-systems/wordpress-composer-managed/pull/66)) + ### 2023-01-11 * Remove Dependabot ([#58](https://github.com/pantheon-systems/wordpress-composer-managed/pull/58)) * Resolves issue where updates to commit choosing logic were causing a merge conflict. ([#60](https://github.com/pantheon-systems/wordpress-composer-managed/pull/60)) From 010f4a41b6de2647d39c9c819a997a6962a4c925 Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Tue, 7 Feb 2023 15:37:38 -0700 Subject: [PATCH 11/16] [CMSP-220] Decoupled deploy bug (#71) * break out the conditional to be more explicit this if statement was failing when it was all on one line. Breaking it out has the result of actually accomplishing what is intended in the code * fix skip check previously we were skipping everything * fixes an unbound variable error * accept incoming code from cherry pick * Be explicit in our check vs $skip Co-authored-by: Phil Tyler --------- Co-authored-by: Phil Tyler --- devops/scripts/deploy-decoupled-upstream.sh | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/devops/scripts/deploy-decoupled-upstream.sh b/devops/scripts/deploy-decoupled-upstream.sh index 8d816257..d5939a59 100755 --- a/devops/scripts/deploy-decoupled-upstream.sh +++ b/devops/scripts/deploy-decoupled-upstream.sh @@ -40,10 +40,13 @@ for commit in $newcommits; do # Exclude commits which have been manually rejected skip=false for item in "${exclude_list[@]}"; do - [[ $item == $commit ]] && echo "Commit ${commit} has been manually excluded."; skip=true + if [[ $item == $commit ]]; then + echo "Commit ${commit} has been manually excluded." + skip=true + fi done - if [[ $skip==true ]] ; then + if [[ $skip == true ]] ; then continue fi @@ -57,11 +60,13 @@ for commit in $newcommits; do echo "You may wish to ensure that nothing in this commit is meant for release." delete=(${commit}) for remove in "${delete[@]}"; do - for i in "${commits[@]}"; do - if [ [ ${commits[i]} = $remove ]]; then - unset 'commits[i]' - fi - done + if (( ${#commits[@]} )); then + for i in "${commits[@]}"; do + if [[ ${commits[0]} = $remove ]]; then + unset 'commits[i]' + fi + done + fi done fi done @@ -88,7 +93,7 @@ for commit in "${commits[@]}"; do fi echo "Adding $commit:" git --no-pager log --format=%B -n 1 "$commit" - git cherry-pick -rn "$commit" 2>&1 + git cherry-pick -rn -X theirs "$commit" 2>&1 # Product request - single commit per release # The commit message from the last commit will be used. git log --format=%B -n 1 "$commit" > /tmp/commit_message From b2e0b5351eff1baf7390c9578528d38410f8b933 Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Tue, 7 Feb 2023 15:37:38 -0700 Subject: [PATCH 12/16] [CMSP-220] Decoupled deploy bug (#71) * break out the conditional to be more explicit this if statement was failing when it was all on one line. Breaking it out has the result of actually accomplishing what is intended in the code * fix skip check previously we were skipping everything * fixes an unbound variable error * accept incoming code from cherry pick * Be explicit in our check vs $skip Co-authored-by: Phil Tyler --------- Co-authored-by: Phil Tyler --- devops/scripts/deploy-decoupled-upstream.sh | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/devops/scripts/deploy-decoupled-upstream.sh b/devops/scripts/deploy-decoupled-upstream.sh index 8d816257..d5939a59 100755 --- a/devops/scripts/deploy-decoupled-upstream.sh +++ b/devops/scripts/deploy-decoupled-upstream.sh @@ -40,10 +40,13 @@ for commit in $newcommits; do # Exclude commits which have been manually rejected skip=false for item in "${exclude_list[@]}"; do - [[ $item == $commit ]] && echo "Commit ${commit} has been manually excluded."; skip=true + if [[ $item == $commit ]]; then + echo "Commit ${commit} has been manually excluded." + skip=true + fi done - if [[ $skip==true ]] ; then + if [[ $skip == true ]] ; then continue fi @@ -57,11 +60,13 @@ for commit in $newcommits; do echo "You may wish to ensure that nothing in this commit is meant for release." delete=(${commit}) for remove in "${delete[@]}"; do - for i in "${commits[@]}"; do - if [ [ ${commits[i]} = $remove ]]; then - unset 'commits[i]' - fi - done + if (( ${#commits[@]} )); then + for i in "${commits[@]}"; do + if [[ ${commits[0]} = $remove ]]; then + unset 'commits[i]' + fi + done + fi done fi done @@ -88,7 +93,7 @@ for commit in "${commits[@]}"; do fi echo "Adding $commit:" git --no-pager log --format=%B -n 1 "$commit" - git cherry-pick -rn "$commit" 2>&1 + git cherry-pick -rn -X theirs "$commit" 2>&1 # Product request - single commit per release # The commit message from the last commit will be used. git log --format=%B -n 1 "$commit" > /tmp/commit_message From 410f21245d6f0868d0967a8b1b9b9d33a0a57b41 Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Tue, 21 Mar 2023 08:24:22 -0600 Subject: [PATCH 13/16] Add CMS Platform to CODEOWNERS (#70) * Add CMS Platform to CODEOWNERS * Update CODEOWNERS Co-authored-by: Phil Tyler --------- Co-authored-by: Phil Tyler --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 074bbf0c..3ee2a26f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,4 @@ # Code owners. See: # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners -* @pantheon-systems/cms-ecosystem \ No newline at end of file +* @pantheon-systems/cms-ecosystem @pantheon-systems/cms-platform From 186e2351e29d1f164b6bff4086cd3635c7c685b5 Mon Sep 17 00:00:00 2001 From: Matthew Bernhardt Date: Mon, 10 Jul 2023 14:33:42 -0400 Subject: [PATCH 14/16] Output of composer install --- composer.lock | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index 19668fee..3b36ad17 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f6eb2172ed742628459f967062487e7e", + "content-hash": "3b3d9be6b3786ccc9f831e3056a97871", "packages": [ { "name": "ConnectThink/WP-SCSS", @@ -176,6 +176,54 @@ ], "time": "2022-08-20T06:45:11+00:00" }, + { + "name": "cweagans/composer-patches", + "version": "1.7.3", + "source": { + "type": "git", + "url": "https://github.com/cweagans/composer-patches.git", + "reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweagans/composer-patches/zipball/e190d4466fe2b103a55467dfa83fc2fecfcaf2db", + "reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.3.0" + }, + "require-dev": { + "composer/composer": "~1.0 || ~2.0", + "phpunit/phpunit": "~4.6" + }, + "type": "composer-plugin", + "extra": { + "class": "cweagans\\Composer\\Patches" + }, + "autoload": { + "psr-4": { + "cweagans\\Composer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Cameron Eagans", + "email": "me@cweagans.net" + } + ], + "description": "Provides a way to patch Composer packages.", + "support": { + "issues": "https://github.com/cweagans/composer-patches/issues", + "source": "https://github.com/cweagans/composer-patches/tree/1.7.3" + }, + "time": "2022-12-20T22:53:13+00:00" + }, { "name": "firebase/php-jwt", "version": "v6.8.0", From e061d6e70de24d32f96adc3af2a54edf5b2f4421 Mon Sep 17 00:00:00 2001 From: Matthew Bernhardt Date: Mon, 10 Jul 2023 14:43:13 -0400 Subject: [PATCH 15/16] Update symlinks and add stub document for changes ** Why are these changes being introduced: * The symlinks for the sites on our network are no longer needed, and can be removed. * Additionally, we need a place for documenting how upstream changes like these should be merged into our codebase. ** Relevant ticket(s): * https://mitlibraries.atlassian.net/browse/pw-49 ** How does this address that need: * This removes all the site-related symlinks in the web/ directory, as well as their entries in the phpcs.xml configuration. They are no longer needed. * Additionally, this adds a stub documentation page for how to apply these updates, which will be fleshed out in a subsequent PR. ** Document any side effects to this change: * None, unless you count having the stub page as a side effect. --- docs/howto/apply-pantheon-updates.md | 4 ++++ phpcs.xml | 22 ---------------------- web/150books | 1 - web/about | 1 - web/akdc | 1 - web/collections | 1 - web/council | 1 - web/creos | 1 - web/data-management | 1 - web/distinctive-collections | 1 - web/docs | 1 - web/exhibits | 1 - web/future-spaces | 1 - web/giving | 1 - web/mit-and-slavery | 1 - web/mit-reads | 1 - web/mithistory | 1 - web/music-oral-history | 1 - web/news | 1 - web/opendata | 1 - web/pomeroy | 1 - web/scholarly | 1 - 22 files changed, 4 insertions(+), 42 deletions(-) create mode 100644 docs/howto/apply-pantheon-updates.md delete mode 120000 web/150books delete mode 120000 web/about delete mode 120000 web/akdc delete mode 120000 web/collections delete mode 120000 web/council delete mode 120000 web/creos delete mode 120000 web/data-management delete mode 120000 web/distinctive-collections delete mode 120000 web/docs delete mode 120000 web/exhibits delete mode 120000 web/future-spaces delete mode 120000 web/giving delete mode 120000 web/mit-and-slavery delete mode 120000 web/mit-reads delete mode 120000 web/mithistory delete mode 120000 web/music-oral-history delete mode 120000 web/news delete mode 120000 web/opendata delete mode 120000 web/pomeroy delete mode 120000 web/scholarly diff --git a/docs/howto/apply-pantheon-updates.md b/docs/howto/apply-pantheon-updates.md new file mode 100644 index 00000000..4e895405 --- /dev/null +++ b/docs/howto/apply-pantheon-updates.md @@ -0,0 +1,4 @@ +# How to apply updates from Pantheon + +This document will describe the process for keeping our repository up-to-date +with upstream changes introduced by Pantheon. diff --git a/phpcs.xml b/phpcs.xml index 31feac5c..54dbe2d1 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -31,28 +31,6 @@ web/app/themes/twentytwentytwo/ vendor/ - - web/150books - web/about - web/akdc - web/collections - web/council - web/creos - web/data-management - web/distinctive-collections - web/docs - web/exhibits - web/future-spaces - web/giving - web/mit-and-slavery - web/mit-reads - web/mithistory - web/music-oral-history - web/news - web/opendata - web/pomeroy - web/scholarly - web/app/mu-plugins/bedrock-disallow-indexing web/app/mu-plugins/multisite-url-fixer diff --git a/web/150books b/web/150books deleted file mode 120000 index 9101ba0c..00000000 --- a/web/150books +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/about b/web/about deleted file mode 120000 index 9101ba0c..00000000 --- a/web/about +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/akdc b/web/akdc deleted file mode 120000 index 9101ba0c..00000000 --- a/web/akdc +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/collections b/web/collections deleted file mode 120000 index 9101ba0c..00000000 --- a/web/collections +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/council b/web/council deleted file mode 120000 index 9101ba0c..00000000 --- a/web/council +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/creos b/web/creos deleted file mode 120000 index 9101ba0c..00000000 --- a/web/creos +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/data-management b/web/data-management deleted file mode 120000 index 9101ba0c..00000000 --- a/web/data-management +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/distinctive-collections b/web/distinctive-collections deleted file mode 120000 index 9101ba0c..00000000 --- a/web/distinctive-collections +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/docs b/web/docs deleted file mode 120000 index 9101ba0c..00000000 --- a/web/docs +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/exhibits b/web/exhibits deleted file mode 120000 index 9101ba0c..00000000 --- a/web/exhibits +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/future-spaces b/web/future-spaces deleted file mode 120000 index 9101ba0c..00000000 --- a/web/future-spaces +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/giving b/web/giving deleted file mode 120000 index 9101ba0c..00000000 --- a/web/giving +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/mit-and-slavery b/web/mit-and-slavery deleted file mode 120000 index 9101ba0c..00000000 --- a/web/mit-and-slavery +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/mit-reads b/web/mit-reads deleted file mode 120000 index 9101ba0c..00000000 --- a/web/mit-reads +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/mithistory b/web/mithistory deleted file mode 120000 index 9101ba0c..00000000 --- a/web/mithistory +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/music-oral-history b/web/music-oral-history deleted file mode 120000 index 9101ba0c..00000000 --- a/web/music-oral-history +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/news b/web/news deleted file mode 120000 index 9101ba0c..00000000 --- a/web/news +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/opendata b/web/opendata deleted file mode 120000 index 9101ba0c..00000000 --- a/web/opendata +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/pomeroy b/web/pomeroy deleted file mode 120000 index 9101ba0c..00000000 --- a/web/pomeroy +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file diff --git a/web/scholarly b/web/scholarly deleted file mode 120000 index 9101ba0c..00000000 --- a/web/scholarly +++ /dev/null @@ -1 +0,0 @@ -wp \ No newline at end of file From b645c162abb57249cca6feefa427bf2441180768 Mon Sep 17 00:00:00 2001 From: Matthew Bernhardt Date: Tue, 11 Jul 2023 16:23:01 -0400 Subject: [PATCH 16/16] Update CODEOWNERS for local context --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 3ee2a26f..b93b0286 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,4 @@ # Code owners. See: # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners -* @pantheon-systems/cms-ecosystem @pantheon-systems/cms-platform +# @pantheon-systems/cms-ecosystem @pantheon-systems/cms-platform