Merge pull request #1226 from qualcomm/chore/bump-aihub-v0.58.0 #47
Workflow file for this run
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
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: "Tag to release, for example v1.2.3" | |
| required: true | |
| type: string | |
| permissions: | |
| contents: read | |
| packages: read | |
| concurrency: | |
| group: release-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| resolve-tag: | |
| name: resolve-tag | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 1 | |
| outputs: | |
| tag: ${{ steps.resolve.outputs.tag }} | |
| is_prerelease: ${{ steps.resolve.outputs.is_prerelease }} | |
| steps: | |
| - id: resolve | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| GITHUB_SHA: ${{ github.sha }} | |
| TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }} | |
| run: | | |
| set -euo pipefail | |
| semver='^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$' | |
| [[ "${TAG}" =~ $semver ]] || { echo "::error::Invalid SemVer 2.0 tag: ${TAG}"; exit 1; } | |
| # workflow_dispatch runs against GITHUB_SHA = the ref the workflow | |
| # was launched from. If that's not the tag's commit, downstream | |
| # _build-* jobs will check out the wrong source and stamp it as | |
| # ${TAG} — which we cannot move (tags are immutable). | |
| if [[ "${EVENT_NAME}" == "workflow_dispatch" ]]; then | |
| ref_obj=$(gh api "repos/${GH_REPO}/git/ref/tags/${TAG}" 2>/dev/null) \ | |
| || { echo "::error::Tag ${TAG} not found on origin"; exit 1; } | |
| tag_sha=$(jq -r '.object.sha' <<<"${ref_obj}") | |
| tag_type=$(jq -r '.object.type' <<<"${ref_obj}") | |
| if [[ "${tag_type}" == "tag" ]]; then | |
| tag_sha=$(gh api "repos/${GH_REPO}/git/tags/${tag_sha}" --jq '.object.sha') | |
| fi | |
| if [[ "${tag_sha}" != "${GITHUB_SHA}" ]]; then | |
| echo "::error::Dispatch ref ${GITHUB_SHA} != tag ${TAG} (${tag_sha}). Re-run from the tag ref: Actions → Release → Run workflow → Use workflow from → Tags → ${TAG}." | |
| exit 1 | |
| fi | |
| fi | |
| # Stable tags are immutable once they've shipped assets; prereleases | |
| # (hyphen-bearing) may be re-cut. An existing stable release with no | |
| # assets is a placeholder (e.g. created empty via the UI before the | |
| # workflow ran) — let the workflow populate it instead of erroring. | |
| if [[ "${TAG}" == *-* ]]; then | |
| is_prerelease=true | |
| else | |
| is_prerelease=false | |
| asset_count=$(gh release view "${TAG}" --json assets --jq '.assets | length' 2>/dev/null || echo "none") | |
| if [[ "${asset_count}" != "none" && "${asset_count}" -gt 0 ]]; then | |
| echo "::error::Stable release ${TAG} already has ${asset_count} asset(s) — refusing to overwrite." | |
| exit 1 | |
| fi | |
| fi | |
| echo "tag=${TAG}" >> "$GITHUB_OUTPUT" | |
| echo "is_prerelease=${is_prerelease}" >> "$GITHUB_OUTPUT" | |
| build-sdk: | |
| name: build-sdk | |
| needs: [resolve-tag] | |
| uses: ./.github/workflows/_build-sdk.yml | |
| secrets: inherit | |
| with: | |
| version_tag: ${{ needs.resolve-tag.outputs.tag }} | |
| upload_artifact: true | |
| build-android-aar: | |
| name: build-android-aar | |
| needs: [build-sdk] | |
| uses: ./.github/workflows/_build-android-aar.yml | |
| secrets: inherit | |
| with: | |
| upload_artifact: true | |
| build-python-sdist: | |
| name: build-python-sdist | |
| needs: [resolve-tag] | |
| uses: ./.github/workflows/_build-python-sdist.yml | |
| secrets: inherit | |
| with: | |
| version_tag: ${{ needs.resolve-tag.outputs.tag }} | |
| upload_artifact: true | |
| # Overlay the Microsoft-signed HTP bundle from S3 if available; otherwise | |
| # the Windows SDK stays self-signed and gets marked as such downstream. | |
| overlay-htp: | |
| name: overlay-htp (windows-arm64) | |
| runs-on: ubuntu-latest | |
| needs: [build-sdk] | |
| timeout-minutes: 10 | |
| outputs: | |
| signed: ${{ steps.htp.outputs.signed }} | |
| llama_sha: ${{ steps.htp.outputs.llama_sha }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 1 | |
| submodules: false | |
| - name: Init llama.cpp submodule | |
| run: git submodule update --init --depth=1 third-party/llama.cpp | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: sdk-windows-arm64 | |
| path: sdk-windows-arm64 | |
| - name: Overlay Microsoft-signed HTP bundle from S3 (if available) | |
| id: htp | |
| run: | | |
| set -euo pipefail | |
| sha=$(git -C third-party/llama.cpp rev-parse --short=6 HEAD) | |
| url="https://qaihub-public-assets.s3.us-west-2.amazonaws.com/llama-cpp/libggml-htp-${sha}.zip" | |
| if curl -fsSL -o htp-signed.zip "$url"; then | |
| unzip -o htp-signed.zip -d sdk-windows-arm64/lib/llama_cpp/ | |
| signed=true | |
| else | |
| signed=false | |
| fi | |
| rm -f htp-signed.zip | |
| echo "Signed HTP bundle for llama.cpp @ ${sha}: ${signed}" | |
| echo "signed=${signed}" >> "$GITHUB_OUTPUT" | |
| echo "llama_sha=${sha}" >> "$GITHUB_OUTPUT" | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: sdk-windows-arm64 | |
| path: sdk-windows-arm64/ | |
| retention-days: 1 | |
| overwrite: true | |
| build-cli: | |
| name: build-cli | |
| needs: [resolve-tag, overlay-htp] | |
| uses: ./.github/workflows/_build-cli.yml | |
| secrets: inherit | |
| with: | |
| version_tag: ${{ needs.resolve-tag.outputs.tag }} | |
| build_installer: true | |
| upload_artifact: true | |
| # TODO: wire Authenticode signing for the Windows installer (AzureSignTool | |
| # / ESRP / .pfx secret). Gate publish-github-release + publish-winget on it. | |
| sign-windows: | |
| name: sign-windows | |
| needs: [build-cli] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - run: 'echo "TODO: sign cli-setup-windows-arm64."' | |
| # Assemble every release asset into one release-assets artifact so | |
| # publish-github-release and publish-s3 can run in parallel. | |
| package-release: | |
| name: package-release | |
| needs: | |
| - resolve-tag | |
| - overlay-htp | |
| - build-cli | |
| - build-python-sdist | |
| - build-android-aar | |
| - sign-windows | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| env: | |
| RELEASE_TAG: ${{ needs.resolve-tag.outputs.tag }} | |
| HTP_SIGNED: ${{ needs.overlay-htp.outputs.signed }} | |
| LLAMA_SHA: ${{ needs.overlay-htp.outputs.llama_sha }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 1 | |
| submodules: false | |
| # Needed for the self-signed HTP path (pulls libggml-htp.inf from llama.cpp). | |
| - name: Init llama.cpp submodule | |
| if: needs.overlay-htp.outputs.signed != 'true' | |
| run: git submodule update --init --depth=1 third-party/llama.cpp | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: sdk-windows-arm64 | |
| path: sdk-windows-arm64 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: sdk-linux-arm64 | |
| path: sdk-linux-arm64 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: sdk-android-arm64 | |
| path: sdk-android-arm64 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: cli-setup-windows-arm64 | |
| path: . | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: cli-linux-arm64 | |
| path: cli-linux-arm64/ | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: python-sdist | |
| path: . | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: android-aar | |
| path: . | |
| - name: Package artifacts and write SHA256 sidecars | |
| run: | | |
| set -euo pipefail | |
| HTP_DIR=sdk-windows-arm64/lib/llama_cpp | |
| mv geniex-cli-setup.exe "geniex-cli-setup-windows-arm64-${RELEASE_TAG}.exe" | |
| mv geniex-android-aar.aar "geniex-android-aar-${RELEASE_TAG}.aar" | |
| staged="geniex-cli-linux-arm64-${RELEASE_TAG}" | |
| mkdir -p "${staged}" | |
| unzip -q cli-linux-arm64/artifact.zip -d "${staged}" | |
| chmod +x "${staged}/geniex" | |
| tar -czf "${staged}.tar.gz" "${staged}" | |
| rm -rf "${staged}" | |
| # Stage the install script as a versioned release asset so users can | |
| # pin to a specific tag's script — the mutable install.sh pointer is | |
| # advanced only on stable tags (see publish-s3 below). | |
| cp cli/release/linux/install.sh "install-${RELEASE_TAG}.sh" | |
| sdk_suffix="" | |
| if [[ "$HTP_SIGNED" != "true" ]]; then | |
| sdk_suffix="-selfsigned" | |
| # Ship cert (users import) + to-sign bundle (operator finishes out-of-band). | |
| cp .github/certs/hexagon/ggml-htp-v1.cer . | |
| mkdir to-sign | |
| cp "$HTP_DIR"/libggml-htp-v*.so to-sign/ | |
| cp "$HTP_DIR"/libggml-htp.cat to-sign/ | |
| cp third-party/llama.cpp/ggml/src/ggml-hexagon/libggml-htp.inf to-sign/ | |
| (cd to-sign && zip -r "../libggml-htp-to-sign-${LLAMA_SHA}.zip" .) | |
| fi | |
| zip -r "geniex-sdk-windows-arm64-${RELEASE_TAG}${sdk_suffix}.zip" sdk-windows-arm64 | |
| zip -r "geniex-sdk-linux-arm64-${RELEASE_TAG}.zip" sdk-linux-arm64 | |
| # Package standalone geniex-bench archives (bin + runtime libs). | |
| for plat in linux-arm64 windows-arm64 android-arm64; do | |
| src="sdk-${plat}" | |
| bench_dir="geniex-bench-${plat}-${RELEASE_TAG}" | |
| mkdir -p "${bench_dir}/bin" "${bench_dir}/lib" | |
| if [[ "$plat" == "windows-arm64" ]]; then | |
| cp "${src}/bin/geniex-bench.exe" "${bench_dir}/bin/" | |
| cp "${src}"/lib/*.dll "${bench_dir}/lib/" 2>/dev/null || true | |
| else | |
| cp "${src}/bin/geniex-bench" "${bench_dir}/bin/" | |
| chmod +x "${bench_dir}/bin/geniex-bench" | |
| cp "${src}"/lib/*.so "${bench_dir}/lib/" 2>/dev/null || true | |
| fi | |
| # Include plugin libs (llama_cpp / qairt subdirs). | |
| cp -r "${src}"/lib/llama_cpp "${bench_dir}/lib/" 2>/dev/null || true | |
| cp -r "${src}"/lib/qairt "${bench_dir}/lib/" 2>/dev/null || true | |
| if [[ "$plat" == "windows-arm64" ]]; then | |
| zip -r "${bench_dir}.zip" "${bench_dir}" | |
| else | |
| tar -czf "${bench_dir}.tar.gz" "${bench_dir}" | |
| fi | |
| rm -rf "${bench_dir}" | |
| done | |
| rm -rf sdk-windows-arm64 sdk-linux-arm64 sdk-android-arm64 cli-linux-arm64 to-sign | |
| shopt -s nullglob | |
| files=(*.zip *.exe *.tar.gz *.cer *.aar install-*.sh) | |
| for f in "${files[@]}"; do sha256sum "$f" > "$f.sha256"; done | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: release-assets | |
| path: | | |
| *.zip | |
| *.zip.sha256 | |
| *.exe | |
| *.exe.sha256 | |
| *.tar.gz | |
| *.tar.gz.sha256 | |
| *.cer | |
| *.cer.sha256 | |
| *.aar | |
| *.aar.sha256 | |
| install-*.sh | |
| install-*.sh.sha256 | |
| if-no-files-found: error | |
| retention-days: 1 | |
| publish-github-release: | |
| name: publish-github-release | |
| needs: [resolve-tag, overlay-htp, package-release] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 1 | |
| submodules: false | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: release-assets | |
| path: . | |
| - name: Collect file list | |
| id: assets | |
| run: | | |
| set -euo pipefail | |
| shopt -s nullglob | |
| files=(*.zip *.zip.sha256 *.exe *.exe.sha256 *.tar.gz *.tar.gz.sha256 *.cer *.cer.sha256 *.aar *.aar.sha256) | |
| { | |
| echo "files<<EOF" | |
| for f in "${files[@]}"; do echo "$f"; done | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Publish release | |
| uses: actions/github-script@v9 | |
| env: | |
| VERSION: ${{ needs.resolve-tag.outputs.tag }} | |
| FILES: ${{ steps.assets.outputs.files }} | |
| HTP_SIGNED: ${{ needs.overlay-htp.outputs.signed }} | |
| LLAMA_SHA: ${{ needs.overlay-htp.outputs.llama_sha }} | |
| with: | |
| script: | | |
| const release = require('./.github/scripts/release.js'); | |
| await release({ github, context, core }); | |
| # S3 publish runs in the geniex repo, not here: the bitsyfactory IAM role's | |
| # OIDC trust only allows repo:qcom-ai-hub/geniex, so GenieX cannot assume it. | |
| # We dispatch geniex's chore/publish-s3 workflow (GH_PAT, with actions:rw on | |
| # geniex), passing this run's id so it can pull our release-assets artifact | |
| # cross-repo, then watch it so an S3 failure surfaces here instead of silently. | |
| publish-s3: | |
| name: publish-s3 (via geniex) | |
| needs: [resolve-tag, overlay-htp, package-release] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Trigger & watch geniex publish-s3 | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_PAT }} | |
| TAG: ${{ needs.resolve-tag.outputs.tag }} | |
| IS_PRERELEASE: ${{ needs.resolve-tag.outputs.is_prerelease }} | |
| HTP_SIGNED: ${{ needs.overlay-htp.outputs.signed }} | |
| LLAMA_SHA: ${{ needs.overlay-htp.outputs.llama_sha }} | |
| RUN_ID: ${{ github.run_id }} | |
| run: | | |
| set -euo pipefail | |
| gh workflow run release.yml \ | |
| --repo qcom-ai-hub/geniex \ | |
| --ref chore/publish-s3 \ | |
| -f tag="${TAG}" \ | |
| -f is_prerelease="${IS_PRERELEASE}" \ | |
| -f run_id="${RUN_ID}" \ | |
| -f htp_signed="${HTP_SIGNED}" \ | |
| -f llama_sha="${LLAMA_SHA}" | |
| # The geniex run-name embeds "run ${RUN_ID}", so match on it to find | |
| # the run we just dispatched rather than racing on most-recent. | |
| target="" | |
| for _ in $(seq 1 12); do | |
| target=$(gh run list --repo qcom-ai-hub/geniex --workflow release.yml \ | |
| --branch chore/publish-s3 --json databaseId,displayTitle \ | |
| --jq "[.[] | select(.displayTitle | contains(\"run ${RUN_ID}\"))][0].databaseId") | |
| [ -n "${target}" ] && break | |
| sleep 5 | |
| done | |
| [ -n "${target}" ] || { echo "::error::geniex publish-s3 run for GenieX run ${RUN_ID} not found"; exit 1; } | |
| echo "Watching geniex publish-s3 run ${target}" | |
| gh run watch "${target}" --repo qcom-ai-hub/geniex --exit-status | |
| publish-docker: | |
| name: publish-docker | |
| needs: [resolve-tag, build-sdk] | |
| permissions: | |
| contents: read | |
| packages: write | |
| uses: ./.github/workflows/_build-docker.yml | |
| secrets: inherit | |
| with: | |
| version_tag: ${{ needs.resolve-tag.outputs.tag }} | |
| push: true | |
| tag: ${{ needs.resolve-tag.outputs.tag }} | |
| is_prerelease: ${{ needs.resolve-tag.outputs.is_prerelease == 'true' }} | |
| # Prerelease (hyphen-bearing) tags go to TestPyPI. | |
| publish-testpypi: | |
| name: publish-testpypi | |
| needs: [resolve-tag, build-python-sdist] | |
| if: needs.resolve-tag.outputs.is_prerelease == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| # OIDC token for TestPyPI Trusted Publishing — no API token needed. | |
| id-token: write | |
| steps: | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: python-sdist | |
| path: dist/ | |
| - name: Publish sdist to TestPyPI | |
| uses: pypa/gh-action-pypi-publish@v1.14.1 | |
| with: | |
| repository-url: https://test.pypi.org/legacy/ | |
| packages-dir: dist/ | |
| skip-existing: true | |
| # Stable (bare vX.Y.Z) tags publish to production PyPI. | |
| publish-pypi: | |
| name: publish-pypi | |
| needs: [resolve-tag, build-python-sdist] | |
| if: needs.resolve-tag.outputs.is_prerelease != 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| # OIDC token for PyPI Trusted Publishing — no API token needed. | |
| id-token: write | |
| steps: | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: python-sdist | |
| path: dist/ | |
| - name: Publish sdist to PyPI | |
| uses: pypa/gh-action-pypi-publish@v1.14.1 | |
| with: | |
| packages-dir: dist/ | |
| skip-existing: true | |
| # Uploads the AAR to the Sonatype Central Portal under com.qualcomm.qti:geniex-android. | |
| # Stable tags only. Default publishingType is USER_MANAGED — upload lands in the Portal | |
| # under PENDING → VALIDATED, and an operator clicks Publish in the UI to go live | |
| # (Maven Central is immutable, so we keep a human gate on the final button). Flip | |
| # `publishing_type` to AUTOMATIC once the release pipeline is trusted end-to-end. | |
| # See maven_upload.md for the manual procedure this job mirrors. | |
| publish-maven-central: | |
| name: publish-maven-central | |
| needs: [resolve-tag, build-android-aar] | |
| if: needs.resolve-tag.outputs.is_prerelease != 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| env: | |
| RELEASE_TAG: ${{ needs.resolve-tag.outputs.tag }} | |
| GROUP_ID: com.qualcomm.qti | |
| ARTIFACT_ID: geniex-android | |
| PUBLISHING_TYPE: USER_MANAGED | |
| steps: | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: android-aar | |
| path: . | |
| - name: Import GPG signing key | |
| env: | |
| GPG_PRIVATE_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p ~/.gnupg && chmod 700 ~/.gnupg | |
| printf '%s\n' "allow-loopback-pinentry" > ~/.gnupg/gpg-agent.conf | |
| printf '%s\n' "pinentry-mode loopback" > ~/.gnupg/gpg.conf | |
| gpgconf --kill gpg-agent || true | |
| # Add trailing newline — GitHub Actions secrets sometimes drop it and | |
| # armored GPG blocks fail to parse without it. | |
| printf '%s\n' "$GPG_PRIVATE_KEY" | gpg --batch --import | |
| key_id=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec/{print $5; exit}') | |
| [ -n "$key_id" ] || { echo "::error::No signing key imported from MAVEN_GPG_PRIVATE_KEY"; exit 1; } | |
| echo "GPG_KEY_ID=${key_id}" >> "$GITHUB_ENV" | |
| - name: Prepare Maven bundle | |
| env: | |
| GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} | |
| run: | | |
| set -euo pipefail | |
| VERSION="${RELEASE_TAG#v}" | |
| echo "VERSION=${VERSION}" >> "$GITHUB_ENV" | |
| group_path="${GROUP_ID//./\/}" | |
| bundle_dir="maven-bundle/${group_path}/${ARTIFACT_ID}/${VERSION}" | |
| mkdir -p "${bundle_dir}" | |
| base="${ARTIFACT_ID}-${VERSION}" | |
| cp geniex-android-aar.aar "${bundle_dir}/${base}.aar" | |
| cat > "${bundle_dir}/${base}.pom" <<EOF | |
| <?xml version="1.0" encoding="UTF-8"?> | |
| <project xmlns="http://maven.apache.org/POM/4.0.0"> | |
| <modelVersion>4.0.0</modelVersion> | |
| <groupId>${GROUP_ID}</groupId> | |
| <artifactId>${ARTIFACT_ID}</artifactId> | |
| <version>${VERSION}</version> | |
| <packaging>aar</packaging> | |
| <name>${ARTIFACT_ID}</name> | |
| <description>GenieX Android AAR - multi-platform AI inference runtime (Snapdragon / Hexagon). Subject to Qualcomm Terms of Use: https://www.qualcomm.com/site/terms-of-use</description> | |
| <url>https://github.com/qualcomm/GenieX</url> | |
| <licenses><license><name>BSD 3-Clause License</name><url>https://github.com/qualcomm/geniex/blob/main/LICENSE</url><distribution>repo</distribution></license><license><name>Qualcomm Terms of Use</name><url>https://www.qualcomm.com/site/terms-of-use</url><distribution>repo</distribution></license></licenses> | |
| <developers><developer><id>qualcomm-aisw</id><name>Qualcomm AISW</name><organization>Qualcomm</organization><organizationUrl>https://www.qualcomm.com</organizationUrl></developer></developers> | |
| <scm><connection>scm:git:git://github.com/qualcomm/GenieX.git</connection><developerConnection>scm:git:ssh://github.com/qualcomm/GenieX.git</developerConnection><url>https://github.com/qualcomm/GenieX</url></scm> | |
| </project> | |
| EOF | |
| # Stub sources/javadoc jars — Central requires both to exist. | |
| ( cd "${bundle_dir}" \ | |
| && printf 'Sources not published for this release.\n' > README.txt \ | |
| && zip -q "${base}-sources.jar" README.txt \ | |
| && printf 'Javadoc not published for this release.\n' > README.txt \ | |
| && zip -q "${base}-javadoc.jar" README.txt \ | |
| && rm README.txt ) | |
| for f in \ | |
| "${bundle_dir}/${base}.aar" \ | |
| "${bundle_dir}/${base}.pom" \ | |
| "${bundle_dir}/${base}-sources.jar" \ | |
| "${bundle_dir}/${base}-javadoc.jar"; do | |
| gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \ | |
| --local-user "$GPG_KEY_ID" --armor --detach-sign --output "${f}.asc" "$f" | |
| md5sum "$f" | awk '{print $1}' > "${f}.md5" | |
| sha1sum "$f" | awk '{print $1}' > "${f}.sha1" | |
| done | |
| ( cd maven-bundle && zip -qr ../geniex-android-aar-bundle.zip . ) | |
| unzip -l geniex-android-aar-bundle.zip | |
| - name: Upload bundle to Sonatype Central Portal | |
| env: | |
| BEARER: ${{ secrets.MAVEN_CENTRAL_BEARER_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| http_code=$(curl -sS -o response.txt -w '%{http_code}' -X POST \ | |
| "https://central.sonatype.com/api/v1/publisher/upload?publishingType=${PUBLISHING_TYPE}&name=${ARTIFACT_ID}-${VERSION}" \ | |
| -H "Authorization: Bearer ${BEARER}" \ | |
| -H "accept: text/plain" \ | |
| -F "bundle=@geniex-android-aar-bundle.zip") | |
| echo "HTTP ${http_code}" | |
| cat response.txt; echo | |
| [ "$http_code" = "201" ] || { echo "::error::Upload failed (HTTP ${http_code})"; exit 1; } | |
| echo "::notice::Deployment uploaded. Validate + click Publish at https://central.sonatype.com/publishing/deployments" | |
| # TODO: winget manifest submission for the Windows installer. |