@@ -149,12 +149,13 @@ jobs:
149149 - name : Publish to NPM
150150 if : steps.check-npm.outputs.has_token == 'true'
151151 run : |
152- # Remove private flag to allow public publishing
153- jq 'del(.private)' package.json > tmp.json && mv tmp.json package.json
152+ # Remove private flag and prepare script (which runs husky)
153+ # The prepare script runs even with --ignore-scripts, so we must remove it
154+ jq 'del(.private) | del(.scripts.prepare)' package.json > tmp.json && mv tmp.json package.json
155+
154156 # Publish with provenance for supply chain security
155157 # --provenance creates a signed attestation of the build
156- # --ignore-scripts prevents running prepare/prepack scripts (husky) during publish
157- npm publish --provenance --access public --ignore-scripts
158+ npm publish --provenance --access public
158159 env :
159160 # SECURITY: NPM_TOKEN required for authentication
160161 NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
@@ -245,11 +246,11 @@ jobs:
245246
246247 - name : Publish to GitHub Packages
247248 run : |
248- # Scope package name to organization (required for GitHub Packages)
249- # Changes 'my-package' to '@org/my-package'
250- jq '.name = "@${{ github.repository_owner }}/" + .name | del(.private)' package.json > tmp.json && mv tmp.json package.json
251- # --ignore-scripts prevents running prepare/prepack scripts (husky) during publish
252- npm publish --access public --ignore-scripts
249+ # Scope package name to organization and remove private flag and prepare script
250+ # The prepare script runs even with --ignore-scripts, so we must remove it
251+ jq '.name = "@${{ github.repository_owner }}/" + .name | del(.private) | del(.scripts.prepare) ' package.json > tmp.json && mv tmp.json package.json
252+
253+ npm publish --access public
253254 env :
254255 # SECURITY: Uses GITHUB_TOKEN for authentication
255256 # Automatically available, no configuration needed
@@ -363,43 +364,46 @@ jobs:
363364 sudo apt-get update
364365 sudo apt-get install -y skopeo
365366
366- - name : Load and push Docker image
367- # Load the pre-built OCI image and push with proper tags
367+ - name : Push Docker image
368+ # Push the pre-built OCI image directly to Docker Hub using skopeo
368369 if : steps.check-docker.outputs.has_credentials == 'true'
370+ env :
371+ # Skopeo uses these environment variables for Docker Hub authentication
372+ REGISTRY_AUTH_FILE : /tmp/auth.json
369373 run : |
374+ echo "🔐 Configuring skopeo authentication..."
375+ # Create auth config for skopeo
376+ mkdir -p "$(dirname "$REGISTRY_AUTH_FILE")"
377+ echo "{\"auths\":{\"docker.io\":{\"auth\":\"$(echo -n \"${{ secrets.DOCKERHUB_USERNAME }}:${{ secrets.DOCKERHUB_TOKEN }}\" | base64 -w0)\"}}}" > "$REGISTRY_AUTH_FILE"
378+
370379 echo "📥 Decompressing Docker image..."
371380 gunzip ./docker-artifact/${{ steps.artifact.outputs.artifact_name }}.tar.gz
372381
373- # The artifact is in OCI format (for multi-platform builds)
374- # We need to use skopeo to copy it to docker-daemon
375- SOURCE_IMAGE_NAME="sonarqube-mcp-server"
376382 TARGET_REPO="${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}"
377383 VERSION="${{ steps.version.outputs.version }}"
378384
379- echo "🔄 Loading OCI image to Docker daemon ..."
380- # Use skopeo to copy from OCI archive to docker-daemon
381- # The tag in the OCI archive should match what was built in Main workflow
385+ echo "📤 Pushing OCI image directly to Docker Hub ..."
386+ # Use skopeo to push from OCI archive directly to Docker Hub
387+ # This preserves multi-platform manifest lists
382388 skopeo copy \
383- oci-archive:./docker-artifact/${{ steps.artifact.outputs.artifact_name }}.tar:$SOURCE_IMAGE_NAME:$VERSION \
384- docker-daemon:$TARGET_REPO:$VERSION
385-
386- echo "🏷️ Tagging image for Docker Hub..."
387- docker tag "$TARGET_REPO:$VERSION" "$TARGET_REPO:latest"
389+ --all \
390+ oci-archive:./docker-artifact/${{ steps.artifact.outputs.artifact_name }}.tar \
391+ docker://$TARGET_REPO:$VERSION
388392
389- # Also add major and major.minor tags
393+ echo "🏷️ Creating additional tags..."
394+ # Also add latest, major, and major.minor tags
390395 MAJOR=$(echo "$VERSION" | cut -d. -f1)
391396 MINOR=$(echo "$VERSION" | cut -d. -f2)
392- docker tag "$TARGET_REPO:$VERSION" "$TARGET_REPO:$MAJOR"
393- docker tag "$TARGET_REPO:$VERSION" "$TARGET_REPO:$MAJOR.$MINOR"
394397
395- echo "📤 Pushing to Docker Hub..."
396- docker push "$TARGET_REPO:$VERSION"
397- docker push "$TARGET_REPO:latest"
398- docker push "$TARGET_REPO:$MAJOR"
399- docker push "$TARGET_REPO:$MAJOR.$MINOR"
398+ skopeo copy docker://$TARGET_REPO:$VERSION docker://$TARGET_REPO:latest
399+ skopeo copy docker://$TARGET_REPO:$VERSION docker://$TARGET_REPO:$MAJOR
400+ skopeo copy docker://$TARGET_REPO:$VERSION docker://$TARGET_REPO:$MAJOR.$MINOR
400401
401402 echo "✅ Docker image published successfully"
402403
404+ # Cleanup auth file
405+ rm -f $REGISTRY_AUTH_FILE
406+
403407 # =============================================================================
404408 # NOTIFICATION
405409 # Send status updates to team communication channels
0 commit comments