Skip to main content
Glama
publish-alpha.ymlβ€’14.4 kB
name: Publish Multi-Package Alpha to npm on: push: branches: - master - main jobs: verify: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' # Enable Corepack for Yarn support - name: Enable Corepack run: corepack enable - name: Install dependencies run: yarn install --immutable - name: Lint code run: yarn lint - name: Build packages run: yarn build - name: Run tests run: yarn test discover-packages: needs: verify runs-on: ubuntu-latest outputs: packages: ${{ steps.find-packages.outputs.packages }} package-count: ${{ steps.find-packages.outputs.package-count }} steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Find publishable packages id: find-packages run: | echo "πŸ” Discovering publishable packages in packages/ directory..." # Ensure jq is available which jq || (echo "Installing jq..." && sudo apt-get update && sudo apt-get install -y jq) PACKAGES="[]" PACKAGE_COUNT=0 # Find all package.json files in packages/ subdirectories for package_dir in packages/*/; do if [ -f "${package_dir}package.json" ]; then # Check if package is not private IS_PRIVATE=$(node -p " try { const pkg = require('./${package_dir}package.json'); pkg.private === true ? 'true' : 'false'; } catch(e) { 'true'; } ") if [ "$IS_PRIVATE" = "false" ]; then PACKAGE_NAME=$(node -p "require('./${package_dir}package.json').name") PACKAGE_VERSION=$(node -p "require('./${package_dir}package.json').version") PACKAGE_PATH=${package_dir%/} # Remove trailing slash echo "βœ… Found publishable package: $PACKAGE_NAME@$PACKAGE_VERSION in $PACKAGE_PATH" # Add to packages array with error handling NEW_PACKAGES=$(echo "$PACKAGES" | jq --arg name "$PACKAGE_NAME" --arg version "$PACKAGE_VERSION" --arg path "$PACKAGE_PATH" '. + [{name: $name, version: $version, path: $path}]') if [ $? -eq 0 ]; then PACKAGES="$NEW_PACKAGES" PACKAGE_COUNT=$((PACKAGE_COUNT + 1)) else echo "❌ Error adding package $PACKAGE_NAME to JSON array" exit 1 fi else PACKAGE_NAME=$(node -p "require('./${package_dir}package.json').name") echo "⏭️ Skipping private package: $PACKAGE_NAME in ${package_dir%/}" fi fi done echo "πŸ“Š Total publishable packages found: $PACKAGE_COUNT" # Display package names safely if [ "$PACKAGE_COUNT" -gt 0 ]; then echo "πŸ“¦ Packages to publish: $(echo "$PACKAGES" | jq -c '.[].name')" else echo "πŸ“¦ No publishable packages found" fi # Output for matrix strategy - properly escape JSON for GitHub Actions echo "packages<<EOF" >> $GITHUB_OUTPUT echo "$PACKAGES" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT echo "package-count=$PACKAGE_COUNT" >> $GITHUB_OUTPUT publish-packages: needs: [verify, discover-packages] runs-on: ubuntu-latest if: fromJson(needs.discover-packages.outputs.package-count) > 0 strategy: matrix: package: ${{ fromJson(needs.discover-packages.outputs.packages) }} fail-fast: false # Continue publishing other packages even if one fails outputs: results: ${{ steps.collect-results.outputs.results }} steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' registry-url: 'https://registry.npmjs.org' # Enable Corepack for Yarn support - name: Enable Corepack run: corepack enable - name: Install dependencies run: yarn install --immutable - name: Lint code run: yarn lint - name: Build packages run: yarn build - name: Check and publish alpha version for ${{ matrix.package.name }} id: publish-package run: | PACKAGE_NAME="${{ matrix.package.name }}" PACKAGE_VERSION="${{ matrix.package.version }}" PACKAGE_PATH="${{ matrix.package.path }}" echo "πŸš€ Processing package: $PACKAGE_NAME@$PACKAGE_VERSION" echo "πŸ“ Package path: $PACKAGE_PATH" # Change to package directory cd "$PACKAGE_PATH" # Safety check: Ensure we never publish a non-alpha version if [[ "$PACKAGE_VERSION" =~ -alpha\. ]]; then echo "❌ ERROR: package.json version already contains '-alpha' suffix!" echo "❌ This workflow should only work with clean base versions (e.g., '4.0.0')" exit 1 fi # Get the latest alpha version number for this base version LATEST_ALPHA_NUMBER=0 # Check for existing alpha versions and find the highest number echo "πŸ” Checking for existing alpha versions of $PACKAGE_VERSION for $PACKAGE_NAME..." for i in {1..100}; do if npm view "$PACKAGE_NAME@${PACKAGE_VERSION}-alpha.$i" version 2>/dev/null; then LATEST_ALPHA_NUMBER=$i echo " Found: ${PACKAGE_VERSION}-alpha.$i" else break fi done # Increment the alpha number NEW_ALPHA_NUMBER=$((LATEST_ALPHA_NUMBER + 1)) ALPHA_VERSION="${PACKAGE_VERSION}-alpha.${NEW_ALPHA_NUMBER}" echo "πŸ“Š Latest alpha number: $LATEST_ALPHA_NUMBER" echo "πŸ†• New alpha number: $NEW_ALPHA_NUMBER" echo "🏷️ New alpha version: $ALPHA_VERSION" echo "⚠️ Will publish ONLY to 'alpha' tag, NOT 'latest'" # Setup npmrc for this package (for both npm and yarn) echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > .npmrc echo "registry=https://registry.npmjs.org/" >> .npmrc echo "always-auth=true" >> .npmrc # Also configure Yarn for npm registry echo "πŸ“‹ Configuring Yarn for npm registry..." yarn config set npmRegistryServer "https://registry.npmjs.org" yarn config set npmAlwaysAuth true yarn config set npmAuthToken "${NODE_AUTH_TOKEN}" # Debug: Show package.json dependencies to understand workspace resolution echo "πŸ“¦ Current package.json dependencies:" node -p "JSON.stringify(require('./package.json').dependencies || {}, null, 2)" # Safety verification before publishing if [[ ! "$ALPHA_VERSION" =~ -alpha\. ]]; then echo "❌ CRITICAL ERROR: Version '$ALPHA_VERSION' does not contain '-alpha' suffix!" echo "❌ Refusing to publish - this could pollute the main npm release!" exit 1 fi echo "πŸ”’ Safety check passed: Publishing alpha version $ALPHA_VERSION" # Temporarily update package.json version to alpha (Yarn v4 doesn't create git tags automatically) yarn version $ALPHA_VERSION # Debug: Show how Yarn resolves workspace dependencies echo "πŸ” Yarn workspace dependency resolution:" node -p "JSON.stringify(require('./package.json').dependencies || {}, null, 2)" # Publish with alpha tag (NOT latest - ensures no main version pollution) echo "πŸš€ Publishing $PACKAGE_NAME@$ALPHA_VERSION to npm with 'alpha' tag (NOT 'latest')..." # Always use Yarn for workspace packages (handles workspace: dependencies correctly) echo "πŸ”§ Using Yarn to publish (handles workspace dependencies automatically)" yarn npm publish --access public --tag alpha # Revert package.json version back to original yarn version $PACKAGE_VERSION echo "βœ… Successfully published $PACKAGE_NAME@$ALPHA_VERSION to npm with 'alpha' tag" echo "⚠️ This version is NOT published to 'latest' - only available via 'alpha' tag" echo "πŸ“₯ Users can install with: npm install $PACKAGE_NAME@alpha" # Set outputs for notification echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT echo "package_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT echo "alpha_version=$ALPHA_VERSION" >> $GITHUB_OUTPUT echo "alpha_number=$NEW_ALPHA_NUMBER" >> $GITHUB_OUTPUT echo "published=true" >> $GITHUB_OUTPUT env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} YARN_NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Collect results id: collect-results run: | # This step helps aggregate results for the notification job echo "results={\"name\": \"${{ steps.publish-package.outputs.package_name }}\", \"version\": \"${{ steps.publish-package.outputs.alpha_version }}\", \"published\": \"${{ steps.publish-package.outputs.published }}\"}" >> $GITHUB_OUTPUT notify-discord: needs: [verify, discover-packages, publish-packages] runs-on: ubuntu-latest if: always() # Run even if previous jobs fail steps: - name: Send Discord notification continue-on-error: true env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} run: | # Check if Discord webhook is configured if [ -z "$DISCORD_WEBHOOK" ]; then echo "ℹ️ DISCORD_WEBHOOK not configured, skipping notification" exit 0 fi # Determine overall status and color VERIFY_RESULT="${{ needs.verify.result }}" DISCOVER_RESULT="${{ needs.discover-packages.result }}" PUBLISH_RESULT="${{ needs.publish-packages.result }}" PACKAGE_COUNT="${{ needs.discover-packages.outputs.package-count || '0' }}" if [ "$VERIFY_RESULT" == "failure" ] || [ "$DISCOVER_RESULT" == "failure" ] || [ "$PUBLISH_RESULT" == "failure" ]; then STATUS="❌ **Failed**" COLOR=15158332 # Red if [ "$VERIFY_RESULT" == "failure" ]; then DESCRIPTION="Build or test verification failed" elif [ "$DISCOVER_RESULT" == "failure" ]; then DESCRIPTION="Package discovery failed" else DESCRIPTION="Package publishing failed" fi elif [ "$PACKAGE_COUNT" -gt "0" ]; then STATUS="πŸš€ **Multi-Package Alpha Published**" COLOR=3066993 # Green DESCRIPTION="Successfully published $PACKAGE_COUNT alpha packages to npm" else STATUS="βœ… **Success**" COLOR=3066993 # Green DESCRIPTION="Build completed successfully (no publishable packages found)" fi # Get commit info COMMIT_SHA="${{ github.sha }}" SHORT_SHA="${COMMIT_SHA:0:7}" COMMIT_MSG="${{ github.event.head_commit.message }}" AUTHOR="${{ github.event.head_commit.author.name }}" # Escape JSON special characters to prevent injection COMMIT_MSG_ESCAPED=$(echo "$COMMIT_MSG" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | tr '\n' ' ' | tr '\r' ' ') AUTHOR_ESCAPED=$(echo "$AUTHOR" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g') # Create base fields BASE_FIELDS='[ { "name": "Status", "value": "'$STATUS'", "inline": true }, { "name": "Packages Found", "value": "'$PACKAGE_COUNT'", "inline": true }, { "name": "Author", "value": "'$AUTHOR_ESCAPED'", "inline": true }, { "name": "Commit", "value": "[`'$SHORT_SHA'`](https://github.com/${{ github.repository }}/commit/${{ github.sha }})", "inline": true }, { "name": "Branch", "value": "`${{ github.ref_name }}`", "inline": true }, { "name": "Repository", "value": "[View on GitHub](https://github.com/${{ github.repository }})", "inline": true }, { "name": "Commit Message", "value": "'$COMMIT_MSG_ESCAPED'", "inline": false } ]' # Create JSON payload PAYLOAD=$(cat <<EOF { "username": "NPM Multi-Package Alpha Publisher", "avatar_url": "https://raw.githubusercontent.com/npm/logos/master/npm%20logo/npm-logo-red.png", "embeds": [{ "title": "πŸ“¦ Octocode Multi-Package Alpha Release", "description": "$DESCRIPTION", "color": $COLOR, "fields": $BASE_FIELDS, "footer": { "text": "GitHub Actions β€’ $(date -u +'%Y-%m-%d %H:%M:%S UTC')" } }] } EOF ) # Send Discord webhook with error handling if ! curl -H "Content-Type: application/json" -X POST -d "$PAYLOAD" "$DISCORD_WEBHOOK"; then echo "⚠️ Failed to send Discord notification, but this won't fail the workflow" else echo "βœ… Discord notification sent successfully" fi

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bgauryy/octocode-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server