xeploy
v1.3.2
Published
Interactive GitHub release pipeline CLI with multi-environment releases, meta-repo submodules, and branch sync via gh CLI
Maintainers
Readme
__ _______ ____ _ _____ __
\ \/ / ____| _ \| | / _ \ \ / /
\ /| _| | |_) | | | | | \ V /
/ \| |___| __/| |__| |_| || |
/_/\_\_____|_| |_____\___/ |_|xeploy
Interactive GitHub release pipeline CLI with multi-environment releases, meta-repo submodules, and branch sync via gh CLI.
Overview
xeploy automates the GitHub release lifecycle through a guided interactive CLI:
- Multi-environment releases — select staging, uat, sandbox, and/or production in one run; RC envs share one pre-release tag, final envs share one production tag.
- Production without RC — create a final production release even when no
-rc.Ntag exists. - Release branches and PRs — optionally create
release/X.Y.Zbranches and open PRs per environment instead of direct merges. - Meta-repo support — parallel releases across git submodules, then a serial umbrella release.
- Old release management — list past RC releases and promote or re-publish them.
Release notes are auto-generated by the GitHub CLI (when enabled), diffed against the previous release tag.
Prerequisites
| Tool | Version |
| ----------------------------------------------------------------------- | ---------- |
| Node.js | ≥ 18 |
| GitHub CLI (gh) | any recent |
| Git | any |
The gh CLI must be authenticated (gh auth login) before running.
Installation
npm install --save-dev xeploy
# or
yarn add -D xeploy
# or
pnpm add -D xeploy
# or
bun add -D xeployUsage
npx xeploy
# or
bunx xeployOr add to your package.json scripts:
{
"scripts": {
"deploy": "xeploy"
}
}Then run:
npm run deploy
# or
bun run deployMakefile integration
deploy:
npx xeployInteractive flow
🚀 xeploy
? What would you like to do?
▶ Deploy new release
Deploy old release
Config
→ Deploy new release
? Select repos to bump (mono/meta only; multiselect, umbrella + subprojects all checked by default)
▶ Umbrella (this repo)
frontend
backend
? Select release environment (single choice; only envs with a branch in `environments`)
▶ staging release (RC)
production release (final)
? Select bump type (current latest: 1.2.3-rc.4)
▶ Release Candidate → 1.2.3-rc.5
Bug Fix → 1.2.4-rc.1
Minor → 1.3.0-rc.1
Major → 2.0.0-rc.1
Custom
→ Config
Edit .xeploy.json settings interactively
→ Deploy old release
Lists all previous RC tags
? What to do with 1.2.1-rc.2?
▶ Promote to production → 1.2.1 (final)
Re-publish as same RC → 1.2.1-rc.2On first run, if .xeploy.json is missing, you are prompted to create one with auto-detected settings.
Semver conventions
| Tag format | Meaning |
| ------------ | ------------------------------------ |
| X.Y.Z-rc.N | Staging / UAT pre-release |
| X.Y.Z | Final release (sandbox / production) |
No v prefix is used. RC tags sort lower than final tags for the same X.Y.Z.
Empty-repo behaviour
When no tags exist yet, the first release defaults to 0.1.0-rc.1 (or 1.0.0-rc.1 for a major bump). Release notes cover the full commit history.
Configuration
Create .xeploy.json in your project root (or let the CLI create it on first run):
{
"type": "default",
"subprojectsDir": null,
"tag_prefix": "v",
"generate_release_notes": true,
"create_production_release_branch": true,
"create_tag": true,
"create_pr": {
"staging": false,
"uat": false,
"sandbox": false,
"production": false
},
"environments": {
"develop": "develop",
"staging": "staging",
"uat": "uat",
"sandbox": "sandbox",
"production": "main"
}
}| Option | Type | Default | Description |
| ---------------------------------- | ----------- | -------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ---------------------- |
| type | "default" | "mono" | "meta" | auto-detected | Repository layout type |
| subprojectsDir | string | null | auto-detected | Parent directory for mono/meta sub-projects |
| tag_prefix | string | auto-detected | Prefix for git/GitHub tags (e.g. "v" → v1.0.0); package.json stays unprefixed |
| generate_release_notes | boolean | true | Generate GitHub release notes vs previous tag |
| create_production_release_branch | boolean | true | Create release/X.Y.Z before production merge/PR |
| create_tag | boolean | true | Create git tag and GitHub release; when false, only bump package.json |
| create_pr | object | all false | Open PR instead of direct merge per environment |
| environments | object | branch-matched | Maps env names to git branch names (null if missing); only non-null release envs appear in "Select release environments" |
| subprojects | array | auto-detected | Per-subproject config when type is "mono" or "meta" — see below |
The version field of each subproject's own package.json is always what gets bumped — there's no separate versionFiles list to maintain.
Repository types
| Type | Detection | Behaviour |
| --------- | ----------------------------- | ------------------------------------------ |
| default | single package.json | standard single-repo release |
| mono | multiple package.json files | version-bumps all configured packages |
| meta | .gitmodules present | parallel submodule releases, then umbrella |
Subproject config
When type is "mono" or "meta", each subproject can be disabled from release/bump entirely with "enabled": false — disabled subprojects are skipped and don't show up in the "Select repos to bump" step. "meta" submodules (separate repos) can additionally override create_tag, create_pr, and environments; "mono" subprojects share the umbrella's create_tag/create_pr/environments since they release together as one repo.
{
"type": "mono",
"subprojectsDir": "apps",
"subprojects": [
{ "repo": "frontend", "enabled": true },
{ "repo": "internal-tool", "enabled": false }
]
}{
"type": "meta",
"subprojectsDir": "apps",
"subprojects": [
{
"repo": "frontend",
"enabled": true,
"create_tag": true,
"create_pr": {
"staging": true,
"uat": true,
"sandbox": true,
"production": true
},
"environments": {
"develop": "develop",
"staging": "staging",
"uat": "uat",
"sandbox": "sandbox",
"production": "main"
}
}
]
}Programmatic API
All internals are exported for use in custom scripts:
import {
loadConfig,
createDefaultConfig,
flowNewRelease,
flowOldRelease,
executeReleasePlan,
getTags,
getLatestTag,
parseSemVer,
formatSemVer,
bumpVersion,
} from "xeploy";
const config = loadConfig(process.cwd()) ?? createDefaultConfig(process.cwd());
const tags = getTags();
await flowNewRelease(tags, config, process.cwd());Development
git clone https://github.com/Hussain7Abbas/xeploy.git
cd xeploy
make install
make build| Command | Description |
| ------------------ | ----------------------------------------- |
| make build | Compile TypeScript → dist/ |
| make dev | Watch mode |
| make clean | Remove dist/ |
| make typecheck | Type-check without emitting |
| make lint | Biome lint |
| make format | Biome format |
| make check | Biome check + format |
| make publish-dry | Preview npm publish |
| make publish | Build + publish to npm |
| make deploy | Run xeploy CLI, then optional npm publish |
Contributing
Pull requests are welcome. Please open an issue first to discuss significant changes.
License
MIT © Hussain Abbas
