Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .github/workflows/deploy-production.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Deploy to Production Server

on:
push:
branches:
- master
workflow_dispatch:

jobs:
deploy:
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'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build library
run: npm run build

- name: Build Storybook
run: npm run build-storybook

- name: Setup SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H ${{ secrets.PRODUCTION_HOST }} >> ~/.ssh/known_hosts

- name: Deploy to production server
run: |
rsync -avz --delete \
--exclude '.git' \
--exclude '.github' \
--exclude 'logs/*.log' \
--exclude '.env*' \
--exclude 'coverage' \
--exclude '.DS_Store' \
--exclude 'debug-storybook.log' \
-e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no" \
./ ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }}:${{ secrets.PRODUCTION_PATH }}/

- name: Restart PM2 process
run: |
ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no \
${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }} << 'EOF'
cd ${{ secrets.PRODUCTION_PATH }}
echo "🔄 Restarting PM2 storybook process..."
pm2 restart storybook
echo "✅ PM2 process restarted successfully"
echo ""
echo "📊 PM2 Status:"
pm2 list
echo ""
echo "📁 Deployed to: $(pwd)"
echo "📅 Deployment time: $(date)"
EOF

- name: Cleanup SSH key
if: always()
run: rm -f ~/.ssh/deploy_key

- name: Deployment summary
if: success()
run: |
echo "✅ Deployment completed successfully!"
echo "📂 Files deployed to production server"
31 changes: 31 additions & 0 deletions bin/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,37 @@ echo -e "\nSyncing files..."

rsync -av "$SRC_DIR/" "$BUILD_DIR" --exclude-from "$SRC_DIR/.distignore"

# Trim the manifest consumers receive. npm's git fetcher runs a nested
# `npm install --include=dev` inside any git dependency declaring an install
# script, and our postinstall makes force-ui one, so every devDependency named
# here gets re-resolved live in every consumer's CI.
# Errors are handled explicitly: `bash bin/release.sh` ignores the shebang's -e.
echo -e "\nTrimming package.json for distribution..."
DIST_MANIFEST="$BUILD_DIR/package.json" node <<'NODE' || { echo "ERROR: could not trim the distribution manifest." >&2; exit 1; }
const fs = require( 'fs' );
const file = process.env.DIST_MANIFEST;
const pkg = JSON.parse( fs.readFileSync( file, 'utf8' ) );

// postinstall -> patch-package is what applies the Lexical patches in a
// consumer's tree; never ship a manifest that has lost it.
if ( pkg.scripts?.postinstall !== 'node apply-patches.cjs' || ! pkg.dependencies?.[ 'patch-package' ] ) {
throw new Error( 'refusing to trim: postinstall or patch-package is missing' );
}

delete pkg.devDependencies;
pkg.scripts = { postinstall: pkg.scripts.postinstall };

fs.writeFileSync( file, JSON.stringify( pkg, null, 4 ) + '\n' );
NODE

# Pin what the nested install resolves, so a publish between releases cannot
# break consumers. `files` keeps this out of the packed tarball.
echo -e "\nResolving distribution lockfile..."
npm install --package-lock-only --ignore-scripts --no-audit --no-fund || {
echo "ERROR: could not resolve the distribution lockfile." >&2
exit 1
}

# Add changed files
git add .

Expand Down
Loading