name: build on: push: branches: [main] paths: - "data/**" - "tools/**" - ".gitea/workflows/build.yml" pull_request: paths: - "data/**" - "tools/**" - ".gitea/workflows/build.yml" schedule: - cron: "17 3 * * *" workflow_dispatch: env: GITEA_URL: ${{ github.server_url }} GITEA_REPO: ${{ github.repository }} # Автоматического токена обычно хватает. Если у раннера нет прав на push # или на релизы — заведите секрет RELEASE_TOKEN с правами repo:write. AUTO_TOKEN: ${{ github.token }} RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Окружение run: | set -eu missing="" for cmd in python3 curl unzip tar git; do command -v "$cmd" >/dev/null 2>&1 || missing="$missing $cmd" done if [ -n "$missing" ]; then echo "не хватает:$missing — доустанавливаем" sudo=""; [ "$(id -u)" -eq 0 ] || sudo=sudo $sudo apt-get update -qq $sudo apt-get install -y -qq python3 curl unzip tar git ca-certificates fi python3 --version # Раньше сборки: sing-box нужен не только для .srs, но и синхронизации — # три из пяти апстримов отдают уже скомпилированный rule-set. - name: Внешние инструменты run: | sh tools/fetch-tools.sh "$GITHUB_WORKSPACE/bin" echo "$GITHUB_WORKSPACE/bin" >> "$GITHUB_PATH" - name: Синхронизация апстримов run: python3 tools/sync.py - name: Проверка исходников run: python3 tools/build.py --check - name: Тесты run: python3 -m unittest discover -s tools -t tools - name: Сборка run: | SOURCE_DATE_EPOCH=$(git log -1 --format=%ct) python3 tools/build.py - name: Проверка .dat настоящим Xray run: | # Роутинг-правило заставляет Xray реально распарсить оба файла: # битый .dat или отсутствующий тег дают ненулевой код возврата. cat > /tmp/xray-test.json <<'EOF' { "inbounds": [{"port": 10800, "protocol": "socks"}], "outbounds": [{"protocol": "freedom", "tag": "direct"}], "routing": { "rules": [ {"type": "field", "domain": ["ext:discord-geosite.dat:discord"], "outboundTag": "direct"}, {"type": "field", "ip": ["ext:discord-geoip.dat:discord"], "outboundTag": "direct"}, {"type": "field", "ip": ["ext:geoip.dat:discord-base"], "outboundTag": "direct"} ] } } EOF XRAY_LOCATION_ASSET="$GITHUB_WORKSPACE/dist" xray run -test -c /tmp/xray-test.json - name: Проверка rule-set для sing-box run: | set -eu sing-box rule-set decompile --output /tmp/site.json dist/sing-box/site/discord.srs grep -q '"discord.com"' /tmp/site.json sing-box rule-set decompile --output /tmp/ip.json dist/sing-box/ip/discord.srs grep -q 'ip_cidr' /tmp/ip.json # Ограниченные категории обязаны донести протокол и порты до .srs. for src in dist/sing-box/ip/*-udp*.json; do [ -e "$src" ] || continue sing-box rule-set decompile --output /tmp/udp.json "${src%.json}.srs" grep -q '"udp"' /tmp/udp.json grep -q 'port_range' /tmp/udp.json done - name: Обновление data/ в main if: github.event_name != 'pull_request' run: | set -eu if git diff --quiet -- data; then echo "апстримы не изменились" exit 0 fi token="${RELEASE_TOKEN:-$AUTO_TOKEN}" [ -n "$token" ] || { echo "нет токена для push" >&2; exit 1; } host="${GITEA_URL#*://}" scheme="${GITEA_URL%%://*}" git config user.name "gitea-actions" git config user.email "gitea-actions@noreply.local" git add data git commit -q -m "sync: обновление списков из апстримов" git push -q "$scheme://gitea-actions:$token@$host/$GITEA_REPO.git" HEAD:main echo "data/ обновлён в main" - name: Описание релиза id: notes run: | set -eu tag=$(date -u '+%Y.%m.%d-%H%M') echo "tag=$tag" >> "$GITHUB_OUTPUT" { echo "Собрано из \`$(git rev-parse --short HEAD)\`." echo echo '| Категория | Доменов |' echo '| --- | ---: |' python3 -c "import json; [print(f'| {k} | {v} |') for k, v in json.load(open('dist/metadata.json'))['categories'].items()]" echo echo '| IP-категория | Сетей | Ограничения |' echo '| --- | ---: | --- |' python3 -c " import json for k, v in json.load(open('dist/metadata.json'))['ip_categories'].items(): limits = ' '.join(filter(None, ['/'.join(v.get('network', [])), v.get('ports', '')])) or '—' print(f\"| {k} | {v['count']} | {limits} |\") " echo echo "sha256(discord-geosite.dat) = \`$(cut -d' ' -f1 dist/discord-geosite.dat.sha256sum)\`" echo "sha256(discord-geoip.dat) = \`$(cut -d' ' -f1 dist/discord-geoip.dat.sha256sum)\`" } > /tmp/notes.md cat /tmp/notes.md - name: Публикация в ветку release if: github.event_name != 'pull_request' run: | set -eu token="${RELEASE_TOKEN:-$AUTO_TOKEN}" [ -n "$token" ] || { echo "нет токена для push" >&2; exit 1; } host="${GITEA_URL#*://}" scheme="${GITEA_URL%%://*}" cp README.md LICENSE dist/ cd dist git init -q -b release git config user.name "gitea-actions" git config user.email "gitea-actions@noreply.local" git add . git commit -q -m "build $(date -u '+%Y-%m-%d %H:%M UTC') ($GITHUB_SHA)" git push -qf "$scheme://gitea-actions:$token@$host/$GITEA_REPO.git" release cd .. rm -f dist/README.md dist/LICENSE echo "ветка release обновлена" - name: Релиз в Gitea if: github.event_name != 'pull_request' run: | set -eu export GITEA_TOKEN="${RELEASE_TOKEN:-$AUTO_TOKEN}" # Собираем архив вне dist/, иначе tar пакует сам себя на лету. tar -czf /tmp/discord-geodata-all.tar.gz -C dist . mv /tmp/discord-geodata-all.tar.gz dist/ sh tools/gitea-release.sh "${{ steps.notes.outputs.tag }}" /tmp/notes.md \ dist/discord-geosite.dat \ dist/discord-geosite.dat.sha256sum \ dist/discord-geoip.dat \ dist/discord-geoip.dat.sha256sum \ dist/xray/routing.json \ dist/sing-box/site/discord.srs \ dist/sing-box/ip/discord.srs \ dist/metadata.json \ dist/SHA256SUMS \ dist/discord-geodata-all.tar.gz