diff --git a/includes/class-sensei.php b/includes/class-sensei.php index 59410cc508..239233d188 100644 --- a/includes/class-sensei.php +++ b/includes/class-sensei.php @@ -814,7 +814,7 @@ public function update() { /** * Helper function to check to see if any courses exist in the database. * - * @deprected $$next-version$$ + * @deprecated $$next-version$$ * * @return bool */ diff --git a/package.json b/package.json index 3a1e534f9b..59f192a9ca 100644 --- a/package.json +++ b/package.json @@ -167,4 +167,4 @@ "woorelease": { "wp_org_slug": "sensei-lms" } -} +} \ No newline at end of file diff --git a/scripts/Dockerfile b/scripts/Dockerfile new file mode 100644 index 0000000000..ea5caacdaf --- /dev/null +++ b/scripts/Dockerfile @@ -0,0 +1,55 @@ +FROM composer:2 AS composer +FROM php:7.4-cli + +RUN set -ex; \ + echo "deb http://deb.debian.org/debian bullseye-backports main" > /etc/apt/sources.list.d/bullseye-backports.list; \ + apt-get update ; \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + zip unzip \ + zlib1g-dev libzip-dev \ + git/bullseye-backports ssh \ + jq; \ + rm -rf /var/lib/apt/lists/* + +RUN eval `ssh-agent -s` + +# Install GitHub CLI. +ENV GITHUB_CLI_VERSION 2.32.1 +RUN set -ex; \ + curl -L "https://github.com/cli/cli/releases/download/v${GITHUB_CLI_VERSION}/gh_${GITHUB_CLI_VERSION}_checksums.txt" -o checksums.txt; \ + curl -OL "https://github.com/cli/cli/releases/download/v${GITHUB_CLI_VERSION}/gh_${GITHUB_CLI_VERSION}_linux_arm64.deb"; \ + shasum --ignore-missing -a 512 -c checksums.txt; \ + dpkg -i "gh_${GITHUB_CLI_VERSION}_linux_arm64.deb"; \ + rm -rf "gh_${GITHUB_CLI_VERSION}_linux_arm64.deb"; \ + # verify gh binary works + gh --version; +RUN docker-php-ext-install zip + +# Install composer. +ENV COMPOSER_ALLOW_SUPERUSER 1 +ENV COMPOSER_HOME /tmp +COPY --from=composer /usr/bin/composer /usr/bin/composer + +# Install WP CLI +RUN curl https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar > /root/wp-cli.phar && \ + chmod +x /root/wp-cli.phar && \ + mv /root/wp-cli.phar /usr/local/bin/wp + +# Install Node & NPM. +RUN curl -sL https://deb.nodesource.com/setup_18.x | bash - +RUN apt-get install -y \ + --no-install-recommends nodejs \ + && rm -rf /var/lib/apt/lists/* + +# Copy a script with release PR steps. +COPY release-pr-steps.sh /usr/bin/release-pr-steps.sh +COPY update-version.sh /usr/bin/update-version.sh +COPY changelog-unwrap-pr-links.sh /usr/bin/changelog-unwrap-pr-links.sh + +# Copy ssh confid and keys! Not secure! +# TODO: https://www.fastruby.io/blog/docker/docker-ssh-keys.html +COPY ssh-data /root/.ssh + +CMD ["bash"] diff --git a/scripts/RELEASE.md b/scripts/RELEASE.md new file mode 100644 index 0000000000..2821a0a028 --- /dev/null +++ b/scripts/RELEASE.md @@ -0,0 +1,48 @@ +# Release + +Here, we have 2 scripts and one Dockerfile that help preparing the release PR. + +## scripts/release-pr.sh + +Run it from the repository's root: `./scripts/release-pr.sh X.Y.Z`, where X.Y.Z is the version you're releasing. + +If you want to create the release not from `trunk`, specify the branch name: +``` +./scripts/release-pr.sh X.Y.Z feature/branch +``` + +The script assumes, you have: + +- ~/.ssh - directory that contain all needed SSH configuration and keys for GitHub. +- ~/.gitconfig - your configuration for Git. + +This script creates a copy of your SSH directory. This approach is not ideal and is considered as non-secure. +The script removes all the data in the end, so, hopefully, it won't cause damage. + +However, use cautiously: don't share your Docker image or tempory directory/data. + +## scripts/release-pr-steps.sh + +This script is being run from inside the Docker container and runs all the needed steps: + +- Checkout Sensei repository. +- Install dependencies. +- Create a local release branch. +- Replace the next version tag. +- Update changelog. +- Build POT file. +- Push all the changes to GitHub. +- Create the release PR. + +## scripts/Dockerfile + +Describes the image for Docker, containing: + +- PHP 7.4 +- Node 18.x +- composer 2 +- GitHub CLI +- WordPress CLI + +It also copies the ssh data directory. Once again: this approach is not ideal and is considered as non-secure. + diff --git a/scripts/changelog-unwrap-pr-links.sh b/scripts/changelog-unwrap-pr-links.sh new file mode 100755 index 0000000000..c2ae8c5883 --- /dev/null +++ b/scripts/changelog-unwrap-pr-links.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +# Exit on error and output commands. +set -ex + +CURRENT_DIR=$(pwd) +OS_TYPE=$(uname -s) +# sed arguments in different OS passed a bit differently. +if [[ "$OS_TYPE" == "Darwin" ]]; then + sed -E -i '' "s/^.* \[#([0-9]+)\]$/&(https:\/\/github.com\/Automattic\/sensei\/pull\/\\1)/" "$CURRENT_DIR/changelog.txt" +elif [[ "$OS_TYPE" == "Linux" ]]; then + # You are on Linux + sed -E -i'' "s/^.* \[#([0-9]+)\]$/&(https:\/\/github.com\/Automattic\/sensei\/pull\/\\1)/" "$CURRENT_DIR/changelog.txt" +else + echo "Unsupported operating system" +fi + + + diff --git a/scripts/release-pr-steps.sh b/scripts/release-pr-steps.sh new file mode 100755 index 0000000000..cf62b77035 --- /dev/null +++ b/scripts/release-pr-steps.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash + +# Exit on error and output commands. +set -ex + +NEXT_VERSION=$1 +if [ "$NEXT_VERSION" = "" ]; then + echo "Error: Version not set!" + exit +fi + +RELEASE_BRANCH=$2 +if [ "$RELEASE_BRANCH" = "" ]; then + echo "Error: Release branch not set!" + exit +fi + +# Fix permissions for ssh config and keys. +chown -R root:root /root/.ssh +export GIT_SSH_COMMAND="ssh -i /root/.ssh/id_rsa" + +# Create working directory and checkout Sensei. +mkdir /release && cd /release +git clone git@github.com:Automattic/sensei.git +cd /release/sensei + +# Checkout release branch. +git switch $RELEASE_BRANCH + +# Exit if could not switch to release branch. +if [ $? -ne 0 ]; then + echo "Error: Could not switch to release branch!" + exit +fi + +# Install dependencies. +composer install && npm ci + +# Disable commit signing. +git config --global commit.gpgsign false + +# Create the release branch. +git switch -c "release/$NEXT_VERSION" + +echo "Replace next version tag" +./scripts/replace-next-version-tag.sh $NEXT_VERSION +if [[ -n $(git status -s) ]]; then + git add . + git commit -m 'Replace next version tag' +else + echo "There are no changes after next version tag replacement." +fi + +echo "Update plugin version" +update-version.sh $NEXT_VERSION +if [[ -n $(git status -s) ]]; then + git add . + git commit -m 'Update plugin version' +else + echo "There are no changes after updating the version in plugin files." +fi + +echo "Changlogger write" +# Write changelog. +composer exec -- changelogger write --add-pr-num +# Unwrap PR links. +changelog-unwrap-pr-links.sh +# Copy changelog section in readme. +./scripts/copy-changelog-to-readme.php + +if [[ -n $(git status -s) ]]; then + git add . + git commit -m 'Update chaneglog' +else + echo "There are no changes after running changelogger." +fi + +echo "Build translations" +npm run i18n:build -- --allow-root +if [[ -n $(git status -s) ]]; then + git add . + git commit -m 'Update translations' +else + echo "There are no changes after building translations." +fi + +# Push all changes to GitHub +git push --set-upstream origin "release/$NEXT_VERSION" + +# Login to create PR. +gh auth login + +# Create PR. +gh pr create --assignee @me --base trunk --draft --title "Release $NEXT_VERSION" --reviewer Automattic/nexus --label "[Type] Maintenance" --label "No Changelog" diff --git a/scripts/release-pr.sh b/scripts/release-pr.sh new file mode 100755 index 0000000000..0339f628a1 --- /dev/null +++ b/scripts/release-pr.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +# Output commands. +set -x + +NEXT_VERSION=$1 +if [ "$NEXT_VERSION" = "" ]; then + echo "Error: Version not set" + exit +fi + +RELEASE_BRANCH=$2 +if [ "$RELEASE_BRANCH" = "" ]; then + RELEASE_BRANCH="trunk" +fi + +echo "Preparing release/$NEXT_VERSION from $RELEASE_BRANCH" + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +echo $SCRIPT_DIR + +# Dangerous! Considered as non-secure way of sharing keys! +# TODO: https://www.fastruby.io/blog/docker/docker-ssh-keys.html +cp -r ~/.ssh "$SCRIPT_DIR/ssh-data" + +docker build -t release-build $SCRIPT_DIR && \ + docker run --name release-steps --rm -it \ + -v ~/.gitconfig:/etc/gitconfig \ + release-build \ + bash -c "/usr/bin/release-pr-steps.sh $NEXT_VERSION $RELEASE_BRANCH" + +docker image rm release-build +rm -rf "$SCRIPT_DIR/ssh-data" + diff --git a/scripts/update-version.sh b/scripts/update-version.sh new file mode 100755 index 0000000000..ee2a3ea943 --- /dev/null +++ b/scripts/update-version.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +set -ex + +# Check version provided +VERSION=$1 +if [ -z "$VERSION" ]; then + echo "No version provided." + exit 1 +fi + +if ! [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Version provided is not a valid SemVer version." + exit 1 +fi + +# Check if jq is installed. We use it to update the version in package.json and package-lock.json +if ! command -v "jq" >/dev/null 2>&1; then + echo "jq is not installed. https://jqlang.github.io/jq/download/" +fi + +CURRENT_DIR=$(pwd) +OS_TYPE=$(uname -s) +# sed arguments in different OS passed a bit differently. +if [[ "$OS_TYPE" == "Darwin" ]]; then + # You are on macOS + + # Update version in sensei-lms.php + sed -E -i '' "s/\* Version: [0-9]+\.[0-9]+\.[0-9]+/\* Version: $VERSION/" "$CURRENT_DIR/sensei-lms.php" + + # Find constant and replace the version in sensei-lms.php: + # define( 'SENSEI_LMS_VERSION', '4.15.0' ); // WRCS: DEFINED_VERSION. + sed -E -i '' "s/'SENSEI_LMS_VERSION', '[0-9]+\.[0-9]+\.[0-9]+/'SENSEI_LMS_VERSION', '$VERSION/" "$CURRENT_DIR/sensei-lms.php" + + # Update version in the Stable Tag comment in readme.txt + # Stable tag: 4.15.0 + sed -E -i '' "s/^Stable tag: [0-9]+\.[0-9]+\.[0-9]+/Stable tag: $VERSION/" "$CURRENT_DIR/readme.txt" +elif [[ "$OS_TYPE" == "Linux" ]]; then + # You are on Linux + + # Update version in sensei-lms.php + sed -E -i'' "s/\* Version: [0-9]+\.[0-9]+\.[0-9]+/\* Version: $VERSION/" "$CURRENT_DIR/sensei-lms.php" + + # Find constant and replace the version in sensei-lms.php: + # define( 'SENSEI_LMS_VERSION', '4.15.0' ); // WRCS: DEFINED_VERSION. + sed -E -i'' "s/'SENSEI_LMS_VERSION', '[0-9]+\.[0-9]+\.[0-9]+/'SENSEI_LMS_VERSION', '$VERSION/" "$CURRENT_DIR/sensei-lms.php" + + # Update version in the Stable Tag comment in readme.txt + # Stable tag: 4.15.0 + sed -E -i'' "s/^Stable tag: [0-9]+\.[0-9]+\.[0-9]+/Stable tag: $VERSION/" "$CURRENT_DIR/readme.txt" +else + echo "Unsupported operating system" +fi + +# Update package.json. +jq ".version = \"$VERSION\"" "$CURRENT_DIR/package.json" > "$CURRENT_DIR/package.json.tmp" && \ + mv "$CURRENT_DIR/package.json.tmp" "$CURRENT_DIR/package.json" + +# Update package-lock.json: the first occurrence of version in the root object. +jq ".version = \"$VERSION\"" "$CURRENT_DIR/package-lock.json" > "$CURRENT_DIR/package-lock.json.tmp" && \ + mv "$CURRENT_DIR/package-lock.json.tmp" "$CURRENT_DIR/package-lock.json" + +# Update package-lock.json: the second occurrence of version. +jq ".packages.\"\".version = \"$VERSION\"" "$CURRENT_DIR/package-lock.json" > "$CURRENT_DIR/package-lock.json.tmp" && \ + mv "$CURRENT_DIR/package-lock.json.tmp" "$CURRENT_DIR/package-lock.json"