name: CI · Автономное обновление пакетов on: schedule: # 03:00 Asia/Vladivostok (UTC+10) - cron: "0 17 * * *" workflow_dispatch: permissions: contents: write issues: write concurrency: group: nivora-autonomous-updates cancel-in-progress: false defaults: run: shell: bash jobs: detect: name: Найти обновления runs-on: ubuntu-24.04 timeout-minutes: 30 outputs: packages: ${{ steps.updates.outputs.packages }} has_updates: ${{ steps.updates.outputs.has_updates }} github_desktop_update: ${{ steps.updates.outputs.github_desktop_update }} github_desktop_version: ${{ steps.updates.outputs.github_desktop_version }} steps: - name: Получить репозиторий uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Подготовить инструменты uses: ./.github/actions/setup-stplr-spec with: system-packages: jq - name: Сформировать план обновления id: updates env: GITHUB_TOKEN: ${{ github.token }} run: | packages_output="$(tools/package_updates.sh outdated)" mapfile -t packages <<<"$packages_output" if [[ -z "$packages_output" ]]; then packages=() fi if [[ "${#packages[@]}" -eq 0 ]]; then { echo 'packages=[]' echo 'has_updates=false' echo 'github_desktop_update=false' echo 'github_desktop_version=' } >>"$GITHUB_OUTPUT" exit 0 fi packages_json="$( printf '%s\n' "${packages[@]}" | jq -Rsc 'split("\n") | map(select(length > 0))' )" github_desktop_update=false github_desktop_version='' for package in "${packages[@]}"; do if [[ "$package" == github-desktop ]]; then github_desktop_update=true read -r _ github_desktop_version < <( tools/package_updates.sh check github-desktop ) fi done { echo "packages=${packages_json}" echo 'has_updates=true' echo "github_desktop_update=${github_desktop_update}" echo "github_desktop_version=${github_desktop_version}" } >>"$GITHUB_OUTPUT" github-desktop: name: Подготовить GitHub Desktop needs: detect if: ${{ needs.detect.outputs.github_desktop_update == 'true' }} uses: ./.github/workflows/github-desktop-linux.yml with: version: ${{ needs.detect.outputs.github_desktop_version }} publish: true permissions: contents: write update: name: Изолированно обновить и опубликовать needs: - detect - github-desktop if: >- ${{ always() && needs.detect.result == 'success' && needs.detect.outputs.has_updates == 'true' }} runs-on: ubuntu-24.04 timeout-minutes: 360 steps: - name: Получить репозиторий uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: ref: main fetch-depth: 0 - name: Подготовить инструменты uses: ./.github/actions/setup-stplr-spec with: system-packages: jq rpm shellcheck - name: Изолированно обновить и проверить каждый пакет id: isolated env: GITHUB_TOKEN: ${{ github.token }} PACKAGES_JSON: ${{ needs.detect.outputs.packages }} AUTONOMOUS_UPDATE_RESULTS_DIR: ${{ runner.temp }}/update-results run: | mapfile -t packages < <(jq -r '.[]' <<<"$PACKAGES_JSON") tools/autonomous_package_updates.sh "${packages[@]}" successful_json="$( jq -Rsc 'split("\n") | map(select(length > 0))' \ <"$AUTONOMOUS_UPDATE_RESULTS_DIR/successful-packages" )" failed_json="$( cut -f1 "$AUTONOMOUS_UPDATE_RESULTS_DIR/failed-packages" | jq -Rsc 'split("\n") | map(select(length > 0))' )" echo "successful=${successful_json}" >>"$GITHUB_OUTPUT" echo "failed=${failed_json}" >>"$GITHUB_OUTPUT" - name: Сохранить журналы и diff каждого пакета if: ${{ always() }} uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: autonomous-update-diagnostics-${{ github.run_id }} path: ${{ runner.temp }}/update-results if-no-files-found: error retention-days: 30 - name: Применить только успешные обновления env: AUTONOMOUS_UPDATE_RESULTS_DIR: ${{ runner.temp }}/update-results run: | while IFS= read -r package; do [[ -n "$package" ]] || continue git apply \ "$AUTONOMOUS_UPDATE_RESULTS_DIR/${package}/update.patch" done <"$AUTONOMOUS_UPDATE_RESULTS_DIR/successful-packages" tools/sync_readme_versions.py tools/run_checks.sh - name: Отправить обновления прямо в main id: publish env: SUCCESSFUL_PACKAGES: ${{ steps.isolated.outputs.successful }} run: | if git diff --quiet; then echo 'Изменений после обновления нет' exit 0 fi git config user.name 'github-actions[bot]' git config user.email '41898282+github-actions[bot]@users.noreply.github.com' git add README.md ./*/Staplerfile packages="$(jq -r 'join(", ")' <<<"$SUCCESSFUL_PACKAGES")" git commit -m "chore: autonomously update ${packages}" git pull --rebase origin main git push origin HEAD:main - name: Синхронизировать постоянные отчёты о сбоях if: ${{ always() && steps.isolated.outcome == 'success' }} env: AUTONOMOUS_UPDATE_RESULTS_DIR: ${{ runner.temp }}/update-results GH_TOKEN: ${{ github.token }} run: tools/report_update_failures.sh - name: Сообщить о несовместимых пакетах if: ${{ always() && steps.isolated.outputs.failed != '[]' }} env: FAILED_PACKAGES: ${{ steps.isolated.outputs.failed }} AUTONOMOUS_UPDATE_RESULTS_DIR: ${{ runner.temp }}/update-results run: | { echo '## Требуется ручная диагностика' echo echo 'Обновление остальных пакетов продолжено и опубликовано.' echo 'Для несовместимых пакетов сохранён artifact с логами и diff:' echo while IFS=$'\t' read -r package phase; do printf -- '- **%s**: сбой на фазе **%s**\n' "$package" "$phase" done <"$AUTONOMOUS_UPDATE_RESULTS_DIR/failed-packages" } >>"$GITHUB_STEP_SUMMARY" echo "::warning::Требуется ручная диагностика: $(jq -r 'join(\", \")' <<<"$FAILED_PACKAGES")"