feat: create autonomous Nivora package repository

Maintain a validated cross-distribution package catalog.
Automate upstream updates, isolated builds, diagnostics, and direct publication.
Build the official GitHub Desktop sources for Linux with working OAuth.
This commit is contained in:
Александр
2026-07-25 00:49:32 +10:00
commit f405ae2bcf
168 changed files with 8483 additions and 0 deletions
+201
View File
@@ -0,0 +1,201 @@
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")"
+47
View File
@@ -0,0 +1,47 @@
name: CI · Ручная сборка пакетов
on:
workflow_dispatch:
inputs:
packages:
description: "all или package ID через пробел"
required: true
default: all
type: string
permissions:
contents: read
concurrency:
group: nivora-clean-build
cancel-in-progress: false
defaults:
run:
shell: bash
jobs:
build:
name: Изолированная сборка
runs-on: ubuntu-24.04
timeout-minutes: 300
steps:
- name: Получить репозиторий
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Подготовить инструменты
uses: ./.github/actions/setup-stplr-spec
- name: Собрать пакеты
env:
REQUESTED_PACKAGES: ${{ inputs.packages }}
run: |
if [[ "$REQUESTED_PACKAGES" == all ]]; then
tools/clean_build.sh --all
tools/verify_artifacts.sh --all
NIVORA_DEB_BUILD_MODE=host tools/test_package_lifecycle.sh
else
read -r -a packages <<<"$REQUESTED_PACKAGES"
tools/clean_build.sh "${packages[@]}"
tools/verify_artifacts.sh "${packages[@]}"
fi
+166
View File
@@ -0,0 +1,166 @@
name: CI · Сборка GitHub Desktop для Linux
on:
workflow_call:
inputs:
version:
description: "Версия desktop/desktop без префикса release-"
required: true
type: string
publish:
description: "Опубликовать tar.gz в GitHub Release Nivora"
required: false
default: true
type: boolean
workflow_dispatch:
inputs:
version:
description: "Версия desktop/desktop без префикса release-"
required: true
default: "3.6.3"
type: string
publish:
description: "Опубликовать tar.gz в GitHub Release Nivora"
required: true
default: true
type: boolean
permissions:
contents: write
concurrency:
group: nivora-github-desktop-linux-${{ inputs.version || '3.6.3' }}
cancel-in-progress: false
defaults:
run:
shell: bash
jobs:
build:
name: Linux ${{ matrix.arch }}
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
arch: x64
- runner: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.runner }}
timeout-minutes: 180
steps:
- name: Установить Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: "24.15.0"
- name: Установить системные зависимости
run: |
sudo apt-get update
sudo apt-get install -y build-essential libsecret-1-dev pkg-config python3
- name: Получить официальные исходники GitHub Desktop
env:
VERSION: ${{ inputs.version || '3.6.3' }}
run: |
git clone \
--branch "release-${VERSION}" \
--depth 1 \
--recurse-submodules \
--shallow-submodules \
https://github.com/desktop/desktop.git \
github-desktop
git -C github-desktop remote set-url origin \
https://github.com/desktop/desktop.git
- name: Добавить поддержку OAuth callback в Linux
working-directory: github-desktop
run: |
main_process='app/src/main-process/main.ts'
perl -0pi -e \
"s/if \\(__DEV_SECRETS__\\) \\{\\n possibleProtocols\\.add\\('x-github-desktop-dev-auth'\\)\\n\\} else \\{\\n possibleProtocols\\.add\\('x-github-desktop-auth'\\)\\n\\}/possibleProtocols.add('x-github-desktop-auth')\\nif (__DEV_SECRETS__) {\\n possibleProtocols.add('x-github-desktop-dev-auth')\\n}/" \
"$main_process"
perl -0pi -e \
"s/if \\(__WIN32__ && args\\['protocol-launcher'\\] === true\\)/if ((__WIN32__ || __LINUX__) \\&\\& args['protocol-launcher'] === true)/" \
"$main_process"
grep -Fq "possibleProtocols.add('x-github-desktop-auth')" \
"$main_process"
grep -Fq "(__WIN32__ || __LINUX__)" "$main_process"
- name: Установить зависимости из upstream lockfile
working-directory: github-desktop
run: |
node vendor/yarn-1.21.1.js install --frozen-lockfile --non-interactive
- name: Собрать официальный Electron-клиент
working-directory: github-desktop
env:
NODE_ENV: production
RELEASE_CHANNEL: production
run: node vendor/yarn-1.21.1.js build:prod
- name: Упаковать Linux-сборку
env:
ARCH: ${{ matrix.arch }}
VERSION: ${{ inputs.version || '3.6.3' }}
run: |
dist="github-desktop/dist/desktop-linux-${ARCH}"
test -x "${dist}/desktop"
grep -aFq 'x-github-desktop-auth' \
"${dist}/resources/app/main.js"
mkdir -p package/github-desktop
cp -a "${dist}/." package/github-desktop/
printf '%s\n' "$(git -C github-desktop rev-parse HEAD)" \
>package/github-desktop/UPSTREAM_COMMIT
tar \
--sort=name \
--mtime='UTC 2020-01-01' \
--owner=0 \
--group=0 \
--numeric-owner \
-C package \
-cf "github-desktop-${VERSION}-linux-${ARCH}.tar" \
github-desktop
gzip -n -9 "github-desktop-${VERSION}-linux-${ARCH}.tar"
- name: Сохранить артефакт
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: github-desktop-${{ inputs.version || '3.6.3' }}-linux-${{ matrix.arch }}
path: github-desktop-${{ inputs.version || '3.6.3' }}-linux-${{ matrix.arch }}.tar.gz
if-no-files-found: error
retention-days: 14
publish:
name: Опубликовать Linux-артефакты
if: ${{ inputs.publish }}
needs: build
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- name: Скачать обе архитектуры
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
pattern: github-desktop-${{ inputs.version || '3.6.3' }}-linux-*
merge-multiple: true
- name: Создать контрольные суммы
run: sha256sum github-desktop-*.tar.gz >SHA256SUMS
- name: Создать или обновить GitHub Release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
VERSION: ${{ inputs.version || '3.6.3' }}
run: |
tag="github-desktop-${VERSION}-linux"
if ! gh release view "$tag" >/dev/null 2>&1; then
gh release create "$tag" \
--title "GitHub Desktop ${VERSION} for Linux" \
--notes "Linux artifacts built by Nivora CI from the official desktop/desktop release-${VERSION} source and its pinned submodules."
fi
gh release upload "$tag" \
github-desktop-*.tar.gz \
SHA256SUMS \
--clobber
+49
View File
@@ -0,0 +1,49 @@
name: CI · Проверка репозитория
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: nivora-quality-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
quality:
name: Статика, метаданные и тесты
runs-on: ubuntu-24.04
timeout-minutes: 35
steps:
- name: Получить репозиторий
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Подготовить инструменты
uses: ./.github/actions/setup-stplr-spec
with:
system-packages: jq rpm shellcheck
- name: Выполнить проверки
run: tools/run_checks.sh
- name: Сверить upstream-версии
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
set +e
tools/package_updates.sh check-all
status=$?
set -e
if [[ "$status" -eq 10 ]]; then
echo "::warning::Для одного или нескольких пакетов доступны обновления"
elif [[ "$status" -ne 0 ]]; then
exit "$status"
fi