Skip to content

ризик, ліквідність і НКД окремою фазою #143

ризик, ліквідність і НКД окремою фазою

ризик, ліквідність і НКД окремою фазою #143

Workflow file for this run

name: ci
on:
push: { branches: [main] }
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
# Версія одна на всі місця: go.mod, Dockerfile і deploy/proxmox-lxc.sh
# мали три різні, і «яка в нас насправді» ставало питанням.
with: { go-version-file: go.mod }
# Формат — окремим кроком і першим: діф, у якому перемішані правка й
# вирівнювання, читати неможливо, а gofmt цю різницю прибирає назавжди.
- name: Формат
run: |
if [ -n "$(gofmt -l .)" ]; then
echo "неформатовані файли:"
gofmt -l .
echo "запусти: make fmt"
exit 1
fi
- run: go vet ./...
# Екшен саме v9: v6 ставить golangci-lint 1.x, який конфіг формату v2
# (.golangci.yml) відкидає як «invalid elements». Версію лінтера
# закріплюємо, щоб локальний `make lint` і CI бачили одне й те саме.
- name: Лінтер
uses: golangci/golangci-lint-action@v9
with: { version: v2.12.2 }
# -race, бо MQTT-публікатор, добовий планувальник і HTTP-сервер ділять
# один стор: саме та форма програми, де гонку не побачиш очима.
- run: go test ./... -race -count=1
# Контракт: фікстура oddinvest/state має бути згенерована поточним кодом.
# Репозиторій ha-oddinvest у своєму CI підтягує contract/ звідси і ганяє
# свої парсери проти цих фікстур.
- run: go test ./internal/state -run TestFixtureUpToDate -count=1
ui:
name: спільний UI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Збірки в UI немає навмисно (сервіс ставиться в LXC без Node, модулі
# віддаються браузеру як є), тож бандлера, який ловив би друкарські
# помилки, теж немає. Ці дві перевірки — його заміна.
- uses: actions/setup-node@v4
with: { node-version: "22" }
# 1. Синтаксис кожного модуля. package.json у каталозі каже node,
# що це ESM, а не CommonJS.
- name: Синтаксис модулів
working-directory: internal/api/web
run: |
for f in $(find js -name '*.js'); do
node --check "$f" || exit 1
done
# 2. Чи резолвиться КОЖЕН імпорт. node --check бачить лише синтаксис і
# пропускає «does not provide an export named X» — найімовірнішу
# помилку після перейменування чи переносу функції між модулями.
- name: Граф імпортів
working-directory: internal/api/web
run: |
cat > /tmp/imports.mjs <<'EOF'
globalThis.HTMLElement = class { attachShadow() { return {}; } };
globalThis.customElements = { get: () => undefined, define: () => {} };
globalThis.localStorage = { getItem: () => null, setItem: () => {} };
globalThis.Document = { prototype: {} };
import { readdirSync, statSync } from "node:fs";
const walk = (d) => readdirSync(d).flatMap((f) =>
statSync(`${d}/${f}`).isDirectory() ? walk(`${d}/${f}`) : [`${d}/${f}`]);
let bad = 0;
for (const m of walk("js").filter((f) => f.endsWith(".js")).sort()) {
try { await import(`${process.cwd()}/${m}`); console.log(`ok ${m}`); }
catch (e) { bad++; console.log(`FAIL ${m}\n ${e.message.split("\n")[0]}`); }
}
process.exit(bad ? 1 : 0);
EOF
node /tmp/imports.mjs
# 3. Чи ВИЗНАЧЕНЕ кожне вжите імʼя. Дві перевірки вище цього не бачать:
# модуль із `fmtCur(...)` у тілі й без `fmtCur` у шапці імпорту має
# правильний синтаксис, чисто резолвиться — і падає в браузері.
# Саме так після розбиття portfolio.js на модулі розділ «Портфель»
# поклався на «fmtCur is not defined», а ще два імені зникли тихо.
#
# eslint тут CI-only: ставиться через npx і в застосунок не
# потрапляє — правило «жодних залежностей у web/» не порушене.
- name: Невизначені імена
run: npx --yes eslint@9 internal/api/web/js
# 3. Манiфест описує те, що є насправді: за ним синхронізується
# вендорена копія в ha-oddinvest, і застарілі хеші зробили б із
# перевірки дрейфу в тому репозиторії пустушку.
- name: Манiфест свіжий
run: sh scripts/gen-ui-manifest.sh --check