This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch ci/two-phase-release-workflow in repository https://gitbox.apache.org/repos/asf/struts-intellij-plugin.git
commit 849c24bd98c715fcfbb609b192e393ce19639a76 Author: Lukasz Lenart <[email protected]> AuthorDate: Mon Feb 23 17:18:22 2026 +0100 ci: add two-phase release workflow with prepare and publish steps Add prepare_release.yml workflow (manual dispatch) that builds the plugin, creates a git tag, and publishes a GitHub pre-release for PMC review. When the pre-release is promoted to a full release, the existing release.yml fires and publishes to the Marketplace Stable channel. Also fixes: - release.yml trigger narrowed to [released] only (was [prereleased, released]) - build.yml nightly builds now publish to Marketplace nightly channel - build.yml HEREDOC bug in pre-release notes creation - README.md documents the full release process 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --- .github/workflows/build.yml | 37 ++++++---- .github/workflows/prepare_release.yml | 132 ++++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 2 +- README.md | 18 +++++ 4 files changed, 174 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 078ed4e..fbf87bf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -282,7 +282,7 @@ jobs: BUILD=$((LATEST_BUILD + 1)) # Update pluginVersion in gradle.properties - sed -i "s/pluginVersion = [0-9]*\.[0-9]*\.[0-9]*/pluginVersion = ${BRANCH}.${BUILD}.1/" gradle.properties + sed -i "s/pluginVersion = [0-9]*\.[0-9]*\.[0-9]*/pluginVersion = ${BRANCH}.${BUILD}-nightly.1/" gradle.properties # Get final version and changelog PROPERTIES="$(./gradlew properties --no-configuration-cache --console=plain -q)" @@ -298,6 +298,15 @@ jobs: - name: Build Plugin run: ./gradlew buildPlugin --no-configuration-cache + # Publish pre-release to JetBrains Marketplace nightly channel + - name: Publish Plugin to Marketplace (Nightly) + env: + PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} + CERTIFICATE_CHAIN: ${{ secrets.CERTIFICATE_CHAIN }} + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }} + run: ./gradlew publishPlugin --no-configuration-cache + # Prepare plugin archive content for creating artifact - name: Prepare Plugin Artifact id: artifact @@ -336,24 +345,24 @@ jobs: - name: Create Pre-release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CHANGELOG: ${{ steps.version.outputs.changelog }} run: | # Find the plugin zip file PLUGIN_ZIP=$(find ./build/distributions -name "*.zip" -type f | head -1) - - gh release create "v${{ steps.version.outputs.version }}" \ - --prerelease \ - --title "v${{ steps.version.outputs.version }}" \ - --notes "$(cat << 'EOM' - 🚀 **Pre-release v${{ steps.version.outputs.version }}** - + + NOTES="🚀 **Pre-release v${{ steps.version.outputs.version }}** + This is an automated pre-release build from the main branch. - + ## Changes - ${{ steps.version.outputs.changelog }} - + ${CHANGELOG} + ## Installation Download the plugin zip file and install it manually in IntelliJ IDEA via: - `Settings → Plugins → ⚙️ → Install Plugin from Disk...` - EOM - )" \ + \`Settings → Plugins → ⚙️ → Install Plugin from Disk...\`" + + gh release create "v${{ steps.version.outputs.version }}" \ + --prerelease \ + --title "v${{ steps.version.outputs.version }}" \ + --notes "$NOTES" \ "$PLUGIN_ZIP" \ No newline at end of file diff --git a/.github/workflows/prepare_release.yml b/.github/workflows/prepare_release.yml new file mode 100644 index 0000000..8b7c641 --- /dev/null +++ b/.github/workflows/prepare_release.yml @@ -0,0 +1,132 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# GitHub Actions Workflow for preparing a release candidate. +# Builds the plugin, creates a git tag, and publishes a GitHub pre-release +# with the plugin zip attached for PMC review and voting. +# Does NOT publish to JetBrains Marketplace — that happens when the +# pre-release is promoted to a full release (see release.yml). + +name: Prepare Release +on: + workflow_dispatch: + inputs: + version: + description: 'Release version (e.g. 253.18970.1). Leave empty to use pluginVersion from gradle.properties.' + required: false + default: '' + +jobs: + prepare: + name: Prepare Release + runs-on: ubuntu-latest + permissions: + contents: write + steps: + + # Free GitHub Actions Environment Disk Space + - name: Maximize Build Space + uses: jlumbroso/[email protected] + with: + tool-cache: false + large-packages: false + + # Check out the selected branch + - name: Fetch Sources + uses: actions/checkout@v6 + + # Set up Java environment for the next steps + - name: Setup Java + uses: actions/setup-java@v5 + with: + distribution: zulu + java-version: 21 + + # Setup Gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + gradle-home-cache-cleanup: true + + # Resolve the release version + - name: Resolve Version + id: version + shell: bash + run: | + if [ -n "${{ github.event.inputs.version }}" ]; then + VERSION="${{ github.event.inputs.version }}" + # Update pluginVersion in gradle.properties with the override + sed -i "s/pluginVersion = .*/pluginVersion = ${VERSION}/" gradle.properties + echo "Using version override: $VERSION" + else + VERSION=$(grep "pluginVersion" gradle.properties | cut -d '=' -f2 | tr -d ' ') + echo "Using version from gradle.properties: $VERSION" + fi + + echo "version=$VERSION" >> $GITHUB_OUTPUT + + # Build plugin + - name: Build Plugin + run: ./gradlew buildPlugin --no-configuration-cache + + # Get changelog for release notes + - name: Get Changelog + id: changelog + shell: bash + run: | + CHANGELOG="$(./gradlew getChangelog --no-configuration-cache --unreleased --no-header --console=plain -q)" + + echo "changelog<<EOF" >> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + # Create and push git tag + - name: Create Tag + run: | + TAG="v${{ steps.version.outputs.version }}" + git config user.email "[email protected]" + git config user.name "GitHub Action" + git tag -a "$TAG" -m "Release $TAG" + git push origin "$TAG" + + # Create GitHub pre-release with plugin zip attached + - name: Create Pre-release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CHANGELOG: ${{ steps.changelog.outputs.changelog }} + run: | + TAG="v${{ steps.version.outputs.version }}" + PLUGIN_ZIP=$(find ./build/distributions -name "*.zip" -type f | head -1) + + NOTES="## Release candidate ${{ steps.version.outputs.version }} + + This is a release candidate for PMC review and voting. + + ### Changes + ${CHANGELOG} + + ### Installation + Download the plugin zip file and install it manually in IntelliJ IDEA via: + \`Settings → Plugins → ⚙️ → Install Plugin from Disk...\` + + ### Voting + Once testing is complete, promote this pre-release to a full release to + trigger publication to the JetBrains Marketplace Stable channel." + + gh release create "$TAG" \ + --prerelease \ + --title "$TAG" \ + --notes "$NOTES" \ + "$PLUGIN_ZIP" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bcf79a9..7bbe259 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ name: Release on: release: - types: [prereleased, released] + types: [released] jobs: release: diff --git a/README.md b/README.md index d3b1f75..f872a5a 100644 --- a/README.md +++ b/README.md @@ -167,3 +167,21 @@ GitHub Actions will swap it and provide you an empty section for the next releas ``` To configure how the Changelog plugin behaves, i.e., to create headers with the release date, see [Gradle Changelog Plugin][gh:gradle-changelog-plugin] README file. + +### Release process + +The plugin uses a two-phase release process with nightly builds for continuous delivery: + +**Nightly builds** are created automatically when commits are merged to `main`. The [Build](.github/workflows/build.yml) workflow runs tests, builds the plugin, and publishes it to the JetBrains Marketplace **nightly** channel. A GitHub pre-release is also created with the plugin zip attached. + +**Preparing a release** is a manual step. Go to **Actions → Prepare Release → Run workflow**, optionally providing a version override. This workflow: +1. Builds the plugin (using the version from `gradle.properties` or your override) +2. Creates a git tag `v{VERSION}` and pushes it +3. Creates a GitHub **pre-release** with the plugin zip attached + +PMC members can then download the zip from the pre-release, test it locally, and vote. + +**Publishing a release** happens when the pre-release is promoted to a full release. Edit the GitHub pre-release, uncheck **"Set as a pre-release"**, and save. This triggers the [Release](.github/workflows/release.yml) workflow which: +1. Publishes the plugin to the JetBrains Marketplace **Stable** channel +2. Uploads the plugin zip as a release asset +3. Creates a pull request to update the changelog
