Files
chemavxandClaude Fable 5 4928a3c1e4
CI/CD / build-and-push (push) Successful in 7s
ci: build only the images whose source files changed
Path-based build selection diffed against github.event.before:
- bot/, api/, requirements.txt -> bot + api images (both COPY the same
  python sources; only the CMD differs)
- Dockerfile -> bot only; Dockerfile.api -> api only
- dashboard/ -> dashboard only
- .gitea/workflows/ci.yml, first push or force push -> all (safe fallback)
- anything else (tests/, docs) -> no builds, no manifest update

The k8s-manifests sed only bumps tags of rebuilt images, so unchanged
deployments keep their current tag and don't restart. Registry login,
buildx, verification and manifest update are all skipped when nothing
needs building. Telegram message now lists what was built.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 08:07:49 +00:00

246 lines
10 KiB
YAML

name: CI/CD
on:
push:
branches:
- main
env:
REGISTRY: gitea.gitea.svc.cluster.local:3000
K8S_MANIFESTS_REPO: http://chemavx:${{ secrets.CI_TOKEN }}@gitea.gitea.svc.cluster.local:3000/chemavx/k8s-manifests.git
GIT_SSL_NO_VERIFY: "true"
TELEGRAM_CHAT_ID: "5138407666"
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ssl-verify: false
# Full history: needed to diff against github.event.before
fetch-depth: 0
- name: Set image tag
id: tag
run: echo "TAG=${GITHUB_SHA::8}" >> $GITHUB_OUTPUT
- name: Detect changed components
id: changes
run: |
BEFORE="${{ github.event.before }}"
CHANGED=""
case "$BEFORE" in
""|0000000000000000000000000000000000000000)
echo "First push or unknown base — building all images"
CHANGED="__all__"
;;
*)
if git cat-file -e "$BEFORE" 2>/dev/null; then
CHANGED=$(git diff --name-only "$BEFORE" "$GITHUB_SHA")
else
echo "Base commit $BEFORE not in history (force push?) — building all images"
CHANGED="__all__"
fi
;;
esac
echo "Changed files:"
echo "$CHANGED"
if [ "$CHANGED" = "__all__" ]; then
BOT=true; API=true; DASH=true
else
BOT=false; API=false; DASH=false
matches() { echo "$CHANGED" | grep -qE "$1"; }
# The workflow itself affects every image build
if matches '^\.gitea/workflows/ci\.yml$'; then BOT=true; API=true; DASH=true; fi
# bot and api images both COPY bot/, api/ and requirements.txt
if matches '^(bot/|api/|requirements\.txt$)'; then BOT=true; API=true; fi
if matches '^Dockerfile$'; then BOT=true; fi
if matches '^Dockerfile\.api$'; then API=true; fi
# dashboard image builds from the dashboard/ context only
if matches '^dashboard/'; then DASH=true; fi
fi
ANY=false
if [ "$BOT" = "true" ] || [ "$API" = "true" ] || [ "$DASH" = "true" ]; then ANY=true; fi
echo "build_bot=$BOT" >> $GITHUB_OUTPUT
echo "build_api=$API" >> $GITHUB_OUTPUT
echo "build_dashboard=$DASH" >> $GITHUB_OUTPUT
echo "build_any=$ANY" >> $GITHUB_OUTPUT
echo "Will build: bot=$BOT api=$API dashboard=$DASH"
- name: Log in to registry
if: steps.changes.outputs.build_any == 'true'
run: echo "${{ secrets.CI_TOKEN }}" | docker login gitea.gitea.svc.cluster.local:3000 -u chemavx --password-stdin
- name: Create buildx builder
if: steps.changes.outputs.build_any == 'true'
run: |
cat > /tmp/buildkitd.toml << 'EOF'
[registry."registry-cache.registry-cache.svc.cluster.local:5000"]
http = true
insecure = true
[registry."gitea.gitea.svc.cluster.local:3000"]
http = true
insecure = true
[registry."docker.io"]
mirrors = ["registry-cache.registry-cache.svc.cluster.local:5000"]
EOF
docker buildx create \
--name ci-builder \
--driver docker-container \
--driver-opt network=host \
--config /tmp/buildkitd.toml \
--use
docker buildx inspect --bootstrap
- name: Build and push bot image
if: steps.changes.outputs.build_bot == 'true'
run: |
TAG=${{ steps.tag.outputs.TAG }}
docker buildx build \
--builder ci-builder \
--cache-from type=registry,ref=gitea.gitea.svc.cluster.local:3000/chemavx/polymarket-bot:buildcache \
--cache-to type=registry,ref=gitea.gitea.svc.cluster.local:3000/chemavx/polymarket-bot:buildcache,mode=max \
-t gitea.gitea.svc.cluster.local:3000/chemavx/polymarket-bot:${TAG} \
--push \
-f Dockerfile .
- name: Build and push API image
if: steps.changes.outputs.build_api == 'true'
run: |
TAG=${{ steps.tag.outputs.TAG }}
docker buildx build \
--builder ci-builder \
--cache-from type=registry,ref=gitea.gitea.svc.cluster.local:3000/chemavx/polymarket-bot-api:buildcache \
--cache-to type=registry,ref=gitea.gitea.svc.cluster.local:3000/chemavx/polymarket-bot-api:buildcache,mode=max \
-t gitea.gitea.svc.cluster.local:3000/chemavx/polymarket-bot-api:${TAG} \
--push \
-f Dockerfile.api .
- name: Build and push dashboard image
if: steps.changes.outputs.build_dashboard == 'true'
run: |
TAG=${{ steps.tag.outputs.TAG }}
docker buildx build \
--builder ci-builder \
--cache-from type=registry,ref=gitea.gitea.svc.cluster.local:3000/chemavx/polymarket-bot-dashboard:buildcache \
--cache-to type=registry,ref=gitea.gitea.svc.cluster.local:3000/chemavx/polymarket-bot-dashboard:buildcache,mode=max \
-t gitea.gitea.svc.cluster.local:3000/chemavx/polymarket-bot-dashboard:${TAG} \
--push \
-f dashboard/Dockerfile \
dashboard
- name: Verify images in registry
if: steps.changes.outputs.build_any == 'true'
run: |
TAG=${{ steps.tag.outputs.TAG }}
check_image() {
local image=$1
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-u "chemavx:${{ secrets.CI_TOKEN }}" \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
"http://gitea.gitea.svc.cluster.local:3000/v2/chemavx/${image}/manifests/${TAG}")
if [ "$HTTP_CODE" != "200" ]; then
echo "ERROR: chemavx/${image}:${TAG} not found in registry (HTTP $HTTP_CODE)"
exit 1
fi
echo "OK: chemavx/${image}:${TAG} verified in registry"
}
if [ "${{ steps.changes.outputs.build_bot }}" = "true" ]; then
check_image polymarket-bot
fi
if [ "${{ steps.changes.outputs.build_api }}" = "true" ]; then
check_image polymarket-bot-api
fi
if [ "${{ steps.changes.outputs.build_dashboard }}" = "true" ]; then
check_image polymarket-bot-dashboard
fi
- name: Update k8s manifests
if: steps.changes.outputs.build_any == 'true'
run: |
pip3 install pyyaml -q
TAG=${{ steps.tag.outputs.TAG }}
git config --global user.email "ci@git.chemavx.xyz"
git config --global user.name "Gitea CI"
git clone ${{ env.K8S_MANIFESTS_REPO }} /tmp/k8s-manifests
cd /tmp/k8s-manifests
# Only bump the tag of images that were actually rebuilt: the others
# keep their current (still existing) tag in the registry.
if [ "${{ steps.changes.outputs.build_bot }}" = "true" ]; then
sed -i "s|image: .*polymarket-bot[^-].*|image: git.chemavx.xyz/chemavx/polymarket-bot:${TAG}|g" \
polymarket-bot/deployment-bot.yaml
fi
if [ "${{ steps.changes.outputs.build_api }}" = "true" ]; then
sed -i "s|image: .*polymarket-bot-api.*|image: git.chemavx.xyz/chemavx/polymarket-bot-api:${TAG}|g" \
polymarket-bot/deployment-api.yaml
fi
if [ "${{ steps.changes.outputs.build_dashboard }}" = "true" ]; then
sed -i "s|image: .*polymarket-bot-dashboard.*|image: git.chemavx.xyz/chemavx/polymarket-bot-dashboard:${TAG}|g" \
polymarket-bot/deployment-dashboard.yaml
fi
sed -i "s|imagePullPolicy: Never|imagePullPolicy: Always|g" \
polymarket-bot/deployment-bot.yaml \
polymarket-bot/deployment-api.yaml \
polymarket-bot/deployment-dashboard.yaml
python3 -c "
import yaml, sys
files = [
'polymarket-bot/deployment-bot.yaml',
'polymarket-bot/deployment-api.yaml',
'polymarket-bot/deployment-dashboard.yaml',
]
errors = []
for f in files:
try:
yaml.safe_load(open(f))
print('OK: ' + f)
except yaml.YAMLError as e:
errors.append('FAIL: ' + f + ': ' + str(e))
if errors:
for e in errors: print(e, file=sys.stderr)
sys.exit(1)
"
git add polymarket-bot/deployment-bot.yaml polymarket-bot/deployment-api.yaml polymarket-bot/deployment-dashboard.yaml
git diff --cached --quiet || git commit -m "ci: update polymarket-bot images to ${TAG} [skip ci]"
git push
- name: Notify Telegram
if: always()
env:
TAG: ${{ steps.tag.outputs.TAG }}
JOB_STATUS: ${{ job.status }}
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
BUILD_BOT: ${{ steps.changes.outputs.build_bot }}
BUILD_API: ${{ steps.changes.outputs.build_api }}
BUILD_DASH: ${{ steps.changes.outputs.build_dashboard }}
run: |
TAG="${TAG:-${GITHUB_SHA:0:8}}"
BUILT=""
[ "$BUILD_BOT" = "true" ] && BUILT="${BUILT}bot "
[ "$BUILD_API" = "true" ] && BUILT="${BUILT}api "
[ "$BUILD_DASH" = "true" ] && BUILT="${BUILT}dashboard "
if [ "$JOB_STATUS" = "success" ]; then
if [ -n "$BUILT" ]; then
MSG="✅ Deploy polymarket-bot:${TAG} completado (imágenes: ${BUILT% })"
else
MSG="✅ CI polymarket-bot:${TAG} OK — sin cambios de imagen, nada que desplegar"
fi
else
MSG="❌ Deploy polymarket-bot:${TAG} fallido (status: ${JOB_STATUS})"
fi
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" \
-d "chat_id=${{ env.TELEGRAM_CHAT_ID }}" \
--data-urlencode "text=${MSG}"