-
Notifications
You must be signed in to change notification settings - Fork 870
[Release] Automate most manual steps #9419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
acstll
wants to merge
4
commits into
elastic:main
Choose a base branch
from
acstll:feat/release-automation
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
65f07ec
[Release] Automate some manual steps (WIP)
acstll 5320ab3
Merge remote-tracking branch 'upstream/main' into feat/release-automa…
acstll efb7da0
[Release] Polish automation scripts
acstll 88aa4e9
[Release] Add install script for reviewers
acstll File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # Official release preparation script (pre-PR) | ||
| # | ||
| # Automates steps 1-8 of the official release process: | ||
| # 1. Log out of npm | ||
| # 2. Checkout main | ||
| # 3. Pull latest from upstream | ||
| # 4. Create a timestamped release branch | ||
| # 5. Build the release CLI | ||
| # 6. Run the release dry-run (interactive) | ||
| # 7. (User confirms in the interactive CLI) | ||
| # 8. Push the branch to origin and open a PR | ||
| # | ||
| # Usage: yarn release:prep | ||
| # | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| RED='\033[0;31m' | ||
| GREEN='\033[0;32m' | ||
| YELLOW='\033[0;33m' | ||
| BOLD='\033[1m' | ||
| RESET='\033[0m' | ||
|
|
||
| step() { | ||
| echo "" | ||
| echo -e "${GREEN}${BOLD}[$1]${RESET} $2" | ||
| } | ||
|
|
||
| warn() { | ||
| echo -e "${YELLOW}Warning:${RESET} $1" | ||
| } | ||
|
|
||
| error() { | ||
| echo -e "${RED}Error:${RESET} $1" >&2 | ||
| exit 1 | ||
| } | ||
|
|
||
| REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || error "Not inside a git repository" | ||
| cd "$REPO_ROOT" | ||
|
|
||
| # Verify the upstream remote exists | ||
| git remote get-url upstream &>/dev/null || error "'upstream' remote not found. Please add it: git remote add upstream git@github.com:elastic/eui.git" | ||
|
|
||
| # ── Step 1: Log out of npm ────────────────────────────────────────────────── | ||
|
|
||
| step "1/8" "Ensuring npm is not authenticated..." | ||
| npm logout 2>/dev/null || true | ||
| yarn npm logout 2>/dev/null || true | ||
|
|
||
| # ── Step 2: Checkout main ─────────────────────────────────────────────────── | ||
|
|
||
| step "2/8" "Checking out main branch..." | ||
| git checkout main | ||
|
|
||
| # ── Step 3: Pull latest ──────────────────────────────────────────────────── | ||
|
|
||
| step "3/8" "Pulling latest changes from upstream..." | ||
| git pull upstream main | ||
|
|
||
| # ── Step 4: Create release branch ─────────────────────────────────────────── | ||
|
|
||
| BRANCH_NAME="release/$(date +%s)" | ||
| step "4/8" "Creating release branch: ${BOLD}${BRANCH_NAME}${RESET}" | ||
| git checkout -b "$BRANCH_NAME" | ||
|
|
||
| # ── Step 5: Build release CLI ─────────────────────────────────────────────── | ||
|
|
||
| step "5/8" "Installing dependencies and building release CLI..." | ||
| yarn | ||
| yarn workspace @elastic/eui-release-cli run build | ||
|
|
||
| # ── Step 6: Run release (dry-run) ─────────────────────────────────────────── | ||
|
|
||
| step "6/8" "Starting release process (dry-run)..." | ||
| echo "" | ||
| yarn release run official --dry-run --allow-custom --skip-auth-check --use-auth-token | ||
|
|
||
| # ── Step 7: Push branch ──────────────────────────────────────────────────── | ||
|
|
||
| step "7/8" "Pushing branch to origin..." | ||
| git push -u origin "$BRANCH_NAME" | ||
|
|
||
| # ── Step 8: Open PR ──────────────────────────────────────────────────────── | ||
|
|
||
| step "8/8" "Opening release PR..." | ||
|
|
||
| # Detect changed packages by comparing versions on this branch vs main | ||
| PR_TITLE_PARTS="" | ||
| PR_BODY_LINES="" | ||
|
|
||
| for pkg_dir in packages/eui packages/eui-theme-common packages/eui-theme-borealis packages/docusaurus-preset packages/docusaurus-theme packages/eslint-plugin; do | ||
| pkg_json="${pkg_dir}/package.json" | ||
| [[ -f "$pkg_json" ]] || continue | ||
|
|
||
| new_version=$(node -p "require('./${pkg_json}').version") | ||
| old_version=$(git show "main:${pkg_json}" 2>/dev/null | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).version" 2>/dev/null || echo "") | ||
|
|
||
| if [[ -n "$old_version" && "$new_version" != "$old_version" ]]; then | ||
| pkg_name=$(node -p "require('./${pkg_json}').name") | ||
|
|
||
| if [[ -n "$PR_TITLE_PARTS" ]]; then | ||
| PR_TITLE_PARTS="${PR_TITLE_PARTS}, ${pkg_name} v${new_version}" | ||
| else | ||
| PR_TITLE_PARTS="${pkg_name} v${new_version}" | ||
| fi | ||
| PR_BODY_LINES="${PR_BODY_LINES}\n- \`${pkg_name}\` - v${old_version} → v${new_version}" | ||
| fi | ||
| done | ||
|
|
||
| if [[ -z "$PR_TITLE_PARTS" ]]; then | ||
| error "No changed package versions detected. Did the release dry-run update any versions?" | ||
| fi | ||
|
|
||
| PR_TITLE="Release: ${PR_TITLE_PARTS}" | ||
| PR_BODY="$(printf "Packages to release:\n${PR_BODY_LINES}")" | ||
|
|
||
| PR_URL=$(gh pr create \ | ||
| --title "$PR_TITLE" \ | ||
| --body "$PR_BODY" \ | ||
| --label "skip-changelog" \ | ||
| --label "release" \ | ||
| --base main) | ||
|
|
||
| echo "" | ||
| echo -e "${GREEN}${BOLD}Prep complete!${RESET}" | ||
| echo "" | ||
| echo -e " PR: ${BOLD}${PR_URL}${RESET}" | ||
| echo "" | ||
| echo -e " ${BOLD}After the PR is merged:${RESET}" | ||
| echo -e " yarn release:publish" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # Official release publish script (post-merge) | ||
| # | ||
| # Automates steps 10-11 of the official release process: | ||
| # - Detects the EUI version and changed workspaces | ||
| # - Tags the merge commit | ||
| # - Pushes the tag to upstream | ||
| # - Triggers the GitHub Actions release workflow | ||
| # | ||
| # Usage: yarn release:publish [merge-commit-sha] | ||
| # | ||
| # If no SHA is provided, defaults to HEAD on main. | ||
| # | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| RED='\033[0;31m' | ||
| GREEN='\033[0;32m' | ||
| YELLOW='\033[0;33m' | ||
| BOLD='\033[1m' | ||
| RESET='\033[0m' | ||
|
|
||
| step() { | ||
| echo "" | ||
| echo -e "${GREEN}${BOLD}[$1]${RESET} $2" | ||
| } | ||
|
|
||
| warn() { | ||
| echo -e "${YELLOW}Warning:${RESET} $1" | ||
| } | ||
|
|
||
| error() { | ||
| echo -e "${RED}Error:${RESET} $1" >&2 | ||
| exit 1 | ||
| } | ||
|
|
||
| REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || error "Not inside a git repository" | ||
| cd "$REPO_ROOT" | ||
|
|
||
| git remote get-url upstream &>/dev/null || error "'upstream' remote not found" | ||
|
|
||
| # ── Ensure we're on main and up to date ────────────────────────────────────── | ||
|
|
||
| step "1/5" "Updating main branch..." | ||
| git checkout main | ||
| git pull upstream main | ||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should probably also do
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. addressed in efb7da0 |
||
| # ── Determine the merge commit SHA ─────────────────────────────────────────── | ||
|
|
||
| MERGE_SHA="${1:-$(git rev-parse HEAD)}" | ||
|
|
||
| step "2/5" "Detecting release details from ${BOLD}${MERGE_SHA:0:12}${RESET}..." | ||
|
|
||
| # Read the EUI version at the target commit | ||
| EUI_VERSION=$(git show "${MERGE_SHA}:packages/eui/package.json" | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).version") | ||
| TAG_NAME="v${EUI_VERSION}" | ||
|
|
||
| # Check if this tag already exists | ||
| if git rev-parse "$TAG_NAME" &>/dev/null; then | ||
| error "Tag ${TAG_NAME} already exists. Has this release already been published?" | ||
| fi | ||
|
|
||
| # ── Detect changed workspaces ──────────────────────────────────────────────── | ||
|
|
||
| # Find the most recent existing release tag to compare against | ||
| PREV_TAG=$(git describe --tags --abbrev=0 "${MERGE_SHA}^" 2>/dev/null) || error "Could not find a previous release tag" | ||
|
|
||
| # Compare package.json versions between previous tag and release commit | ||
| # to determine which public packages changed | ||
| CHANGED_WORKSPACES="" | ||
| for pkg_dir in packages/eui packages/eui-theme-common packages/eui-theme-borealis packages/docusaurus-preset packages/docusaurus-theme packages/eslint-plugin; do | ||
| pkg_json="${pkg_dir}/package.json" | ||
|
|
||
| # Skip if package.json doesn't exist at the merge commit | ||
| git show "${MERGE_SHA}:${pkg_json}" &>/dev/null || continue | ||
|
|
||
| new_version=$(git show "${MERGE_SHA}:${pkg_json}" | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).version") | ||
| old_version=$(git show "${PREV_TAG}:${pkg_json}" 2>/dev/null | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).version" 2>/dev/null || echo "") | ||
|
|
||
| if [[ "$new_version" != "$old_version" ]]; then | ||
| pkg_name=$(git show "${MERGE_SHA}:${pkg_json}" | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).name") | ||
| if [[ -n "$CHANGED_WORKSPACES" ]]; then | ||
| CHANGED_WORKSPACES="${CHANGED_WORKSPACES},${pkg_name}" | ||
| else | ||
| CHANGED_WORKSPACES="${pkg_name}" | ||
| fi | ||
| fi | ||
| done | ||
|
|
||
| if [[ -z "$CHANGED_WORKSPACES" ]]; then | ||
| error "No changed workspaces detected. Are you sure the release PR was merged?" | ||
| fi | ||
|
|
||
| # ── Summary & confirmation ────────────────────────────────────────────────── | ||
|
|
||
| step "3/5" "Release summary" | ||
| echo "" | ||
| echo -e " Tag: ${BOLD}${TAG_NAME}${RESET}" | ||
| echo -e " Commit: ${BOLD}${MERGE_SHA:0:12}${RESET}" | ||
| echo -e " Previous tag: ${BOLD}${PREV_TAG}${RESET}" | ||
| echo -e " Workspaces: ${BOLD}${CHANGED_WORKSPACES}${RESET}" | ||
| echo "" | ||
| read -r -p "Proceed with tagging and triggering the release? (y/N) " confirm | ||
| if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then | ||
| echo "Aborted." | ||
| exit 0 | ||
| fi | ||
|
|
||
| # ── Tag and push ──────────────────────────────────────────────────────────── | ||
|
|
||
| step "4/5" "Creating and pushing tag ${BOLD}${TAG_NAME}${RESET}..." | ||
| git tag -a "$TAG_NAME" "$MERGE_SHA" -m "@elastic/eui ${TAG_NAME}" | ||
| git push upstream "$TAG_NAME" --no-verify | ||
|
|
||
| # ── Trigger release workflow ──────────────────────────────────────────────── | ||
|
|
||
| step "5/5" "Triggering release workflow..." | ||
| gh workflow run release.yml \ | ||
| --repo elastic/eui \ | ||
| -f release_ref="$MERGE_SHA" \ | ||
| -f type=official \ | ||
| -f workspaces="$CHANGED_WORKSPACES" \ | ||
| -f dry_run=false | ||
|
|
||
| echo "" | ||
| echo -e "${GREEN}${BOLD}Release triggered!${RESET}" | ||
| echo "" | ||
| echo -e " Monitor: ${BOLD}https://github.com/elastic/eui/actions/workflows/release.yml${RESET}" | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The repo’s CI/release workflows use
yarn install --immutable(Yarn 4) to ensure installs don’t modify the lockfile or create unexpected changes. Using plainyarnhere can introduce uncommitted changes (e.g. lockfile/install state) and cause the later dirty-worktree prompt to trigger for unrelated reasons. Consider switching this toyarn install --immutable(and any other flags the repo standardizes on) to keep the release branch clean and reproducible.