diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..7489fa0 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,171 @@ +name: Publish Package + +on: + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: "Existing release tag to publish, for example v0.1.9" + required: true + type: string + +permissions: + contents: read + +env: + NODE_VERSION: "24" + PACKAGE_SCOPE: "@jungle-grid" + NPM_REGISTRY: "https://registry.npmjs.org" + GITHUB_PACKAGES_REGISTRY: "https://npm.pkg.github.com" + RELEASE_TAG: ${{ github.event_name == 'release' && github.event.release.tag_name || inputs.tag }} + +jobs: + validate: + name: Validate Package + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + outputs: + package-name: ${{ steps.package.outputs.name }} + package-version: ${{ steps.package.outputs.version }} + steps: + - name: Check out release tag + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ env.RELEASE_TAG }} + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ env.NODE_VERSION }} + package-manager-cache: false + + - name: Install dependencies + run: npm ci + + - name: Read package metadata + id: package + run: | + name="$(npm pkg get name | tr -d '"')" + version="$(npm pkg get version | tr -d '"')" + expected_tag="v${version}" + + if [ "${RELEASE_TAG}" != "${expected_tag}" ]; then + echo "Release tag ${RELEASE_TAG} does not match package version ${version}; expected ${expected_tag}." >&2 + exit 1 + fi + + echo "name=${name}" >> "${GITHUB_OUTPUT}" + echo "version=${version}" >> "${GITHUB_OUTPUT}" + + - name: Build + run: npm run build + + - name: Test + run: npm test + + - name: Verify package contents + run: npm pack --dry-run + + publish-npm: + name: Publish to npmjs + needs: validate + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + id-token: write + steps: + - name: Check out release tag + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ env.RELEASE_TAG }} + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: ${{ env.NPM_REGISTRY }} + package-manager-cache: false + + - name: Install dependencies + run: npm ci + + - name: Check npmjs version + id: npm-version + env: + PACKAGE_NAME: ${{ needs.validate.outputs.package-name }} + PACKAGE_VERSION: ${{ needs.validate.outputs.package-version }} + run: | + if npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" version --registry="${NPM_REGISTRY}" >/dev/null 2>&1; then + echo "exists=true" >> "${GITHUB_OUTPUT}" + echo "${PACKAGE_NAME}@${PACKAGE_VERSION} is already published to npmjs; skipping." + else + echo "exists=false" >> "${GITHUB_OUTPUT}" + fi + + - name: Build package + if: steps.npm-version.outputs.exists != 'true' + run: npm run build + + - name: Publish to npmjs + if: steps.npm-version.outputs.exists != 'true' + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + if [ -n "${NODE_AUTH_TOKEN:-}" ]; then + npm config set //registry.npmjs.org/:_authToken "${NODE_AUTH_TOKEN}" + fi + + npm publish --access public --provenance --registry="${NPM_REGISTRY}" + + publish-github-packages: + name: Publish to GitHub Packages + needs: validate + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + packages: write + steps: + - name: Check out release tag + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ env.RELEASE_TAG }} + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: ${{ env.GITHUB_PACKAGES_REGISTRY }} + scope: ${{ env.PACKAGE_SCOPE }} + package-manager-cache: false + + - name: Install dependencies + run: npm ci + + - name: Check GitHub Packages version + id: github-packages-version + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PACKAGE_NAME: ${{ needs.validate.outputs.package-name }} + PACKAGE_VERSION: ${{ needs.validate.outputs.package-version }} + run: | + if npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" version --registry="${GITHUB_PACKAGES_REGISTRY}" >/dev/null 2>&1; then + echo "exists=true" >> "${GITHUB_OUTPUT}" + echo "${PACKAGE_NAME}@${PACKAGE_VERSION} is already published to GitHub Packages; skipping." + else + echo "exists=false" >> "${GITHUB_OUTPUT}" + fi + + - name: Build package + if: steps.github-packages-version.outputs.exists != 'true' + run: npm run build + + - name: Publish to GitHub Packages + if: steps.github-packages-version.outputs.exists != 'true' + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: npm publish --registry="${GITHUB_PACKAGES_REGISTRY}" diff --git a/README.md b/README.md index 27fcd51..9aafd18 100644 --- a/README.md +++ b/README.md @@ -155,8 +155,15 @@ docker run --rm -p 3000:3000 \ ## Publishing +Normal users should continue to run the MCP server through the public npmjs +package: + ```sh -npm run build -npm pack --dry-run -npm publish --access public +npx -y @jungle-grid/mcp ``` + +Releases are published from GitHub Releases and version tags. The package is +distributed publicly through npmjs for normal installation, and the same package +version is also published to GitHub Packages as a repository-linked package +mirror. GitHub Packages is not the default install path for end users unless a +specific workflow requires it. diff --git a/package-lock.json b/package-lock.json index 481c832..097f452 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@jungle-grid/mcp", - "version": "0.1.8", + "version": "0.1.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@jungle-grid/mcp", - "version": "0.1.8", + "version": "0.1.9", "license": "MIT", "dependencies": { "@jungle-grid/gpu-registry": "^0.1.0", diff --git a/package.json b/package.json index 1eb398e..f44c01a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@jungle-grid/mcp", - "version": "0.1.8", + "version": "0.1.9", "description": "MCP server for Jungle Grid - submit and manage GPU workloads from any MCP-aware AI host", "license": "MIT", "homepage": "https://github.com/Jungle-Grid/mcp-server#readme", @@ -48,6 +48,7 @@ "!dist/*.test.d.ts.map", "!dist/*.test.js", "!dist/*.test.js.map", - "README.md" + "README.md", + "LICENSE" ] }