diff --git a/.commitlintrc.js b/.commitlintrc.js index 76bce06..474a907 100644 --- a/.commitlintrc.js +++ b/.commitlintrc.js @@ -35,6 +35,14 @@ const scopes = [ ]; module.exports = { + // commitlint CLI config (used in CI) + extends: ["@commitlint/config-conventional"], + rules: { + "scope-enum": [2, "always", scopes], + "header-max-length": [2, "always", 100], + }, + + // cz-git config (used by `git cz` interactive prompt) allowCustomIssuePrefixs: false, allowEmptyIssuePrefixs: false, issuePrefixs: [{ value: "Closes" }], diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..788f893 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,48 @@ +# Dependabot автоматически создаёт PR при выходе новых версий зависимостей. +# Документация: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates + +version: 2 + +updates: + # npm: commitlint, cz-git, @commitlint/config-conventional + - package-ecosystem: npm + directory: / + schedule: + interval: monthly + commit-message: + prefix: "chore(other)" + labels: + - dependencies + open-pull-requests-limit: 3 + # Группировка: все npm-обновления в один PR вместо отдельного на каждый пакет + groups: + npm-dependencies: + patterns: + - "*" + # Игнорировать patch-обновления (0.0.x) — обычно это мелкие фиксы, + # которые не стоят отдельного PR для devDependencies + ignore: + - dependency-name: "*" + update-types: + - "version-update:semver-patch" + + # GitHub Actions: actions/checkout, actions/setup-node, actions/cache + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + commit-message: + prefix: "ci(other)" + labels: + - dependencies + - github-actions + open-pull-requests-limit: 3 + # Все actions-обновления в один PR + groups: + github-actions: + patterns: + - "*" + ignore: + - dependency-name: "*" + update-types: + - "version-update:semver-patch" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..85c9260 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,69 @@ +# Конфигурация для actions/labeler. +# Автоматически добавляет лейблы к PR на основе изменённых файлов. +# Документация: https://github.com/actions/labeler + +fish: + - changed-files: + - any-glob-to-any-file: "home/dot_config/fish/**" + +sketchybar: + - changed-files: + - any-glob-to-any-file: "home/dot_config/sketchybar/**" + +yabai: + - changed-files: + - any-glob-to-any-file: "home/dot_config/yabai/**" + +skhd: + - changed-files: + - any-glob-to-any-file: "home/dot_config/skhd/**" + +nvim: + - changed-files: + - any-glob-to-any-file: "home/dot_config/nvim/**" + +wezterm: + - changed-files: + - any-glob-to-any-file: "home/dot_config/wezterm/**" + +yazi: + - changed-files: + - any-glob-to-any-file: "home/dot_config/yazi/**" + +git: + - changed-files: + - any-glob-to-any-file: + - "home/dot_config/git/**" + - "home/dot_config/lazygit/**" + +mise: + - changed-files: + - any-glob-to-any-file: "home/dot_config/mise/**" + +brew: + - changed-files: + - any-glob-to-any-file: "home/dot_config/homebrew/**" + +raycast: + - changed-files: + - any-glob-to-any-file: "home/dot_bin/raycast/**" + +ci: + - changed-files: + - any-glob-to-any-file: + - ".github/**" + - ".commitlintrc.js" + - "package.json" + +docs: + - changed-files: + - any-glob-to-any-file: + - "docs/**" + - "*.md" + +chezmoi: + - changed-files: + - any-glob-to-any-file: + - "home/.chezmoiscripts/**" + - "home/.chezmoiexternals/**" + - "home/.chezmoi*" diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml new file mode 100644 index 0000000..7244aae --- /dev/null +++ b/.github/workflows/commit-lint.yml @@ -0,0 +1,31 @@ +# Проверка коммитов на соответствие Conventional Commits. +# Использует commitlint с конфигом из .commitlintrc.js. +# +# wagoid/commitlint-github-action — готовый action, который: +# 1. Сам устанавливает Node.js и зависимости из package.json +# 2. Корректно обрабатывает force-push, merge-коммиты, squash +# 3. Проверяет все коммиты в PR за один шаг + +name: Commit Lint + +on: + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + commitlint: + name: Validate commits + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # wagoid/commitlint-github-action сам найдёт .commitlintrc.js, + # установит зависимости и проверит все коммиты в PR. + - uses: wagoid/commitlint-github-action@v6 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000..a29dfb5 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,26 @@ +# Автоматически добавляет лейблы к PR на основе изменённых файлов. +# Конфигурация маппинга: .github/labeler.yml +# +# Пример: PR с изменениями в home/dot_config/fish/ получит лейбл "fish". +# Лейблы создаются автоматически при первом использовании. + +name: Labeler + +on: + pull_request_target: + types: [opened, synchronize, reopened] + +# Нужны права для добавления лейблов к PR +permissions: + contents: read + pull-requests: write + +jobs: + labeler: + name: Label PR + runs-on: ubuntu-latest + + steps: + - uses: actions/labeler@v5 + with: + sync-labels: true diff --git a/.github/workflows/lock-threads.yml b/.github/workflows/lock-threads.yml new file mode 100644 index 0000000..ae79fed --- /dev/null +++ b/.github/workflows/lock-threads.yml @@ -0,0 +1,50 @@ +# Автоматическая блокировка неактивных issues и PR. +# +# После N дней без активности добавляет комментарий и блокирует обсуждение. +# Это предотвращает некропостинг в старых issues и поддерживает порядок. +# +# dessant/lock-threads запускается по расписанию (cron) и проверяет +# все закрытые issues/PR на дату последней активности. + +name: Lock Threads + +on: + schedule: + # Запуск раз в неделю, в понедельник в 00:00 UTC + - cron: "0 0 * * 1" + + # Позволяет запустить вручную из вкладки Actions + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + +concurrency: + group: lock-threads + +jobs: + lock: + name: Lock old threads + runs-on: ubuntu-latest + + steps: + - uses: dessant/lock-threads@v5 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + # Блокировать issues, закрытые более 60 дней назад + issue-inactive-days: 60 + issue-comment: > + This issue has been automatically locked since there + has been no recent activity after it was closed. + Please open a new issue for related bugs or questions. + issue-lock-reason: resolved + + # Блокировать PR, закрытые/смёрженные более 60 дней назад + pr-inactive-days: 60 + pr-comment: > + This pull request has been automatically locked since there + has been no recent activity after it was closed. + Please open a new issue for related discussions. + pr-lock-reason: resolved diff --git a/.github/workflows/lua-lint.yml b/.github/workflows/lua-lint.yml new file mode 100644 index 0000000..d04e0af --- /dev/null +++ b/.github/workflows/lua-lint.yml @@ -0,0 +1,61 @@ +# Проверка форматирования Lua-файлов с помощью StyLua. +# Покрывает: SketchyBar, Neovim, WezTerm, Yazi. +# +# StyLua — форматтер для Lua, аналог Prettier для JS. +# Использует конфиг из home/dot_config/nvim/stylua.toml: +# indent_type = "Tabs", indent_width = 4, column_width = 120 + +name: Lua Lint + +on: + push: + branches: [main] + # Запускается только при изменении Lua-файлов + paths: + - "home/dot_config/**/*.lua" + pull_request: + branches: [main] + paths: + - "home/dot_config/**/*.lua" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# Версия StyLua — вынесена в env для удобства обновления +env: + STYLUA_VERSION: "2.0.2" + +jobs: + stylua: + name: StyLua format check + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + # Скачать StyLua из GitHub Releases и добавить в PATH. + # Кешируется между запусками по версии. + - name: Cache StyLua + id: cache-stylua + uses: actions/cache@v4 + with: + path: ~/.local/bin/stylua + key: stylua-${{ env.STYLUA_VERSION }} + + - name: Install StyLua + if: steps.cache-stylua.outputs.cache-hit != 'true' + run: | + mkdir -p ~/.local/bin + curl -fsSL "https://github.com/JohnnyMorganz/StyLua/releases/download/v${STYLUA_VERSION}/stylua-linux-x86_64.zip" -o stylua.zip + unzip stylua.zip -d ~/.local/bin + chmod +x ~/.local/bin/stylua + + - name: Add StyLua to PATH + run: echo "$HOME/.local/bin" >> "$GITHUB_PATH" + + # --check: не модифицирует файлы, только проверяет. + # Если форматирование не соответствует — exit code 1. + # --config-path: путь к stylua.toml (он лежит в nvim/, но применим ко всем Lua) + - name: Check Lua formatting + run: stylua --check --config-path home/dot_config/nvim/stylua.toml home/ diff --git a/.github/workflows/markdown-lint.yml b/.github/workflows/markdown-lint.yml new file mode 100644 index 0000000..2c19898 --- /dev/null +++ b/.github/workflows/markdown-lint.yml @@ -0,0 +1,37 @@ +# Линтинг Markdown-документации. +# +# Проверяет: последовательность заголовков, пустые строки вокруг блоков кода, +# корректность списков, длину строк и другие правила форматирования. +# Конфигурация: .markdownlint.yml (создаётся в этом же коммите). + +name: Markdown Lint + +on: + push: + branches: [main] + paths: + - "**/*.md" + pull_request: + branches: [main] + paths: + - "**/*.md" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + markdownlint: + name: Lint Markdown + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + # avto-dev/markdown-lint — запускает markdownlint-cli в Docker. + # fix: false — только проверка, без автоисправления. + # config: путь к конфигу с правилами. + - uses: avto-dev/markdown-lint@v1 + with: + args: "**/*.md" + config: ".markdownlint.yml" diff --git a/.github/workflows/misspell.yml b/.github/workflows/misspell.yml new file mode 100644 index 0000000..2e1abef --- /dev/null +++ b/.github/workflows/misspell.yml @@ -0,0 +1,49 @@ +# Поиск опечаток в коде, комментариях и документации. +# +# Использует reviewdog + misspell — оставляет inline-комментарии +# прямо в diff PR, указывая на конкретную строку с опечаткой. +# На push в main просто фейлится при наличии опечаток. + +name: Misspell + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + misspell: + name: Check spelling + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + # reviewdog/action-misspell: + # - Сканирует все текстовые файлы в репозитории + # - На PR: оставляет inline-комментарии с предложениями исправлений + # - На push: выводит ошибки в лог + # - locale: US — проверяет по американскому английскому + - uses: reviewdog/action-misspell@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review + locale: US + level: warning + # Пропускать бинарные и сгенерированные файлы + exclude: | + .git/* + node_modules/* + *.png + *.jpg + *.gif + *.ico diff --git a/.github/workflows/shell-lint.yml b/.github/workflows/shell-lint.yml new file mode 100644 index 0000000..4506822 --- /dev/null +++ b/.github/workflows/shell-lint.yml @@ -0,0 +1,72 @@ +# Проверка синтаксиса Fish и Bash скриптов. +# +# Fish: `fish --no-execute` — парсит скрипт без выполнения (аналог bash -n). +# Bash: reviewdog/action-shellcheck — оставляет inline-комментарии в PR +# с описанием каждой проблемы от ShellCheck. +# +# .fish.tmpl файлы пропускаются — они содержат Go-шаблоны chezmoi, +# которые ломают синтаксис Fish до обработки. + +name: Shell Lint + +on: + push: + branches: [main] + paths: + - "home/**/*.fish" + - "home/**/*.sh" + pull_request: + branches: [main] + paths: + - "home/**/*.fish" + - "home/**/*.sh" + +permissions: + contents: read + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + fish-syntax: + name: Fish syntax check + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + # Fish shell доступен через PPA + - name: Install Fish shell + run: | + sudo apt-add-repository -y ppa:fish-shell/release-4 + sudo apt-get update + sudo apt-get install -y fish + + # Найти все .fish файлы (но НЕ .fish.tmpl) и проверить синтаксис. + # --no-execute: только парсинг, без выполнения. + - name: Check Fish syntax + run: | + find home/ -name '*.fish' -not -name '*.fish.tmpl' -print0 | \ + xargs -0 -I{} fish --no-execute {} + + shellcheck: + name: ShellCheck + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + # reviewdog/action-shellcheck: + # - На PR: оставляет inline-комментарии прямо в diff + # - На push: выводит ошибки в лог + # - Гораздо информативнее, чем просто "job failed" + - uses: reviewdog/action-shellcheck@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review + level: warning + path: home/ + pattern: "*.sh" + shellcheck_flags: "--severity=warning" diff --git a/.github/workflows/validate-configs.yml b/.github/workflows/validate-configs.yml new file mode 100644 index 0000000..2ec3844 --- /dev/null +++ b/.github/workflows/validate-configs.yml @@ -0,0 +1,134 @@ +# Валидация конфигурационных файлов: JSON, YAML, TOML. +# Проверяет только синтаксис (парсится ли файл), не схему. +# +# dorny/paths-filter определяет какие типы файлов изменились, +# и запускает только соответствующие jobs. Если изменён только .toml — +# JSON и YAML jobs пропускаются. +# +# .tmpl файлы пропускаются — они содержат Go-шаблоны chezmoi. + +name: Validate Configs + +on: + push: + branches: [main] + paths: + - "home/**/*.json" + - "home/**/*.yml" + - "home/**/*.yaml" + - "home/**/*.toml" + pull_request: + branches: [main] + paths: + - "home/**/*.json" + - "home/**/*.yml" + - "home/**/*.yaml" + - "home/**/*.toml" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # Определяет, какие типы файлов изменились. + # Остальные jobs используют needs + if для условного запуска. + changes: + name: Detect changes + runs-on: ubuntu-latest + + outputs: + json: ${{ steps.filter.outputs.json }} + yaml: ${{ steps.filter.outputs.yaml }} + toml: ${{ steps.filter.outputs.toml }} + + steps: + - uses: actions/checkout@v4 + + # dorny/paths-filter — сравнивает файлы в PR/push с базовой веткой + # и выдаёт булевы outputs для каждого фильтра. + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + json: + - "home/**/*.json" + yaml: + - "home/**/*.yml" + - "home/**/*.yaml" + toml: + - "home/**/*.toml" + + json: + name: Validate JSON + runs-on: ubuntu-latest + needs: changes + if: needs.changes.outputs.json == 'true' + + steps: + - uses: actions/checkout@v4 + + # python3 -m json.tool — встроенный JSON-валидатор Python. + # Пропускаем .json.tmpl (содержат Go-шаблоны). + - name: Validate JSON files + run: | + failed=0 + while IFS= read -r -d '' file; do + if ! python3 -m json.tool "$file" > /dev/null 2>&1; then + echo "::error file=$file::Invalid JSON syntax" + failed=1 + fi + done < <(find home/ -name '*.json' -not -name '*.json.tmpl' -print0) + + if [ "$failed" -eq 1 ]; then + exit 1 + fi + echo "All JSON files are valid" + + yaml: + name: Validate YAML + runs-on: ubuntu-latest + needs: changes + if: needs.changes.outputs.yaml == 'true' + + steps: + - uses: actions/checkout@v4 + + # yamllint — линтер для YAML, проверяет синтаксис и стиль. + # -d relaxed: менее строгие правила (допускает длинные строки и т.п.) + - name: Install yamllint + run: pip install yamllint + + - name: Validate YAML files + run: | + files=$(find home/ -name '*.yml' -o -name '*.yaml' | grep -v '.tmpl$' || true) + if [ -n "$files" ]; then + echo "$files" | xargs yamllint -d relaxed + else + echo "No YAML files to validate" + fi + + toml: + name: Validate TOML + runs-on: ubuntu-latest + needs: changes + if: needs.changes.outputs.toml == 'true' + + steps: + - uses: actions/checkout@v4 + + # Python 3.11+ имеет встроенный модуль tomllib. + # Используем его для валидации без внешних зависимостей. + - name: Validate TOML files + run: | + failed=0 + while IFS= read -r -d '' file; do + if ! python3 -c "import tomllib; tomllib.load(open('$file', 'rb'))" 2>&1; then + echo "::error file=$file::Invalid TOML syntax" + failed=1 + fi + done < <(find home/ -name '*.toml' -not -name '*.toml.tmpl' -print0) + + if [ "$failed" -eq 1 ]; then + exit 1 + fi + echo "All TOML files are valid" diff --git a/.markdownlint.yml b/.markdownlint.yml new file mode 100644 index 0000000..f36db80 --- /dev/null +++ b/.markdownlint.yml @@ -0,0 +1,18 @@ +# Конфигурация markdownlint. +# Документация правил: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md + +# Разрешить длинные строки — в документации часто встречаются длинные ссылки и таблицы +MD013: false + +# Разрешить inline HTML — используется в README для бейджей и изображений +MD033: false + +# Разрешить дублирование заголовков в разных секциях (например, "Installation" в нескольких docs) +MD024: + siblings_only: true + +# Разрешить несколько заголовков первого уровня (некоторые .md файлы — не документы с одним h1) +MD025: false + +# Разрешить отсутствие пустой строки перед списком внутри blockquote +MD032: false