janhoy commented on code in PR #18: URL: https://github.com/apache/solr-mcp/pull/18#discussion_r2508337908
########## .github/workflows/release-publish.yml: ########## @@ -0,0 +1,374 @@ +# 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. + +# Official Release Publishing Workflow +# ===================================== +# +# Purpose: +# - Publish Docker images as convenience binaries that correspond 1:1 to a +# voted and approved source release of Apache Solr MCP. +# - NOTE: Docker images are NOT the release of record; the authoritative +# release artifacts are the signed source tarballs published to the ASF +# distribution system (dist.apache.org / mirrors). +# +# When to run: +# - AFTER the ASF voting process has completed successfully (minimum 72 hours +# and at least three +1 binding PMC votes) and the source release has been +# finalized/published. +# +# ASF Release Process (summary): +# ------------------------------ +# 1. Release Manager creates release candidate (RC) +# 2. RC is staged for voting (72-hour minimum voting period) +# 3. PMC members vote on the release +# 4. Source release is published to dist.apache.org / mirrors +# 5. After successful vote and published source, this workflow is triggered manually +# 6. Publishes Docker images to official registries as convenience binaries +# +# Prerequisites: +# -------------- +# - Release must have passed ASF voting process +# - Source release artifacts must be signed and available on dist.apache.org +# - Release Manager must have necessary credentials +# +# Manual Trigger Required: +# ------------------------ +# This workflow MUST be triggered manually by the Release Manager +# after the ASF vote passes and the source release is published. + +name: Release Publish + +# Trigger this workflow manually from the GitHub UI and capture structured inputs +# - We require the GA version (e.g., 1.0.0) and the RC tag suffix (e.g., rc1) +# - Optional inputs help document the vote thread and enable experimental signing +on: + workflow_dispatch: + inputs: + # Semantic version of the approved release (no -rc suffix) + release_version: + description: 'Release version (e.g., 1.0.0)' + required: true + type: string + # Which release candidate was approved (used to check out the exact tag) Review Comment: The indentation of the comments are confusing, should be in line with the block below ########## DOCKER_PUBLISHING.md: ########## @@ -0,0 +1,252 @@ +# Docker Publishing Guide for Apache Solr MCP + +This guide documents the Docker image publishing process for Apache Solr MCP, including nightly builds, release candidates, and official releases. + +## Overview + +The Solr MCP project publishes Docker images to multiple registries: + +1. **GitHub Container Registry (GHCR)**: `ghcr.io/apache/solr-mcp` +2. **Docker Hub Official**: `apache/solr-mcp` (requires Apache PMC credentials) +3. **Docker Hub Nightly**: `apache/solr-mcp-nightly` (for pre-release builds) + +## Build System + +The project uses **Jib** (Google's containerization plugin) for building Docker images: +- No Docker daemon required for building +- Multi-platform support (linux/amd64 and linux/arm64) +- Optimized layering for faster deployments +- Reproducible builds + +## Publishing Workflows + +### 1. Development Builds (Per-merge to GHCR) + +Currently, this repository does not define an automated workflow for per-merge dev images. The recommended practice is to publish per-merge or ad-hoc development images to GHCR (not Docker Hub under `apache/`). This keeps the `apache/` namespace reserved for nightlies and voted releases. + +- Suggested images (if/when automated): + - `ghcr.io/{owner}/solr-mcp:VERSION-SNAPSHOT-SHA` + - `ghcr.io/{owner}/solr-mcp:latest` +- No ASF vote required for dev images (they are not releases and must be clearly marked as such). + +### 2. Nightly Builds + +**Workflow**: `.github/workflows/nightly-build.yml` + +- **Schedule**: Daily at 2 AM UTC +- **Images Published**: + - `apache/solr-mcp-nightly:nightly-YYYYMMDD-SHA` + - `apache/solr-mcp-nightly:latest-nightly` +- **Artifacts**: + - Source tarball to `https://nightlies.apache.org/solr/mcp/` + - GitHub pre-release with build artifacts +- **No ASF vote required** + +### 3. Official Releases + +**Workflow**: `.github/workflows/release-publish.yml` + +- **Trigger**: Manual (after ASF vote passes) +- **Prerequisites**: + - 72-hour ASF voting period completed + - Successful PMC vote + - Release artifacts signed by Release Manager +- **Images Published**: + - `apache/solr-mcp:VERSION` + - `apache/solr-mcp:latest` + - `apache/solr-mcp:MAJOR` + - `apache/solr-mcp:MAJOR.MINOR` + - `ghcr.io/apache/solr-mcp:VERSION` + +## ASF Policy Notes + +- The authoritative ASF release is the signed source distribution published to the ASF distribution system (`dist.apache.org` / `downloads.apache.org` mirrors). Docker images and other binaries are considered convenience binaries and must be built from the voted source, but they are not the release of record. +- Releases require a minimum 72-hour vote with at least three +1 binding PMC votes. Only after the vote passes may convenience binaries (e.g., Docker images) be published. +- Release artifacts must be signed by the Release Manager using their PGP key that is present in the project `KEYS` file. Automated signing via ASF Infra may be possible but must be explicitly arranged with INFRA; manual RM signing remains the baseline. +- Nightly and per-merge builds are allowed as non-release artifacts. They must be clearly marked as such and must not be uploaded to the ASF release distribution system. + +## ASF Release Process + +### Step 1: Create Release Candidate + +```bash +# Tag the release candidate +git tag -s v1.0.0-rc1 -m "Release candidate 1 for version 1.0.0" + +# Create source distribution +tar czf solr-mcp-1.0.0-rc1-src.tar.gz --exclude='.git' --exclude='build' . + +# Sign the release +gpg --armor --detach-sign solr-mcp-1.0.0-rc1-src.tar.gz + +# Generate checksums +sha512sum solr-mcp-1.0.0-rc1-src.tar.gz > solr-mcp-1.0.0-rc1-src.tar.gz.sha512 +``` + +### Step 2: Stage for Voting + +1. Upload release candidate to Apache staging area +2. Send vote email to [email protected] +3. Wait for 72-hour voting period + +### Step 3: After Successful Vote + +Trigger the release publish workflow: + +```bash +# Via GitHub UI +# Go to Actions → Release Publish → Run workflow + +# Fill in: +# - Release version: 1.0.0 +# - Release candidate: rc1 +# - Vote thread URL: https://lists.apache.org/... +# - Use ASF code signing: true (if available) +``` + +## Building Docker Images Locally + +### Using Gradle with Jib + +```bash +# Build to local Docker daemon +./gradlew jibDockerBuild + +# Build and push to registry +./gradlew jib -Djib.to.image=myregistry/solr-mcp:my-tag \ + -Djib.to.auth.username=USERNAME \ + -Djib.to.auth.password=TOKEN +``` + +### Multi-platform Build + +The Jib configuration in `build.gradle.kts` automatically builds for: +- `linux/amd64` (x86_64) +- `linux/arm64` (Apple Silicon, ARM servers) + +## Registry Authentication + +### GitHub Container Registry + +GHCR uses the built-in `GITHUB_TOKEN` in workflows. For local pushing: + +```bash +echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin +``` + +### Docker Hub + +For Apache official images, set these secrets in GitHub: +- `DOCKERHUB_APACHE_USERNAME` +- `DOCKERHUB_APACHE_TOKEN` + +Create token at: https://hub.docker.com/settings/security + +### Apache Nightlies + +Requires Apache committer credentials: +- `APACHE_NIGHTLIES_USER` +- `APACHE_NIGHTLIES_KEY` + +## MCP Registry Integration + +The Docker image includes MCP metadata labels: + +```dockerfile +LABEL io.modelcontextprotocol.server.name="io.github.apache/solr-mcp" +``` + +After release, the image should be registered with the MCP registry for discoverability. + +## Security Considerations + +### Code Signing + +For official releases, we aim to use ASF's code signing infrastructure: + +1. Contact ASF INFRA for setup requirements +2. Enable in release workflow with `sign_with_asf_infra: true` +3. Signatures will be automatically applied to artifacts Review Comment: Here is the description from INFRA about using GitHub actions for signing artifacts: https://infra.apache.org/release-signing.html#automated-release-signing First we need to assess whether this repo qualifies, where the crucial part is reproducible builds. If it does, the release process must include a reproduction of the same artifacts (with same SHA) on developer's hardware. Etc. Once we feel all boxes are checked we can file an INFRA Jira issue to apply for signing secret to be deployed to the proejct. ########## .github/workflows/release-publish.yml: ########## @@ -0,0 +1,374 @@ +# 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. + +# Official Release Publishing Workflow +# ===================================== +# +# Purpose: +# - Publish Docker images as convenience binaries that correspond 1:1 to a +# voted and approved source release of Apache Solr MCP. +# - NOTE: Docker images are NOT the release of record; the authoritative +# release artifacts are the signed source tarballs published to the ASF +# distribution system (dist.apache.org / mirrors). +# +# When to run: +# - AFTER the ASF voting process has completed successfully (minimum 72 hours +# and at least three +1 binding PMC votes) and the source release has been +# finalized/published. +# +# ASF Release Process (summary): +# ------------------------------ +# 1. Release Manager creates release candidate (RC) +# 2. RC is staged for voting (72-hour minimum voting period) +# 3. PMC members vote on the release +# 4. Source release is published to dist.apache.org / mirrors +# 5. After successful vote and published source, this workflow is triggered manually +# 6. Publishes Docker images to official registries as convenience binaries +# +# Prerequisites: +# -------------- +# - Release must have passed ASF voting process +# - Source release artifacts must be signed and available on dist.apache.org +# - Release Manager must have necessary credentials +# +# Manual Trigger Required: +# ------------------------ +# This workflow MUST be triggered manually by the Release Manager +# after the ASF vote passes and the source release is published. + +name: Release Publish + +# Trigger this workflow manually from the GitHub UI and capture structured inputs +# - We require the GA version (e.g., 1.0.0) and the RC tag suffix (e.g., rc1) +# - Optional inputs help document the vote thread and enable experimental signing +on: + workflow_dispatch: + inputs: + # Semantic version of the approved release (no -rc suffix) + release_version: + description: 'Release version (e.g., 1.0.0)' + required: true + type: string + # Which release candidate was approved (used to check out the exact tag) + release_candidate: + description: 'Release candidate number (e.g., rc1, rc2)' + required: true + type: string + # Link to the public ASF vote thread for traceability in the summary + vote_thread_url: + description: 'URL to the vote thread (for documentation)' + required: false + type: string + # If true, attempt to use ASF Infra code-signing (placeholder; requires coordination) + sign_with_asf_infra: + description: 'Use ASF code signing infrastructure' + required: false + type: boolean + default: false + +# Global environment settings used across jobs +# - JAVA_VERSION: version of JDK used to build the project +# - JAVA_DISTRIBUTION: OpenJDK distribution to install via actions/setup-java +env: + JAVA_VERSION: '25' + JAVA_DISTRIBUTION: 'temurin' + +jobs: + validate-release: + name: Validate Release Prerequisites + runs-on: ubuntu-latest + + outputs: + proceed: ${{ steps.validation.outputs.proceed }} + + steps: + # Step: Check out the exact RC tag that was approved (e.g., v1.0.0-rc1) + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: "v${{ inputs.release_version }}-${{ inputs.release_candidate }}" + + # Step: Validate that the supplied tag exists in the repo + # - Uses `git rev-parse` to resolve the tag; sets an output flag to gate downstream jobs + - name: Validate release tag exists + id: validation + run: | + # Check if the release tag exists + if git rev-parse "v${{ inputs.release_version }}-${{ inputs.release_candidate }}" >/dev/null 2>&1; then + echo "Release tag found: v${{ inputs.release_version }}-${{ inputs.release_candidate }}" + echo "proceed=true" >> $GITHUB_OUTPUT + else + echo "ERROR: Release tag not found: v${{ inputs.release_version }}-${{ inputs.release_candidate }}" + echo "proceed=false" >> $GITHUB_OUTPUT + exit 1 + fi + + # Optional: Document the vote approval in the Actions summary for traceability + - name: Document vote approval + if: ${{ inputs.vote_thread_url != '' }} + run: | + echo "### Release Vote Approval" >> $GITHUB_STEP_SUMMARY + echo "Release v${{ inputs.release_version }} was approved via ASF voting process." >> $GITHUB_STEP_SUMMARY + echo "Vote thread: ${{ inputs.vote_thread_url }}" >> $GITHUB_STEP_SUMMARY + + publish-docker: + name: Publish Docker Images + runs-on: ubuntu-latest + needs: validate-release + if: ${{ needs.validate-release.outputs.proceed == 'true' }} + + permissions: + contents: read + packages: write + id-token: write # For OIDC/code signing if needed + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: "v${{ inputs.release_version }}-${{ inputs.release_candidate }}" + + - name: Set up JDK ${{ env.JAVA_VERSION }} + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_DISTRIBUTION }} + cache: 'gradle' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Update version in build.gradle.kts + run: | + # Ensure the Gradle project version matches the GA version (removes any -SNAPSHOT) + # This keeps image tags and any generated artifacts consistent with the voted release + sed -i 's/version = ".*"/version = "${{ inputs.release_version }}"/' build.gradle.kts + + - name: Build project + run: ./gradlew build + + - name: Sign artifacts with ASF infrastructure + if: ${{ inputs.sign_with_asf_infra }} + run: | + # Placeholder for ASF code signing integration + # This would integrate with ASF's code signing service + # Requires coordination with ASF INFRA team + echo "Would sign artifacts with ASF code signing infrastructure" + echo "Contact INFRA for setup requirements" + + - name: Build and publish to Docker Hub (apache/solr-mcp) + run: | + # Publish official release to apache/solr-mcp + # This requires Apache PMC credentials + if [[ -n "${{ secrets.DOCKERHUB_APACHE_USERNAME }}" ]]; then + # Build and push with multiple tags + ./gradlew jib \ + -Djib.to.image=apache/solr-mcp:${{ inputs.release_version }} \ + -Djib.to.auth.username=${{ secrets.DOCKERHUB_APACHE_USERNAME }} \ + -Djib.to.auth.password=${{ secrets.DOCKERHUB_APACHE_TOKEN }} \ + -Djib.to.tags=${{ inputs.release_version }},latest + + # Also tag with major and minor versions + MAJOR_VERSION=$(echo "${{ inputs.release_version }}" | cut -d. -f1) + MINOR_VERSION=$(echo "${{ inputs.release_version }}" | cut -d. -f1-2) + + ./gradlew jib \ + -Djib.to.image=apache/solr-mcp:${MAJOR_VERSION} \ + -Djib.to.auth.username=${{ secrets.DOCKERHUB_APACHE_USERNAME }} \ + -Djib.to.auth.password=${{ secrets.DOCKERHUB_APACHE_TOKEN }} + + ./gradlew jib \ + -Djib.to.image=apache/solr-mcp:${MINOR_VERSION} \ + -Djib.to.auth.username=${{ secrets.DOCKERHUB_APACHE_USERNAME }} \ + -Djib.to.auth.password=${{ secrets.DOCKERHUB_APACHE_TOKEN }} + else + echo "WARNING: Apache Docker Hub credentials not configured" + fi + + - name: Build and publish to GitHub Container Registry + run: | + # Also publish to GitHub Container Registry + ./gradlew jib \ + -Djib.to.image=ghcr.io/${{ github.repository_owner }}/solr-mcp:${{ inputs.release_version }} \ Review Comment: If we're anyway publishing nightlies to hub, is there a particular benefit of also using ghcr? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
