ci: ubuntu-latest workflows + dependabot (#18)

* ci: migrate workflows + dependabot from opencode

* ci: replace self-hosted with ubuntu-latest + update paths

* ci: add bootstrap job + hashFiles conditions for bootstrapping

* docs(handoff): add pr-6 handoff + ADR-002

* fix(ci): wrap hashFiles in expression syntax for job-level if

* fix(ci): replace hashFiles with output-based skip conditions

* docs(handoff): update pr-6 handoff + ADR-002 for output-based

* docs(handoff): fix PR number in handoff filename

* docs: add project map for PR #18

---------

Co-authored-by: opencode-agent <agent@slaid098.dev>
This commit is contained in:
Sergey 2026-07-23 22:22:09 +03:00 committed by GitHub
parent e1f427511e
commit 1dbec56140
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 271 additions and 0 deletions

17
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,17 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 5
- package-ecosystem: "npm"
directory: "/config"
schedule:
interval: weekly
open-pull-requests-limit: 5
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 5

33
.github/workflows/adr-check.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: ADR References Check
on:
pull_request:
paths:
- 'docs/**'
- '.opencode/**'
- '**/*.md'
- '.github/workflows/adr-check.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- id: check
run: |
if [ -f .opencode/scripts/check-adr-refs.py ]; then
echo "has_script=true" >> $GITHUB_OUTPUT
else
echo "has_script=false" >> $GITHUB_OUTPUT
fi
- uses: actions/setup-python@v5
if: steps.check.outputs.has_script == 'true'
with:
python-version: "3.12"
- run: python3 .opencode/scripts/check-adr-refs.py
if: steps.check.outputs.has_script == 'true'

93
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,93 @@
name: CI
on:
pull_request:
branches: [main]
paths-ignore: ['**/*.md', 'docs/**', 'LICENSE']
push:
branches: [main]
paths-ignore: ['**/*.md', 'docs/**', 'LICENSE']
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
bootstrap:
runs-on: ubuntu-latest
outputs:
has_src: ${{ steps.check.outputs.has_src }}
steps:
- uses: actions/checkout@v4
- id: check
run: |
if [ -n "$(find src/ -name '*.py' -print -quit 2>/dev/null)" ]; then
echo "has_src=true" >> $GITHUB_OUTPUT
else
echo "has_src=false" >> $GITHUB_OUTPUT
fi
- run: echo "CI bootstrap OK"
lint:
needs: bootstrap
if: needs.bootstrap.outputs.has_src == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@v3
- run: uv sync --extra dev
- run: uv run ruff check src/ tests/ .opencode/scripts/
- run: uv run ruff format --check src/ tests/ .opencode/scripts/
typecheck:
needs: bootstrap
if: needs.bootstrap.outputs.has_src == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@v3
- run: uv sync --extra dev
- run: uv run mypy src/
test:
needs: bootstrap
if: needs.bootstrap.outputs.has_src == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
python: ["3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- uses: actions/setup-node@v4
with:
node-version: '22'
- uses: astral-sh/setup-uv@v3
- run: uv sync --extra dev --python ${{ matrix.python }}
- run: uv run --python ${{ matrix.python }} pytest
complexity:
needs: bootstrap
if: needs.bootstrap.outputs.has_src == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@v3
- run: uv sync --extra dev
- run: uv run xenon --max-absolute B --max-modules A --max-average A src/

33
.github/workflows/permissions-check.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: Permission Security Check
on:
pull_request:
paths:
- '.opencode/opencode.json'
- '.opencode/agents/**'
- '.opencode/scripts/check-permissions.py'
- '.github/workflows/permissions-check.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- id: check
run: |
if [ -f .opencode/scripts/check-permissions.py ]; then
echo "has_script=true" >> $GITHUB_OUTPUT
else
echo "has_script=false" >> $GITHUB_OUTPUT
fi
- uses: actions/setup-python@v5
if: steps.check.outputs.has_script == 'true'
with:
python-version: "3.12"
- run: python3 .opencode/scripts/check-permissions.py
if: steps.check.outputs.has_script == 'true'

View file

@ -0,0 +1,22 @@
# ADR-001: CI bootstrap job + output-based skip conditions
## Статус
Accepted
## Контекст
Chicken-and-egg: pipeline-driver требует CI ✅ для merge, но CI не может работать без #7 (scripts) и #5 (src/tests). Нужен способ иметь CI runs на каждом PR даже когда src/ и scripts/ ещё не мигрированы.
## Решение
1. ci.yml: bootstrap job (checkout + file check + always passes) — гарантирует CI run → pipeline_status CI phase = DONE
2. lint/test/typecheck/complexity jobs: `if: needs.bootstrap.outputs.has_src == 'true'` — skip без src/*.py
3. permissions-check/adr-check: step-level file checks (checkout → check script exists → conditional run)
## Альтернативы
- `hashFiles()` в job-level `if` — отклонено: GitHub Actions не распознаёт `hashFiles` как функцию в job-level `if` (ошибка "Unrecognized function: 'hashFiles'"). Заменено на output-based conditions.
- Объединить #5+#6+#7 в один PR — отклонено (пользователь хочет атомарные PR)
- Merge без pipeline-driver (admin override) — отклонено (нарушает pipeline протокол)
- ci.yml без modifications (перенести как есть) — отклонено (CI падает без src/tests, нет runs → AMBIGUOUS → pipeline STOP)

View file

@ -0,0 +1,36 @@
# PR #18: CI workflows (ubuntu-latest) + dependabot
## Что сделано
- Перенесены .github/workflows/ (ci.yml, permissions-check.yml, adr-check.yml) + dependabot.yml
- runs-on: [self-hosted, linux] → ubuntu-latest (security risk для public repo)
- config/scripts/ → .opencode/scripts/ (пути в run steps + trigger paths)
- ci.yml: branches [master] → [main] (новый репо использует main)
- ci.yml: matrix 3.14 добавлен (ubuntu-latest поддерживает, self-hosted комментарий убран)
- ci.yml: добавлен bootstrap job (checkout + file check + always passes) + output-based skip conditions на lint/test/typecheck/complexity (skip без src/*.py)
- permissions-check.yml, adr-check.yml: step-level file checks (skip script execution без .opencode/scripts/)
## Почему
Bootstrapping: CI нужен до #7 (.opencode/ scripts) и #5 (src/tests). bootstrap job гарантирует CI run на каждом PR. Output-based conditions skip jobs которые не могут работать без src/ или scripts/.
## Отклонение от spec
- hashFiles() не распознан GitHub Actions в job-level `if` — заменён на output-based conditions (bootstrap job checks files, sets `has_src` output, jobs use `if: needs.bootstrap.outputs.has_src == 'true'`)
- permissions-check/adr-check: job-level `if` заменён на step-level file checks (checkout → check → conditional run)
- Дополнительно: branches [master] → [main], trigger paths config/ → .opencode/ (spec не упоминал)
## Pending
- После #7: permissions-check/adr-check jobs активируются (scripts доступны)
- После #5 (merge PR#17): lint/test/typecheck/complexity jobs активируются (src/ доступен)
- Matrix 3.14 — проверить совместимость с ubuntu-latest
## Watch out
- ci.yml НЕ перенесён "как есть" — добавлен bootstrap job + output-based conditions (адаптация для bootstrapping)
- hashFiles() не работает в GitHub Actions job-level `if` — это известное ограничение, см. ADR-001
- branches: [master] → [main] — старый репо использовал master, новый main
- trigger paths в permissions-check.yml/adr-check.yml: config/ → .opencode/ (config/ не существует в новом репо)
- permissions-check.yml, adr-check.yml — skip до #7 (нет .opencode/scripts/)
- dependabot.yml — без изменений (directory: "/config" для npm безвреден — директория не существует, dependabot просто пропустит)

View file

@ -0,0 +1,37 @@
# Project Map
opencode-config — Docker-based AI coding assistant with persistent memory (opencode configuration).
## Structure
```
opencode-config/
├── .github/
│ ├── workflows/
│ │ ├── ci.yml # Lint, test, typecheck, complexity (bootstrap + output-based skip)
│ │ ├── permissions-check.yml # .opencode/scripts/permissions.py validator (step-level skip)
│ │ └── adr-check.yml # ADR cross-reference validator (step-level skip)
│ └── dependabot.yml # pip + github-actions ecosystem updates
├── docs/
│ ├── handoff/ # PR handoffs (pr-<N>-<slug>.md)
│ ├── decisions/ # ADRs (NNN-pr-<N>-<slug>.md)
│ └── project-map/ # This file — structure snapshot
├── app_data/
│ ├── workspaces/ # Agent working directory (.gitkeep)
│ └── ssh/ # SSH keys, not in git (.gitkeep)
├── .editorconfig
├── .gitignore
├── .python-version
├── LICENSE
└── README.md
```
## Pending (future PRs)
- `.opencode/` — global opencode config (agents, skills, tools, scripts) — after #7
- `src/` — Python RAG CLI (second-brain) — after #5 (PR#17)
- `tests/` — pytest test suite — after #5
## Update Protocol
Updated by docs-reviewer subagent on each PR. Reflects tracked files only (`git ls-files`).