This is an automated email from the ASF dual-hosted git repository. jdaugherty pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/grails-intellij-plugin.git
commit 5242c7ecd41660c905408f1e2ed7b61f32fc265d Author: James Daugherty <[email protected]> AuthorDate: Sat Jul 18 16:29:34 2026 -0400 Drop Maven publishing; distribute via GitHub, dist.apache.org, and Marketplace --- .github/scripts/releaseDistributions.sh | 90 -------------------- .github/scripts/releaseJarFiles.sh | 143 -------------------------------- .github/workflows/release.yml | 41 --------- MIGRATION-PLAN.md | 49 ++++------- build.gradle.kts | 35 +------- settings.gradle.kts | 31 ------- 6 files changed, 19 insertions(+), 370 deletions(-) diff --git a/.github/scripts/releaseDistributions.sh b/.github/scripts/releaseDistributions.sh deleted file mode 100755 index eef4ffa..0000000 --- a/.github/scripts/releaseDistributions.sh +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash - -# -# 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 -# -# https://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. -# - -# ./releaseDistributions.sh <tag> <svn-folder> <username> - -set -euo pipefail - -if [[ $# -ne 3 ]]; then - echo "Usage: $0 <tag> <svn-folder> <username>" >&2 - exit 1 -fi - -RELEASE_TAG="$1" -SVN_FOLDER="$2" -SVN_USER="$3" -read -r -s -p "Password: " SVN_PASS -echo - -if [[ -z "${RELEASE_TAG}" ]]; then - echo "❌ ERROR: Release Tag must not be empty." >&2 - exit 1 -fi -if [[ -z "${SVN_USER}" ]]; then - echo "❌ ERROR: Username must not be empty." >&2 - exit 1 -fi -if [[ -z "${SVN_PASS}" ]]; then - echo "❌ ERROR: Password must not be empty." >&2 - exit 1 -fi - -RELEASE_VERSION="${RELEASE_TAG#v}" -RELEASE_ROOT="https://dist.apache.org/repos/dist/release/grails/${SVN_FOLDER}" -DEV_ROOT="https://dist.apache.org/repos/dist/dev/grails/${SVN_FOLDER}" - -svn_flags=(--non-interactive --trust-server-cert --username "${SVN_USER}" --password "${SVN_PASS}") - -svn_exists() { - local url="$1" - svn ls "${svn_flags[@]}" --depth=empty "${url}" >/dev/null 2>&1 -} - -for folder in $(svn ls "${svn_flags[@]}" "${RELEASE_ROOT}"); do - folder=$(echo "$folder" | sed 's|/$||') - [[ "${folder}" == "${RELEASE_VERSION}" ]] && continue - PRIOR_RELEASE_URL="${RELEASE_ROOT}/${folder}" - read -r -p "Remove old release folder '${folder}' at ${PRIOR_RELEASE_URL}? [y/N] " confirm < /dev/tty - if [[ "${confirm}" =~ ^[Yy](es)?$ ]]; then - echo "🗑️ Deleting old release folder: ${PRIOR_RELEASE_URL}" - svn rm "${svn_flags[@]}" -m "Remove previous release ${folder}" "${PRIOR_RELEASE_URL}" - echo "✅ Deleted old release folder" - else - echo "⏭️ Skipping removal of old release folder: ${PRIOR_RELEASE_URL}" - fi -done - -DEV_VERSION_URL="$DEV_ROOT/${RELEASE_VERSION}" -RELEASE_VERSION_URL="$RELEASE_ROOT/${RELEASE_VERSION}" - -if ! svn_exists "${DEV_VERSION_URL}"; then - echo "❌ ERROR: dev folder for ${RELEASE_VERSION} does not exist at: ${DEV_VERSION_URL}" >&2 - exit 2 -fi - -if svn_exists "${RELEASE_VERSION_URL}"; then - echo "❌ ERROR: release folder for ${RELEASE_VERSION} already exists at: ${RELEASE_VERSION_URL}" >&2 - exit 3 -fi - -echo "🚀 Promoting ${DEV_VERSION_URL} -> ${RELEASE_VERSION_URL}" -svn mv "${svn_flags[@]}" -m "Promote Apache Grails ${RELEASE_VERSION} from dev to release" "${DEV_VERSION_URL}" "${RELEASE_VERSION_URL}" -echo "✅ Promoted" diff --git a/.github/scripts/releaseJarFiles.sh b/.github/scripts/releaseJarFiles.sh deleted file mode 100755 index a18f7c5..0000000 --- a/.github/scripts/releaseJarFiles.sh +++ /dev/null @@ -1,143 +0,0 @@ -#!/bin/bash - -# -# 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 -# -# https://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. -# - -# ./releaseJarFiles.sh <staging-repo-description> <username> - -set -euo pipefail - -if [[ $# -ne 2 ]]; then - echo "Usage: $0 <staging-repo-description> <username>" >&2 - exit 1 -fi - -STAGING_DESCRIPTION="$1" -NEXUS_USER="$2" -read -r -s -p "Password: " NEXUS_PASS -echo - -if [[ -z "${STAGING_DESCRIPTION}" ]]; then - echo "ERROR: Staging Description must not be empty." >&2 - exit 1 -fi -if [[ -z "${NEXUS_USER}" ]]; then - echo "ERROR: Username must not be empty." >&2 - exit 1 -fi -if [[ -z "${NEXUS_PASS}" ]]; then - echo "ERROR: Password must not be empty." >&2 - exit 1 -fi - -NEXUS_URL="https://repository.apache.org" - -nexusApi() { - local request_method="$1"; shift - local path="$1"; shift - curl -fsS -u "${NEXUS_USER}:${NEXUS_PASS}" \ - -H 'Accept: application/json' \ - -H 'Content-Type: application/json' \ - -X "${request_method}" "${NEXUS_URL}/service/local/${path}" "$@" -} - -wait_for_promotion() { - local repoId="$1" - local timeout_s="${2:-600}" # default 10 minutes - local interval_s="${3:-3}" - local started - started="$(date +%s)" - - echo "Waiting for release promotion to complete (timeout ${timeout_s}s)…" - - while :; do - # 1) If any ERROR appears in activity, fail fast - act="$(nexusApi GET "/staging/repository/${repoId}/activity" || true)" - if [[ -n "$act" ]]; then - err_count="$(jq -r '[.. | objects? | select(has("severity")) | select(.severity=="ERROR")] | length' <<<"$act" 2>/dev/null || echo 0)" - if [[ "$err_count" != "0" ]]; then - echo "ERROR: Staging activity contains failure(s). Aborting." >&2 - # Optionally dump recent relevant lines: - jq -r '.. | objects? | select(has("severity")) | "\(.severity): \(.name // "event") - \(.message // "")"' <<<"$act" || true - return 1 - fi - fi - - # 2) Check transitioning flag — when false after promote, action is done - trans="$(nexusApi GET '/staging/profile_repositories' \ - | jq -r --arg r "$repoId" '.data[]? | select(.repositoryId==$r) | .transitioning' 2>/dev/null || echo "true")" - - if [[ "$trans" == "false" ]]; then - # sanity: make sure we actually saw some "release/promote" activity; otherwise keep waiting a bit - if [[ -n "$act" ]]; then - # did we see any promote/release-ish step? - saw_promote="$(jq -r ' - [ .. | objects? | .name? // empty | ascii_downcase - | select(test("release|promote|finish")) ] | length' <<<"$act" 2>/dev/null || echo 0)" - if [[ "$saw_promote" -gt 0 ]]; then - echo "Promotion appears complete." - return 0 - fi - fi - fi - - # timeout? - now="$(date +%s)" - if (( now - started >= timeout_s )); then - echo "ERROR: Timed out waiting for promotion to complete." >&2 - # Show a short summary to aid debugging - if [[ -n "$act" ]]; then - echo "--- Recent activity snapshot ---" - jq -r '.. | objects? | select(has("severity") or has("name")) | "\(.severity // "")\t\(.name // "")\t\(.message // "")"' <<<"$act" | tail -n 20 || true - fi - return 1 - fi - - sleep "$interval_s" - done -} - -repos_json="$(nexusApi GET '/staging/profile_repositories')" -repoId="$(jq -r --arg d "${STAGING_DESCRIPTION}" '.data[] | select(.description==$d) | .repositoryId' <<<"${repos_json}")" -profileId="$(jq -r --arg d "${STAGING_DESCRIPTION}" '.data[] | select(.description==$d) | .profileId' <<<"${repos_json}")" -state="$(jq -r --arg d "${STAGING_DESCRIPTION}" '.data[] | select(.description==$d) | .type' <<<"${repos_json}")" - -if [[ -z "${repoId}" || -z "${profileId}" ]]; then - echo "ERROR: No staged repository found with description: ${STAGING_DESCRIPTION}" >&2 - exit 2 -fi -echo "Found staged repo: ${repoId} (profile: ${profileId}, state: ${state})" -if [[ "${state}" == "open" ]]; then - echo "ERROR: Staged Repo is not closed: ${STAGING_DESCRIPTION}" >&2 - exit 3 -fi - -if [[ "${state}" == "closed" ]]; then - echo "Promoting (release) ${repoId}…" - nexusApi POST "/staging/profiles/${profileId}/promote" \ - --data "$(jq -n --arg r "${repoId}" --arg d "${STAGING_DESCRIPTION}" '{data:{stagedRepositoryId:$r,description:$d}}')" -fi - -wait_for_promotion "$repoId" 600 3 - -echo "Dropping staging repository ${repoId}…" -nexusApi POST "/staging/profiles/${profileId}/drop" \ - --data "$(jq -n --arg r "$repoId" --arg d "${STAGING_DESCRIPTION}" '{data:{stagedRepositoryId:$r,description:$d}}')" - -echo "Done. Released ${repoId}." \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 31e4c7f..d4302dc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,6 @@ on: permissions: { } env: DIST_NAME: apache-grails-intellij-plugin - GRAILS_PUBLISH_RELEASE: 'true' JAVA_DISTRIBUTION: liberica JAVA_VERSION: 21 PROJECT_NAME: Apache Grails IntelliJ Plugin @@ -85,41 +84,6 @@ jobs: ${DIST_NAME}-${VERSION}-bin.zip - name: "📦 Create plugin ZIP checksum" run: sha512sum ${DIST_NAME}-${VERSION}-bin.zip > ${DIST_NAME}-${VERSION}-bin.zip.sha512 - - name: "✨ Create Staging Repository" - env: - NEXUS_PUBLISH_USERNAME: ${{ secrets.NEXUS_STAGE_DEPLOYER_USER }} - NEXUS_PUBLISH_PASSWORD: ${{ secrets.NEXUS_STAGE_DEPLOYER_PW }} - NEXUS_PUBLISH_URL: ${{ vars.STAGING_URL }} - NEXUS_PUBLISH_STAGING_PROFILE_ID: ${{ secrets.STAGING_PROFILE_ID }} - NEXUS_PUBLISH_DESCRIPTION: '${{ github.event.repository.name }}:${{ env.VERSION }}' - run: ./gradlew initializeSonatypeStagingRepository -Pversion=${VERSION} - - name: "📤 Publish to Staging Repository" - env: - NEXUS_PUBLISH_USERNAME: ${{ secrets.NEXUS_STAGE_DEPLOYER_USER }} - NEXUS_PUBLISH_PASSWORD: ${{ secrets.NEXUS_STAGE_DEPLOYER_PW }} - NEXUS_PUBLISH_URL: ${{ vars.STAGING_URL }} - NEXUS_PUBLISH_STAGING_PROFILE_ID: ${{ secrets.STAGING_PROFILE_ID }} - NEXUS_PUBLISH_DESCRIPTION: '${{ github.event.repository.name }}:${{ env.VERSION }}' - SIGNING_KEY: ${{ secrets.GPG_KEY_ID }} - run: > - ./gradlew - -x initializeSonatypeStagingRepository - findSonatypeStagingRepository - publishToSonatype - -Pversion=${VERSION} - - name: "✅ Close Staging Repository" - env: - NEXUS_PUBLISH_USERNAME: ${{ secrets.NEXUS_STAGE_DEPLOYER_USER }} - NEXUS_PUBLISH_PASSWORD: ${{ secrets.NEXUS_STAGE_DEPLOYER_PW }} - NEXUS_PUBLISH_URL: ${{ vars.STAGING_URL }} - NEXUS_PUBLISH_STAGING_PROFILE_ID: ${{ secrets.STAGING_PROFILE_ID }} - NEXUS_PUBLISH_DESCRIPTION: '${{ github.event.repository.name }}:${{ env.VERSION }}' - run: > - ./gradlew - -x initializeSonatypeStagingRepository - findSonatypeStagingRepository - closeSonatypeStagingRepository - -Pversion=${VERSION} - name: "🚀 Upload plugin ZIP to GitHub Release" uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 with: @@ -295,11 +259,6 @@ jobs: PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }} PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} run: ./gradlew publishPlugin -Pversion=${VERSION} - - name: "🚀 MANUAL - Release Maven staging repository" - run: | - echo "::group::Manual Nexus Staging Release" - echo "Run .github/scripts/releaseJarFiles.sh ${{ github.event.repository.name }}:${VERSION} <ASF_USER>" - echo "::endgroup::" - name: "✅ MANUAL - Update ASF Reporter" run: | echo "::group::Manual ASF Reporter Update" diff --git a/MIGRATION-PLAN.md b/MIGRATION-PLAN.md index 033e9f8..4dbb4a6 100644 --- a/MIGRATION-PLAN.md +++ b/MIGRATION-PLAN.md @@ -64,28 +64,16 @@ blind deletion of imported infra). channel. 5. **Versioning**: keep the `<platform-branch>.x.y` scheme (`253.0.0`) or align with a Grails-style scheme. Marketplace convention favors the platform-branch scheme — keep it. -6. **Maven publishing** (added 2026-07-18): also publish the plugin ZIP to the ASF Nexus - (`repository.apache.org`, syncs to Maven Central on staging release) under - `org.apache.grails:grails-intellij-plugin` — Maven coordinates are independent of the - Marketplace plugin id, so the Apache groupId works even though the plugin id stays - `org.intellij.grails`. AMENDED (2026-07-18): done via the **Grails Publish plugin** - (`org.apache.grails.gradle:grails-publish:1.0.0-M1`, same flow as grails-core) with - `addComponents=false` and the ZIP attached to its `maven` publication. Notes: - - `settings.gradle.kts` adds the ASF snapshots/staging groups to `pluginManagement`, - content-filtered exactly like grails-core's `GrailsRepoSettingsPlugin` (grails-publish - modules only, plus `org.apache.groovy` on staging) — never for other dependencies. - - the plugin needs `project.version` at apply time, so `pluginVersion` in - gradle.properties was renamed to the standard `version` property (release workflow - passes `-Pversion=`). - - grails-publish 1.0.0-M1 pom generation is not configuration-cache compatible; the - build marks `GenerateMavenPom` tasks `notCompatibleWithConfigurationCache`. The - proper fix should be made on the grails-gradle-publish **1.x branch** (any changes - to that plugin go on 1.x). - - staging flow in release.yml mirrors grails-core: `initializeSonatypeStagingRepository` - → `publishToSonatype` → `closeSonatypeStagingRepository` (NEXUS_PUBLISH_* env, - secrets NEXUS_STAGE_DEPLOYER_USER/PW, vars.STAGING_URL, STAGING_PROFILE_ID, - SIGNING_KEY=GPG key id); post-vote promotion via `.github/scripts/releaseJarFiles.sh` - (copied from grails-core along with `releaseDistributions.sh`). +6. **Maven publishing** RESOLVED (2026-07-18): **none**. The plugin ZIP is never + consumed from Maven Central/ASF Nexus, so there is no Maven/Nexus publishing at all. + Distribution channels are: the GitHub release assets, `dist.apache.org` dev → release + via svn as part of the PMC vote, and the JetBrains Marketplace convenience binary. + A trial adoption of the Grails Publish plugin was reverted as unnecessary; two rough + edges found during that trial are candidate fixes on the grails-gradle-publish **1.x + branch** if it is ever adopted here: (a) it requires `project.version` at plugin apply + time, and (b) its pom generation is not configuration-cache compatible. Kept from the + trial: the project version now uses the standard `version` property in + gradle.properties (was `pluginVersion`); workflows pass `-Pversion=`. 7. **Signing keys** (added 2026-07-18): the existing Grails release GPG key (from the project `KEYS` file) covers all ASF signing — source zip, convenience binary, Maven `.asc` files. JetBrains Marketplace plugin signing is a separate mechanism: it @@ -315,15 +303,14 @@ test jobs via `needs:` **and** `if:` result guards. ## Phase 6 — GitHub Actions: ASF release & Marketplace publishing DONE (2026-07-18, initial draft): committed as "Add release workflow and Marketplace -signing config" + "Publish plugin ZIP to ASF Maven repository". `release.yml` jobs: -`publish` (check/buildPlugin/signPlugin, GPG-sign + sha512, attach to GitHub release, -stage Maven artifacts to repository.apache.org), `source` (src zip without wrapper/ -.github, GPG-sign + sha512), `upload` (svn to dist/dev for the vote), `release` -(environment-gated: svn mv dev->release, `publishPlugin` to Marketplace, manual Nexus -staging release + reporter/email reminders). Secrets needed: GRAILS_GPG_KEY, -GPG_KEY_ID, GPG_PASSPHRASE, SVC_DIST_GRAILS_USERNAME/PASSWORD, NEXUS_USERNAME/PASSWORD, -CERTIFICATE_CHAIN, PRIVATE_KEY, PRIVATE_KEY_PASSWORD, PUBLISH_TOKEN. Needs a dry-run -against a test tag before first use (Phase 8). +signing config" (Maven/Nexus staging later removed per decision 6). `release.yml` jobs: +`publish` (check/buildPlugin/signPlugin, GPG-sign + sha512, attach ZIP to GitHub +release), `source` (src zip without wrapper/.github, GPG-sign + sha512), `upload` (svn +to dist/dev for the vote), `release` (environment-gated: svn mv dev->release, +`publishPlugin` to Marketplace, reporter/email reminders). Secrets needed: +GRAILS_GPG_KEY, GPG_KEY_ID, SVC_DIST_GRAILS_USERNAME/PASSWORD, CERTIFICATE_CHAIN, +PRIVATE_KEY, PRIVATE_KEY_PASSWORD, PUBLISH_TOKEN. Needs a dry-run against a test tag +before first use (Phase 8). One commit: "ASF Compliance - release workflow". Modeled on grails-core's `release.yml` and the `apache/grails-github-actions` composite actions, adapted because the deliverable diff --git a/build.gradle.kts b/build.gradle.kts index d9cfd4c..65d8d40 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,11 +23,10 @@ plugins { id("org.jetbrains.kotlin.jvm") version "2.3.0" id("org.jetbrains.intellij.platform") version "2.11.0" id("org.nosphere.apache.rat") version "0.8.1" - id("org.apache.grails.gradle.grails-publish") version "1.0.0-M1" } group = "org.apache.grails.intellij" -// project version comes from gradle.properties `version` (read by grails-publish at apply time) +// project version comes from gradle.properties `version` (override with -Pversion=) repositories { mavenCentral() @@ -225,35 +224,3 @@ tasks.rat { outputs.upToDateWhen { false } } -// Publish the plugin ZIP to the ASF Nexus via the Grails Publish plugin (same flow as -// grails-core: NEXUS_PUBLISH_* env vars, initialize/publishToSonatype/close staging tasks, -// post-vote promotion with .github/scripts/releaseJarFiles.sh). Maven coordinates are -// independent of the JetBrains Marketplace plugin id (org.intellij.grails). -grailsPublish { - groupId.set("org.apache.grails") - artifactId.set("grails-intellij-plugin") - // the deliverable is the plugin ZIP, not the java component/sources/javadoc jars - addComponents.set(false) - githubSlug.set("apache/grails-intellij-plugin") - license.name = "Apache-2.0" - title.set("Apache Grails IntelliJ Plugin") - desc.set("IntelliJ IDEA plugin for the Apache Grails framework") - developer { - id.set("grails") - name.set("Apache Grails Team") - } -} - -// grails-publish creates the `maven` publication in afterEvaluate; attach the ZIP lazily -publishing.publications.withType<MavenPublication>().configureEach { - if (name == "maven") { - artifact(tasks.buildPlugin) - } -} - -// grails-publish 1.0.0-M1 pom generation captures the Project and breaks the -// configuration cache; degrade gracefully for publish runs. Proper fix belongs on the -// grails-gradle-publish 1.x branch. -tasks.withType<org.gradle.api.publish.maven.tasks.GenerateMavenPom>().configureEach { - notCompatibleWithConfigurationCache("grails-publish pom generation captures Project") -} diff --git a/settings.gradle.kts b/settings.gradle.kts index da7b7f4..caefd5a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,37 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -pluginManagement { - repositories { - // ASF repos for resolving snapshot/staged builds of the Grails Publish plugin - // ONLY — filtered like grails-core's GrailsRepoSettingsPlugin so these repos - // can never serve any other dependency. - maven { - url = uri("https://repository.apache.org/content/groups/snapshots") - content { - includeVersionByRegex("org[.]apache[.]grails[.]gradle.*", ".*", ".*-SNAPSHOT") - } - mavenContent { - snapshotsOnly() - } - } - maven { - url = uri("https://repository.apache.org/content/groups/staging") - content { - includeModuleByRegex("org[.]apache[.]grails[.]gradle", "grails-publish") - includeModuleByRegex("org[.]apache[.]groovy", "groovy.*") - // the plugins-block marker artifact - includeModule("org.apache.grails.gradle.grails-publish", "org.apache.grails.gradle.grails-publish.gradle.plugin") - } - mavenContent { - releasesOnly() - } - } - mavenCentral() // grails-publish is published to Maven Central, not the plugin portal - gradlePluginPortal() - } -} - rootProject.name = "Grails" include("copyright")
