diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 00000000..e6202d89 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,50 @@ +--- +name: Build and Push Docker Image +on: + workflow_call: + secrets: + DOCKERHUB_USERNAME: + required: true + DOCKERHUB_PASSWORD: + required: true + +jobs: + build-push: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Check out code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + with: + persist-credentials: false + + - name: Get version and date + id: release-meta + run: | + VERSION=$(npm pkg get version | tr -d '"') + DATE=$(date +'%Y-%m-%d') + echo "VERSION=${VERSION}" >> "$GITHUB_OUTPUT" + echo "DATE=${DATE}" >> "$GITHUB_OUTPUT" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 + + - name: Login to Docker Hub + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef + with: + username: "${{ secrets.DOCKERHUB_USERNAME }}" + password: "${{ secrets.DOCKERHUB_PASSWORD }}" + + - name: Build and push image to dockerhub registry + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 + with: + context: . + platforms: linux/amd64,linux/arm64 + tags: ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:latest, ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:${{ steps.release-meta.outputs.VERSION }}, ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:${{ steps.release-meta.outputs.VERSION }}-${{ steps.release-meta.outputs.DATE }} + file: Dockerfile + push: true + provenance: mode=max + sbom: true + build-args: | + VERSION=${{ steps.release-meta.outputs.VERSION }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5d32b7be..01987ad7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -7,8 +7,21 @@ permissions: contents: read issues: write jobs: - push: + docker-push: + uses: ./.github/workflows/docker-publish.yml + permissions: + contents: read + secrets: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} + + handle-failure: runs-on: ubuntu-latest + permissions: + contents: read + issues: write + needs: docker-push + if: ${{ always() && needs.docker-push.result == 'failure' }} steps: - uses: GitHubSecurityLab/actions-permissions/monitor@v1 with: @@ -17,43 +30,22 @@ jobs: uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: persist-credentials: false - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 - - name: Login to Docker Hub - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef - with: - username: "${{ secrets.DOCKERHUB_USERNAME }}" - password: "${{ secrets.DOCKERHUB_PASSWORD }}" - - name: Set date and version - id: set-properties + - name: Get version and date + id: release-meta run: | - DATE=$(date +'%Y-%m-%d') VERSION=$(npm pkg get version | tr -d '"') - echo "DATE=${DATE}" >> "$GITHUB_OUTPUT" + DATE=$(date +'%Y-%m-%d') echo "VERSION=${VERSION}" >> "$GITHUB_OUTPUT" - - name: Build and push image to dockerhub registry - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 - with: - context: . - platforms: linux/amd64,linux/arm64 - tags: ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:latest, ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:${{ steps.set-properties.outputs.VERSION }}, ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:${{ steps.set-properties.outputs.VERSION }}-${{ steps.set-properties.outputs.DATE }} - file: Dockerfile - push: true - provenance: mode=max - sbom: true - build-args: | - VERSION=${{ steps.set-properties.outputs.VERSION }} + echo "DATE=${DATE}" >> "$GITHUB_OUTPUT" - uses: mongodb-js/devtools-shared/actions/setup-bot-token@main id: app-token - if: ${{ failure() }} with: app-id: ${{ vars.DEVTOOLS_BOT_APP_ID }} private-key: ${{ secrets.DEVTOOLS_BOT_PRIVATE_KEY }} - name: Create Issue - if: ${{ failure() }} uses: imjohnbo/issue-bot@572eed14422c4d6ca37e870f97e7da209422f5bd with: token: ${{ steps.app-token.outputs.token }} - title: Release Failure for Docker Image ${{ steps.set-properties.outputs.VERSION }}-${{ steps.set-properties.outputs.DATE }} + title: Release Failure for Docker Image ${{ steps.release-meta.outputs.VERSION }}-${{ steps.release-meta.outputs.DATE }} body: See https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} labels: "docker, release_failure" diff --git a/.github/workflows/mcp-publish.yml b/.github/workflows/mcp-publish.yml new file mode 100644 index 00000000..8ae57ec1 --- /dev/null +++ b/.github/workflows/mcp-publish.yml @@ -0,0 +1,28 @@ +--- +name: Publish to MCP Registry +on: + workflow_call: + workflow_dispatch: + +jobs: + mcp-publish: + runs-on: ubuntu-latest + environment: Production + permissions: + id-token: write + contents: read + steps: + - uses: GitHubSecurityLab/actions-permissions/monitor@v1 + - uses: actions/checkout@v5 + with: + persist-credentials: false + + - name: Install MCP Publisher + run: | + curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher + + - name: Login to MCP Registry + run: ./mcp-publisher login github-oidc + + - name: Publish to MCP Registry + run: ./mcp-publisher publish diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d17a341e..9f9342ef 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -101,12 +101,42 @@ jobs: run: | gh release create ${{ needs.check.outputs.VERSION }} --title "${{ needs.check.outputs.VERSION }}" --generate-notes --target ${{ github.sha }} ${{ (needs.check.outputs.RELEASE_CHANNEL != 'latest' && '--prerelease') || ''}} - - name: Install MCP Publisher + - name: Wait for package to be available on npm run: | - curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher + PACKAGE_NAME=$(jq -r '.name' < package.json) + VERSION="${{ needs.check.outputs.VERSION }}" + # Strip the 'v' prefix for npm + NPM_VERSION="${VERSION#v}" + MAX_ATTEMPTS=30 + SLEEP_SECONDS=10 - - name: Login to MCP Registry - run: ./mcp-publisher login github-oidc + echo "Waiting for ${PACKAGE_NAME}@${NPM_VERSION} to be available on npm..." - - name: Publish to MCP Registry - run: ./mcp-publisher publish + for i in $(seq 1 $MAX_ATTEMPTS); do + if npm view "${PACKAGE_NAME}@${NPM_VERSION}" version >/dev/null 2>&1; then + echo "✓ Package ${PACKAGE_NAME}@${NPM_VERSION} is now available on npm" + exit 0 + fi + echo "Attempt $i/$MAX_ATTEMPTS: Package not yet available, waiting ${SLEEP_SECONDS}s..." + sleep $SLEEP_SECONDS + done + + echo "::error::Package ${PACKAGE_NAME}@${NPM_VERSION} did not become available after $((MAX_ATTEMPTS * SLEEP_SECONDS)) seconds" + exit 1 + + docker-push: + needs: [check, publish] + uses: ./.github/workflows/docker-publish.yml + permissions: + contents: read + secrets: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} + + mcp-publish: + needs: [check, docker-push] + if: needs.check.outputs.VERSION_EXISTS == 'false' + uses: ./.github/workflows/mcp-publish.yml + permissions: + id-token: write + contents: read