Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/parse-release-tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Parse Release Tag

on:
workflow_call:
inputs:
tag:
description: 'Release tag (e.g., selenium-4.28.0 or selenium-4.28.1-ruby)'
required: true
type: string
outputs:
tag:
description: 'The validated tag'
value: ${{ jobs.parse.outputs.tag }}
version:
description: 'The version number (e.g., 4.28.0)'
value: ${{ jobs.parse.outputs.version }}
language:
description: 'The language (ruby, python, etc.) or "all" for full releases'
value: ${{ jobs.parse.outputs.language }}

permissions: {}

jobs:
parse:
name: Parse Tag
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.parse.outputs.tag }}
version: ${{ steps.parse.outputs.version }}
language: ${{ steps.parse.outputs.language }}
steps:
- name: Parse and validate tag
id: parse
shell: bash
run: |
TAG="${{ inputs.tag }}"
TAG="${TAG//[[:space:]]/}"

# Validate tag format: selenium-X.Y.Z or selenium-X.Y.Z-lang
if [[ ! "$TAG" =~ ^selenium-[0-9]+\.[0-9]+\.[0-9]+(-(ruby|python|javascript|java|dotnet))?$ ]]; then
echo "::error::Invalid tag format: '$TAG'. Expected selenium-X.Y.Z or selenium-X.Y.Z-lang (ruby, python, javascript, java, dotnet)"
exit 1
fi

# Extract version
VERSION=$(echo "$TAG" | sed -E 's/^selenium-([0-9]+\.[0-9]+\.[0-9]+)(-(ruby|python|javascript|java|dotnet))?$/\1/')
PATCH=$(echo "$VERSION" | cut -d. -f3)

# Extract language suffix
if [[ "$TAG" =~ -(ruby|python|javascript|java|dotnet)$ ]]; then
LANG_SUFFIX="${BASH_REMATCH[1]}"
else
LANG_SUFFIX=""
fi

# Patch releases must have a language suffix
if [[ "$PATCH" -gt 0 && -z "$LANG_SUFFIX" ]]; then
echo "::error::Patch releases must specify a language (e.g., selenium-${VERSION}-ruby)"
exit 1
fi

# Full releases must not have a language suffix
if [[ "$PATCH" -eq 0 && -n "$LANG_SUFFIX" ]]; then
echo "::error::Full releases (X.Y.0) cannot have a language suffix"
exit 1
fi

# Set language (already validated by regex above)
if [[ -n "$LANG_SUFFIX" ]]; then
LANGUAGE="$LANG_SUFFIX"
else
LANGUAGE="all"
fi

{
echo "tag=$TAG"
echo "version=$VERSION"
echo "language=$LANGUAGE"
} >> "$GITHUB_OUTPUT"
108 changes: 59 additions & 49 deletions .github/workflows/pre-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name: Release Preparation
on:
workflow_dispatch:
inputs:
version:
description: 'Selenium version to release'
tag:
description: 'Release tag (e.g., selenium-4.28.0 or selenium-4.28.1-ruby)'
required: true
chrome_channel:
description: 'Chrome Channel for CDP'
Expand All @@ -25,48 +25,55 @@ jobs:
with:
title: Release approval needed
message: |
Selenium ${{ github.event.inputs.version }} release preparation started.
Selenium ${{ github.event.inputs.tag }} release preparation started.
Please approve to lock trunk when ready.
secrets:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

# Run rust jobs in parallel with approval since work is not on trunk
parse-tag:
name: Parse Tag
uses: ./.github/workflows/parse-release-tag.yml
with:
tag: ${{ inputs.tag }}

# Rust jobs can execute in parallel with approval job since work is in a separate branch
generate-rust-version:
name: Generate Rust Version
if: github.event.repository.fork == false
needs: parse-tag
if: github.event.repository.fork == false && needs.parse-tag.outputs.language == 'all'
uses: ./.github/workflows/bazel.yml
with:
name: Update Rust Version
run: ./go rust:version ${{ inputs.version }}
run: ./go rust:version ${{ needs.parse-tag.outputs.version }}
artifact-name: rust-version

