asxpio/.forgejo/workflows/deploy.yaml
Sergei Poljanski 0fbb6ee809
All checks were successful
Build and Deploy to Production / test (push) Successful in 18s
Build and Deploy to Production / build (push) Successful in 49s
Build and Deploy to Production / deploy (push) Successful in 31s
invoices: multi-crypto payment support
One asset per invoice from a registry (lib/crypto_asset.rb): BTC, LTC,
ETH, XMR, SOL, ALGO, USDT/USDC on ERC-20/TRC-20/BEP-20/Solana/Algorand.
Migration 003 generalizes the ltc_* columns to crypto_* + crypto_coin
(existing LTC invoices backfilled). QR payload adapts per asset: BIP21
amount URIs where supported, bare address for tokens with a network
hint on the PDF. Default addresses come from the CRYPTO_ADDRESSES
secret (JSON code=>address); LTC_ADDRESS still works as legacy.
2026-07-03 02:01:57 +04:00

174 lines
6 KiB
YAML

name: Build and Deploy to Production
on:
push:
branches:
- main
jobs:
# Same job as in test.yaml (which covers non-main branches); duplicated here
# so a red suite blocks the build+deploy — Forgejo has no cross-workflow needs.
test:
runs-on: nix-latest
services:
postgres:
image: postgres:17-alpine
env:
POSTGRES_USER: postgres
POSTGRES_HOST_AUTH_METHOD: trust
POSTGRES_DB: asxpio_test
steps:
- name: Prepare container for actions
run: |
echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf
# node for JS actions (checkout); git-minimal is already in the image
nix-env -iA nixpkgs.nodejs_22
- name: Checkout
uses: actions/checkout@v4
- name: Cache gems
uses: actions/cache@v4
with:
path: .gems
key: gems-${{ hashFiles('Gemfile.lock') }}
- name: Wait for Postgres
run: |
for i in $(seq 1 30); do
nix develop -c pg_isready -h postgres -U postgres && exit 0
sleep 2
done
echo "Postgres service never became ready" >&2
exit 1
- name: Run test suite
env:
TEST_DATABASE_URL: postgres://postgres@postgres:5432/asxpio_test
run: nix develop -c bundle exec rake test
build:
runs-on: arch-latest
needs: test
container:
image: gcr.io/kaniko-project/executor:debug
outputs:
image_tag: ${{ steps.build_image.outputs.image_tag }}
steps:
- name: Build and push Docker Image using Kaniko
id: build_image
run: |
# Tags
SHORT_SHA=${GITHUB_SHA::8}
IMAGE_BASE=${{ secrets.FORGEJO_REGISTRY }}/${{ secrets.FORGEJO_USER }}/asxpio
IMAGE_TAG=${IMAGE_BASE}:${SHORT_SHA}
IMAGE_LATEST=${IMAGE_BASE}:latest
# Auth Conf
mkdir -p /kaniko/.docker
echo "{\"auths\":{\"${{ secrets.FORGEJO_REGISTRY }}\":{\"auth\":\"$(echo -n ${{ secrets.FORGEJO_USER }}:${{ secrets.FORGEJO_TOKEN }} | base64)\"}}}" > /kaniko/.docker/config.json
# Build & push
/kaniko/executor \
--context=git://${{ secrets.FORGEJO_REGISTRY }}/${{ github.repository }}.git \
--git=branch=${{ github.ref_name }} \
--destination=$IMAGE_TAG \
--destination=$IMAGE_LATEST
# Output the specific tag for deployment
echo "image_tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT
deploy:
runs-on: arch-latest
needs: build
steps:
- name: Install dependencies
run: |
pacman -Syu --noconfirm nodejs openssh rsync
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy docker-compose.yml
uses: easingthemes/ssh-deploy@v5.1.0
with:
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
REMOTE_HOST: ${{ secrets.DEPLOY_IP }}
REMOTE_USER: ${{ secrets.DEPLOY_USER }}
SOURCE: "docker-compose.yml"
TARGET: "/opt/asxpio/"
- name: Deploy .env from secrets
uses: appleboy/ssh-action@v1.2.3
env:
SESSION_SECRET: ${{ secrets.SESSION_SECRET }}
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
ADMIN_USER: ${{ secrets.ADMIN_USER }}
ADMIN_PASSWORD: ${{ secrets.ADMIN_PASSWORD }}
ASXPIO_DB_PASSWORD: ${{ secrets.ASXPIO_DB_PASSWORD }}
ASXPIO_S3_ACCESS_KEY: ${{ secrets.ASXPIO_S3_ACCESS_KEY }}
ASXPIO_S3_SECRET_KEY: ${{ secrets.ASXPIO_S3_SECRET_KEY }}
LTC_ADDRESS: ${{ secrets.LTC_ADDRESS }}
CRYPTO_ADDRESSES: ${{ secrets.CRYPTO_ADDRESSES }}
with:
host: ${{ secrets.DEPLOY_IP }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
envs: SESSION_SECRET,SMTP_PASSWORD,ADMIN_USER,ADMIN_PASSWORD,ASXPIO_DB_PASSWORD,ASXPIO_S3_ACCESS_KEY,ASXPIO_S3_SECRET_KEY,LTC_ADDRESS,CRYPTO_ADDRESSES
script_stop: true
script: |
umask 077
mkdir -p /opt/asxpio
cat > /opt/asxpio/.env <<EOF
RACK_ENV=production
SESSION_SECRET=${SESSION_SECRET}
SMTP_ADDR=smtp.fastmail.com
SMTP_PORT=587
SMTP_USER=me@asxp.io
SMTP_PASSWORD=${SMTP_PASSWORD}
MAIL_FROM=IE Sergei Poljanski Contact Form <me@asxp.io>
MAIL_TO=ie@asxp.io
ADMIN_USER=${ADMIN_USER}
ADMIN_PASSWORD=${ADMIN_PASSWORD}
DATABASE_URL=postgres://asxpio:${ASXPIO_DB_PASSWORD}@postgres:5432/asxpio
S3_ENDPOINT=http://minio:9000
S3_PUBLIC_ENDPOINT=https://s3.asxp.io
S3_REGION=us-east-1
S3_BUCKET=asxpio-invoices
S3_ACCESS_KEY=${ASXPIO_S3_ACCESS_KEY}
S3_SECRET_KEY=${ASXPIO_S3_SECRET_KEY}
LTC_ADDRESS=${LTC_ADDRESS}
CRYPTO_ADDRESSES=${CRYPTO_ADDRESSES}
EOF
chmod 600 /opt/asxpio/.env
- name: Deploy and update container
uses: appleboy/ssh-action@v1.2.3
env:
NEW_IMAGE: ${{ needs.build.outputs.image_tag }}
with:
host: ${{ secrets.DEPLOY_IP }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
envs: NEW_IMAGE
script: |
cd /opt/asxpio
sed -i "s|image:.*|image: $NEW_IMAGE|" docker-compose.yml
docker pull $NEW_IMAGE
docker compose up -d
# Wait for the image HEALTHCHECK (GET /healthz) to report healthy;
# `docker ps | grep` passed even while the app crash-looped.
for i in $(seq 1 18); do
status=$(docker inspect --format '{{.State.Health.Status}}' asxpio 2>/dev/null || echo missing)
if [ "$status" = "healthy" ]; then
echo "Deployment successful!"
exit 0
fi
sleep 5
done
echo "asxpio never became healthy (last status: $status)" >&2
docker logs --tail 50 asxpio
exit 1