145 lines
5.5 KiB
YAML
145 lines
5.5 KiB
YAML
# Gitea Actions. While .gitea/workflows exists Gitea ignores .github/workflows (GitHub Pages only).
|
|
#
|
|
# Every push and pull request: install, test and build.
|
|
# Push to main: build the Docker image, push it to the Gitea registry, then start it with
|
|
# docker compose through the runner's Docker socket (the runner lives on the deployment server).
|
|
#
|
|
# Repository settings → Actions → Secrets:
|
|
# REGISTRY_USERNAME Gitea user that publishes images
|
|
# REGISTRY_TOKEN its personal access token with package Read and Write
|
|
# (the built-in GITEA_TOKEN cannot publish packages)
|
|
# Repository settings → Actions → Variables (optional):
|
|
# NPM_REGISTRY npm mirror used by the runner and the server's Docker build when
|
|
# registry.npmjs.org is unreachable, e.g. from servers in Iran
|
|
# HEALTH_URL URL checked after deploy, e.g. https://robotmarkets.ir/
|
|
name: CI/CD
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
workflow_dispatch:
|
|
|
|
# Deploys run one at a time, in push order.
|
|
concurrency:
|
|
group: ci-cd-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
# Fail within minutes instead of hanging when the registry is slow or blocked.
|
|
env:
|
|
NPM_CONFIG_REGISTRY: ${{ vars.NPM_REGISTRY || 'https://registry.npmjs.org/' }}
|
|
NPM_CONFIG_FETCH_RETRIES: '3'
|
|
NPM_CONFIG_FETCH_TIMEOUT: '60000'
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
container:
|
|
image: node:22-bookworm
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Install
|
|
run: npm ci --no-audit --no-fund
|
|
- name: Check formatting
|
|
run: npm run format:check
|
|
- name: Lint
|
|
run: npm run lint
|
|
- name: Test
|
|
run: npm test
|
|
- name: Build
|
|
run: npm run build
|
|
|
|
publish:
|
|
needs: test
|
|
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
outputs:
|
|
image: ${{ steps.push.outputs.image }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Build, push and link the image
|
|
id: push
|
|
shell: bash
|
|
env:
|
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
SOURCE_REPOSITORY: ${{ gitea.repository }}
|
|
COMMIT_SHA: ${{ gitea.sha }}
|
|
RUN_ID: ${{ gitea.run_id }}
|
|
run: |
|
|
set -euo pipefail
|
|
REGISTRY='git.my-rm.com'
|
|
OWNER="${SOURCE_REPOSITORY%%/*}"
|
|
REPO="${SOURCE_REPOSITORY#*/}"
|
|
IMAGE="$REGISTRY/${OWNER,,}/${REPO,,}:build-$(date -u +%Y%m%d-%H%M%S)-${RUN_ID}-${COMMIT_SHA:0:7}"
|
|
|
|
# Keep this job's registry credentials away from the host's own logins.
|
|
DOCKER_CONFIG="$(mktemp -d)"
|
|
export DOCKER_CONFIG
|
|
trap 'rm -rf "$DOCKER_CONFIG"' EXIT
|
|
|
|
printf '%s' "$REGISTRY_TOKEN" | docker login "$REGISTRY" --username "$REGISTRY_USERNAME" --password-stdin
|
|
docker build \
|
|
--build-arg "NPM_REGISTRY=$NPM_CONFIG_REGISTRY" \
|
|
--label "org.opencontainers.image.source=https://$REGISTRY/$SOURCE_REPOSITORY" \
|
|
--label "org.opencontainers.image.revision=$COMMIT_SHA" \
|
|
--tag "$IMAGE" .
|
|
docker push "$IMAGE"
|
|
|
|
# Show the package under this repository's Packages tab. Gitea answers 400 when the package
|
|
# is already linked (every run after the first), and the image is published either way.
|
|
status="$(curl --silent --show-error --output /dev/null --write-out '%{http_code}' --request POST \
|
|
--header "Authorization: token $REGISTRY_TOKEN" \
|
|
"https://$REGISTRY/api/v1/packages/$OWNER/container/${REPO,,}/-/link/$REPO")"
|
|
case "$status" in
|
|
201) echo "Linked the package to $REPO" ;;
|
|
*) echo "Package link request returned HTTP $status (already linked is normal); continuing" ;;
|
|
esac
|
|
|
|
echo "image=$IMAGE" >> "$GITEA_OUTPUT"
|
|
echo "Published and linked: $IMAGE"
|
|
|
|
# The runner shares the server's Docker daemon, so deploying is a local docker compose call:
|
|
# no SSH, and the daemon pulls with the credentials of this job's temporary docker login.
|
|
deploy:
|
|
needs: publish
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Deploy the published image
|
|
shell: bash
|
|
env:
|
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
IMAGE: ${{ needs.publish.outputs.image }}
|
|
run: |
|
|
set -euo pipefail
|
|
DOCKER_CONFIG="$(mktemp -d)"
|
|
export DOCKER_CONFIG
|
|
trap 'rm -rf "$DOCKER_CONFIG"' EXIT
|
|
|
|
printf '%s' "$REGISTRY_TOKEN" | docker login git.my-rm.com --username "$REGISTRY_USERNAME" --password-stdin
|
|
docker compose -p vending-machine-game -f deploy/docker-compose.yml pull
|
|
docker compose -p vending-machine-game -f deploy/docker-compose.yml up -d --remove-orphans
|
|
docker compose -p vending-machine-game -f deploy/docker-compose.yml ps
|
|
docker image prune -f
|
|
|
|
- name: Check the site
|
|
if: vars.HEALTH_URL != ''
|
|
shell: bash
|
|
env:
|
|
HEALTH_URL: ${{ vars.HEALTH_URL }}
|
|
run: |
|
|
for attempt in $(seq 1 20); do
|
|
if curl -fsS -o /dev/null "$HEALTH_URL"; then
|
|
echo "Site is up: $HEALTH_URL"
|
|
exit 0
|
|
fi
|
|
sleep 6
|
|
done
|
|
echo "Site did not answer at $HEALTH_URL" >&2
|
|
exit 1
|