Test

pre-commit==4.3.0
black==25.9.0
isort==5.13.1
ruff==0.13.2
flake8==7.3.0
flake8-bugbear==23.9.0
flake8-docstrings==1.7.0
pylint==3.2.6
mypy==1.16.0
bandit==1.8.6
detect-secrets==1.4.0
commitizen==4.8.1



default_install_hook_types: [pre-commit, commit-msg, pre-push]

repos:
  # ------------------------------
  # Housekeeping
  # ------------------------------
  - repo: local
    hooks:
      - id: trailing-whitespace
        name: Trim trailing whitespace
        entry: bash -c "sed -i 's/[ \t]*$//' \"$@\"" --
        language: system
        files: .*\.(py|md|txt|yaml|yml|json)$

      - id: end-of-file-fixer
        name: Ensure file ends with newline
        entry: bash -c "[[ -f \"$1\" ]] && sed -i -e '\$a\\' \"$@\"" --
        language: system
        files: .*\.(py|md|txt|yaml|yml|json)$

      - id: check-yaml
        name: Check YAML files
        entry: python -c "import sys, yaml; [yaml.safe_load(open(f)) for f in sys.argv[1:]]"
        language: system
        files: \.(yaml|yml)$

      - id: check-json
        name: Check JSON files
        entry: python -c "import sys, json; [json.load(open(f)) for f in sys.argv[1:]]"
        language: system
        files: \.(json)$

      - id: check-added-large-files
        name: Prevent committing large files (>5MB)
        entry: bash -c 'for f in "$@"; do if [ -f "$f" ] && [ $(stat -c%s "$f") -gt 5242880 ]; then echo "❌ Large file detected: $f"; exit 1; fi; done' --
        language: system
        files: .*

  # ------------------------------
  # Formatters
  # ------------------------------
  - repo: local
    hooks:
      - id: black
        name: black
        entry: black
        language: system
        types: [python]
        args: [--check, --diff]

      - id: isort
        name: isort
        entry: isort
        language: system
        types: [python]
        args: [--check-only, --diff]

  # ------------------------------
  # Linters
  # ------------------------------
  - repo: local
    hooks:
      - id: ruff
        name: ruff
        entry: ruff
        language: system
        types: [python]
        args: [--fix]

      - id: flake8
        name: flake8
        entry: flake8
        language: system
        types: [python]

      - id: pylint
        name: pylint
        entry: pylint
        language: system
        types: [python]
        args: [--errors-only, --jobs=4]

  # ------------------------------
  # Typing
  # ------------------------------
  - repo: local
    hooks:
      - id: mypy
        name: mypy
        entry: mypy
        language: system
        types: [python]
        args: [--ignore-missing-imports]

  # ------------------------------
  # Security
  # ------------------------------
  - repo: local
    hooks:
      - id: bandit
        name: bandit
        entry: bandit
        language: system
        types: [python]
        args: [-r, .]

      - id: detect-secrets
        name: detect-secrets
        entry: detect-secrets
        language: system
        types: [text]
        args: ['--baseline', '.secrets.baseline']
        stages: [commit]

  # ------------------------------
  # Commit message checks
  # ------------------------------
  - repo: local
    hooks:
      - id: commitizen
        name: commitizen
        entry: cz
        language: system
        stages: [commit-msg]
        args: [check]



pre-commit install           # installs pre-commit hook
pre-commit install --hook-type commit-msg   # enforces commitizen rules
pre-commit install --hook-type pre-push     # for push-time checks


pre-commit run --all-files

⚙️ 4. Secrets baseline (for detect-secrets)

Initialize a baseline file (checked into repo):

detect-secrets scan > .secrets.baseline git add .secrets.baseline

This ensures secrets are tracked consistently.


⚙️ 5. Commitizen config

Add pyproject.toml or .cz.toml:

[tool.commitizen] name = "cz_conventional_commits" version = "1.0.0" tag_format = "v$version"

Now you can commit like:

cz commit # guided commit messages

⚙️ 4. Secrets baseline (for detect-secrets)

👉 What is it?
detect-secrets scans your repo for potential secrets (API keys, tokens, passwords).
But you don’t want every existing key in history to break your commits.
That’s why we create a baseline file: .secrets.baseline.

👉 How it works

  • Run this once in your project root:

    detect-secrets scan > .secrets.baseline git add .secrets.baseline
  • This file is committed into your repo.

  • It records all currently known secrets in the code.

  • When a developer commits new code, detect-secrets compares against baseline.

  • ✅ If a new secret appears → it blocks the commit.

  • ✅ If the secret already existed in baseline → commit passes (unless updated).

👉 Why do it?

  • Prevents accidentally committing fresh secrets to Git.

  • Ensures consistent secret scanning across team/CI.


⚙️ 5. Commitizen config

👉 What is it?
commitizen enforces conventional commit messages.
Instead of random commit messages like:

fixed bug

you must follow a structured format like:

fix: handle null values in API response feat: add user login endpoint docs: update API usage in README

👉 How to configure?
You add config to pyproject.toml (or .cz.toml):