push-rust-version:
name: Push Rust Version
needs: generate-rust-version
needs: [parse-tag, generate-rust-version]
permissions:
contents: write
actions: read
uses: ./.github/workflows/commit-changes.yml
with:
artifact-name: rust-version
commit-message: "update selenium manager version and rust changelog"
push-branch: rust-release-${{ inputs.version }}
push-branch: rust-release-${{ needs.parse-tag.outputs.version }}
secrets:
SELENIUM_CI_TOKEN: ${{ secrets.SELENIUM_CI_TOKEN }}

selenium-manager:
name: Release Selenium Manager
needs: push-rust-version
needs: [parse-tag, push-rust-version]
uses: ./.github/workflows/ci-rust.yml
with:
release: true
branch: rust-release-${{ inputs.version }}
branch: rust-release-${{ needs.parse-tag.outputs.version }}
secrets:
SELENIUM_CI_TOKEN: ${{ secrets.SELENIUM_CI_TOKEN }}

cleanup-rust-branch:
name: Cleanup Rust Branch
needs: selenium-manager
needs: [parse-tag, selenium-manager]
runs-on: ubuntu-latest
steps:
- name: Checkout repo
Expand All @@ -75,39 +82,21 @@ jobs:
token: ${{ secrets.SELENIUM_CI_TOKEN }}
- name: Delete rust release branch
run: |
git push origin --delete rust-release-${{ inputs.version }}
git push origin --delete rust-release-${{ needs.parse-tag.outputs.version }}

restrict-trunk:
name: Restrict Trunk Branch
needs: [get-approval, selenium-manager]
needs: [parse-tag, get-approval, selenium-manager]
if: always() && !cancelled() && needs.get-approval.result == 'success' && (needs.selenium-manager.result == 'success' || needs.selenium-manager.result == 'skipped')
uses: ./.github/workflows/restrict-trunk.yml
with:
restrict: true
secrets: inherit

