Skip to content

feat: add unified release script for all packages#142

Merged
ashvathsureshkumar merged 5 commits intomainfrom
package-release
Apr 10, 2026
Merged

feat: add unified release script for all packages#142
ashvathsureshkumar merged 5 commits intomainfrom
package-release

Conversation

@ashvathsureshkumar
Copy link
Copy Markdown
Contributor

@ashvathsureshkumar ashvathsureshkumar commented Apr 9, 2026

Summary

  • Adds scripts/release.sh — a single script to build and publish all 8 Moss packages (3 npm, 5 PyPI)
  • Supports --dry-run, --npm-only, --pypi-only, and selective package publishing
  • Includes preflight checks for required tooling and auth

Packages covered

npm: @moss-tools/md-indexer, @moss-tools/vercel-sdk, vitepress-plugin-moss
PyPI: elevenlabs-moss, moss-cli, pipecat-moss, strands-agents-moss, vapi-moss

Usage

./scripts/release.sh --dry-run          # verify builds
./scripts/release.sh                    # publish all
./scripts/release.sh vercel-sdk         # publish one
./scripts/release.sh --pypi-only        # publish only Python packages

Test plan

  • Dry run completes successfully for all 8 packages
  • npm publish with valid auth
  • PyPI publish with valid auth

Open with Devin

