release.sh 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. #!/bin/bash
  2. # Roo Code CLI Release Script
  3. #
  4. # Usage:
  5. # ./apps/cli/scripts/release.sh [options] [version]
  6. #
  7. # Options:
  8. # --dry-run Run all steps except creating the GitHub release
  9. # --local Build for local testing only (no GitHub checks, no changelog prompts)
  10. # --install Install locally after building (only with --local)
  11. # --skip-verify Skip end-to-end verification tests (faster local builds)
  12. #
  13. # Examples:
  14. # ./apps/cli/scripts/release.sh # Use version from package.json
  15. # ./apps/cli/scripts/release.sh 0.1.0 # Specify version
  16. # ./apps/cli/scripts/release.sh --dry-run # Test the release flow without pushing
  17. # ./apps/cli/scripts/release.sh --dry-run 0.1.0 # Dry run with specific version
  18. # ./apps/cli/scripts/release.sh --local # Build for local testing
  19. # ./apps/cli/scripts/release.sh --local --install # Build and install locally
  20. # ./apps/cli/scripts/release.sh --local --skip-verify # Fast local build
  21. #
  22. # This script:
  23. # 1. Builds the extension and CLI
  24. # 2. Creates a tarball for the current platform
  25. # 3. Creates a GitHub release and uploads the tarball (unless --dry-run or --local)
  26. #
  27. # Prerequisites:
  28. # - GitHub CLI (gh) installed and authenticated (not needed for --local)
  29. # - pnpm installed
  30. # - Run from the monorepo root directory
  31. set -e
  32. # Parse arguments
  33. DRY_RUN=false
  34. LOCAL_BUILD=false
  35. LOCAL_INSTALL=false
  36. SKIP_VERIFY=false
  37. VERSION_ARG=""
  38. while [[ $# -gt 0 ]]; do
  39. case $1 in
  40. --dry-run)
  41. DRY_RUN=true
  42. shift
  43. ;;
  44. --local)
  45. LOCAL_BUILD=true
  46. shift
  47. ;;
  48. --install)
  49. LOCAL_INSTALL=true
  50. shift
  51. ;;
  52. --skip-verify)
  53. SKIP_VERIFY=true
  54. shift
  55. ;;
  56. -*)
  57. echo "Unknown option: $1" >&2
  58. exit 1
  59. ;;
  60. *)
  61. VERSION_ARG="$1"
  62. shift
  63. ;;
  64. esac
  65. done
  66. # Validate option combinations
  67. if [ "$LOCAL_INSTALL" = true ] && [ "$LOCAL_BUILD" = false ]; then
  68. echo "Error: --install can only be used with --local" >&2
  69. exit 1
  70. fi
  71. # Colors
  72. RED='\033[0;31m'
  73. GREEN='\033[0;32m'
  74. YELLOW='\033[1;33m'
  75. BLUE='\033[0;34m'
  76. BOLD='\033[1m'
  77. NC='\033[0m'
  78. info() { printf "${GREEN}==>${NC} %s\n" "$1"; }
  79. warn() { printf "${YELLOW}Warning:${NC} %s\n" "$1"; }
  80. error() { printf "${RED}Error:${NC} %s\n" "$1" >&2; exit 1; }
  81. step() { printf "${BLUE}${BOLD}[%s]${NC} %s\n" "$1" "$2"; }
  82. # Get script directory and repo root
  83. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  84. REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
  85. CLI_DIR="$REPO_ROOT/apps/cli"
  86. # Detect current platform
  87. detect_platform() {
  88. OS=$(uname -s | tr '[:upper:]' '[:lower:]')
  89. ARCH=$(uname -m)
  90. case "$OS" in
  91. darwin) OS="darwin" ;;
  92. linux) OS="linux" ;;
  93. *) error "Unsupported OS: $OS" ;;
  94. esac
  95. case "$ARCH" in
  96. x86_64|amd64) ARCH="x64" ;;
  97. arm64|aarch64) ARCH="arm64" ;;
  98. *) error "Unsupported architecture: $ARCH" ;;
  99. esac
  100. PLATFORM="${OS}-${ARCH}"
  101. }
  102. # Check prerequisites
  103. check_prerequisites() {
  104. step "1/8" "Checking prerequisites..."
  105. # Skip GitHub CLI checks for local builds
  106. if [ "$LOCAL_BUILD" = false ]; then
  107. if ! command -v gh &> /dev/null; then
  108. error "GitHub CLI (gh) is not installed. Install it with: brew install gh"
  109. fi
  110. if ! gh auth status &> /dev/null; then
  111. error "GitHub CLI is not authenticated. Run: gh auth login"
  112. fi
  113. fi
  114. if ! command -v pnpm &> /dev/null; then
  115. error "pnpm is not installed."
  116. fi
  117. if ! command -v node &> /dev/null; then
  118. error "Node.js is not installed."
  119. fi
  120. info "Prerequisites OK"
  121. }
  122. # Get version
  123. get_version() {
  124. if [ -n "$VERSION_ARG" ]; then
  125. VERSION="$VERSION_ARG"
  126. else
  127. VERSION=$(node -p "require('$CLI_DIR/package.json').version")
  128. fi
  129. # For local builds, append a local suffix with git short hash
  130. # This creates versions like: 0.1.0-local.abc1234
  131. if [ "$LOCAL_BUILD" = true ]; then
  132. GIT_SHORT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
  133. # Only append suffix if not already a local version
  134. if ! echo "$VERSION" | grep -qE '\-local\.'; then
  135. VERSION="${VERSION}-local.${GIT_SHORT_HASH}"
  136. fi
  137. fi
  138. # Validate semver format (allow -local.hash suffix)
  139. if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then
  140. error "Invalid version format: $VERSION (expected semver like 0.1.0)"
  141. fi
  142. TAG="cli-v$VERSION"
  143. info "Version: $VERSION (tag: $TAG)"
  144. }
  145. # Extract changelog content for a specific version
  146. # Returns the content between the version header and the next version header (or EOF)
  147. get_changelog_content() {
  148. CHANGELOG_FILE="$CLI_DIR/CHANGELOG.md"
  149. if [ ! -f "$CHANGELOG_FILE" ]; then
  150. warn "No CHANGELOG.md found at $CHANGELOG_FILE"
  151. CHANGELOG_CONTENT=""
  152. return
  153. fi
  154. # Try to find the version section (handles both "[0.0.43]" and "[0.0.43] - date" formats)
  155. # Also handles "Unreleased" marker
  156. VERSION_PATTERN="^\#\# \[${VERSION}\]"
  157. # Check if the version exists in the changelog
  158. if ! grep -qE "$VERSION_PATTERN" "$CHANGELOG_FILE"; then
  159. warn "No changelog entry found for version $VERSION"
  160. # Skip prompts for local builds
  161. if [ "$LOCAL_BUILD" = true ]; then
  162. info "Skipping changelog prompt for local build"
  163. CHANGELOG_CONTENT=""
  164. return
  165. fi
  166. warn "Please add an entry to $CHANGELOG_FILE before releasing"
  167. echo ""
  168. echo "Expected format:"
  169. echo " ## [$VERSION] - $(date +%Y-%m-%d)"
  170. echo " "
  171. echo " ### Added"
  172. echo " - Your changes here"
  173. echo ""
  174. read -p "Continue without changelog content? [y/N] " -n 1 -r
  175. echo
  176. if [[ ! $REPLY =~ ^[Yy]$ ]]; then
  177. error "Aborted. Please add a changelog entry and try again."
  178. fi
  179. CHANGELOG_CONTENT=""
  180. return
  181. fi
  182. # Extract content between this version and the next version header (or EOF)
  183. # Uses awk to capture everything between ## [VERSION] and the next ## [
  184. # Using index() with "[VERSION]" ensures exact matching (1.0.1 won't match 1.0.10)
  185. CHANGELOG_CONTENT=$(awk -v version="$VERSION" '
  186. BEGIN { found = 0; content = ""; target = "[" version "]" }
  187. /^## \[/ {
  188. if (found) { exit }
  189. if (index($0, target) > 0) { found = 1; next }
  190. }
  191. found { content = content $0 "\n" }
  192. END { print content }
  193. ' "$CHANGELOG_FILE")
  194. # Trim leading/trailing whitespace
  195. CHANGELOG_CONTENT=$(echo "$CHANGELOG_CONTENT" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
  196. if [ -n "$CHANGELOG_CONTENT" ]; then
  197. info "Found changelog content for version $VERSION"
  198. else
  199. warn "Changelog entry for $VERSION appears to be empty"
  200. fi
  201. }
  202. # Build everything
  203. build() {
  204. step "2/8" "Building extension bundle..."
  205. cd "$REPO_ROOT"
  206. pnpm bundle
  207. step "3/8" "Building CLI..."
  208. pnpm --filter @roo-code/cli build
  209. info "Build complete"
  210. }
  211. # Create release tarball
  212. create_tarball() {
  213. step "4/8" "Creating release tarball for $PLATFORM..."
  214. RELEASE_DIR="$REPO_ROOT/roo-cli-${PLATFORM}"
  215. TARBALL="roo-cli-${PLATFORM}.tar.gz"
  216. # Clean up any previous build
  217. rm -rf "$RELEASE_DIR"
  218. rm -f "$REPO_ROOT/$TARBALL"
  219. # Create directory structure
  220. mkdir -p "$RELEASE_DIR/bin"
  221. mkdir -p "$RELEASE_DIR/lib"
  222. mkdir -p "$RELEASE_DIR/extension"
  223. # Copy CLI dist files
  224. info "Copying CLI files..."
  225. cp -r "$CLI_DIR/dist/"* "$RELEASE_DIR/lib/"
  226. # Create package.json for npm install (runtime dependencies that can't be bundled)
  227. info "Creating package.json..."
  228. node -e "
  229. const pkg = require('$CLI_DIR/package.json');
  230. const newPkg = {
  231. name: '@roo-code/cli',
  232. version: '$VERSION',
  233. type: 'module',
  234. dependencies: {
  235. '@inkjs/ui': pkg.dependencies['@inkjs/ui'],
  236. '@trpc/client': pkg.dependencies['@trpc/client'],
  237. 'commander': pkg.dependencies.commander,
  238. 'fuzzysort': pkg.dependencies.fuzzysort,
  239. 'ink': pkg.dependencies.ink,
  240. 'p-wait-for': pkg.dependencies['p-wait-for'],
  241. 'react': pkg.dependencies.react,
  242. 'superjson': pkg.dependencies.superjson,
  243. 'zustand': pkg.dependencies.zustand
  244. }
  245. };
  246. console.log(JSON.stringify(newPkg, null, 2));
  247. " > "$RELEASE_DIR/package.json"
  248. # Copy extension bundle
  249. info "Copying extension bundle..."
  250. cp -r "$REPO_ROOT/src/dist/"* "$RELEASE_DIR/extension/"
  251. # Add package.json to extension directory to mark it as CommonJS
  252. # This is necessary because the main package.json has "type": "module"
  253. # but the extension bundle is CommonJS
  254. echo '{"type": "commonjs"}' > "$RELEASE_DIR/extension/package.json"
  255. # Find and copy ripgrep binary
  256. # The extension looks for ripgrep at: appRoot/node_modules/@vscode/ripgrep/bin/rg
  257. # The CLI sets appRoot to the CLI package root, so we need to put ripgrep there
  258. info "Looking for ripgrep binary..."
  259. RIPGREP_PATH=$(find "$REPO_ROOT/node_modules" -path "*/@vscode/ripgrep/bin/rg" -type f 2>/dev/null | head -1)
  260. if [ -n "$RIPGREP_PATH" ] && [ -f "$RIPGREP_PATH" ]; then
  261. info "Found ripgrep at: $RIPGREP_PATH"
  262. # Create the expected directory structure for the extension to find ripgrep
  263. mkdir -p "$RELEASE_DIR/node_modules/@vscode/ripgrep/bin"
  264. cp "$RIPGREP_PATH" "$RELEASE_DIR/node_modules/@vscode/ripgrep/bin/"
  265. chmod +x "$RELEASE_DIR/node_modules/@vscode/ripgrep/bin/rg"
  266. # Also keep a copy in bin/ for direct access
  267. mkdir -p "$RELEASE_DIR/bin"
  268. cp "$RIPGREP_PATH" "$RELEASE_DIR/bin/"
  269. chmod +x "$RELEASE_DIR/bin/rg"
  270. else
  271. warn "ripgrep binary not found - users will need ripgrep installed"
  272. fi
  273. # Create the wrapper script
  274. info "Creating wrapper script..."
  275. cat > "$RELEASE_DIR/bin/roo" << 'WRAPPER_EOF'
  276. #!/usr/bin/env node
  277. import { fileURLToPath } from 'url';
  278. import { dirname, join } from 'path';
  279. const __filename = fileURLToPath(import.meta.url);
  280. const __dirname = dirname(__filename);
  281. // Set environment variables for the CLI
  282. // ROO_CLI_ROOT is the installed CLI package root (where node_modules/@vscode/ripgrep is)
  283. process.env.ROO_CLI_ROOT = join(__dirname, '..');
  284. process.env.ROO_EXTENSION_PATH = join(__dirname, '..', 'extension');
  285. process.env.ROO_RIPGREP_PATH = join(__dirname, 'rg');
  286. // Import and run the actual CLI
  287. await import(join(__dirname, '..', 'lib', 'index.js'));
  288. WRAPPER_EOF
  289. chmod +x "$RELEASE_DIR/bin/roo"
  290. # Create empty .env file to suppress dotenvx warnings
  291. touch "$RELEASE_DIR/.env"
  292. # Create empty .env file to suppress dotenvx warnings
  293. touch "$RELEASE_DIR/.env"
  294. # Create tarball
  295. info "Creating tarball..."
  296. cd "$REPO_ROOT"
  297. tar -czvf "$TARBALL" "$(basename "$RELEASE_DIR")"
  298. # Clean up release directory
  299. rm -rf "$RELEASE_DIR"
  300. # Show size
  301. TARBALL_PATH="$REPO_ROOT/$TARBALL"
  302. TARBALL_SIZE=$(ls -lh "$TARBALL_PATH" | awk '{print $5}')
  303. info "Created: $TARBALL ($TARBALL_SIZE)"
  304. }
  305. # Verify local installation
  306. verify_local_install() {
  307. if [ "$SKIP_VERIFY" = true ]; then
  308. step "5/8" "Skipping verification (--skip-verify)"
  309. return
  310. fi
  311. step "5/8" "Verifying local installation..."
  312. VERIFY_DIR="$REPO_ROOT/.verify-release"
  313. VERIFY_INSTALL_DIR="$VERIFY_DIR/cli"
  314. VERIFY_BIN_DIR="$VERIFY_DIR/bin"
  315. # Clean up any previous verification directory
  316. rm -rf "$VERIFY_DIR"
  317. mkdir -p "$VERIFY_DIR"
  318. # Run the actual install script with the local tarball
  319. info "Running install script with local tarball..."
  320. TARBALL_PATH="$REPO_ROOT/$TARBALL"
  321. ROO_LOCAL_TARBALL="$TARBALL_PATH" \
  322. ROO_INSTALL_DIR="$VERIFY_INSTALL_DIR" \
  323. ROO_BIN_DIR="$VERIFY_BIN_DIR" \
  324. ROO_VERSION="$VERSION" \
  325. "$CLI_DIR/install.sh" || {
  326. echo ""
  327. warn "Install script failed. Showing tarball contents:"
  328. tar -tzf "$TARBALL_PATH" 2>&1 || true
  329. echo ""
  330. rm -rf "$VERIFY_DIR"
  331. error "Installation verification failed! The install script could not complete successfully."
  332. }
  333. # Verify the CLI runs correctly with basic commands
  334. info "Testing installed CLI..."
  335. # Test --help
  336. if ! "$VERIFY_BIN_DIR/roo" --help > /dev/null 2>&1; then
  337. echo ""
  338. warn "CLI --help output:"
  339. "$VERIFY_BIN_DIR/roo" --help 2>&1 || true
  340. echo ""
  341. rm -rf "$VERIFY_DIR"
  342. error "CLI --help check failed! The release tarball may have missing dependencies."
  343. fi
  344. info "CLI --help check passed"
  345. # Test --version
  346. if ! "$VERIFY_BIN_DIR/roo" --version > /dev/null 2>&1; then
  347. echo ""
  348. warn "CLI --version output:"
  349. "$VERIFY_BIN_DIR/roo" --version 2>&1 || true
  350. echo ""
  351. rm -rf "$VERIFY_DIR"
  352. error "CLI --version check failed! The release tarball may have missing dependencies."
  353. fi
  354. info "CLI --version check passed"
  355. # Run a simple end-to-end test to verify the CLI actually works
  356. info "Running end-to-end verification test..."
  357. # Create a temporary workspace for the test
  358. VERIFY_WORKSPACE="$VERIFY_DIR/workspace"
  359. mkdir -p "$VERIFY_WORKSPACE"
  360. # Run the CLI with a simple prompt
  361. if timeout 60 "$VERIFY_BIN_DIR/roo" --yes --oneshot -w "$VERIFY_WORKSPACE" "1+1=?" > "$VERIFY_DIR/test-output.log" 2>&1; then
  362. info "End-to-end test passed"
  363. else
  364. EXIT_CODE=$?
  365. echo ""
  366. warn "End-to-end test failed (exit code: $EXIT_CODE). Output:"
  367. cat "$VERIFY_DIR/test-output.log" 2>&1 || true
  368. echo ""
  369. rm -rf "$VERIFY_DIR"
  370. error "CLI end-to-end test failed! The CLI may be broken."
  371. fi
  372. # Clean up verification directory
  373. cd "$REPO_ROOT"
  374. rm -rf "$VERIFY_DIR"
  375. info "Local verification passed!"
  376. }
  377. # Create checksum
  378. create_checksum() {
  379. step "6/8" "Creating checksum..."
  380. cd "$REPO_ROOT"
  381. if command -v sha256sum &> /dev/null; then
  382. sha256sum "$TARBALL" > "${TARBALL}.sha256"
  383. elif command -v shasum &> /dev/null; then
  384. shasum -a 256 "$TARBALL" > "${TARBALL}.sha256"
  385. else
  386. warn "No sha256sum or shasum found, skipping checksum"
  387. return
  388. fi
  389. info "Checksum: $(cat "${TARBALL}.sha256")"
  390. }
  391. # Check if release already exists
  392. check_existing_release() {
  393. step "7/8" "Checking for existing release..."
  394. if gh release view "$TAG" &> /dev/null; then
  395. warn "Release $TAG already exists"
  396. read -p "Do you want to delete it and create a new one? [y/N] " -n 1 -r
  397. echo
  398. if [[ $REPLY =~ ^[Yy]$ ]]; then
  399. info "Deleting existing release..."
  400. gh release delete "$TAG" --yes
  401. # Also delete the tag if it exists
  402. git tag -d "$TAG" 2>/dev/null || true
  403. git push origin ":refs/tags/$TAG" 2>/dev/null || true
  404. else
  405. error "Aborted. Use a different version or delete the existing release manually."
  406. fi
  407. fi
  408. }
  409. # Create GitHub release
  410. create_release() {
  411. step "8/8" "Creating GitHub release..."
  412. cd "$REPO_ROOT"
  413. # Get the current commit SHA for the release target
  414. COMMIT_SHA=$(git rev-parse HEAD)
  415. # Verify the commit exists on GitHub before attempting to create the release
  416. # This prevents the "Release.target_commitish is invalid" error
  417. info "Verifying commit ${COMMIT_SHA:0:8} exists on GitHub..."
  418. git fetch origin 2>/dev/null || true
  419. if ! git branch -r --contains "$COMMIT_SHA" 2>/dev/null | grep -q "origin/"; then
  420. warn "Commit ${COMMIT_SHA:0:8} has not been pushed to GitHub"
  421. echo ""
  422. echo "The release script needs to create a release at your current commit,"
  423. echo "but this commit hasn't been pushed to GitHub yet."
  424. echo ""
  425. read -p "Push current branch to origin now? [Y/n] " -n 1 -r
  426. echo
  427. if [[ ! $REPLY =~ ^[Nn]$ ]]; then
  428. info "Pushing to origin..."
  429. git push origin HEAD || error "Failed to push to origin. Please push manually and try again."
  430. else
  431. error "Aborted. Please push your commits to GitHub and try again."
  432. fi
  433. fi
  434. info "Commit verified on GitHub"
  435. # Build the What's New section from changelog content
  436. WHATS_NEW_SECTION=""
  437. if [ -n "$CHANGELOG_CONTENT" ]; then
  438. WHATS_NEW_SECTION="## What's New
  439. $CHANGELOG_CONTENT
  440. "
  441. fi
  442. RELEASE_NOTES=$(cat << EOF
  443. ${WHATS_NEW_SECTION}## Installation
  444. \`\`\`bash
  445. curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh
  446. \`\`\`
  447. Or install a specific version:
  448. \`\`\`bash
  449. ROO_VERSION=$VERSION curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh
  450. \`\`\`
  451. ## Requirements
  452. - Node.js 20 or higher
  453. - macOS (Intel or Apple Silicon) or Linux (x64 or ARM64)
  454. ## Usage
  455. \`\`\`bash
  456. # Run a task
  457. roo "What is this project?"
  458. # See all options
  459. roo --help
  460. \`\`\`
  461. ## Platform Support
  462. This release includes:
  463. - \`roo-cli-${PLATFORM}.tar.gz\` - Built on $(uname -s) $(uname -m)
  464. > **Note:** Additional platforms will be added as needed. If you need a different platform, please open an issue.
  465. ## Checksum
  466. \`\`\`
  467. $(cat "${TARBALL}.sha256" 2>/dev/null || echo "N/A")
  468. \`\`\`
  469. EOF
  470. )
  471. info "Creating release at commit: ${COMMIT_SHA:0:8}"
  472. # Create release (gh will create the tag automatically)
  473. info "Creating release..."
  474. RELEASE_FILES="$TARBALL"
  475. if [ -f "${TARBALL}.sha256" ]; then
  476. RELEASE_FILES="$RELEASE_FILES ${TARBALL}.sha256"
  477. fi
  478. gh release create "$TAG" \
  479. --title "Roo Code CLI v$VERSION" \
  480. --notes "$RELEASE_NOTES" \
  481. --prerelease \
  482. --target "$COMMIT_SHA" \
  483. $RELEASE_FILES
  484. info "Release created!"
  485. }
  486. # Cleanup
  487. cleanup() {
  488. info "Cleaning up..."
  489. cd "$REPO_ROOT"
  490. rm -f "$TARBALL" "${TARBALL}.sha256"
  491. }
  492. # Print summary
  493. print_summary() {
  494. echo ""
  495. printf "${GREEN}${BOLD}✓ Release v$VERSION created successfully!${NC}\n"
  496. echo ""
  497. echo " Release URL: https://github.com/RooCodeInc/Roo-Code/releases/tag/$TAG"
  498. echo ""
  499. echo " Install with:"
  500. echo " curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh"
  501. echo ""
  502. }
  503. # Print dry-run summary
  504. print_dry_run_summary() {
  505. echo ""
  506. printf "${YELLOW}${BOLD}✓ Dry run complete for v$VERSION${NC}\n"
  507. echo ""
  508. echo " The following artifacts were created:"
  509. echo " - $TARBALL"
  510. if [ -f "${TARBALL}.sha256" ]; then
  511. echo " - ${TARBALL}.sha256"
  512. fi
  513. echo ""
  514. echo " To complete the release, run without --dry-run:"
  515. echo " ./apps/cli/scripts/release.sh $VERSION"
  516. echo ""
  517. echo " Or manually upload the tarball to a new GitHub release."
  518. echo ""
  519. }
  520. # Print local build summary
  521. print_local_summary() {
  522. echo ""
  523. printf "${GREEN}${BOLD}✓ Local build complete for v$VERSION${NC}\n"
  524. echo ""
  525. echo " Tarball: $REPO_ROOT/$TARBALL"
  526. if [ -f "${TARBALL}.sha256" ]; then
  527. echo " Checksum: $REPO_ROOT/${TARBALL}.sha256"
  528. fi
  529. echo ""
  530. echo " To install manually:"
  531. echo " ROO_LOCAL_TARBALL=$REPO_ROOT/$TARBALL ./apps/cli/install.sh"
  532. echo ""
  533. echo " Or re-run with --install to install automatically:"
  534. echo " ./apps/cli/scripts/release.sh --local --install"
  535. echo ""
  536. }
  537. # Install locally using the install script
  538. install_local() {
  539. step "7/8" "Installing locally..."
  540. TARBALL_PATH="$REPO_ROOT/$TARBALL"
  541. ROO_LOCAL_TARBALL="$TARBALL_PATH" \
  542. ROO_VERSION="$VERSION" \
  543. "$CLI_DIR/install.sh" || {
  544. error "Local installation failed!"
  545. }
  546. info "Local installation complete!"
  547. }
  548. # Print local install summary
  549. print_local_install_summary() {
  550. echo ""
  551. printf "${GREEN}${BOLD}✓ Local build installed for v$VERSION${NC}\n"
  552. echo ""
  553. echo " Tarball: $REPO_ROOT/$TARBALL"
  554. echo " Installed to: ~/.roo/cli"
  555. echo " Binary: ~/.local/bin/roo"
  556. echo ""
  557. echo " Test it out:"
  558. echo " roo --version"
  559. echo " roo --help"
  560. echo ""
  561. }
  562. # Main
  563. main() {
  564. echo ""
  565. printf "${BLUE}${BOLD}"
  566. echo " ╭─────────────────────────────────╮"
  567. echo " │ Roo Code CLI Release Script │"
  568. echo " ╰─────────────────────────────────╯"
  569. printf "${NC}"
  570. if [ "$DRY_RUN" = true ]; then
  571. printf "${YELLOW} (DRY RUN MODE)${NC}\n"
  572. elif [ "$LOCAL_BUILD" = true ]; then
  573. printf "${YELLOW} (LOCAL BUILD MODE)${NC}\n"
  574. fi
  575. echo ""
  576. detect_platform
  577. check_prerequisites
  578. get_version
  579. get_changelog_content
  580. build
  581. create_tarball
  582. verify_local_install
  583. create_checksum
  584. if [ "$LOCAL_BUILD" = true ]; then
  585. step "7/8" "Skipping GitHub checks (local build)"
  586. if [ "$LOCAL_INSTALL" = true ]; then
  587. install_local
  588. print_local_install_summary
  589. else
  590. step "8/8" "Skipping installation (use --install to auto-install)"
  591. print_local_summary
  592. fi
  593. elif [ "$DRY_RUN" = true ]; then
  594. step "7/8" "Skipping existing release check (dry run)"
  595. step "8/8" "Skipping GitHub release creation (dry run)"
  596. print_dry_run_summary
  597. else
  598. check_existing_release
  599. create_release
  600. cleanup
  601. print_summary
  602. fi
  603. }
  604. main