name: Test, Build, and Deploy on: push: branches: ['**'] env: REGISTRY: registry.rose-ash.com:5000 APP_DIR: /root/rose-ash BUILD_DIR: /root/rose-ash-ci jobs: test-build-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install tools run: | apt-get update && apt-get install -y --no-install-recommends openssh-client - name: Set up SSH env: SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} run: | mkdir -p ~/.ssh echo "$SSH_KEY" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null || true - name: Sync CI build directory env: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} run: | ssh "root@$DEPLOY_HOST" " BUILD=${{ env.BUILD_DIR }} ORIGIN=\$(git -C ${{ env.APP_DIR }} remote get-url origin) if [ ! -d \"\$BUILD/.git\" ]; then git clone \"\$ORIGIN\" \"\$BUILD\" fi cd \"\$BUILD\" git fetch origin git reset --hard origin/${{ github.ref_name }} " - name: Test SX language suite env: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} run: | ssh "root@$DEPLOY_HOST" " cd ${{ env.BUILD_DIR }} echo '=== Building SX test image ===' docker build \ -f .gitea/Dockerfile.test \ -t sx-test:${{ github.sha }} \ . echo '=== Running SX tests ===' docker run --rm sx-test:${{ github.sha }} " - name: Build and deploy changed apps env: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} run: | ssh "root@$DEPLOY_HOST" " cd ${{ env.BUILD_DIR }} # Detect changes using push event SHAs (not local checkout state) BEFORE='${{ github.event.before }}' AFTER='${{ github.sha }}' REBUILD_ALL=false if [ -z \"\$BEFORE\" ] || [ \"\$BEFORE\" = '0000000000000000000000000000000000000000' ] || ! git cat-file -e \"\$BEFORE\" 2>/dev/null; then # New branch, force push, or unreachable parent — rebuild all REBUILD_ALL=true else CHANGED=\$(git diff --name-only \$BEFORE \$AFTER) if echo \"\$CHANGED\" | grep -q '^shared/'; then REBUILD_ALL=true fi if echo \"\$CHANGED\" | grep -q '^docker-compose.yml'; then REBUILD_ALL=true fi fi # Map compose service name to source directory app_dir() { case \"\$1\" in sx_docs) echo \"sx\" ;; *) echo \"\$1\" ;; esac } for app in blog market cart events federation account relations likes orders test sx_docs; do dir=\$(app_dir \"\$app\") IMAGE_EXISTS=\$(docker image ls -q ${{ env.REGISTRY }}/\$app:latest 2>/dev/null) if [ \"\$REBUILD_ALL\" = true ] || echo \"\$CHANGED\" | grep -q \"^\$dir/\" || [ -z \"\$IMAGE_EXISTS\" ]; then echo \"Building \$app...\" docker build \ --build-arg CACHEBUST=\$(date +%s) \ -f \$dir/Dockerfile \ -t ${{ env.REGISTRY }}/\$app:latest \ -t ${{ env.REGISTRY }}/\$app:${{ github.sha }} \ . docker push ${{ env.REGISTRY }}/\$app:latest docker push ${{ env.REGISTRY }}/\$app:${{ github.sha }} else echo \"Skipping \$app (no changes)\" fi done # Deploy swarm stacks only on main branch if [ '${{ github.ref_name }}' = 'main' ]; then source ${{ env.APP_DIR }}/.env docker stack deploy --resolve-image always -c docker-compose.yml rose-ash echo 'Waiting for swarm services to update...' sleep 10 docker stack services rose-ash # Deploy sx-web standalone stack (sx-web.org) SX_REBUILT=false if [ \"\$REBUILD_ALL\" = true ] || echo \"\$CHANGED\" | grep -q '^sx/'; then SX_REBUILT=true fi if [ \"\$SX_REBUILT\" = true ]; then echo 'Deploying sx-web stack (sx-web.org)...' docker stack deploy --resolve-image always -c /root/sx-web/docker-compose.yml sx-web sleep 5 docker stack services sx-web docker service update --force caddy_caddy 2>/dev/null || true fi else echo 'Skipping swarm deploy (branch: ${{ github.ref_name }})' fi # Dev stack uses working tree (bind-mounted source + auto-reload) cd ${{ env.APP_DIR }} echo 'Deploying dev stack...' docker compose -p rose-ash-dev -f docker-compose.yml -f docker-compose.dev.yml up -d echo 'Dev stack deployed' docker compose -p rose-ash-dev -f docker-compose.yml -f docker-compose.dev.yml ps "