normalize-version:
name: Normalize Version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.value }}
steps:
- name: Normalize version
id: version
shell: bash
run: |
VERSION="${{ github.event.inputs.version }}"
VERSION="${VERSION//[[:space:]]/}"
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+$ ]]; then
VERSION="${VERSION}.0"
elif [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid version format: '$VERSION'. Expected major.minor or major.minor.patch"
exit 1
fi
echo "value=$VERSION" >> "$GITHUB_OUTPUT"

release-updates:
name: Generate ${{ matrix.name }} update
needs: [restrict-trunk, normalize-version]
needs: [parse-tag, restrict-trunk]
if: needs.parse-tag.outputs.language == 'all'
strategy:
fail-fast: false
matrix:
Expand All @@ -121,9 +110,9 @@ jobs:
- name: multitool
run: ./go update_multitool
- name: binding-versions
run: ./go all:version ${{ needs.normalize-version.outputs.version }} && ./go all:update
run: ./go all:version ${{ needs.parse-tag.outputs.version }} && ./go all:update
- name: rust-versions
run: ./go rust:version ${{ needs.normalize-version.outputs.version }} && ./go rust:update
run: ./go rust:version ${{ needs.parse-tag.outputs.version }} && ./go rust:update
- name: authors
run: ./go authors
uses: ./.github/workflows/bazel.yml
Expand All @@ -132,9 +121,19 @@ jobs:
run: ${{ matrix.run }}
artifact-name: patch-${{ matrix.name }}

patch-release-updates:
name: Generate ${{ needs.parse-tag.outputs.language }} version update
needs: [parse-tag, restrict-trunk]
if: needs.parse-tag.outputs.language != 'all'
uses: ./.github/workflows/bazel.yml
with:
name: Update ${{ needs.parse-tag.outputs.language }} version
run: ./go ${{ needs.parse-tag.outputs.language }}:version ${{ needs.parse-tag.outputs.version }} && ./go ${{ needs.parse-tag.outputs.language }}:update
artifact-name: patch-binding-versions

calculate-changelog-depth:
name: Calculate Changelog Depth
needs: normalize-version
needs: parse-tag
runs-on: ubuntu-latest
outputs:
depth: ${{ steps.calc.outputs.depth }}
Expand All @@ -143,7 +142,8 @@ jobs:
id: calc
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ needs.normalize-version.outputs.version }}
VERSION: ${{ needs.parse-tag.outputs.version }}
shell: bash
run: |
set -euo pipefail
if [[ "$VERSION" =~ ([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then
Expand Down Expand Up @@ -175,17 +175,20 @@ jobs:

generate-changelogs:
name: Generate Changelogs
needs: [restrict-trunk, normalize-version, calculate-changelog-depth]
needs: [parse-tag, restrict-trunk, calculate-changelog-depth]
uses: ./.github/workflows/bazel.yml
with:
name: Update Changelogs
run: ./go all:changelogs && ./go rust:changelogs
run: ./go ${{ needs.parse-tag.outputs.language }}:changelogs${{ needs.parse-tag.outputs.language == 'all' && ' && ./go rust:changelogs' || '' }}
artifact-name: patch-changelogs
fetch-depth: ${{ needs.calculate-changelog-depth.outputs.depth }}

create-pr:
name: Create Pull Request
needs: [normalize-version, release-updates, generate-changelogs]
needs: [parse-tag, release-updates, patch-release-updates, generate-changelogs]
if: >-
always() && !cancelled() && needs.release-updates.result != 'failure' && needs.patch-release-updates.result != 'failure' &&
needs.generate-changelogs.result == 'success'
runs-on: ubuntu-latest
steps:
- name: Checkout trunk
Expand Down Expand Up @@ -233,21 +236,28 @@ jobs:
token: ${{ secrets.SELENIUM_CI_TOKEN }}
author: Selenium CI Bot <[email protected]>
delete-branch: true
branch: release-preparation-${{ needs.normalize-version.outputs.version }}
branch: release-preparation-${{ needs.parse-tag.outputs.tag }}
base: trunk
title: "[build] Prepare for release of Selenium ${{ needs.normalize-version.outputs.version }}"
title: "[build] Prepare for release of ${{ needs.parse-tag.outputs.tag }}"
body: |

### Release Info
| | |
|-----------|--------|
| **Tag** | ${{ needs.parse-tag.outputs.tag }} |
| **Version** | ${{ needs.parse-tag.outputs.version }} |
| **Language** | ${{ needs.parse-tag.outputs.language }} |

### Updates Applied
| Component | Status |
|-----------|--------|
| Browser and driver versions | ${{ steps.apply.outputs.browsers == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)' }} |
| CDP version | ${{ steps.apply.outputs.devtools == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)' }} |
| Selenium Manager version | ${{ steps.apply.outputs.manager == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)' }} |
| Multitool binaries | ${{ steps.apply.outputs.multitool == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)' }} |
| Browser and driver versions | ${{ needs.parse-tag.outputs.language != 'all' && 'N/A' || (steps.apply.outputs.browsers == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)') }} |
| CDP version | ${{ needs.parse-tag.outputs.language != 'all' && 'N/A' || (steps.apply.outputs.devtools == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)') }} |
| Selenium Manager version | ${{ needs.parse-tag.outputs.language != 'all' && 'N/A' || (steps.apply.outputs.manager == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)') }} |
| Multitool binaries | ${{ needs.parse-tag.outputs.language != 'all' && 'N/A' || (steps.apply.outputs.multitool == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)') }} |
| Bindings Version & Dependencies | ${{ steps.apply.outputs.binding-versions == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)' }} |
| Rust Version & Dependencies | ${{ steps.apply.outputs.rust-versions == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)' }} |
| Authors | ${{ steps.apply.outputs.authors == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)' }} |
| Rust Version & Dependencies | ${{ needs.parse-tag.outputs.language != 'all' && 'N/A' || (steps.apply.outputs.rust-versions == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)') }} |
| Authors | ${{ needs.parse-tag.outputs.language != 'all' && 'N/A' || (steps.apply.outputs.authors == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)') }} |
| Draft Changelogs | ${{ steps.apply.outputs.changelogs == 'true' && '✅ Updated' || '⏭️ Skipped (no changes)' }} |

---
Expand Down
Loading
Loading