Repository navigation
Merge pull request #86 from debugmcp/chore/prepare-v0.21.0 #48
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: | |
| ref: | |
| description: 'Git ref (tag or branch) to release from' | |
| required: true | |
| default: 'refs/tags/v0.21.0' | |
| permissions: {} | |
| jobs: | |
| build-and-test: | |
| name: Build and Test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.inputs.ref || github.ref }} | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 | |
| with: | |
| version: 10 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: '22.x' | |
| cache: 'pnpm' | |
| - name: Setup Python 3.11 | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: '3.11' | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install "pip==25.0.1" | |
| pip install "debugpy==1.8.14" | |
| - name: Setup Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: '1.21' | |
| - name: Install Delve debugger | |
| run: go install github.com/go-delve/delve/cmd/dlv@v1.24.2 | |
| - name: Setup Java 21 | |
| uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '21' | |
| - name: Sanity versions | |
| run: | | |
| node -v | |
| npm -v | |
| pnpm -v | |
| - name: Approve build scripts (esbuild) | |
| run: pnpm approve-builds esbuild | |
| continue-on-error: true | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile --ignore-scripts | |
| - name: Build project | |
| run: pnpm run build | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Run tests | |
| run: pnpm run test:ci-no-python | |
| docker-publish: | |
| name: Build and Push Docker Image | |
| needs: build-and-test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.inputs.ref || github.ref }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Determine Docker latest tag strategy | |
| shell: bash | |
| env: | |
| GITHUB_REF_TYPE: ${{ github.ref_type }} | |
| GITHUB_REF_NAME: ${{ github.ref_name }} | |
| DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} | |
| run: | | |
| if [[ "${GITHUB_REF_TYPE}" == "branch" && "${GITHUB_REF_NAME}" == "${DEFAULT_BRANCH}" ]]; then | |
| echo "PUBLISH_LATEST=true" >> "$GITHUB_ENV" | |
| echo "latest will track default branch build (${GITHUB_REF_NAME})" | |
| elif [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" != *"-alpha"* && "${GITHUB_REF_NAME}" != *"-beta"* && "${GITHUB_REF_NAME}" != *"-rc"* ]]; then | |
| echo "PUBLISH_LATEST=true" >> "$GITHUB_ENV" | |
| echo "latest will point to release ${GITHUB_REF_NAME}" | |
| else | |
| echo "PUBLISH_LATEST=false" >> "$GITHUB_ENV" | |
| echo "latest tag update skipped for ref ${GITHUB_REF_NAME}" | |
| fi | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 | |
| with: | |
| images: debugmcp/mcp-debugger | |
| tags: | | |
| type=ref,event=tag | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=raw,value=latest,enable=${{ env.PUBLISH_LATEST == 'true' }} | |
| - name: Build and push Docker image | |
| uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| pypi-publish: | |
| name: Publish Python Launcher to PyPI | |
| needs: build-and-test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.inputs.ref || github.ref }} | |
| - name: Set up Python | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: '3.11' | |
| - name: Install Python build dependencies | |
| run: | | |
| python -m pip install "pip==25.0.1" | |
| pip install "build==1.2.2" "twine==6.1.0" "tomlkit==0.13.2" | |
| - name: Resolve release ref | |
| run: | | |
| if [ -n "${{ github.event.inputs.ref }}" ]; then | |
| echo "RELEASE_REF=${{ github.event.inputs.ref }}" >> $GITHUB_ENV | |
| else | |
| echo "RELEASE_REF=${GITHUB_REF}" >> $GITHUB_ENV | |
| fi | |
| - name: Set launcher version from tag | |
| run: | | |
| VERSION="${RELEASE_REF#refs/tags/v}" | |
| echo "VERSION=$VERSION" >> $GITHUB_ENV | |
| - name: Sync version into pyproject.toml | |
| run: | | |
| python - <<'PY' | |
| import os | |
| from tomlkit import parse, dumps | |
| p = os.path.join('mcp_debugger_launcher','pyproject.toml') | |
| with open(p,'r',encoding='utf-8') as f: | |
| doc = parse(f.read()) | |
| ver = os.environ.get('VERSION','0.0.0') | |
| if 'project' in doc and 'version' in doc['project']: | |
| doc['project']['version'] = ver | |
| elif 'tool' in doc and 'poetry' in doc['tool'] and 'version' in doc['tool']['poetry']: | |
| doc['tool']['poetry']['version'] = ver | |
| else: | |
| doc.setdefault('project', {})['version'] = ver | |
| with open(p,'w',encoding='utf-8') as f: | |
| f.write(dumps(doc)) | |
| print(f"Set pyproject version to {ver}") | |
| PY | |
| - name: Build Python package | |
| run: | | |
| cd mcp_debugger_launcher | |
| rm -rf dist build *.egg-info | |
| python -m build | |
| - name: Publish to PyPI | |
| env: | |
| TWINE_USERNAME: __token__ | |
| TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} | |
| run: | | |
| cd mcp_debugger_launcher | |
| python -m twine check dist/* | |
| python -m twine upload --skip-existing dist/* | |
| npm-publish: | |
| name: Publish to npm | |
| needs: build-and-test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| id-token: write # Required for npm trusted publishing (OIDC) | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.inputs.ref || github.ref }} | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 | |
| with: | |
| version: 10 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: '22.x' | |
| registry-url: 'https://registry.npmjs.org' | |
| cache: 'pnpm' | |
| - name: Setup Java 21 | |
| uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '21' | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile --ignore-scripts | |
| - name: Sanity versions | |
| run: | | |
| node -v | |
| npm -v | |
| pnpm -v | |
| - name: Resolve release ref | |
| run: | | |
| if [ -n "${{ github.event.inputs.ref }}" ]; then | |
| echo "RELEASE_REF=${{ github.event.inputs.ref }}" >> $GITHUB_ENV | |
| else | |
| echo "RELEASE_REF=${GITHUB_REF}" >> $GITHUB_ENV | |
| fi | |
| - name: Set CLI package version from tag (monorepo-safe) | |
| run: | | |
| VERSION="${RELEASE_REF#refs/tags/v}" | |
| echo "Setting CLI package version to $VERSION" | |
| VERSION_STRIPPED="$VERSION" node -e "const fs=require('fs');const p='packages/mcp-debugger/package.json';const pkg=JSON.parse(fs.readFileSync(p,'utf8'));const ver=process.env.VERSION_STRIPPED; if(!/^[0-9]+\\.[0-9]+\\.[0-9]+(-.+)?$/.test(ver)){console.error('Invalid semver:',ver);process.exit(1);} pkg.version=ver; fs.writeFileSync(p,JSON.stringify(pkg,null,2)+'\\n');console.log('Updated',p,'to',pkg.version)" | |
| - name: Capture workspace package versions (robust) | |
| run: | | |
| node -e 'console.log("SHARED_VERSION="+require("./packages/shared/package.json").version)' >> $GITHUB_ENV | |
| node -e 'console.log("ADAPTER_MOCK_VERSION="+require("./packages/adapter-mock/package.json").version)' >> $GITHUB_ENV | |
| node -e 'console.log("ADAPTER_PYTHON_VERSION="+require("./packages/adapter-python/package.json").version)' >> $GITHUB_ENV | |
| node -e 'console.log("CLI_VERSION="+require("./packages/mcp-debugger/package.json").version)' >> $GITHUB_ENV | |
| - name: Set npm dist-tag | |
| run: | | |
| if [[ "${CLI_VERSION}" == *"-beta"* ]] || [[ "${CLI_VERSION}" == *"-alpha"* ]]; then | |
| echo "NPM_TAG=beta" >> $GITHUB_ENV | |
| else | |
| echo "NPM_TAG=latest" >> $GITHUB_ENV | |
| fi | |
| - name: Build project | |
| run: pnpm run build | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Pack npm tarballs (dry-run) | |
| run: | | |
| npm pack --dry-run -w @debugmcp/shared | |
| npm pack --dry-run -w @debugmcp/adapter-mock | |
| npm pack --dry-run -w @debugmcp/adapter-python | |
| npm pack --dry-run -w @debugmcp/mcp-debugger | |
| - name: Publish to npm (workspaces) | |
| run: | | |
| # Auth via NPM_TOKEN (granular access token scoped to @debugmcp packages) | |
| # --provenance adds signed build attestation (requires id-token: write) | |
| # Trusted publisher config on npmjs.com verifies provenance against this repo | |
| # Publish packages in dependency order if the target version does NOT yet exist | |
| if npm view @debugmcp/shared@${SHARED_VERSION} version >/dev/null 2>&1; then | |
| echo "@debugmcp/shared@${SHARED_VERSION} already exists, skipping" | |
| else | |
| npm publish -w @debugmcp/shared --access public --provenance | |
| fi | |
| if npm view @debugmcp/adapter-mock@${ADAPTER_MOCK_VERSION} version >/dev/null 2>&1; then | |
| echo "@debugmcp/adapter-mock@${ADAPTER_MOCK_VERSION} already exists, skipping" | |
| else | |
| npm publish -w @debugmcp/adapter-mock --access public --provenance | |
| fi | |
| if npm view @debugmcp/adapter-python@${ADAPTER_PYTHON_VERSION} version >/dev/null 2>&1; then | |
| echo "@debugmcp/adapter-python@${ADAPTER_PYTHON_VERSION} already exists, skipping" | |
| else | |
| npm publish -w @debugmcp/adapter-python --access public --provenance | |
| fi | |
| if npm view @debugmcp/mcp-debugger@${CLI_VERSION} version >/dev/null 2>&1; then | |
| echo "@debugmcp/mcp-debugger@${CLI_VERSION} already exists, skipping" | |
| else | |
| npm publish -w @debugmcp/mcp-debugger --access public --provenance --tag ${NPM_TAG} | |
| fi | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| create-release: | |
| name: Create GitHub Release | |
| needs: [docker-publish, pypi-publish, npm-publish] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # Grant permission to create releases | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.inputs.ref || github.ref }} | |
| - name: Resolve release ref | |
| run: | | |
| if [ -n "${{ github.event.inputs.ref }}" ]; then | |
| echo "RELEASE_REF=${{ github.event.inputs.ref }}" >> $GITHUB_ENV | |
| else | |
| echo "RELEASE_REF=${GITHUB_REF}" >> $GITHUB_ENV | |
| fi | |
| - name: Generate changelog | |
| id: changelog | |
| run: | | |
| # Extract version from tag | |
| VERSION=${RELEASE_REF#refs/tags/v} | |
| echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | |
| # Get changelog for this version | |
| CHANGELOG=$(sed -n "/^## \[$VERSION\]/,/^## \[/p" CHANGELOG.md | sed '$ d') | |
| echo "CHANGELOG<<EOF" >> $GITHUB_OUTPUT | |
| echo "$CHANGELOG" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| - name: Create Release with GitHub CLI | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Create the release body in a file | |
| cat << 'EOF' > release_notes.md | |
| ## 🎉 Release ${{ steps.changelog.outputs.VERSION }} | |
| ${{ steps.changelog.outputs.CHANGELOG }} | |
| ### 📦 Installation | |
| **Docker:** | |
| ```bash | |
| docker pull debugmcp/mcp-debugger:${{ steps.changelog.outputs.VERSION }} | |
| ``` | |
| **npm (global install):** | |
| ```bash | |
| npm install -g @debugmcp/mcp-debugger@${{ steps.changelog.outputs.VERSION }} | |
| ``` | |
| **npx (no install):** | |
| ```bash | |
| npx @debugmcp/mcp-debugger@${{ steps.changelog.outputs.VERSION }} stdio | |
| ``` | |
| **PyPI:** | |
| ```bash | |
| pip install debug-mcp-server-launcher==${{ steps.changelog.outputs.VERSION }} | |
| ``` | |
| **Optional adapters:** | |
| ```bash | |
| npm install -g @debugmcp/adapter-python | |
| npm install -g @debugmcp/adapter-mock | |
| ``` | |
| ### 📚 Documentation | |
| See the [README](https://github.com/debugmcp/mcp-debugger#readme) for usage instructions. | |
| EOF | |
| # Determine if this is a prerelease | |
| if [[ "${{ github.ref_name }}" == *"-beta"* ]] || [[ "${{ github.ref_name }}" == *"-alpha"* ]]; then | |
| PRERELEASE_FLAG="--prerelease" | |
| else | |
| PRERELEASE_FLAG="" | |
| fi | |
| # Create the release using GitHub CLI | |
| gh release create "${{ github.ref_name }}" \ | |
| --title "Release ${{ steps.changelog.outputs.VERSION }}" \ | |
| --notes-file release_notes.md \ | |
| $PRERELEASE_FLAG |