Docker Publish #37
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: Docker Publish | |
| on: | |
| workflow_run: | |
| workflows: | |
| - "CI build" | |
| types: | |
| - "completed" | |
| jobs: | |
| docker-test: | |
| name: Build and test Docker image | |
| if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.workflow_run.head_sha }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| # Build for local platform only (amd64) and load into Docker for testing | |
| - name: Build image for testing | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| load: true | |
| tags: bitsocial-cli:test | |
| secrets: | | |
| github_token=${{ secrets.GITHUB_TOKEN }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: Prepare compose files | |
| run: cp .github/docker-compose.ci.yml docker-compose.yml | |
| - name: Start services with docker compose | |
| env: | |
| BITSOCIAL_IMAGE: bitsocial-cli:test | |
| run: docker compose up -d | |
| - name: Wait for daemon to be ready | |
| run: | | |
| echo "Waiting for daemon to start..." | |
| for i in $(seq 1 60); do | |
| if docker compose exec -T bitsocial node -e "const net=require('net');const s=net.connect(9138,'localhost',()=>{s.end();process.exit(0)});s.on('error',()=>process.exit(1));setTimeout(()=>process.exit(1),3000)" 2>/dev/null; then | |
| echo "Daemon is ready after ${i}s" | |
| break | |
| fi | |
| if [ "$i" = "60" ]; then | |
| echo "Daemon failed to start within 60s" | |
| docker compose logs --no-color | |
| exit 1 | |
| fi | |
| sleep 1 | |
| done | |
| - name: Verify WebSocket RPC is accessible | |
| run: | | |
| docker compose exec -T bitsocial node -e " | |
| const WebSocket = require('ws'); | |
| const ws = new WebSocket('ws://localhost:9138'); | |
| const timeout = setTimeout(() => { console.error('WebSocket connection timed out'); process.exit(1); }, 10000); | |
| ws.on('open', () => { clearTimeout(timeout); console.log('WebSocket connected successfully'); ws.close(); process.exit(0); }); | |
| ws.on('error', (err) => { clearTimeout(timeout); console.error('WebSocket error:', err.message); process.exit(1); }); | |
| " | |
| - name: Test CLI commands inside compose service | |
| run: | | |
| # Create a community | |
| COMMUNITY_ADDRESS=$(docker compose exec -T bitsocial node ./bin/run community create --description "docker-ci-test" | tr -d '\r' | tail -n 1) | |
| if [ -z "$COMMUNITY_ADDRESS" ]; then | |
| echo "FAIL: community create did not return an address" | |
| exit 1 | |
| fi | |
| echo "Created community: $COMMUNITY_ADDRESS" | |
| # Verify the created community can be loaded | |
| COMMUNITY_JSON=$(docker compose exec -T bitsocial node ./bin/run community get "$COMMUNITY_ADDRESS" | tr -d '\r') | |
| echo "$COMMUNITY_JSON" | EXPECTED_ADDRESS="$COMMUNITY_ADDRESS" node -e " | |
| process.stdin.resume(); | |
| let data = ''; | |
| process.stdin.on('data', chunk => data += chunk); | |
| process.stdin.on('end', () => { | |
| const community = JSON.parse(data); | |
| if (community.address !== process.env.EXPECTED_ADDRESS) { | |
| console.error(\`FAIL: expected address '\${process.env.EXPECTED_ADDRESS}', got '\${community.address}'\`); | |
| process.exit(1); | |
| } | |
| if (community.description !== 'docker-ci-test') { | |
| console.error(\`FAIL: expected description 'docker-ci-test', got '\${community.description}'\`); | |
| process.exit(1); | |
| } | |
| console.log('community get returned expected payload'); | |
| }); | |
| " | |
| echo "All CLI commands passed inside docker compose service" | |
| - name: Dump compose logs on failure | |
| if: failure() | |
| run: docker compose logs --no-color | |
| - name: Stop and remove docker compose services | |
| if: always() | |
| run: docker compose down -v | |
| docker-push: | |
| name: Push Docker image | |
| needs: | |
| - docker-test | |
| if: ${{ github.event.workflow_run.conclusion == 'success' && needs.docker-test.result == 'success' }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.workflow_run.head_sha }} | |
| - name: Get latest release tag | |
| id: previoustag | |
| uses: WyriHaximus/github-action-get-previous-tag@v1 | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/bitsocialhq/bitsocial-cli | |
| tags: | | |
| type=semver,pattern={{version}},value=${{ steps.previoustag.outputs.tag }} | |
| type=semver,pattern={{major}}.{{minor}},value=${{ steps.previoustag.outputs.tag }} | |
| type=semver,pattern={{major}},value=${{ steps.previoustag.outputs.tag }} | |
| type=raw,value=latest | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # Full multi-arch build and push | |
| - name: Build and push | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| push: true | |
| platforms: linux/amd64,linux/arm64 | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| secrets: | | |
| github_token=${{ secrets.GITHUB_TOKEN }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max |