Skip to content
161 changes: 24 additions & 137 deletions .github/scripts/create-platform-release-pr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ set -e
set -u
set -o pipefail

# Sourcing helper functions
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# shellcheck source=.github/scripts/utils.sh
source "${SCRIPT_DIR}/utils.sh"

# Input assignments (quoted args prevent shifting). Use defaults only for optional args.
PLATFORM="${1}"
PREVIOUS_VERSION_REF="${2:-}"
Expand All @@ -32,6 +37,7 @@ NEW_VERSION="${NEW_VERSION//[[:space:]]/}"
NEW_VERSION_NUMBER="${4:-}"
GIT_USER_NAME="${5:-metamaskbot}"
GIT_USER_EMAIL="${6:[email protected]}"
BASE_BRANCH="${BASE_BRANCH:-main}"

# Log assigned variables for debugging (after defaults and trimming)
echo "Assigned variables:"
Expand Down Expand Up @@ -127,101 +133,6 @@ get_version_bump_branch_name() {
# Main workflow functions
# -----------------------

# Helper function to check if branch exists and checkout/create it
checkout_or_create_branch() {
local branch_name="$1"
local base_branch="${2:-}" # Optional base branch for new branches

echo "Checking for existing branch ${branch_name}"

if git show-ref --verify --quiet "refs/heads/${branch_name}" || git ls-remote --heads origin "${branch_name}" | grep -q "${branch_name}"; then
echo "Branch ${branch_name} already exists, checking it out"
if git ls-remote --heads origin "${branch_name}" | grep -q "${branch_name}"; then
git fetch origin "${branch_name}"
git checkout "${branch_name}"
else
git checkout "${branch_name}"
fi
else
echo "Creating new branch ${branch_name}"
if [[ -n "$base_branch" ]]; then
git checkout "$base_branch"
git pull origin "$base_branch"
fi
git checkout -b "${branch_name}"
fi

echo "Branch ${branch_name} ready"
}

# Helper function to push branch with error handling
push_branch_with_handling() {
local branch_name="$1"

echo "Pushing changes to the remote.."
if ! git push --set-upstream origin "${branch_name}"; then
echo "No changes to push to ${branch_name}"
# Check if branch exists remotely
if git ls-remote --heads origin "${branch_name}" | grep -q "${branch_name}"; then
echo "Branch ${branch_name} already exists remotely"
else
echo "Error: Failed to push and branch doesn't exist remotely"
exit 1
fi
fi
}

# Helper function to create PR if it doesn't exist
create_pr_if_not_exists() {
local branch_name="$1"
local title="$2"
local body="$3"
local base_branch="${4:-main}"
local labels="${5:-}"
local search_method="${6:-head}" # "head" or "search"

echo "Creating PR for ${branch_name}.."

# Check if PR already exists using different methods
local pr_exists=false
if [[ "$search_method" == "search" ]]; then
if gh pr list --search "head:${branch_name}" --json number --jq 'length' | grep -q "1"; then
pr_exists=true
fi
else
if gh pr list --head "${branch_name}" --json number --jq 'length' | grep -q "1"; then
pr_exists=true
fi
fi

if $pr_exists; then
echo "PR for branch ${branch_name} already exists"
else
# Build command array with conditional label inclusion
local gh_cmd=(gh pr create --draft --title "${title}" --body "${body}" --base "${base_branch}" --head "${branch_name}")

# Add labels only if provided (GitHub CLI doesn't accept empty label values)
if [[ -n "${labels:-}" ]]; then
gh_cmd+=(--label "${labels}")
fi

# Execute the command
# echo "Executing: ${gh_cmd[@]}"
"${gh_cmd[@]}"
echo "PR Created: ${title}"
fi
}

# Configure git for automation
configure_git() {
echo "Configuring git.."
git config user.name "${GIT_USER_NAME}"
git config user.email "${GIT_USER_EMAIL}"

echo "Fetching from remote..."
git fetch
}

# Create release branch, update versions, and create PR
create_release_pr() {
local platform="$1"
Expand All @@ -231,7 +142,7 @@ create_release_pr() {
local changelog_branch_name="$5"

echo "Checking out the release branch: ${release_branch_name}"
git checkout "${release_branch_name}"
checkout_or_create_branch "${release_branch_name}" "${BASE_BRANCH}"

echo "Release Branch Checked Out"
echo "version : ${new_version}"
Expand Down Expand Up @@ -342,19 +253,6 @@ create_changelog_pr() {
local release_branch_name="$4"
local changelog_branch_name="$5"

# Use helper function for branch checkout/creation
checkout_or_create_branch "${changelog_branch_name}"

# Generate Changelog and Test Plan
echo "Generating changelog for ${platform}.."
yarn auto-changelog update --rc \
--repo "${GITHUB_REPOSITORY_URL}" \
--currentVersion "${new_version}" \
--autoCategorize \
--useChangelogEntry \
--useShortPrLink \
--requirePrNumbers

# Skip commits.csv for hotfix releases (previous_version_ref is literal "null")
# - When we create a new major/minor release, we fetch all commits included in the release, by fetching the diff between HEAD and previous version reference.
# - When we create a new hotfix release, there are no commits included in the release by default (they will be cherry-picked one by one). So we don't have previous version reference, which is why the value is set to 'null'.
Expand Down Expand Up @@ -399,33 +297,22 @@ create_changelog_pr() {
cd ../
fi

# Skipping Google Sheets update since there is no need for it anymore
# TODO: Remove this once the current post-main validation approach is stable
# if [[ "${TEST_ONLY:-false}" == 'false' ]]; then
# echo "Updating release sheet.."
# # Create a new Release Sheet Page for the new version with our commits.csv content
# yarn run update-release-sheet "${platform}" "${new_version}" "${GOOGLE_DOCUMENT_ID}" "./commits.csv" "${PROJECT_GIT_DIR}" "${MOBILE_TEMPLATE_SHEET_ID}" "${EXTENSION_TEMPLATE_SHEET_ID}"
# fi
# Note: Only change directories when we actually entered ./github-tools/

# Commit and Push Changelog Changes (exclude commits.csv)
echo "Adding and committing changes.."
local commit_msg="update changelog for ${new_version}"
if [[ "${previous_version_ref,,}" == "null" ]]; then
commit_msg="${commit_msg} (hotfix - no test plan)"
fi
if ! (git commit -am "${commit_msg}"); then
echo "No changes detected; skipping commit."
fi

local pr_body="This PR updates the change log for ${new_version}."
if [[ "${previous_version_ref,,}" == "null" ]]; then
pr_body="${pr_body} (Hotfix - no test plan generated.)"
fi

# Use helper functions for push and PR creation
push_branch_with_handling "${changelog_branch_name}"
create_pr_if_not_exists "${changelog_branch_name}" "release: ${changelog_branch_name}" "${pr_body}" "${release_branch_name}" "" "search"
# Delegate changelog update and PR creation to the shared update-release-changelog.sh script
echo "Updating changelog and creating PR.."

# Export git identity for the shared script
export GIT_AUTHOR_NAME="${GIT_USER_NAME}"
export GIT_AUTHOR_EMAIL="${GIT_USER_EMAIL}"

# Call the shared script
# The script is located in the same directory as this one
"${SCRIPT_DIR}/update-release-changelog.sh" \
"${release_branch_name}" \
"${platform}" \
"${GITHUB_REPOSITORY_URL}" \
"${previous_version_ref}" \
"${changelog_branch_name}" \
"${new_version}"

echo "Changelog PR Ready"
}
Expand Down Expand Up @@ -547,7 +434,7 @@ main() {
release_branch_name=$(get_release_branch_name "$NEW_VERSION")
changelog_branch_name="release/${NEW_VERSION}-Changelog"
version_bump_branch_name=$(get_version_bump_branch_name "$next_version") # Execute main workflow
configure_git
configure_git "${GIT_USER_NAME}" "${GIT_USER_EMAIL}"

# Step 1: Create release branch and PR
create_release_pr "$PLATFORM" "$NEW_VERSION" "$NEW_VERSION_NUMBER" "$release_branch_name" "$changelog_branch_name"
Expand Down
133 changes: 30 additions & 103 deletions .github/scripts/update-release-changelog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@
# 3. repository_url - Full HTTPS URL for the invoking repository.
#
# Optional arguments:
# 4. previous_version_ref - Previous version reference (branch/tag/SHA). Defaults to literal "null"
# so that commits.csv generation is skipped, matching hotfix behaviour.
# 4. previous_version_ref - Previous version reference (branch/tag/SHA). Defaults to "null"
# (Hotfix mode) if omitted. If provided as an empty string,
# it indicates a regular release.
# 5. changelog_branch - Specific name for the changelog branch. If not provided, it will be
# determined automatically (checking for existing release/ or chore/ branches).
# 6. version - The semantic version (e.g., 6.20.0). If not provided, it will be
# derived from the release_branch name.
#
# Environment (optional):
# GITHUB_TOKEN - Token for GitHub CLI operations (falls back to gh auth config)
Expand All @@ -21,109 +26,22 @@

set -euo pipefail

# Sourcing helper functions
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# shellcheck source=.github/scripts/utils.sh
source "${SCRIPT_DIR}/utils.sh"

RELEASE_BRANCH="${1:?release branch is required}"
PLATFORM="${2:-extension}"
REPOSITORY_URL="${3:?repository url is required}"
PREVIOUS_VERSION_REF="${4:-null}"
PREVIOUS_VERSION_REF="${4-null}"
CHANGELOG_BRANCH_INPUT="${5:-}"
VERSION_INPUT="${6:-}"

AUTHOR_NAME="${GIT_AUTHOR_NAME:-metamaskbot}"
AUTHOR_EMAIL="${GIT_AUTHOR_EMAIL:[email protected]}"
TEST_ONLY="${TEST_ONLY:-false}"

# --- Helper functions copied or adapted from create-platform-release-pr.sh ---

configure_git() {
# Configure git identity and fetch remote refs so subsequent operations run
# with the same context as create-platform-release-pr.sh.
echo "Configuring git.."
git config user.name "${AUTHOR_NAME}"
git config user.email "${AUTHOR_EMAIL}"

echo "Fetching from remote..."
git fetch
}

checkout_or_create_branch() {
# Ensure a branch exists locally for the changelog workflow. If it already
# exists locally or remotely, check it out; otherwise create it (optionally
# from a provided base branch) so changelog updates have the proper base.
local branch_name="$1"
local base_branch="${2:-}"

echo "Checking for existing branch ${branch_name}"

if git show-ref --verify --quiet "refs/heads/${branch_name}" || git ls-remote --heads origin "${branch_name}" | grep -q "${branch_name}"; then
echo "Branch ${branch_name} already exists, checking it out"
if git ls-remote --heads origin "${branch_name}" | grep -q "${branch_name}"; then
git fetch origin "${branch_name}"
git checkout "${branch_name}"
else
git checkout "${branch_name}"
fi
else
echo "Creating new branch ${branch_name}"
if [[ -n "${base_branch}" ]]; then
git checkout "${base_branch}"
git pull origin "${base_branch}"
fi
git checkout -b "${branch_name}"
fi

echo "Branch ${branch_name} ready"
}

push_branch_with_handling() {
# Push changelog updates upstream, tolerating no-op pushes while still
# surfacing failures when the remote branch is missing.
local branch_name="$1"

echo "Pushing changes to the remote.."
if ! git push --set-upstream origin "${branch_name}"; then
echo "No changes to push to ${branch_name}"
if git ls-remote --heads origin "${branch_name}" | grep -q "${branch_name}"; then
echo "Branch ${branch_name} already exists remotely"
else
echo "Error: Failed to push and branch doesn't exist remotely"
exit 1
fi
fi
}

create_pr_if_not_exists() {
# Guard against duplicate changelog PRs by checking existing PRs before
# opening a draft that targets the release branch.
local branch_name="$1"
local title="$2"
local body="$3"
local base_branch="${4:-main}"
local labels="${5:-}"
local search_method="${6:-head}"

echo "Creating PR for ${branch_name}.."

local pr_exists=false
if [[ "${search_method}" == "search" ]]; then
if gh pr list --search "head:${branch_name}" --json number --jq 'length' | grep -q "1"; then
pr_exists=true
fi
else
if gh pr list --head "${branch_name}" --json number --jq 'length' | grep -q "1"; then
pr_exists=true
fi
fi

if ${pr_exists}; then
echo "PR for branch ${branch_name} already exists"
else
local gh_cmd=(gh pr create --draft --title "${title}" --body "${body}" --base "${base_branch}" --head "${branch_name}")
if [[ -n "${labels}" ]]; then
gh_cmd+=(--label "${labels}")
fi
"${gh_cmd[@]}"
echo "PR Created: ${title}"
fi
}

# -----------------------------------------------------------------
# -----------------------------------------------------------------

Expand Down Expand Up @@ -200,20 +118,29 @@ commit_and_push_changelog() {
# -----------------------------------------------------------------

# Derive the semantic version from the branch naming convention (release/x.y.z only).
if [[ "${RELEASE_BRANCH}" =~ ^release/([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
VERSION="${BASH_REMATCH[1]}"
if [[ -n "${VERSION_INPUT}" ]]; then
VERSION="${VERSION_INPUT}"
else
echo "Release branch '${RELEASE_BRANCH}' does not match known patterns." >&2
exit 1
if [[ "${RELEASE_BRANCH}" =~ ^release/([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
VERSION="${BASH_REMATCH[1]}"
else
echo "Release branch '${RELEASE_BRANCH}' does not match known patterns and no version was provided." >&2
exit 1
fi
fi

GITHUB_REPOSITORY_URL="${REPOSITORY_URL}"

configure_git
configure_git "${AUTHOR_NAME}" "${AUTHOR_EMAIL}"

ensure_release_branch "${RELEASE_BRANCH}"

CHANGELOG_BRANCH=$(determine_changelog_branch "${VERSION}")
if [[ -n "${CHANGELOG_BRANCH_INPUT}" ]]; then
CHANGELOG_BRANCH="${CHANGELOG_BRANCH_INPUT}"
else
CHANGELOG_BRANCH=$(determine_changelog_branch "${VERSION}")
fi

checkout_or_create_branch "${CHANGELOG_BRANCH}" "${RELEASE_BRANCH}"

echo "Generating changelog for ${PLATFORM} ${VERSION}.."
Expand Down
Loading
Loading