diff --git a/.ci/github/clean_up b/.ci/github/clean_up new file mode 100755 index 0000000000..b3fe09805d --- /dev/null +++ b/.ci/github/clean_up @@ -0,0 +1,74 @@ +#!/bin/bash -x + +set -eo pipefail + +# Install Terminus Build Bools. +terminus self:plugin:install terminus-build-tools-plugin + +# Get release sites and convert to an array. +readarray -t sites_array <<< "$(tr -d '\r' <<< "$RELEASE_SITES")" + +# Release branch variable does not exist, so create multidevs for the first time. +if [ "$RELEASE_BRANCH" ]; then + # Set release branch. + #gh variable set RELEASE_BRANCH --body "$RELEASE_BRANCH" + + # Prepare output file for comment. + echo "Environments ready for review:" >> output.txt +else + echo "test" + # Get release branch if already set. + #release_branch=$(gh api /repos/"$REPO"/actions/variables --jq '.variables.[] | select(.name=="RELEASE_BRANCH") | .value') +fi + +push_code() { + git_path=$(terminus connection:info "$site_with_env" --field=git_url) + git remote add "$site_machine_name" "$git_path" + git fetch "$site_machine_name" + git push "$site_machine_name" "$RELEASE_BRANCH:$RELEASE_BRANCH" --force + terminus workflow:wait "$site_machine_name"."$RELEASE_BRANCH" --max=300 +} + +process_site() { + site_with_env="$1" + site_machine_name="${site_with_env%.*}" + + echo -e "\nCreating multidev $site_machine_name.$RELEASE_BRANCH from $site_with_env...\n" + + if [ "$site_machine_name" = "yalesites-platform" ]; then + terminus multidev:create "$site_with_env" "$RELEASE_BRANCH" --no-db --no-files + else + terminus multidev:create "$site_with_env" "$RELEASE_BRANCH" + fi + + push_code + + # Do a fresh install on yalesites-platform site. + if [ "$site_machine_name" = "yalesites-platform" ]; then + echo -e "\nInstalling clean site for $site_machine_name.$RELEASE_BRANCH...\n" + terminus -n env:wake "$site_machine_name"."$RELEASE_BRANCH" + terminus -n drush "$site_machine_name"."$RELEASE_BRANCH" -- si yalesites_profile -y + terminus -n drush "$site_machine_name"."$RELEASE_BRANCH" -- cr + SITE_MACHINE_NAME="$site_machine_name" env="$RELEASE_BRANCH" ./scripts/shared/content-import.sh + fi + + terminus -n env:wake "$site_machine_name"."$RELEASE_BRANCH" + echo -e "\nRunning drush deploy...\n" + terminus -n drush "$site_machine_name"."$RELEASE_BRANCH" -- deploy -v -y + + # Get site URL and output to file + site_url=$(terminus -n domain:list "$site_machine_name"."$RELEASE_BRANCH" --filter='type=platform' --field=id) + echo "- https://$site_url" >> output.txt +} + +# Export functions so that GNU Parallel can access them +export -f push_code +export -f process_site + +parallel --jobs 0 --keep-order --line-buffer process_site {} ::: "${sites_array[@]}" + +# If we are creating the PR for the first time, post a comment with the created site URLs. +gh issue comment "$PR_NUMBER" --body-file output.txt + +# TODO: after PR closed, delete multidevs +# TODO: support new commits, push new code to multidevs diff --git a/.ci/github/create_release_pull_request b/.ci/github/create_release_pull_request index 69242acaeb..f11530d777 100755 --- a/.ci/github/create_release_pull_request +++ b/.ci/github/create_release_pull_request @@ -2,14 +2,14 @@ set -eo pipefail -# If we aren't updating an existing pull request, create one to merge develop into master. +# If we aren't updating an existing pull request, create one to merge the release branch into master. if [[ -z "$PR_NUMBER" ]]; then pull_request_response=$(curl -s -H "Accept: application/vnd.github+json" \ -H "Authorization: token $ACCESS_TOKEN" \ - -X POST -d '{"title": "Release", "head": "develop", "base": "master"}' \ + -X POST -d '{"title": "Release", "head": "'"$RELEASE_BRANCH"'", "base": "master"}' \ "https://api.github.com/repos/$REPO/pulls") - message=$(echo "$pull_request_response" | jq -r 'if has("errors") then .errors[].message else null end') + message=$(echo "$pull_request_response" | jq -r 'if has("errors") then .errors[].message else empty end') # Check if the pull request creation was successful. if [[ -n "$message" ]]; then @@ -23,6 +23,9 @@ if [[ -z "$PR_NUMBER" ]]; then # Extract the pull request number from the response. PR_NUMBER=$(echo "$pull_request_response" | jq -r '.number') + # Set PR_NUMBER for Github Actions. + echo PR_NUMBER="$PR_NUMBER" >> "$GITHUB_OUTPUT" + # If there is an existing PR number, get the PR. else pull_request_response=$(curl --silent -H "Authorization: token $ACCESS_TOKEN" \ @@ -31,6 +34,10 @@ else pr_url=$(echo "$pull_request_response" | jq -r '.html_url') fi +if [[ -z "$RELEASE_PR_URL" ]]; then + RELEASE_PR_URL="$pr_url" +fi + # Page through the /pulls/#/commits endpoint. page=1 per_page=100 @@ -63,7 +70,7 @@ for sha in $commit_shas; do "https://api.github.com/repos/$REPO/commits/$sha/pulls" \ | jq -r 'if type == "object" and has("message") and length > 0 then null else .[].html_url // empty end') - if [[ -n "$single_pr_url" && "$single_pr_url" != "null" ]]; then + if [[ -n "$single_pr_url" && "$single_pr_url" != "null" && "$single_pr_url" != "$RELEASE_PR_URL" ]]; then pull_requests+=("$single_pr_url") elif [[ "$single_pr_url" == "null" ]]; then : diff --git a/.ci/github/deploy_release_sites b/.ci/github/deploy_release_sites new file mode 100755 index 0000000000..b3fe09805d --- /dev/null +++ b/.ci/github/deploy_release_sites @@ -0,0 +1,74 @@ +#!/bin/bash -x + +set -eo pipefail + +# Install Terminus Build Bools. +terminus self:plugin:install terminus-build-tools-plugin + +# Get release sites and convert to an array. +readarray -t sites_array <<< "$(tr -d '\r' <<< "$RELEASE_SITES")" + +# Release branch variable does not exist, so create multidevs for the first time. +if [ "$RELEASE_BRANCH" ]; then + # Set release branch. + #gh variable set RELEASE_BRANCH --body "$RELEASE_BRANCH" + + # Prepare output file for comment. + echo "Environments ready for review:" >> output.txt +else + echo "test" + # Get release branch if already set. + #release_branch=$(gh api /repos/"$REPO"/actions/variables --jq '.variables.[] | select(.name=="RELEASE_BRANCH") | .value') +fi + +push_code() { + git_path=$(terminus connection:info "$site_with_env" --field=git_url) + git remote add "$site_machine_name" "$git_path" + git fetch "$site_machine_name" + git push "$site_machine_name" "$RELEASE_BRANCH:$RELEASE_BRANCH" --force + terminus workflow:wait "$site_machine_name"."$RELEASE_BRANCH" --max=300 +} + +process_site() { + site_with_env="$1" + site_machine_name="${site_with_env%.*}" + + echo -e "\nCreating multidev $site_machine_name.$RELEASE_BRANCH from $site_with_env...\n" + + if [ "$site_machine_name" = "yalesites-platform" ]; then + terminus multidev:create "$site_with_env" "$RELEASE_BRANCH" --no-db --no-files + else + terminus multidev:create "$site_with_env" "$RELEASE_BRANCH" + fi + + push_code + + # Do a fresh install on yalesites-platform site. + if [ "$site_machine_name" = "yalesites-platform" ]; then + echo -e "\nInstalling clean site for $site_machine_name.$RELEASE_BRANCH...\n" + terminus -n env:wake "$site_machine_name"."$RELEASE_BRANCH" + terminus -n drush "$site_machine_name"."$RELEASE_BRANCH" -- si yalesites_profile -y + terminus -n drush "$site_machine_name"."$RELEASE_BRANCH" -- cr + SITE_MACHINE_NAME="$site_machine_name" env="$RELEASE_BRANCH" ./scripts/shared/content-import.sh + fi + + terminus -n env:wake "$site_machine_name"."$RELEASE_BRANCH" + echo -e "\nRunning drush deploy...\n" + terminus -n drush "$site_machine_name"."$RELEASE_BRANCH" -- deploy -v -y + + # Get site URL and output to file + site_url=$(terminus -n domain:list "$site_machine_name"."$RELEASE_BRANCH" --filter='type=platform' --field=id) + echo "- https://$site_url" >> output.txt +} + +# Export functions so that GNU Parallel can access them +export -f push_code +export -f process_site + +parallel --jobs 0 --keep-order --line-buffer process_site {} ::: "${sites_array[@]}" + +# If we are creating the PR for the first time, post a comment with the created site URLs. +gh issue comment "$PR_NUMBER" --body-file output.txt + +# TODO: after PR closed, delete multidevs +# TODO: support new commits, push new code to multidevs diff --git a/.github/workflows/release_pr.yml b/.github/workflows/release_pr.yml index 94069c1edb..88b15e53dd 100644 --- a/.github/workflows/release_pr.yml +++ b/.github/workflows/release_pr.yml @@ -1,17 +1,72 @@ -name: Create/update release pull request +name: Release pull request on: pull_request: + types: + - synchronize + - closed branches: - master workflow_dispatch: env: YALESITES_BUILD_TOKEN: ${{ secrets.YALESITES_BUILD_TOKEN }} + GH_TOKEN: ${{ secrets.YALESITES_BUILD_TOKEN }} ACCESS_TOKEN: ${{ secrets.YALESITES_BUILD_TOKEN }} REPO: ${{ github.repository }} PR_NUMBER: ${{ github.event.number }} + RELEASE_PR_URL: ${{ github.event.pull_request._links.html.href }} + RELEASE_SITES: ${{ vars.RELEASE_SITES }} jobs: + setup: + runs-on: ubuntu-latest + steps: + - name: Determine Terminus version + shell: bash + run: | + TERMINUS_RELEASE=$( + curl --silent \ + --header 'authorization: Bearer ${{ github.token }}' \ + "https://api.github.com/repos/pantheon-systems/terminus/releases/latest" \ + | perl -nle'print $& while m#"tag_name": "\K[^"]*#g' + ) + echo "TERMINUS_RELEASE=$TERMINUS_RELEASE" >> $GITHUB_ENV + + - name: Install Terminus + shell: bash + run: | + mkdir ~/terminus && cd ~/terminus + echo "Installing Terminus v$TERMINUS_RELEASE" + curl -L https://github.com/pantheon-systems/terminus/releases/download/$TERMINUS_RELEASE/terminus.phar -o /usr/local/bin/terminus + chmod +x /usr/local/bin/terminus + + - name: Authenticate to Terminus + env: + TERMINUS_TOKEN: ${{ secrets.TERMINUS_TOKEN }} + run: | + terminus auth:login --machine-token="${TERMINUS_TOKEN}" + + - name: Install SSH key + uses: shimataro/ssh-key-action@v2 + with: + key: ${{ secrets.SSH_PRIVATE_KEY }} + known_hosts: unnecessary + config: ${{ secrets.SSH_CONFIG }} + + - name: Cache terminus + uses: actions/cache@v4 + id: terminus-cache + with: + path: | + /usr/local/bin/terminus + ~/.terminus + ~/.ssh + key: ${{ runner.os }}-terminus-cache-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-terminus-cache- + get_next_release_version: runs-on: ubuntu-latest + needs: [setup] + if: ${{ github.event.action != 'synchronize' && github.event.action != 'closed' }} steps: - name: Checkout uses: actions/checkout@v4 @@ -29,31 +84,106 @@ jobs: git config user.name github-actions git config user.email github-actions@github.com - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 - - name: Get next release number + id: get_release_number run: | - git branch develop origin/develop - git merge develop --no-edit -X theirs - git status - npm install --force - npx --no-install semantic-release --no-ci --dry-run --branches master - next_version=$(npx --no-install semantic-release --no-ci --dry-run --branches master 2>/dev/null | sed -nE 's/.*the next release version is ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p') - echo release_branch="rel-${next_version//.}" >> "$GITHUB_ENV" + if [[ "$PR_NUMBER" ]]; then + release_branch=$(gh pr view "$PR_NUMBER" --json headRefName --jq '.[]') + else + git merge origin/develop --no-edit -X theirs + npm install --force + unset GITHUB_ACTIONS + unset GITHUB_EVENT_NAME + semantic_release=$(npx --no-install semantic-release --no-ci --dry-run 2>/dev/null) + next_version=$(echo "$semantic_release" | sed -nE 's/.*The next release version is ([0-9]+)\.([0-9]+)\.([0-9]+).*/\1\2\3/p') + + if [ -z "$next_version" ]; then + exit 1 + else + release_branch="v${next_version//.}" + fi + fi + # echo release_branch="$release_branch" >> "$GITHUB_OUTPUT" + + # Set release branch as a variable for access. + gh variable set RELEASE_BRANCH --body "$release_branch" - name: Create release branch + if: ${{ github.event.number == '' }} + env: + RELEASE_BRANCH: ${{ vars.RELEASE_BRANCH }} run: | - git checkout -b "$release_branch" - git push origin "$release_branch" - - # create_pull_request: - # if: github.head_ref == 'develop' || - # github.event_name == 'workflow_dispatch' - # runs-on: ubuntu-latest - # steps: - # - name: Checkout - # uses: actions/checkout@v4 - - # - name: Create pull request - # run: ./.ci/github/create_release_pull_request + echo "The release branch is: $RELEASE_BRANCH" + git checkout -b "$RELEASE_BRANCH" + git push origin "$RELEASE_BRANCH" + + create_pull_request: + needs: [setup, get_next_release_version] + if: ${{ always() && github.event.action != 'closed' }} + outputs: + PR_NUMBER: ${{ steps.create_pull_request.outputs.PR_NUMBER }} + env: + RELEASE_BRANCH: ${{ vars.RELEASE_BRANCH }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Create pull request + id: create_pull_request + run: ./.ci/github/create_release_pull_request + + release_sites: + needs: [setup, get_next_release_version, create_pull_request] + runs-on: ubuntu-latest + if: ${{ github.event.action != 'closed' }} + env: + RELEASE_BRANCH: ${{ vars.RELEASE_BRANCH }} + PR_NUMBER: ${{ needs.create_pull_request.outputs.PR_NUMBER }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ env.RELEASE_BRANCH }} + + - name: Git setup + run: | + git config user.name github-actions + git config user.email github-actions@github.com + + - name: Restore cache + uses: actions/cache@v4 + id: terminus-cache + with: + path: | + /usr/local/bin/terminus + ~/.terminus + ~/.ssh + key: ${{ runner.os }}-terminus-cache-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-terminus-cache- + + - name: Deploy to environments + run: ./.ci/github/deploy_release_sites + + clean_up: + if: ${{ github.event.action == 'closed' }} + needs: [setup] + runs-on: ubuntu-latest + env: + RELEASE_BRANCH: ${{ vars.RELEASE_BRANCH }} + steps: + - name: Restore cache + uses: actions/cache@v4 + id: terminus-cache + with: + path: | + /usr/local/bin/terminus + ~/.terminus + ~/.ssh + key: ${{ runner.os }}-terminus-cache-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-terminus-cache- + + - name: Clean up + run: ./.ci/github/clean_up