From 76df1ae460fb2f9910051e0dac2211ab8d156ced Mon Sep 17 00:00:00 2001
From: Egor_P <egor@parity.io>
Date: Fri, 6 Sep 2024 10:29:26 +0200
Subject: [PATCH] [CI/Release] Pipeline to create a stable release branch
 (#5598)

This PR contains a pipeline which is going to branch off the new stable
release branch (e.g. `stab2412`, `stable2503`) and bump `polkadot`
`NODE_VERSION`, `spec_version` of the runtimes and reorganisation of the
`prdocs` related to the new stable release.

This is a first step in the automated `polkadot-sdk` release flow as
part of the task: https://github.com/paritytech/polkadot-sdk/issues/3291

The pipeline is not supposed to be triggered in the main` polkadot-sdk`
repo, but in the fork in the
[`paritytech-release`](https://github.com/paritytech-release/polkadot-sdk)
org, where the whole release flow is going to land.

Closes: https://github.com/paritytech/release-engineering/issues/222
---
 .github/scripts/common/lib.sh                 |  12 +-
 .github/scripts/release/release_lib.sh        | 118 ++++++++++++++++++
 .../workflows/release-branchoff-stable.yml    | 105 ++++++++++++++++
 3 files changed, 229 insertions(+), 6 deletions(-)
 create mode 100644 .github/scripts/release/release_lib.sh
 create mode 100644 .github/workflows/release-branchoff-stable.yml

diff --git a/.github/scripts/common/lib.sh b/.github/scripts/common/lib.sh
index bfb3120ad9b..5361db398ae 100755
--- a/.github/scripts/common/lib.sh
+++ b/.github/scripts/common/lib.sh
@@ -299,23 +299,23 @@ function check_sha256() {
 }
 
 # Import GPG keys of the release team members
-# This is done in parallel as it can take a while sometimes
 function import_gpg_keys() {
-  GPG_KEYSERVER=${GPG_KEYSERVER:-"keyserver.ubuntu.com"}
+  GPG_KEYSERVER=${GPG_KEYSERVER:-"hkps://keyserver.ubuntu.com"}
   SEC="9D4B2B6EB8F97156D19669A9FF0812D491B96798"
   EGOR="E6FC4D4782EB0FA64A4903CCDB7D3555DD3932D3"
   MORGAN="2E92A9D8B15D7891363D1AE8AF9E6C43F7F8C4CF"
+  PARITY_RELEASES="90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE"
 
-  echo "Importing GPG keys from $GPG_KEYSERVER in parallel"
-  for key in $SEC $EGOR $MORGAN; do
+  echo "Importing GPG keys from $GPG_KEYSERVER"
+  for key in $SEC $EGOR $MORGAN $PARITY_RELEASES; do
     (
       echo "Importing GPG key $key"
       gpg --no-tty --quiet --keyserver $GPG_KEYSERVER --recv-keys $key
       echo -e "5\ny\n" | gpg --no-tty --command-fd 0 --expert --edit-key $key trust;
-    ) &
+    )
   done
   wait
-  gpg -k $SEC
+  gpg -k
 }
 
 # Check the GPG signature for a given binary
diff --git a/.github/scripts/release/release_lib.sh b/.github/scripts/release/release_lib.sh
new file mode 100644
index 00000000000..81a3c14edec
--- /dev/null
+++ b/.github/scripts/release/release_lib.sh
@@ -0,0 +1,118 @@
+#!/usr/bin/env bash
+
+# Set the new version by replacing the value of the constant given as patetrn
+# in the file.
+#
+# input: pattern, version, file
+#output: none
+set_version() {
+    pattern=$1
+    version=$2
+    file=$3
+
+    sed -i "s/$pattern/\1\"${version}\"/g" $file
+    return 0
+}
+
+# Commit changes to git with specific message.
+# "|| true" does not let script to fail with exit code 1,
+# in case there is nothing to commit.
+#
+# input: MESSAGE (any message which should be used for the commit)
+# output: none
+commit_with_message() {
+    MESSAGE=$1
+    git commit -a -m "$MESSAGE" || true
+}
+
+# Retun list of the runtimes filterd
+# input: none
+# output: list of filtered runtimes
+get_filtered_runtimes_list() {
+    grep_filters=("runtime.*" "test|template|starters|substrate")
+
+    git grep spec_version: | grep .rs: | grep -e "${grep_filters[0]}" | grep "lib.rs" | grep -vE "${grep_filters[1]}" | cut -d: -f1
+}
+
+# Sets provided spec version
+# input: version
+set_spec_versions() {
+  NEW_VERSION=$1
+  runtimes_list=(${@:2})
+
+  printf "Setting spec_version to $NEW_VERSION\n"
+
+  for f in ${runtimes_list[@]}; do
+      printf "  processing $f"
+      sed -ri "s/spec_version: [0-9]+_[0-9]+_[0-9]+,/spec_version: $NEW_VERSION,/" $f
+  done
+
+  commit_with_message "Bump spec_version to $NEW_VERSION"
+
+  git_show_log 'spec_version'
+}
+
+# Displays formated results of the git log command
+# for the given pattern which needs to be found in logs
+# input: pattern, count (optional, default is 10)
+git_show_log() {
+  PATTERN="$1"
+  COUNT=${2:-10}
+  git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=iso-strict | \
+      head -n $COUNT | grep -iE "$PATTERN" --color=always -z
+}
+
+# Get a spec_version number from the crate version
+#
+# ## inputs
+#  - v1.12.0 or 1.12.0
+#
+# ## output:
+# 1_012_000 or 1_012_001 if SUFFIX is set
+function get_spec_version() {
+    INPUT=$1
+    SUFFIX=${SUFFIX:-000} #this variable makes it possible to set a specific ruuntime version like 93826 it can be intialised as sestem variable
+    [[ $INPUT =~ .*([0-9]+\.[0-9]+\.[0-9]{1,2}).* ]]
+    VERSION="${BASH_REMATCH[1]}"
+    MATCH="${BASH_REMATCH[0]}"
+    if [ -z $MATCH ]; then
+        return 1
+    else
+        SPEC_VERSION="$(sed -e "s/\./_0/g" -e "s/_[^_]*\$/_$SUFFIX/" <<< $VERSION)"
+        echo "$SPEC_VERSION"
+        return 0
+    fi
+}
+
+# Reorganize the prdoc files for the release
+#
+# input: VERSION (e.g. v1.0.0)
+# output: none
+reorder_prdocs() {
+    VERSION="$1"
+
+    printf "[+] ℹ️ Reordering prdocs:"
+
+    VERSION=$(sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+).*$/\1/' <<< "$VERSION") #getting reed of the 'v' prefix
+    mkdir -p "prdoc/$VERSION"
+    mv prdoc/pr_*.prdoc prdoc/$VERSION
+    git add -A
+    commit_with_message "Reordering prdocs for the release $VERSION"
+}
+
+# Bump the binary version of the polkadot-parachain binary with the
+# new bumped version and commit changes.
+#
+# input: version e.g. 1.16.0
+set_polkadot_parachain_binary_version() {
+    bumped_version="$1"
+    cargo_toml_file="$2"
+
+    set_version "\(^version = \)\".*\"" $bumped_version $cargo_toml_file
+
+    cargo update --workspace --offline # we need this to update Cargo.loc with the new versions as well
+
+    MESSAGE="Bump versions in: ${cargo_toml_file}"
+    commit_with_message "$MESSAGE"
+    git_show_log "$MESSAGE"
+}
diff --git a/.github/workflows/release-branchoff-stable.yml b/.github/workflows/release-branchoff-stable.yml
new file mode 100644
index 00000000000..c236a66a9fa
--- /dev/null
+++ b/.github/workflows/release-branchoff-stable.yml
@@ -0,0 +1,105 @@
+name: Release - Branch off stable branch
+
+on:
+  workflow_dispatch:
+    inputs:
+      stable_version:
+        description: New stable version in the format stableYYMM
+        required: true
+        type: string
+
+      node_version:
+        description: Version of the polkadot node in the format vX.XX.X (e.g. 1.15.0)
+        required: true
+
+jobs:
+  # TODO: Activate this job when the pipeline is moved to the fork in the `paritytech-release` org
+  # check-workflow-can-run:
+  #   uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@latest
+
+
+  prepare-tooling:
+    runs-on: ubuntu-latest
+    outputs:
+      node_version: ${{ steps.validate_inputs.outputs.node_version }}
+      stable_version: ${{ steps.validate_inputs.outputs.stable_version }}
+
+    steps:
+      - name: Checkout sources
+        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
+
+      - name: Validate inputs
+        id: validate_inputs
+        run: |
+          . ./.github/scripts/common/lib.sh
+
+          node_version=$(filter_version_from_input "${{ inputs.node_version }}")
+          echo "node_version=${node_version}" >> $GITHUB_OUTPUT
+
+          stable_version=$(validate_stable_tag ${{ inputs.stable_version }})
+          echo "stable_version=${stable_version}" >> $GITHUB_OUTPUT
+
+  create-stable-branch:
+    # needs: [check-workflow-can-run, prepare-tooling]
+    needs: [prepare-tooling]
+    # if: needs. check-workflow-can-run.outputs.checks_passed == 'true'
+    runs-on: ubuntu-latest
+
+    env:
+      PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }}
+      PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }}
+      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+      AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
+      STABLE_BRANCH_NAME: ${{ needs.prepare-tooling.outputs.stable_version }}
+
+    steps:
+      - name: Install pgpkkms
+        run: |
+          # Install pgpkms that is used to sign commits
+          pip install git+https://github.com/paritytech-release/pgpkms.git@5a8f82fbb607ea102d8c178e761659de54c7af69
+
+      - name: Checkout sources
+        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
+        with:
+          ref: master
+
+      - name: Import gpg keys
+        run: |
+          . ./.github/scripts/common/lib.sh
+
+          import_gpg_keys
+
+
+      - name: Config git
+        run: |
+          git config --global commit.gpgsign true
+          git config --global gpg.program /home/runner/.local/bin/pgpkms-git
+          git config --global user.name "ParityReleases"
+          git config --global user.email "release-team@parity.io"
+          git config --global user.signingKey "90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE"
+
+      - name: Create stable branch
+        run: |
+          git checkout -b "$STABLE_BRANCH_NAME"
+          git show-ref "$STABLE_BRANCH_NAME"
+
+      - name: Bump versions, reorder prdocs and push stable branch
+        run: |
+          . ./.github/scripts/release/release_lib.sh
+
+          NODE_VERSION="${{ needs.prepare-tooling.outputs.node_version }}"
+          set_version "\(NODE_VERSION[^=]*= \)\".*\"" $NODE_VERSION "polkadot/node/primitives/src/lib.rs"
+          commit_with_message "Bump node version to $NODE_VERSION in polkadot-cli"
+
+          SPEC_VERSION=$(get_spec_version $NODE_VERSION)
+          runtimes_list=$(get_filtered_runtimes_list)
+          set_spec_versions $SPEC_VERSION "${runtimes_list[@]}"
+
+          # TODO: clarify what to do with the polkadot-parachain binary
+          # Set new version for polkadot-parachain binary to match the polkadot node binary
+          # set_polkadot_parachain_binary_version $NODE_VERSION "cumulus/polkadot-parachain/Cargo.toml"
+
+          reorder_prdocs $NODE_VERSION
+
+          git push origin "$STABLE_BRANCH_NAME"
-- 
GitLab