Two changes that together eliminate changelog merge conflicts from concurrent PRs: 1. **CHANGELOG.md is regenerated only by release.py.** The previous cut still had every changelog.py invocation rewrite CHANGELOG.md with a different [Unreleased] block, so two PRs producing different unreleased content collided on the MD file. Checked-in CHANGELOG.md now contains released versions only. Unreleased is rendered on demand from changelog.d/ via scripts/preview-changelog.py — prints to stdout, writes nothing. 2. **Fragment format: Markdown instead of TOML.** Filenames now look like `<type>-<slug>-<hex4>.md` (e.g. `fixed-dev-version-mismatch-a1b2.md`). Type is readable at-a-glance in the directory listing; 4-char random hex prevents collision when two PRs pick the same slug. Body is plain Markdown with `## English` / `## Русский` sections — renders directly on GitHub, no YAML/TOML parser dependency. - scripts/changelog_lib.py: MD parser replaces tomllib. render_full_md drops the [Unreleased] block; write_md(data) signature simplified; render_unreleased_md(fragments) for on-demand preview. - scripts/changelog.py: writes <type>-<slug>-<hex4>.md, no MD regen. - scripts/release.py: updated to the new write_md signature. - scripts/preview-changelog.py: new. - changelog.d/*.md: 10 existing TOML fragments migrated to MD. One fragment (changelog-entries-now-live-as-per) updated to say Markdown instead of TOML since that's the final state by the time this ships. - CHANGELOG.md: regenerated — Unreleased block gone. - .gitattributes: merge=union moved from *.toml to *.md. - docs/changelog.md, docs/releasing.md, CONTRIBUTING.md, changelog.d/README.md, CLAUDE.md: describe the new format + flow.
2.3 KiB
Contributing to vpnhide
Thanks for your interest. This file covers the contribution process; for build and setup instructions see docs/development.md.
Before you start
- For non-trivial changes, open an issue first to discuss the approach.
- Make sure your change builds locally and passes the CI lints listed in docs/development.md.
Commits
Use conventional-style prefixes, matching the existing history:
fix:— bug fixfeat:— new featurerefactor:— code change without behaviour changedocs:— documentation onlychore:— tooling, release, CI, buildci:— CI-only changes
Scope the prefix where useful: fix(zygisk): …, feat(lsposed): …, fix(kmod): ….
Keep messages focused on why, not what — the diff already shows what changed.
Changelog entry (required for user-visible changes)
Before opening a PR, add a changelog entry:
./scripts/changelog.py <type> "<EN text>" "<RU text>"
# types: added | changed | fixed | removed | deprecated | security
This writes a new Markdown fragment to changelog.d/. That's the only file changed — CHANGELOG.md is regenerated only at release time, which is what keeps concurrent PRs from conflicting. Commit just the fragment alongside your code change. Run ./scripts/preview-changelog.py to see the pending entries together.
Skip the entry for internal refactors with no behaviour change, docs-only, CI-only, and test-only changes.
See docs/changelog.md for the full changelog workflow.
Pull requests
- Target the
mainbranch. - Keep PRs focused — one logical change per PR.
- Include a "why" in the PR description, and a brief "Testing" section if you verified anything manually that CI doesn't cover (hardware testing, specific device models, edge cases).
- CI must pass before merge.
Code style
All style is enforced by CI — run the checks locally before pushing:
- Rust:
cargo fmt+cargo clippy -- -D warnings - C:
clang-formatagainstkmod/vpnhide_kmod.c - Kotlin:
ktlint - Android:
./gradlew :app:lint
License
By contributing, you agree that your contributions will be licensed under the MIT License that covers the project.