Unified release script that builds and publishes all 8 packages
(3 npm, 5 PyPI) with dry-run support, selective publishing, and
preflight checks.
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment thread scripts/release.sh
Comment thread scripts/release.sh
Comment thread scripts/release.sh Outdated
Comment on lines +145 to +157
pkg_name=$(python3 -c "
import tomllib, pathlib
p = pathlib.Path('$pkg_dir/pyproject.toml')
d = tomllib.loads(p.read_text())
print(d['project']['name'])
")
local version
version=$(python3 -c "
import tomllib, pathlib
p = pathlib.Path('$pkg_dir/pyproject.toml')
d = tomllib.loads(p.read_text())
print(d['project']['version'])
")
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: release_pypi relies on tomli for Python < 3.11 but doesn't verify it's installed

The release_pypi function (lines 159-167, 170-179) uses tomllib (stdlib in 3.11+) with a fallback to tomli (third-party). The preflight checks verify python3 and build tools exist, but don't verify tomli is installed for Python < 3.11. If a developer runs this on Python 3.10 without tomli installed, both imports fail and the function returns an error. In practice most developers will be on 3.11+ or will have tomli installed, and the error message from Python would be clear enough to diagnose.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a unified scripts/release.sh entrypoint to build and publish all Moss npm + PyPI packages with shared preflight checks and CLI flags, consolidating release steps into one workflow.

Changes:

  • Introduces scripts/release.sh with support for --dry-run, --npm-only, --pypi-only, and selective package targeting.
  • Implements npm publish flow (install → optional build → publish/pack) per package.
  • Implements PyPI publish flow (clean → build → publish) per package, plus a summary report.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/release.sh
Comment on lines +277 to +283
# Release npm packages
for pkg in "${do_npm[@]}"; do
if ! release_npm "$PACKAGES_DIR/$pkg"; then
fail "Failed to release $pkg"
FAILED+=("$pkg")
fi
done
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The failure-handling logic in the release loops won’t work with set -e: if any command inside release_npm fails (install/build/publish), the script will exit immediately, so the if ! release_npm ...; then branch and the FAILED summary won’t run and remaining packages won’t be attempted. Consider either removing -e and explicitly propagating errors from release_*, or temporarily disabling -e around each package release and capturing the return code so failures can be recorded while continuing.

Copilot uses AI. Check for mistakes.
Comment thread scripts/release.sh
Comment on lines +111 to +118
# Install dependencies
if [[ -f "pnpm-lock.yaml" ]]; then
pnpm install --frozen-lockfile 2>/dev/null || pnpm install
elif [[ -f "package-lock.json" ]]; then
npm ci 2>/dev/null || npm install
else
npm install
fi
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

release_npm may call pnpm install when a pnpm-lock.yaml exists, but the preflight checks don’t verify pnpm is installed. This will fail at runtime for packages like moss-md-indexer/vitepress-plugin-moss which include a pnpm lockfile. Add a preflight check for pnpm (or fallback to npm when pnpm isn’t available).

Copilot uses AI. Check for mistakes.
Comment thread scripts/release.sh Outdated
Comment on lines +145 to +157
pkg_name=$(python3 -c "
import tomllib, pathlib
p = pathlib.Path('$pkg_dir/pyproject.toml')
d = tomllib.loads(p.read_text())
print(d['project']['name'])
")
local version
version=$(python3 -c "
import tomllib, pathlib
p = pathlib.Path('$pkg_dir/pyproject.toml')
d = tomllib.loads(p.read_text())
print(d['project']['version'])
")
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

release_pypi parses pyproject.toml using tomllib, which only exists in Python 3.11+. Several packages in this repo declare requires-python >=3.10, so this script will break on supported Python versions (e.g. 3.10). Either require Python >=3.11 in preflight or implement a fallback to tomli (or another TOML parser) when tomllib isn’t available.

Copilot uses AI. Check for mistakes.
Comment thread scripts/release.sh Outdated
Comment on lines +71 to +79
fi
else
ok "uv $(uv --version 2>&1 | awk '{print $2}')"
fi

if ! command -v twine &>/dev/null && ! command -v uv &>/dev/null; then
warn "twine not found — will try 'uv publish' or 'python3 -m twine'"
fi

Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When uv is not installed, the script falls back to python3 -m build and python3 -m twine, but preflight only checks for pip and only warns about missing twine. This will fail later unless the build and twine modules are installed in the current Python environment. Consider adding explicit preflight checks for python3 -m build and python3 -m twine availability (and fail early with clear install instructions) when uv isn’t present.

Suggested change
fi
else
ok "uv $(uv --version 2>&1 | awk '{print $2}')"
fi
if ! command -v twine &>/dev/null && ! command -v uv &>/dev/null; then
warn "twine not found — will try 'uv publish' or 'python3 -m twine'"
fi
if python3 -m build --version &>/dev/null; then
ok "python build module available"
else
fail "Python module 'build' not available for python3; install it with: python3 -m pip install --user build twine"; missing=1
fi
if python3 -m twine --version &>/dev/null; then
ok "python twine module available"
else
fail "Python module 'twine' not available for python3; install it with: python3 -m pip install --user build twine"; missing=1
fi
fi
else
ok "uv $(uv --version 2>&1 | awk '{print $2}')"
fi

Copilot uses AI. Check for mistakes.
Add workflow_dispatch publish workflows for:
- elevenlabs-moss (PyPI)
- moss-cli (PyPI)
- moss-md-indexer (npm)
- strands-agents-moss (PyPI)
- vapi-moss (PyPI)

Follows the same pattern as existing pipecat-moss, vercel-sdk,
and vitepress-plugin-moss workflows.
github-advanced-security[bot]

This comment was marked as resolved.

- Add || return 1 to critical commands in release functions to
  prevent publishing after failed builds (set -e suppression in if)
- Respect --npm-only/--pypi-only flags when selecting specific packages
- Add tomli fallback for Python <3.11 (tomllib not available)
- Add pnpm preflight check
- Add build/twine module checks when uv is not available
- Add permissions: contents: read to all PyPI workflow files (CodeQL)
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment thread scripts/release.sh Outdated
Comment on lines +126 to +127
if [[ -f "pnpm-lock.yaml" ]]; then
{ pnpm install --frozen-lockfile 2>/dev/null || pnpm install; } || return 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Preflight promises pnpm→npm fallback that release_npm never implements

The preflight check at line 61 warns: "packages with pnpm-lock.yaml will fall back to npm". However, release_npm at lines 126-127 only tries pnpm install twice when pnpm-lock.yaml is present — there is no fallback to npm install. If pnpm is not installed, both pnpm invocations fail and return 1 is triggered, causing the release to fail. A user who trusts the preflight message and skips installing pnpm will get a failed release for any package with a pnpm-lock.yaml (e.g. moss-md-indexer).

Prompt for agents
There is a mismatch between the preflight warning (scripts/release.sh:61) and the actual dependency install logic in release_npm (scripts/release.sh:126-127). The preflight says packages with pnpm-lock.yaml will fall back to npm, but the code only tries pnpm twice and then fails. Either: (1) update the install logic at lines 126-127 to fall back to npm install when pnpm is not available (e.g. check command -v pnpm and fall through to npm install), or (2) update the preflight message at line 61 to accurately say that the release will fail without pnpm.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

When pnpm is not installed, fall back to npm install instead of
failing, matching the preflight warning message.
strategy:
fail-fast: false
matrix:
python: ["3.10", "3.11", "3.12", "3.13"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3.14 ?

Comment thread scripts/release.sh
@@ -0,0 +1,343 @@
#!/usr/bin/env bash
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one time script right for releasing both python and js package ? do you see this script would have repeated use case in future?

Add Python 3.14 to the test matrix in all 5 PyPI publish workflows.
Add top-level permissions block to publish-pipecat-moss.yml to match
the other workflows and satisfy CodeQL security scanning.
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 6 new potential issues.

View 7 additional findings in Devin Review.

Open in Devin Review

fail-fast: false
matrix:
python: ["3.10", "3.11", "3.12", "3.13"]
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Python 3.14 in CI matrix but package declares requires-python <3.14

The pipecat-moss pyproject.toml declares requires-python = ">=3.10,<3.14" (packages/pipecat-moss/pyproject.toml), but this PR adds "3.14" to the build matrix. The smoke test step runs pip install --force-reinstall <wheel>, and pip will refuse to install the wheel on Python 3.14 because the wheel's Requires-Python metadata excludes it. This matrix entry will always fail.

Suggested change
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python: ["3.10", "3.11", "3.12", "3.13"]
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

strategy:
fail-fast: false
matrix:
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Python 3.14 in CI matrix but package declares requires-python <3.14

The elevenlabs-moss pyproject.toml declares requires-python = ">=3.10,<3.14" (packages/elevenlabs-moss/pyproject.toml), but the workflow matrix includes "3.14". The smoke test step runs pip install --force-reinstall <wheel>, and pip will refuse to install the wheel on Python 3.14 because the wheel's Requires-Python metadata excludes it. This matrix entry will always fail.

Suggested change
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python: ["3.10", "3.11", "3.12", "3.13"]
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

strategy:
fail-fast: false
matrix:
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Python 3.14 in CI matrix but package declares requires-python <3.14

The strands-agents-moss pyproject.toml declares requires-python = ">=3.10,<3.14" (packages/strands-agents-moss/pyproject.toml), but the workflow matrix includes "3.14". The smoke test step runs pip install --force-reinstall <wheel>, and pip will refuse to install the wheel on Python 3.14 because the wheel's Requires-Python metadata excludes it. This matrix entry will always fail.

Suggested change
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python: ["3.10", "3.11", "3.12", "3.13"]
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

strategy:
fail-fast: false
matrix:
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Python 3.14 in CI matrix but package declares requires-python <3.14

The vapi-moss pyproject.toml declares requires-python = ">=3.10,<3.14" (packages/vapi-moss/pyproject.toml), but the workflow matrix includes "3.14". The smoke test step runs pip install --force-reinstall <wheel>, and pip will refuse to install the wheel on Python 3.14 because the wheel's Requires-Python metadata excludes it. This matrix entry will always fail.

Suggested change
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python: ["3.10", "3.11", "3.12", "3.13"]
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +84 to +88
run: |
git config user.name "github-actions"
git config user.email "github-actions@users.noreply.github.com"
git tag "moss-md-indexer-v${VERSION}"
git push origin "moss-md-indexer-v${VERSION}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Missing tag existence check causes workflow failure on re-runs

Unlike all other publish workflows in this PR (e.g., publish-elevenlabs-moss.yml:102-111, publish-pipecat-moss.yml:142-151), the publish-moss-md-indexer.yml "Tag release" step does not check whether the tag already exists before creating and pushing it. If the workflow is re-dispatched for the same version (e.g., to retry a failed npm publish), git tag will fail with fatal: tag already exists and the step will error out.

Suggested change
run: |
git config user.name "github-actions"
git config user.email "github-actions@users.noreply.github.com"
git tag "moss-md-indexer-v${VERSION}"
git push origin "moss-md-indexer-v${VERSION}"
run: |
git fetch --tags --force
if git rev-parse "moss-md-indexer-v${VERSION}" >/dev/null 2>&1; then
echo "Tag moss-md-indexer-v${VERSION} already exists"
else
git config user.name "github-actions"
git config user.email "github-actions@users.noreply.github.com"
git tag "moss-md-indexer-v${VERSION}"
git push origin "moss-md-indexer-v${VERSION}"
fi
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +75 to +79
- name: Publish to npm
working-directory: ${{ env.PKG_DIR }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: pnpm publish --no-git-checks --access public
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 moss-md-indexer uses pnpm publish without --skip-existing equivalent

The publish-moss-md-indexer.yml:79 step uses pnpm publish --no-git-checks --access public without any mechanism to handle the case where the version already exists on npm (unlike the Python workflows which use twine upload --skip-existing). If the workflow is re-dispatched for the same version, the npm publish step will fail with a 403 error. This is consistent with pnpm publish not having a --skip-existing flag, but combined with the missing tag existence check (reported as a bug), re-runs are fragile.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@ashvathsureshkumar ashvathsureshkumar merged commit 7c68b7f into main Apr 10, 2026
19 checks passed
Atulsingh1155 pushed a commit to Atulsingh1155/moss that referenced this pull request Apr 30, 2026
## Summary
- Adds `scripts/release.sh` — a single script to build and publish all 8
Moss packages (3 npm, 5 PyPI)
- Supports `--dry-run`, `--npm-only`, `--pypi-only`, and selective
package publishing
- Includes preflight checks for required tooling and auth

## Packages covered
**npm:** `@moss-tools/md-indexer`, `@moss-tools/vercel-sdk`,
`vitepress-plugin-moss`
**PyPI:** `elevenlabs-moss`, `moss-cli`, `pipecat-moss`,
`strands-agents-moss`, `vapi-moss`

## Usage
```bash
./scripts/release.sh --dry-run          # verify builds
./scripts/release.sh                    # publish all
./scripts/release.sh vercel-sdk         # publish one
./scripts/release.sh --pypi-only        # publish only Python packages
```

## Test plan
- [x] Dry run completes successfully for all 8 packages
- [ ] npm publish with valid auth
- [ ] PyPI publish with valid auth
<!-- devin-review-badge-begin -->

---

<a href="https://app.devin.ai/review/usemoss/moss/pull/142"
target="_blank">
  <picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open with Devin">
  </picture>
</a>
<!-- devin-review-badge-end -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants