Merge pull request #3 from bialger/api #64
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "CI tests" | |
| # Push only: one full CI run per push (no duplicate pull_request). | |
| on: | |
| push: | |
| permissions: | |
| contents: read | |
| actions: write | |
| packages: write | |
| jobs: | |
| # Ubuntu matrix equivalent: artifact for Docker + gates release (does not wait for Windows/style/tidy). | |
| build_linux: | |
| name: Tests and application run on Ubuntu Latest GCC | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: seanmiddleditch/gha-setup-ninja@master | |
| - name: Create CMake cache | |
| shell: bash | |
| run: | | |
| cmake -S . -B cmake-build-release -DCMAKE_BUILD_TYPE=Release -G "Ninja" | |
| - name: Build vox-server target | |
| shell: bash | |
| run: | | |
| cmake --build cmake-build-release --target vox-server | |
| - name: Run program | |
| shell: bash | |
| working-directory: ./cmake-build-release/bin | |
| run: ./vox-server --help | |
| - name: Build tests | |
| shell: bash | |
| run: cmake --build ./cmake-build-release --target vox-server_tests | |
| - name: Run tests | |
| shell: bash | |
| working-directory: ./cmake-build-release/tests | |
| run: ./vox-server_tests | |
| - name: Build net integration tests | |
| shell: bash | |
| run: cmake --build ./cmake-build-release --target vox-server_net_tests | |
| - name: Run net integration tests | |
| shell: bash | |
| working-directory: ./cmake-build-release/tests | |
| run: ./vox-server_net_tests | |
| - name: Upload vox-server (Linux) for Docker image | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: vox-server-linux | |
| path: cmake-build-release/bin/vox-server | |
| retention-days: 1 | |
| ci: | |
| uses: ./.github/workflows/ci-reusable.yml | |
| secrets: inherit | |
| # Runs only after Ubuntu build+artifact; parallel Windows/style/tidy do not block this. | |
| release: | |
| name: Image (GHCR) + deploy | |
| runs-on: ubuntu-latest | |
| needs: [build_linux] | |
| permissions: | |
| contents: read | |
| actions: read | |
| packages: write | |
| concurrency: | |
| group: release-${{ github.workflow }} | |
| cancel-in-progress: false | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download vox-server from build_linux | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: vox-server-linux | |
| path: docker-build-context | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| repository: ${{ github.repository }} | |
| run-id: ${{ github.run_id }} | |
| - name: Prepare Docker build context | |
| run: cp deploy/docker-entrypoint.sh docker-build-context/docker-entrypoint.sh | |
| - name: Image name (lowercase for GHCR) | |
| id: meta | |
| run: | | |
| echo "repository_lower=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT" | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push (prebuilt binary) | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: docker-build-context | |
| file: ./deploy/Dockerfile.prebuilt | |
| push: true | |
| tags: ghcr.io/${{ steps.meta.outputs.repository_lower }}:${{ github.sha }} | |
| - name: Tag latest | |
| run: | | |
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin | |
| docker pull "ghcr.io/${{ steps.meta.outputs.repository_lower }}:${{ github.sha }}" | |
| docker tag "ghcr.io/${{ steps.meta.outputs.repository_lower }}:${{ github.sha }}" \ | |
| "ghcr.io/${{ steps.meta.outputs.repository_lower }}:latest" | |
| docker push "ghcr.io/${{ steps.meta.outputs.repository_lower }}:latest" | |
| - name: Deploy via SSH | |
| uses: appleboy/ssh-action@v1.2.0 | |
| env: | |
| GHCR_READ_TOKEN: ${{ secrets.GHCR_READ_TOKEN }} | |
| GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} | |
| GITHUB_REPO_OWNER: ${{ github.repository_owner }} | |
| GHCR_DEPLOY_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_ACTOR_DEPLOY: ${{ github.actor }} | |
| with: | |
| host: messenger.bialger.com | |
| username: ${{ secrets.SERVER_LOGIN }} | |
| password: ${{ secrets.SERVER_PASSWORD }} | |
| port: 22 | |
| command_timeout: 30m | |
| debug: true | |
| envs: GHCR_READ_TOKEN,GHCR_USERNAME,GITHUB_REPO_OWNER,GHCR_DEPLOY_TOKEN,GITHUB_ACTOR_DEPLOY | |
| script_stop: true | |
| script: | | |
| set -euo pipefail | |
| _d() { printf '%s\n' "[vox-deploy] $*"; } | |
| _dcompose_diag() { | |
| _d "--- docker compose ps -a ---" | |
| docker compose ps -a 2>&1 | sed 's/^/[vox-deploy] /' || true | |
| _d "--- docker compose logs (last 400 lines) ---" | |
| docker compose logs --tail 400 2>&1 | sed 's/^/[vox-deploy] /' || true | |
| } | |
| # appleboy/ssh-action runs bash --noprofile --norc; docker/git often live in /usr/local/bin | |
| export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH" | |
| _d "whoami=$(whoami) pwd=$(pwd) PATH=$PATH" | |
| _d "git=$(command -v git 2>/dev/null || echo MISSING) docker=$(command -v docker 2>/dev/null || echo MISSING)" | |
| command -v docker >/dev/null && docker compose version 2>&1 | sed 's/^/[vox-deploy] /' || _d "docker compose: not available" | |
| BRANCH="${{ github.ref_name }}" | |
| REPO_LC=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') | |
| IMAGE="ghcr.io/${REPO_LC}:${{ github.sha }}" | |
| _d "IMAGE=${IMAGE} branch=${BRANCH} deploy_path=/opt/vox-server" | |
| cd /opt/vox-server | |
| _d "repo root $(pwd)" | |
| git fetch origin "${BRANCH}" | |
| git checkout -B "${BRANCH}" "origin/${BRANCH}" | |
| _d "--- after git sync ---" | |
| git rev-parse HEAD && git status -sb || true | |
| if [ ! -d deploy ]; then | |
| _d "ERROR: $(pwd)/deploy is not a directory"; exit 1 | |
| fi | |
| cd deploy | |
| _d "in deploy/: $(pwd)"; ls -la | |
| if [ ! -f .env ]; then | |
| _d ".env: create new" | |
| printf '%s\n' "VOX_IMAGE=${IMAGE}" > .env | |
| elif grep -q '^VOX_IMAGE=' .env 2>/dev/null; then | |
| _d ".env: replace existing VOX_IMAGE line" | |
| grep -v '^VOX_IMAGE=' .env > .env.tmp || true | |
| mv .env.tmp .env | |
| printf '%s\n' "VOX_IMAGE=${IMAGE}" >> .env | |
| else | |
| _d ".env: append VOX_IMAGE" | |
| printf '%s\n' "VOX_IMAGE=${IMAGE}" >> .env | |
| fi | |
| _d "VOX_IMAGE line: $(grep '^VOX_IMAGE=' .env || echo '(missing)')" | |
| TOKEN="${GHCR_READ_TOKEN:-}" | |
| U="${GHCR_USERNAME:-${GITHUB_REPO_OWNER}}" | |
| if [ -z "${TOKEN}" ] && [ -n "${GHCR_DEPLOY_TOKEN:-}" ]; then | |
| TOKEN="${GHCR_DEPLOY_TOKEN}" | |
| U="${GITHUB_ACTOR_DEPLOY}" | |
| _d "docker login ghcr.io (GITHUB_TOKEN fallback, user=${U})" | |
| elif [ -n "${TOKEN}" ]; then | |
| _d "docker login ghcr.io (GHCR_READ_TOKEN, user=${U})" | |
| else | |
| _d "WARNING: no ghcr credentials — pull fails for private images" | |
| fi | |
| if [ -n "${TOKEN}" ]; then | |
| echo "${TOKEN}" | docker login ghcr.io -u "${U}" --password-stdin | |
| fi | |
| _d "docker compose pull vox-server" | |
| docker compose pull vox-server || { _d "ERROR: docker compose pull failed (see above)"; _dcompose_diag; exit 1; } | |
| _d "docker compose up -d" | |
| docker compose up -d || { _d "ERROR: docker compose up failed"; _dcompose_diag; exit 1; } | |
| _d "nginx reload (conf.d bind mount)" | |
| docker compose exec -T nginx nginx -s reload || { _d "ERROR: nginx reload failed"; _dcompose_diag; exit 1; } | |
| _d "finished OK" |