diff --git a/.deploy/ghcr.io/.env b/.deploy/ghcr.io/.env new file mode 100644 index 000000000..c68dcd067 --- /dev/null +++ b/.deploy/ghcr.io/.env @@ -0,0 +1,3 @@ +IMAGE_TAG=latest + +HTTP_FORWARDED_COUNT=2 diff --git a/.deploy/ghcr.io/compose.yaml b/.deploy/ghcr.io/compose.yaml new file mode 100644 index 000000000..f6b41b444 --- /dev/null +++ b/.deploy/ghcr.io/compose.yaml @@ -0,0 +1,4 @@ +services: + patient-web: + build: !reset null + image: ghcr.io/infoderm/patients:${IMAGE_TAG} diff --git a/.env b/.env index faf310ddb..85c792594 100644 --- a/.env +++ b/.env @@ -3,3 +3,5 @@ PORT=3000 MONGO_VERSION=5.0 MONGO_URL=mongodb://patient-db:27017/meteor + +HTTP_FORWARDED_COUNT=1 diff --git a/.github/workflows/ci:test:deploy.yml b/.github/workflows/ci:test:deploy.yml new file mode 100644 index 000000000..9f8e8f140 --- /dev/null +++ b/.github/workflows/ci:test:deploy.yml @@ -0,0 +1,81 @@ +name: ci:test:deploy + +on: + push: + branches: + - main + pull_request: + merge_group: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + + build: + name: Continuous integration (test deploy) + strategy: + matrix: + platform: + - ubuntu-latest + + runs-on: ${{ matrix.platform }} + + timeout-minutes: 4 + + steps: + - name: Checkout 🛎️ + uses: actions/checkout@v4 + + - name: Wait for image build workflow to succeed + uses: ArcticLampyrid/action-wait-for-workflow@v1.0.4 + with: + workflow: ci:build:image.yml + sha: ${{ github.sha }} + + - name: Log in to GitHub Packages registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ github.token }} + + - name: Start + env: + ROOT_URL: http://localhost + IMAGE_TAG: sha-${{ github.sha }} + run: | + docker compose \ + --env-file .env -f compose.yaml \ + --env-file .deploy/ghcr.io/.env -f .deploy/ghcr.io/compose.yaml \ + up --no-build --detach + + - name: Wait for database container to be healthy + run: | + timeout 60 bash -c \ + 'until docker inspect --format "{{json .State.Health }}" "$(docker compose ps -q patient-db)" | jq -e ".Status == \"healthy\"" ; do sleep 1; done' + + - name: Wait for web port to be available + run: | + timeout 60 bash -c \ + 'until nc -z -v -w5 127.0.0.1 3000 ; do sleep 1; done' + + - name: Wait for web container to be healthy + run: | + timeout 60 bash -c \ + 'until docker inspect --format "{{json .State.Health }}" "$(docker compose ps -q patient-web)" | jq -e ".Status == \"healthy\"" ; do sleep 1; done' + + - name: Call healthcheck endpoint + run: | + timeout 60 bash -c \ + 'curl -f http://localhost:3000/api/healthcheck' + + - name: Run healthcheck script + run: | + timeout 60 bash -c \ + 'node scripts/healthcheck.cjs http://localhost:3000/api/healthcheck' + + - name: Stop + run: | + docker compose down diff --git a/README.md b/README.md index ef3c28ef8..46c057b50 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,16 @@ Install dependencies, custom certificates, and MongoDB on server: TAG=vYYYY.MM.DD meteor npm run deploy +#### Generate a Docker `compose` configuration + +:construction: This is work in progress. :construction: + + ROOT_URL=https://example.local IMAGE_TAG=v1 \ + docker compose \ + --env-file .env -f compose.yaml \ + --env-file .deploy/ghcr.io/.env -f .deploy/ghcr.io/compose.yaml \ + config + ## :recycle: Backup & Restore The current backup system requires `age` and the encryption/decryption key at diff --git a/compose.yaml b/compose.yaml index 68a62ef41..da88394a3 100644 --- a/compose.yaml +++ b/compose.yaml @@ -8,6 +8,7 @@ services: - ROOT_URL=${ROOT_URL} - PORT=${PORT} - MONGO_URL=${MONGO_URL} + - HTTP_FORWARDED_COUNT=${HTTP_FORWARDED_COUNT} depends_on: patient-db: condition: service_healthy