[tool.commitizen] name = "cz_conventional_commits" version = "1.0.0" tag_format = "v$version"

👉 How to use it?

  • Instead of writing git commit -m "message", run:

    cz commit
  • It will ask you interactive questions:

    Select type: feat / fix / docs / chore … Enter scope: (optional) Write short description:
  • It generates the commit message automatically.

👉 Why do it?

  • Ensures clean commit history.

  • Automates changelog and versioning.

  • CI/CD pipelines can generate release notes automatically.


In summary:

  • .secrets.baseline → keeps track of what secrets are already in repo so only new leaks are blocked.

  • commitizen → standardizes commit messages so history is structured and usable for releases.

stages: - lint - test - deploy lint: stage: lint image: python:3.11 before_script: - pip install -r requirements.txt - pre-commit install --install-hooks script: - pre-commit run --all-files --show-diff-on-failure




Ui:

#!/bin/sh . "$(dirname "$0")/_/husky.sh" # Run lint-staged (formats and lints staged files) npx lint-staged # Validate JSON npx node scripts/check-json.js **/*.json # Validate YAML npx node scripts/check-yaml.js **/*.{yml,yaml}



chmod +x .husky/pre-commit



#!/bin/sh . "$(dirname "$0")/_/husky.sh" # Enforce Conventional Commits npx commitizen check


chmod +x .husky/commit-msg


const fs = require('fs'); const files = process.argv.slice(2); files.forEach((file) => { const content = fs.readFileSync(file, 'utf8'); try { JSON.parse(content); } catch (err) { console.error(`❌ Invalid JSON: ${file}`); process.exit(1); } });


const fs = require('fs'); const yaml = require('js-yaml'); const files = process.argv.slice(2); files.forEach((file) => { try { yaml.load(fs.readFileSync(file, 'utf8')); } catch (err) { console.error(`❌ Invalid YAML: ${file}`); process.exit(1); } });


{ "name": "your-project", "version": "1.0.0", "scripts": { "prepare": "husky install", "lint": "eslint .", "format": "prettier --write .", "stylelint": "stylelint '**/*.{css,scss}'", "check:json": "node scripts/check-json.js **/*.json", "check:yaml": "node scripts/check-yaml.js **/*.{yml,yaml}" }, "devDependencies": { "husky": "^9.0.0", "lint-staged": "^14.0.0", "prettier": "^3.0.0", "eslint": "^9.0.0", "stylelint": "^16.0.0", "commitizen": "^4.3.0", "cz-conventional-changelog": "^3.3.0", "js-yaml": "^4.1.0" }, "lint-staged": { "*.{js,ts,jsx,tsx,json,css,scss,md,html,yml,yaml}": [ "prettier --write", "eslint --fix", "stylelint --fix", "git add" ] }, "config": { "commitizen": { "path": "cz-conventional-changelog" } } }


# Install dependencies npm install # Husky hooks installed automatically via "prepare" script # Optional: manually add Husky hooks (already included if prepare works) # Pre-commit npx husky add .husky/pre-commit "npx lint-staged && npx node scripts/check-json.js **/*.json && npx node scripts/check-yaml.js **/*.{yml,yaml}" # Commit-msg npx husky add .husky/commit-msg 'npx commitizen check'




npm install --save-dev husky lint-staged prettier eslint stylelint commitizen cz-conventional-changelog js-yaml




# Test lint-staged
npx lint-staged --verbose

# Test JSON/YAML validation
npx node scripts/check-json.js **/*.json
npx node scripts/check-yaml.js **/*.{yml,yaml}

# Test commit message
npx commitizen check




# Test lint-staged
npx lint-staged --verbose

# Test JSON/YAML validation
npx node scripts/check-json.js **/*.json
npx node scripts/check-yaml.js **/*.{yml,yaml}

# Test commit message
npx commitizen check




#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# Run lint-staged (formats and lints staged files)
npx lint-staged

# Validate JSON
npx node scripts/check-json.js **/*.json

# Validate YAML
npx node scripts/check-yaml.js **/*.{yml,yaml}



chmod +x .husky/pre-commit


git commit -m "feat(ui): add dark mode toggle"

npx lint-staged --verbose
npx node scripts/check-json.js **/*.json
npx node scripts/check-yaml.js **/*.{yml,yaml}
npx prettier --check .
npx eslint .
npx stylelint "**/*.{css,scss}"


npm install --save-dev husky lint-staged prettier eslint eslint-plugin-vue eslint-config-prettier eslint-plugin-prettier stylelint commitizen cz-conventional-changelog js-yaml



// eslint.config.js
import vue from 'eslint-plugin-vue';
import prettier from 'eslint-plugin-prettier';

export default [
{
files: ['**/*.{js,vue}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: {
vue,
prettier,
},
rules: {
...vue.configs['vue3-recommended'].rules, // if Vue 3
// ...vue.configs.recommended.rules, // if Vue 2
'prettier/prettier': 'error',
'vue/multi-word-component-names': 'off', // example override
},
},
];



"scripts": {
"lint": "eslint . --ext .js,.vue",
"lint:fix": "eslint . --ext .js,.vue --fix"
}


Comments