Skip to content
This repository was archived by the owner on Nov 14, 2025. It is now read-only.

Commit 2a31f70

Browse files
sapientpantsclaude
andauthored
fix: properly handle NPM prepare script and Docker OCI format (#314)
Previous attempt (PR #313) didn't work because: 1. --ignore-scripts doesn't prevent prepare script from running 2. skopeo couldn't find tag in OCI archive with the reference syntax used This commit implements proper fixes: NPM Fix: - Remove prepare script from package.json before publishing - The prepare script runs even with --ignore-scripts flag - This prevents "husky: not found" error Docker Fix: - Use skopeo to push OCI archive directly to Docker Hub - Configure skopeo authentication with Docker Hub credentials - Use --all flag to preserve multi-platform manifest lists - Create additional tags (latest, major, major.minor) using skopeo copy These fixes address the failures in v1.10.9, v1.10.10, and v1.10.11. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <[email protected]>
1 parent a8fd78a commit 2a31f70

File tree

2 files changed

+43
-30
lines changed

2 files changed

+43
-30
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'sonarqube-mcp-server': patch
3+
---
4+
5+
Fix NPM prepare script and Docker OCI push issues
6+
7+
- NPM: Remove prepare script from package.json before publishing (--ignore-scripts doesn't skip prepare)
8+
- Docker: Use skopeo to push OCI archive directly to Docker Hub instead of loading to docker-daemon
9+
- Docker: Configure skopeo authentication with Docker Hub credentials

.github/workflows/publish.yml

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)