From ce888bca40c6498c6741e5f7d4226c4fe1fce7ed Mon Sep 17 00:00:00 2001 From: PhilippTheServer Date: Fri, 25 Sep 2026 02:57:29 +0200 Subject: [PATCH] docs: add code of conduct, contributing guide and CODEOWNERS Closes #13 Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/CODEOWNERS | 1 + .github/workflows/check-wiki.yml | 3 ++ CODE_OF_CONDUCT.md | 72 ++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 37 ++++++++++++++++ README.md | 4 ++ tools/check_wiki.py | 5 ++- tools/check_wikijs.py | 2 +- tools/serve.py | 5 ++- wikijs/bootstrap.py | 5 ++- 9 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..0c16e84 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @PhilippTheServer @maltonoloco diff --git a/.github/workflows/check-wiki.yml b/.github/workflows/check-wiki.yml index 81cd997..db3dc6f 100644 --- a/.github/workflows/check-wiki.yml +++ b/.github/workflows/check-wiki.yml @@ -17,6 +17,9 @@ jobs: with: python-version: '3.14' + - name: Community files + run: test -f CODE_OF_CONDUCT.md && test -f CONTRIBUTING.md && test -f .github/CODEOWNERS + - name: Check every endpoint is documented and every documented path exists run: python3 tools/check_wiki.py diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..fc7df3c --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,72 @@ +# Code of Conduct + +OpenTaberna is built by people who care about getting things right, and who sometimes +get loud when they don't. That is fine. What is not fine is taking it out on each other. + +## The one rule that makes this project different + +**Swear at code all you like. Never swear at people.** + +Allowed: + +- "This function is a goddamn mess." +- "Who the hell thought a 400-line regex was a good idea? Let's rip it out." +- "This build is fucked again." + +Not allowed: + +- "You're an idiot for writing this." +- "Only a moron would ship this." +- Anything aimed at a person's intelligence, competence, identity or worth, whether it + contains swear words or not. + +Criticise the work, never the person who made it. Assume the author had a reason, ask +what it was, and then say how to make it better. If you would be embarrassed to say it to +their face in a room with everyone else present, don't write it. + +## What we expect + +- Be respectful of differing viewpoints and experience levels. +- Give feedback that is concrete and actionable, and take feedback the same way. +- Own your mistakes, apologise to the people affected, and learn from it. +- Focus on what is best for the project and the people using it. + +## What we do not tolerate + +- Insults, slurs or demeaning remarks about anyone, including profanity directed at a + person. +- Harassment, in public or in private, including continued contact after being asked to + stop. +- Discrimination based on age, body size, disability, ethnicity, sex characteristics, + gender identity and expression, level of experience, education, socio-economic status, + nationality, personal appearance, race, religion, or sexual identity and orientation. +- Sexualised language or imagery, and unwelcome sexual attention. +- Publishing others' private information without their explicit permission. +- Trolling, and deliberately derailing discussions. + +## Scope + +This applies in every OpenTaberna space — repositories, issues, pull requests, reviews, +chats — and when you represent the project elsewhere. + +## Reporting + +Report anything that breaks this code to the maintainers, @PhilippTheServer or +@maltonoloco. Reports are handled privately, and the reporter's identity is protected. + +## Enforcement + +Maintainers decide what counts as a breach and respond in proportion: + +1. **Correction** — a private note explaining what was wrong. A public apology may be + requested. +2. **Warning** — a formal warning with consequences for repeat behaviour. +3. **Temporary ban** — no interaction with the project for a set period. +4. **Permanent ban** — for repeated or severe breaches, including harassment. + +Maintainers may remove or edit comments, commits, code, issues and other contributions +that break this code. + +## Attribution + +Adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ed6ea5a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,37 @@ +# Contributing + +Thanks for helping out. Read the [Code of Conduct](CODE_OF_CONDUCT.md) first — swearing +about code is fine, swearing at people is not. + +## How a change gets in + +`main` is protected. Only the maintainers, @PhilippTheServer and @maltonoloco, can push +to it directly. Everyone else goes through a pull request: + +1. **Open an issue** describing the behaviour you expect once it is solved. Small fixes + too — it is where the discussion lives. +2. **Branch** from `main` (or fork, if you have no write access). +3. **Commit and push** your branch. +4. **Open a pull request** against `main` and link the issue with `Closes #N` in the + body. +5. **CI must pass.** These checks are required before the PR can be merged: + - `Wiki matches the API` + - `Wiki.js stack serves the pages with no login` +6. **A maintainer must approve.** Every file is owned by @PhilippTheServer and + @maltonoloco (see [.github/CODEOWNERS](.github/CODEOWNERS)); one of them has to + review and approve. New commits after an approval need a fresh approval. +7. **Squash merge.** The PR lands as a single commit on `main`; delete the branch + afterwards. + +## Before you open the PR + +Run the same checks locally so CI has no surprises: + +```sh +python3 tools/check_wiki.py +docker compose up -d db wiki && docker compose run --rm bootstrap +python3 tools/check_wikijs.py +``` + +Update the docs in the same PR as the change, not afterwards, and add a test that would +fail if your fix regressed. diff --git a/README.md b/README.md index 9b49a86..b01cc6a 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,10 @@ That is the point at which the check bites: pulling in a snapshot with a new end the check fail until somebody documents it. Refreshing the snapshot and updating the pages belong in the same change. +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md). + ## Conventions - Front matter stays. Wiki.js uses `title`, `description`, `published`, `date`, `tags`, diff --git a/tools/check_wiki.py b/tools/check_wiki.py index 26bdf95..b6067e1 100755 --- a/tools/check_wiki.py +++ b/tools/check_wiki.py @@ -33,6 +33,9 @@ ROOT = Path(__file__).resolve().parent.parent SNAPSHOT = ROOT / "openapi.snapshot.json" +# Present in the repository, deliberately not published as a wiki page. +NOT_WIKI_PAGES = {"README", "CODE_OF_CONDUCT", "CONTRIBUTING"} + # Paths the wiki is allowed to mention without them being API endpoints. IGNORED_PATHS = {"/health/live"} @@ -66,7 +69,7 @@ def wiki_pages() -> list[Path]: return sorted( p for p in ROOT.rglob("*.md") - if ".git" not in p.parts and p.name != "README.md" + if ".git" not in p.parts and p.stem not in NOT_WIKI_PAGES ) diff --git a/tools/check_wikijs.py b/tools/check_wikijs.py index 4455e29..619b6c8 100755 --- a/tools/check_wikijs.py +++ b/tools/check_wikijs.py @@ -45,7 +45,7 @@ WIKI_URL = os.environ.get("WIKI_URL", "http://localhost:3000").rstrip("/") # Present in the repository, deliberately not published as a wiki page. -NOT_WIKI_PAGES = {"README"} +NOT_WIKI_PAGES = {"README", "CODE_OF_CONDUCT", "CONTRIBUTING"} LOGIN_MARKERS = ("login-container", "loginBgUrl", "Sign In") diff --git a/tools/serve.py b/tools/serve.py index c535880..b21b24e 100755 --- a/tools/serve.py +++ b/tools/serve.py @@ -23,6 +23,9 @@ ROOT = Path(__file__).resolve().parent.parent PORT = 8090 +# Present in the repository, deliberately not published as a wiki page. +NOT_WIKI_PAGES = {"README", "CODE_OF_CONDUCT", "CONTRIBUTING"} + SHELL = """ @@ -169,7 +172,7 @@ def pages() -> list[str]: found = sorted( p.relative_to(ROOT).as_posix() for p in ROOT.rglob("*.md") - if ".git" not in p.parts and p.name != "README.md" + if ".git" not in p.parts and p.stem not in NOT_WIKI_PAGES ) # home first, it is the landing page found.sort(key=lambda p: (p != "home.md", p)) diff --git a/wikijs/bootstrap.py b/wikijs/bootstrap.py index 694cf5a..1f812cb 100755 --- a/wikijs/bootstrap.py +++ b/wikijs/bootstrap.py @@ -12,7 +12,8 @@ mirror, not a forum. 3. Points the Local File System storage target at the mounted repository and imports every Markdown page. -4. Removes README, which documents the repository rather than the project. +4. Removes README, CODE_OF_CONDUCT and CONTRIBUTING, which document the + repository rather than the project. 5. Rebuilds the sidebar so every page is reachable without knowing its URL. 6. Verifies guests can read without logging in, and grants it if not. @@ -37,7 +38,7 @@ ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "opentaberna-local-admin") # Pages that exist in the repository but are not wiki content. -NOT_WIKI_PAGES = {"README"} +NOT_WIKI_PAGES = {"README", "CODE_OF_CONDUCT", "CONTRIBUTING"} GUEST_GROUP_ID = 2 READ_PERMISSIONS = ["read:pages", "read:assets", "read:comments"]