diff --git a/.github/scripts/github_actions_utils.py b/.github/scripts/github_actions_utils.py deleted file mode 100644 index 8b90c6c4..00000000 --- a/.github/scripts/github_actions_utils.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2026 Apollo Authors -# -# Licensed 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. -"""Shared helpers for GitHub Actions scripts.""" - -from __future__ import annotations - -import os - - -def write_output(key: str, value: str) -> None: - output_path = os.environ.get("GITHUB_OUTPUT", "").strip() - if not output_path: - return - with open(output_path, "a", encoding="utf-8") as output: - output.write(f"{key}={value}\n") diff --git a/.github/scripts/release_extract_upload_context.py b/.github/scripts/release_extract_upload_context.py deleted file mode 100644 index 52981515..00000000 --- a/.github/scripts/release_extract_upload_context.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2026 Apollo Authors -# -# Licensed 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. -"""Extract uploaded artifact URLs from Maven deploy logs.""" - -from __future__ import annotations - -import json -import os -import re -from pathlib import Path - -from github_actions_utils import write_output - - -def main() -> int: - repository_name = os.environ.get("TARGET_REPOSITORY", "").strip() - log_file = Path(os.environ.get("DEPLOY_LOG", "maven-deploy.log")) - context_file = Path(os.environ.get("DEPLOY_ARTIFACTS_FILE", "deploy-artifacts.json")) - - log_text = log_file.read_text(encoding="utf-8") - pattern = re.compile(r"Uploaded to (\S+):\s+(\S+)") - - uploaded_urls: list[str] = [] - for target_repo, url in pattern.findall(log_text): - if target_repo == repository_name: - uploaded_urls.append(url) - - deduped_urls = sorted(set(uploaded_urls)) - jar_urls = [url for url in deduped_urls if url.endswith(".jar")] - pom_urls = [url for url in deduped_urls if url.endswith(".pom")] - - payload = { - "target_repository": repository_name, - "uploaded_urls": deduped_urls, - "jar_urls": jar_urls, - "pom_urls": pom_urls, - } - context_file.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") - - write_output("uploaded_urls_count", str(len(deduped_urls))) - write_output("jar_urls_count", str(len(jar_urls))) - write_output("pom_urls_count", str(len(pom_urls))) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.github/scripts/release_resolve_repository_context.py b/.github/scripts/release_resolve_repository_context.py deleted file mode 100644 index 226bb99a..00000000 --- a/.github/scripts/release_resolve_repository_context.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2026 Apollo Authors -# -# Licensed 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. -"""Resolve Sonatype repository context for release deployments.""" - -from __future__ import annotations - -import base64 -import json -import os -import urllib.error -import urllib.parse -import urllib.request -from pathlib import Path -from typing import Any - -from github_actions_utils import write_output - -OSSRH_BASE = "https://ossrh-staging-api.central.sonatype.com" - - -def request_json(url: str, headers: dict[str, str]) -> tuple[int | None, dict[str, Any]]: - request = urllib.request.Request(url=url, method="GET", headers=headers) - try: - with urllib.request.urlopen(request, timeout=30) as response: - body = response.read().decode("utf-8") - if not body: - return response.status, {} - try: - return response.status, json.loads(body) - except json.JSONDecodeError: - return response.status, {"raw": body} - except urllib.error.HTTPError as error: - body = error.read().decode("utf-8") - try: - payload = json.loads(body) if body else {} - except json.JSONDecodeError: - payload = {"raw": body} - payload.setdefault("error", f"HTTP {error.code}") - return error.code, payload - except Exception as error: # noqa: BLE001 - return None, {"error": str(error)} - - -def main() -> int: - target_repository = os.environ.get("TARGET_REPOSITORY", "").strip() - namespace = os.environ.get("TARGET_NAMESPACE", "").strip() - username = os.environ.get("MAVEN_USERNAME", "") - password = os.environ.get("MAVEN_CENTRAL_TOKEN", "") - context_path = Path( - os.environ.get("REPOSITORY_CONTEXT_FILE", "repository-context.json") - ) - - context: dict[str, Any] = { - "target_repository": target_repository, - "namespace": namespace, - "status": "not_applicable", - "reason": "repository input is not releases", - "repository_key": "", - "portal_deployment_id": "", - "search_candidates": [], - } - - if target_repository == "releases": - if not username or not password: - context["status"] = "manual_required" - context["reason"] = "Missing MAVEN_USERNAME/MAVEN_CENTRAL_TOKEN" - else: - token = base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8") - headers = { - "Authorization": f"Bearer {token}", - "Accept": "application/json", - } - - searches = [ - ("open", "client"), - ("closed", "client"), - ("open", "any"), - ("closed", "any"), - ] - selected: dict[str, Any] | None = None - last_error = "" - - for state, ip in searches: - url = ( - f"{OSSRH_BASE}/manual/search/repositories?" - f"profile_id={urllib.parse.quote(namespace)}" - f"&state={urllib.parse.quote(state)}" - f"&ip={urllib.parse.quote(ip)}" - ) - status, payload = request_json(url, headers) - if status is None: - last_error = payload.get("error", "unknown error") - context["search_candidates"].append( - { - "state": state, - "ip": ip, - "status": None, - "count": 0, - "error": last_error, - } - ) - continue - - if status < 200 or status >= 300: - http_error = payload.get("error", f"HTTP {status}") - last_error = http_error - context["search_candidates"].append( - { - "state": state, - "ip": ip, - "status": status, - "count": 0, - "error": http_error, - } - ) - continue - - repositories = ( - payload.get("repositories", []) if isinstance(payload, dict) else [] - ) - context["search_candidates"].append( - {"state": state, "ip": ip, "status": status, "count": len(repositories)} - ) - if repositories: - selected = repositories[0] - break - - if selected: - context["status"] = "resolved" - context["reason"] = "" - context["repository_key"] = selected.get("key", "") or "" - context["portal_deployment_id"] = ( - selected.get("portal_deployment_id", "") or "" - ) - else: - context["status"] = "manual_required" - context["reason"] = last_error or "No staging repository key found" - - context_path.write_text(json.dumps(context, indent=2) + "\n", encoding="utf-8") - write_output("repository_key", context.get("repository_key", "")) - write_output("portal_deployment_id", context.get("portal_deployment_id", "")) - write_output("status", context.get("status", "")) - write_output("reason", context.get("reason", "")) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.github/scripts/release_write_summary.py b/.github/scripts/release_write_summary.py deleted file mode 100644 index 4558e5db..00000000 --- a/.github/scripts/release_write_summary.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2026 Apollo Authors -# -# Licensed 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. -"""Write release publish context summary for GitHub Actions.""" - -from __future__ import annotations - -import json -import os -from pathlib import Path -from typing import Any - - -def read_json(path: Path) -> dict[str, Any]: - if not path.exists(): - return {} - try: - return json.loads(path.read_text(encoding="utf-8")) - except json.JSONDecodeError: - return {} - - -def main() -> int: - summary_path = os.environ.get("GITHUB_STEP_SUMMARY", "").strip() - if not summary_path: - return 0 - - deploy_path = Path(os.environ.get("DEPLOY_ARTIFACTS_FILE", "deploy-artifacts.json")) - repository_path = Path( - os.environ.get("REPOSITORY_CONTEXT_FILE", "repository-context.json") - ) - - deploy = read_json(deploy_path) - repository = read_json(repository_path) - - lines = [ - "## Publish Context", - "", - f"- target repository: {deploy.get('target_repository', '')}", - f"- uploaded URLs: {len(deploy.get('uploaded_urls', []))}", - f"- jar URLs: {len(deploy.get('jar_urls', []))}", - f"- pom URLs: {len(deploy.get('pom_urls', []))}", - f"- staging key status: {repository.get('status', '')}", - f"- repository_key: {repository.get('repository_key', '')}", - f"- portal_deployment_id: {repository.get('portal_deployment_id', '')}", - ] - reason = repository.get("reason", "") - if reason: - lines.append(f"- reason: {reason}") - - with open(summary_path, "a", encoding="utf-8") as output: - output.write("\n".join(lines) + "\n") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.github/scripts/sonatype_publish.py b/.github/scripts/sonatype_publish.py deleted file mode 100644 index 559c57d5..00000000 --- a/.github/scripts/sonatype_publish.py +++ /dev/null @@ -1,285 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2026 Apollo Authors -# -# Licensed 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. -"""Trigger and monitor Sonatype portal publish flow.""" - -from __future__ import annotations - -import base64 -import json -import os -import time -import urllib.error -import urllib.parse -import urllib.request -from typing import Any - -from github_actions_utils import write_output - -OSSRH_BASE = "https://ossrh-staging-api.central.sonatype.com" -PORTAL_BASE = "https://central.sonatype.com" - - -def request_json( - method: str, - url: str, - headers: dict[str, str], -) -> tuple[int | None, dict[str, Any]]: - request = urllib.request.Request(url=url, method=method, headers=headers) - try: - with urllib.request.urlopen(request, timeout=30) as response: - body = response.read().decode("utf-8") - if not body: - return response.status, {} - try: - return response.status, json.loads(body) - except json.JSONDecodeError: - return response.status, {"raw": body} - except urllib.error.HTTPError as error: - body = error.read().decode("utf-8") - try: - payload = json.loads(body) if body else {} - except json.JSONDecodeError: - payload = {"raw": body} - payload.setdefault("error", f"HTTP {error.code}") - return error.code, payload - except Exception as error: # noqa: BLE001 - return None, {"error": str(error)} - - -def extract_deployment_state(payload: dict[str, Any]) -> str: - for key in ("deploymentState", "deployment_state", "state"): - value = payload.get(key) - if isinstance(value, str): - return value - return "unknown" - - -def to_int(value: str, default: int) -> int: - try: - return int(value) - except ValueError: - return default - - -def main() -> int: - namespace = os.environ.get("INPUT_NAMESPACE", "com.ctrip.framework.apollo").strip() - repository_key = os.environ.get("INPUT_REPOSITORY_KEY", "").strip() - timeout_minutes = to_int(os.environ.get("INPUT_TIMEOUT_MINUTES", "60"), 60) - mode = os.environ.get("INPUT_MODE", "portal_api").strip().lower() - - username = os.environ.get("MAVEN_USERNAME", "") - password = os.environ.get("MAVEN_CENTRAL_TOKEN", "") - - result = "manual_required" - final_state = "unknown" - deployment_id = "" - deployment_url = "" - reason = "" - - if not username or not password: - reason = "Missing MAVEN_USERNAME/MAVEN_CENTRAL_TOKEN secrets" - else: - token = base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8") - headers = { - "Authorization": f"Bearer {token}", - "Accept": "application/json", - } - - if not repository_key: - searches = ("open", "closed") - search_errors: list[str] = [] - successful_search = False - for state in searches: - search_url = ( - f"{OSSRH_BASE}/manual/search/repositories?" - f"ip=any&profile_id={urllib.parse.quote(namespace)}" - f"&state={urllib.parse.quote(state)}" - ) - search_status, payload = request_json("GET", search_url, headers) - if search_status is None or search_status < 200 or search_status >= 300: - search_error = payload.get("error") if isinstance(payload, dict) else "" - if not search_error: - search_error = ( - f"HTTP {search_status}" - if search_status is not None - else "HTTP unknown" - ) - search_errors.append( - f"Repository search failed ({state}): {search_error}" - ) - continue - - successful_search = True - repositories = payload.get("repositories", []) if isinstance(payload, dict) else [] - if repositories: - repository_key = repositories[0].get("key", "") or "" - break - - if not repository_key: - if search_errors and not successful_search: - reason = "; ".join(search_errors) - else: - reason = "No staging repository key found" - else: - upload_url = ( - f"{OSSRH_BASE}/manual/upload/repository/{urllib.parse.quote(repository_key)}" - f"?publishing_type={urllib.parse.quote(mode)}" - ) - upload_status, upload_payload = request_json("POST", upload_url, headers) - if upload_status is None: - reason = f"Upload API failed: {upload_payload.get('error', 'unknown error')}" - elif upload_status >= 400: - upload_error = upload_payload.get("error") - if not upload_error: - upload_error = f"HTTP {upload_status}" - reason = ( - f"Upload API failed: {upload_error}" - ) - - if not reason: - list_url = ( - f"{OSSRH_BASE}/manual/search/repositories?" - f"ip=any&profile_id={urllib.parse.quote(namespace)}" - ) - list_status, list_payload = request_json("GET", list_url, headers) - if list_status is None or list_status < 200 or list_status >= 300: - list_error = list_payload.get("error") if isinstance(list_payload, dict) else "" - if not list_error: - list_error = ( - f"HTTP {list_status}" - if list_status is not None - else "HTTP unknown" - ) - reason = f"Repository list API failed after upload: {list_error}" - else: - repositories = ( - list_payload.get("repositories", []) - if isinstance(list_payload, dict) - else [] - ) - for item in repositories: - if item.get("key") == repository_key and item.get("portal_deployment_id"): - deployment_id = item.get("portal_deployment_id") - break - - if deployment_id: - deployment_url = f"{PORTAL_BASE}/publishing/deployments/{deployment_id}" - publish_triggered = False - deadline = time.time() + timeout_minutes * 60 - - while time.time() <= deadline: - status_url = ( - f"{PORTAL_BASE}/api/v1/publisher/status?" - f"id={urllib.parse.quote(deployment_id)}" - ) - poll_status, status_payload = request_json( - "POST", - status_url, - headers, - ) - if poll_status is None or poll_status < 200 or poll_status >= 300: - poll_error = ( - status_payload.get("error") - if isinstance(status_payload, dict) - else "" - ) - if not poll_error: - poll_error = ( - f"HTTP {poll_status}" - if poll_status is not None - else "HTTP unknown" - ) - reason = f"Status polling API failed: {poll_error}" - break - - final_state = extract_deployment_state(status_payload) - - if final_state == "PUBLISHED": - result = "published" - reason = "" - break - - if final_state in {"FAILED", "BROKEN", "ERROR"}: - reason = f"Deployment entered terminal state: {final_state}" - break - - if ( - mode == "portal_api" - and final_state == "VALIDATED" - and not publish_triggered - ): - publish_url = ( - f"{PORTAL_BASE}/api/v1/publisher/deployment/" - f"{urllib.parse.quote(deployment_id)}" - ) - publish_status, publish_payload = request_json( - "POST", - publish_url, - headers, - ) - if publish_status is None or publish_status >= 400: - publish_error = publish_payload.get("error") - if not publish_error: - publish_error = ( - f"HTTP {publish_status}" - if publish_status is not None - else "HTTP unknown" - ) - reason = f"Publish API failed: {publish_error}" - break - publish_triggered = True - - if mode == "user_managed" and final_state == "VALIDATED": - reason = "Mode user_managed requires manual publish in portal" - break - - time.sleep(10) - - if result != "published" and not reason: - reason = ( - "Timed out waiting for deployment status. " - f"Latest state={final_state}" - ) - else: - reason = "No portal deployment id found for repository" - - if result != "published" and not reason: - reason = "Automatic publish did not complete" - - write_output("result", result) - write_output("repository_key", repository_key) - write_output("deployment_id", deployment_id) - write_output("deployment_url", deployment_url) - write_output("final_state", final_state) - write_output("reason", reason) - - display_key = repository_key or "-" - display_deployment = deployment_id or "-" - display_url = deployment_url or "-" - print( - "SONATYPE_RESULT " - f"result={result} " - f"repository_key={display_key} " - f"deployment_id={display_deployment} " - f"final_state={final_state} " - f"deployment_url={display_url}" - ) - if reason: - print(f"SONATYPE_REASON {reason}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5e466865..e750b8ca 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,86 +19,29 @@ name: publish sdks on: workflow_dispatch: - inputs: - repository: - description: 'Maven Repository(snapshots or releases)' - required: true - default: 'snapshots' - namespace: - description: 'Sonatype namespace used to search staging repositories' - required: true - default: 'com.ctrip.framework.apollo' jobs: publish: runs-on: ubuntu-latest - outputs: - repository_key: ${{ steps.repository_context.outputs.repository_key }} - portal_deployment_id: ${{ steps.repository_context.outputs.portal_deployment_id }} - uploaded_urls_count: ${{ steps.upload_context.outputs.uploaded_urls_count }} - jar_urls_count: ${{ steps.upload_context.outputs.jar_urls_count }} - pom_urls_count: ${{ steps.upload_context.outputs.pom_urls_count }} steps: - uses: actions/checkout@v4 - - name: Set up Maven Central Repository + - name: Set up Maven Central publishing credentials uses: actions/setup-java@v4 with: distribution: temurin java-version: 8 - server-id: ${{ github.event.inputs.repository }} + server-id: central server-username: MAVEN_USERNAME server-password: MAVEN_CENTRAL_TOKEN gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} gpg-passphrase: MAVEN_GPG_PASSPHRASE - - name: Publish to Apache Maven Central + - name: Publish to Sonatype Central run: | set -eo pipefail - mvn clean deploy -DskipTests=true -Prelease \ - "-Dreleases.repo=https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/" \ - "-Dsnapshots.repo=https://central.sonatype.com/repository/maven-snapshots/" \ - 2>&1 | tee maven-deploy.log + mvn clean deploy -DskipTests=true -Prelease env: MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} - - - name: Extract uploaded artifact URLs - id: upload_context - env: - TARGET_REPOSITORY: ${{ github.event.inputs.repository }} - DEPLOY_LOG: maven-deploy.log - DEPLOY_ARTIFACTS_FILE: deploy-artifacts.json - run: | - python3 .github/scripts/release_extract_upload_context.py - - - name: Resolve staging repository key - id: repository_context - env: - TARGET_REPOSITORY: ${{ github.event.inputs.repository }} - TARGET_NAMESPACE: ${{ github.event.inputs.namespace }} - MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} - MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} - REPOSITORY_CONTEXT_FILE: repository-context.json - run: | - python3 .github/scripts/release_resolve_repository_context.py - - - name: Upload release publish context - if: always() - uses: actions/upload-artifact@v4 - with: - name: release-deploy-context - if-no-files-found: warn - path: | - maven-deploy.log - deploy-artifacts.json - repository-context.json - - - name: Publish summary - if: always() - env: - DEPLOY_ARTIFACTS_FILE: deploy-artifacts.json - REPOSITORY_CONTEXT_FILE: repository-context.json - run: | - python3 .github/scripts/release_write_summary.py diff --git a/.github/workflows/sonatype-publish.yml b/.github/workflows/sonatype-publish.yml deleted file mode 100644 index a96cd600..00000000 --- a/.github/workflows/sonatype-publish.yml +++ /dev/null @@ -1,85 +0,0 @@ -# -# Copyright 2026 Apollo Authors -# -# Licensed 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. -# - -name: sonatype publish - -on: - workflow_dispatch: - inputs: - namespace: - description: 'Sonatype namespace (e.g. com.ctrip.framework.apollo)' - required: true - default: 'com.ctrip.framework.apollo' - repository_key: - description: 'Optional staging repository key; leave blank to auto-detect' - required: false - default: '' - timeout_minutes: - description: 'Max minutes to wait for deployment status polling' - required: true - default: '60' - mode: - description: 'manual upload mode: portal_api|automatic|user_managed' - required: true - default: 'portal_api' - type: choice - options: - - portal_api - - automatic - - user_managed - -jobs: - publish: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Publish via Sonatype API - id: publish - env: - INPUT_NAMESPACE: ${{ github.event.inputs.namespace }} - INPUT_REPOSITORY_KEY: ${{ github.event.inputs.repository_key }} - INPUT_TIMEOUT_MINUTES: ${{ github.event.inputs.timeout_minutes }} - INPUT_MODE: ${{ github.event.inputs.mode }} - MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} - MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} - run: | - python3 .github/scripts/sonatype_publish.py - - - name: Sonatype publish summary - if: always() - env: - PUBLISH_RESULT: ${{ steps.publish.outputs.result }} - PUBLISH_REPOSITORY_KEY: ${{ steps.publish.outputs.repository_key }} - PUBLISH_DEPLOYMENT_ID: ${{ steps.publish.outputs.deployment_id }} - PUBLISH_FINAL_STATE: ${{ steps.publish.outputs.final_state }} - PUBLISH_DEPLOYMENT_URL: ${{ steps.publish.outputs.deployment_url }} - PUBLISH_REASON: ${{ steps.publish.outputs.reason }} - run: | - { - echo "## Sonatype Publish Result" - echo "" - echo "- result: ${PUBLISH_RESULT}" - echo "- repository_key: ${PUBLISH_REPOSITORY_KEY}" - echo "- deployment_id: ${PUBLISH_DEPLOYMENT_ID}" - echo "- final_state: ${PUBLISH_FINAL_STATE}" - echo "- deployment_url: ${PUBLISH_DEPLOYMENT_URL}" - if [ -n "${PUBLISH_REASON}" ]; then - echo "- reason: ${PUBLISH_REASON}" - echo "" - echo "Manual fallback: open https://central.sonatype.com/publishing/deployments and complete publish by deployment id." - fi - } >> "$GITHUB_STEP_SUMMARY" diff --git a/pom.xml b/pom.xml index 70ff7174..0c35c8a5 100644 --- a/pom.xml +++ b/pom.xml @@ -73,6 +73,7 @@ 3.2.2 2.5.2 2.8.2 + 0.10.0 3.4.0 3.0.1 @@ -457,19 +458,18 @@ org.apache.maven.plugins maven-gpg-plugin + + org.sonatype.central + central-publishing-maven-plugin + ${central-publishing-maven-plugin.version} + true + + true + PUBLISHED + + - - - - releases - ${releases.repo} - - - snapshots - ${snapshots.repo} - -