|
| 1 | +Welcome! Thanks for looking into contributing to our project! |
| 2 | + |
| 3 | +# Table of Contents |
| 4 | + |
| 5 | +- [Looking for Help?](#looking-for-help) |
| 6 | + - [Documentation](#documentation) |
| 7 | + - [Chat Rooms](#chat-rooms) |
| 8 | +- [Reporting Issues](#reporting-issues) |
| 9 | +- [Submitting Code](#submitting-code) |
| 10 | + - [Coding Style](#coding-style) |
| 11 | + - [Modifying Endpoints](#modifying-endpoints) |
| 12 | + - [Submitting PRs](#submitting-prs) |
| 13 | + - [Where do I start?](#where-do-i-start) |
| 14 | +- [Testing](#testing) |
| 15 | +- [LLM Contributions](#llm-contributions) |
| 16 | + - [Project-related use of LLMs](#project-related-use-of-llms) |
| 17 | + |
| 18 | +# Looking for Help? |
| 19 | + |
| 20 | +Here is a list of helpful resources you can consult: |
| 21 | + |
| 22 | +## Documentation |
| 23 | + |
| 24 | +- [Synapse Admin API Documentation](https://element-hq.github.io/synapse/latest/usage/administration/admin_api/index.html) |
| 25 | + |
| 26 | +## Chat Rooms |
| 27 | + |
| 28 | +- Ruma Matrix room: [#ruma:matrix.org](https://matrix.to/#/#ruma:matrix.org) |
| 29 | +- Ruma Development Matrix room: [#ruma-dev:matrix.org](https://matrix.to/#/#ruma-dev:matrix.org) |
| 30 | +- Synapse Community room: [#synapse:matrix.org](https://matrix.to/#/#synapse:matrix.org) |
| 31 | + |
| 32 | +# Reporting Issues |
| 33 | + |
| 34 | +If you find any bugs, inconsistencies or other problems, feel free to submit |
| 35 | +a GitHub [issue](https://github.com/ruma/synapse-admin-api/issues/new). |
| 36 | + |
| 37 | +If you have a quick question, it may be easier to leave a message in |
| 38 | +[#ruma:matrix.org](https://matrix.to/#/#ruma:matrix.org). |
| 39 | + |
| 40 | +Also, if you have trouble getting on board, let us know so we can help future |
| 41 | +contributors to the project overcome that hurdle too. |
| 42 | + |
| 43 | +# Submitting Code |
| 44 | + |
| 45 | +Ready to write some code? Great! Here are some guidelines to follow to |
| 46 | +help you on your way: |
| 47 | + |
| 48 | +## Coding Style |
| 49 | + |
| 50 | +In general, try to replicate the coding style that is already present. Specifically: |
| 51 | + |
| 52 | +### Naming |
| 53 | + |
| 54 | +For internal consistency, Ruma uses American spelling for variable names. Names may differ in the |
| 55 | +serialized representation, as the Matrix specification has a mix of British and American English. |
| 56 | + |
| 57 | +### Common Types |
| 58 | + |
| 59 | +When writing endpoint definitions, use the following mapping from request / |
| 60 | +response field types listed in the specification to Rust types: |
| 61 | + |
| 62 | +Specification type | Rust type |
| 63 | +-------------------|--------------------------------------------------------------------------------------------------------------------- |
| 64 | +`boolean` | `bool` |
| 65 | +`integer` | `js_int::UInt` (unless denoted as signed, then `js_int::Int`) |
| 66 | +`string` | If for an identifier (e.g. user ID, room ID), use one of the types from `ruma-identifiers`. Otherwise, use `String`. |
| 67 | +`object` | `serde_json::Value` |
| 68 | +`[…]` | `Vec<…>` |
| 69 | +`{string: …}` | `BTreeMap<String, …>` (or `BTreeMap<SomeId, …>`) |
| 70 | + |
| 71 | +### Code Formatting and Linting |
| 72 | + |
| 73 | +We use [rustfmt] to ensure consistent formatting code and [clippy] to catch |
| 74 | +common mistakes not caught by the compiler as well as enforcing a few custom |
| 75 | +code style choices. |
| 76 | + |
| 77 | +```sh |
| 78 | +# if you don't have them installed, install or update the nightly toolchain |
| 79 | +rustup install nightly |
| 80 | +# … and install prebuilt rustfmt and clippy executables (available for most platforms) |
| 81 | +rustup component add rustfmt clippy |
| 82 | +``` |
| 83 | + |
| 84 | +Before committing your changes, run `cargo +nightly fmt` to format the code (if |
| 85 | +your editor / IDE isn't set up to run it automatically) and |
| 86 | +`cargo +nightly clippy --workspace`¹ to run lints. |
| 87 | + |
| 88 | +¹ If you modified feature-gated code (`#[cfg(feature = "something")]`), you |
| 89 | +have to pass `--all-features` or `--features something` to clippy for it to |
| 90 | +check that code |
| 91 | + |
| 92 | +[rustfmt]: https://github.com/rust-lang/rustfmt#readme |
| 93 | +[clippy]: https://github.com/rust-lang/rust-clippy#readme |
| 94 | + |
| 95 | +### (Type) Privacy and Forwards Compatibility |
| 96 | + |
| 97 | +Generally, all `struct`s that are mirroring types defined in the Synapase Admin API docs should have |
| 98 | +all their fields `pub`lic. Where there are restrictions to the fields value beyond their type, these |
| 99 | +should generally be implemented by creating or using a more constrained type than the spec uses for |
| 100 | +that field – for example, we have a number of identifier types but the Matrix spec uses `string` for |
| 101 | +fields that hold user IDs / room IDs and so on. |
| 102 | + |
| 103 | +Almost all types use the `#[non_exhaustive]` attribute, to allow us to adapt to new releases of |
| 104 | +Synapse without having a major release of our crate. You can generally just apply |
| 105 | +`#[non_exhaustive]` to everything – it's a backwards compatible change to remove it in the rare case |
| 106 | +it is not warranted. |
| 107 | + |
| 108 | +Due to this combination of public fields and non-exhaustiveness, all `struct`s generally need a |
| 109 | +constructor function or `From` / `TryFrom` implementation to be able to create them in a |
| 110 | +straight-forward way (always going through `Deserialize` would be quite ugly). |
| 111 | + |
| 112 | +### Import Formatting |
| 113 | + |
| 114 | +Organize your imports into three groups separated by blank lines: |
| 115 | + |
| 116 | +1. `std` imports |
| 117 | +1. External imports (from other crates) |
| 118 | +1. Local imports (`self::`, `super::`, `crate::` and things like `LocalEnum::*`) |
| 119 | + |
| 120 | +For example, |
| 121 | + |
| 122 | +```rust |
| 123 | +use std::collections::BTreeMap; |
| 124 | + |
| 125 | +use ruma_common::api::ruma_api; |
| 126 | + |
| 127 | +use super::MyType; |
| 128 | +``` |
| 129 | + |
| 130 | +### Commit Messages |
| 131 | + |
| 132 | +Write commit messages using the imperative mood, as if completing the sentence: |
| 133 | +"If applied, this commit will \_\_\_." For example, use "Fix some bug" instead |
| 134 | +of "Fixed some bug" or "Add a feature" instead of "Added a feature". |
| 135 | + |
| 136 | +(Take a look at this |
| 137 | +[blog post](https://www.freecodecamp.org/news/writing-good-commit-messages-a-practical-guide/) |
| 138 | +for more information on writing good commit messages.) |
| 139 | + |
| 140 | +## Modifying Endpoints |
| 141 | + |
| 142 | +### Endpoint Module Structure |
| 143 | + |
| 144 | +Synapse uses versioned endpoints (with a few small exceptions), we follow this versioning approach |
| 145 | +in modules as well. |
| 146 | + |
| 147 | +We structure endpoints and their versions like the following; |
| 148 | + |
| 149 | +`endpoint_name::v1` |
| 150 | + |
| 151 | +All bits pertaining a specific version (that can be linked to in the spec) reside in such a module, |
| 152 | +some bits may be shared between endpoint versions, but this should be handled on a case-by-case basis. |
| 153 | + |
| 154 | +Endpoint files may have their version modules embedded; |
| 155 | + |
| 156 | +```rs |
| 157 | +// endpoint_name.rs |
| 158 | + |
| 159 | +mod v1 { |
| 160 | + // (version-specific stuff) |
| 161 | +} |
| 162 | +``` |
| 163 | + |
| 164 | +This happens if the endpoint either has a single version, or a few versions of sufficiently small size. |
| 165 | + |
| 166 | +### Endpoint Documentation Header |
| 167 | + |
| 168 | +Add a comment to the top of each endpoint file that includes the path |
| 169 | +and a link to the documentation of the spec. Replace the version |
| 170 | +marker (`v2`) with a `*`, like so; |
| 171 | + |
| 172 | +```rust |
| 173 | +//! `GET /_synapse/admin/*/users` |
| 174 | +``` |
| 175 | + |
| 176 | +Then, in the subsequent version module, embed the version and specification link like so; |
| 177 | + |
| 178 | +```rs |
| 179 | +pub mod v2 { |
| 180 | + //! `/v2/` ([spec]) |
| 181 | + //! |
| 182 | + //! [spec]: https://github.com/element-hq/synapse/blob/master/docs/admin_api/user_admin_api.md#list-accounts-v2 |
| 183 | +} |
| 184 | +``` |
| 185 | + |
| 186 | +### Naming Endpoints |
| 187 | + |
| 188 | +When adding new endpoints, select the module that fits the purpose of the |
| 189 | +endpoint. When naming the endpoint itself, you can use the following |
| 190 | +guidelines: |
| 191 | +- The name should be a verb describing what the client is requesting, e.g. |
| 192 | + `get_some_resource`. |
| 193 | +- Endpoints which are basic CRUD operations should use the prefixes |
| 194 | + `create`, `get`, `update`, and `delete`. |
| 195 | +- The prefix `set` is preferred to create if the resource is a singleton. |
| 196 | + In other words, when there's no distinction between `create` and `update`. |
| 197 | +- Try to use names that are as descriptive as possible and distinct from |
| 198 | + other endpoints in all other modules. (For example, instead of |
| 199 | + `v1::room::get_event`, use `v1::room::get_room_event`). |
| 200 | +- If you're not sure what to name it, pick any name and we can help you |
| 201 | + with it. |
| 202 | + |
| 203 | +### Tracking Changes |
| 204 | + |
| 205 | +If your changes affect the public API add an entry about them to the change log |
| 206 | +(`CHANGELOG.md`). Where applicable, try to find and denote the version of |
| 207 | +Synapse that included the change you are making. |
| 208 | + |
| 209 | +## Submitting PRs |
| 210 | + |
| 211 | +Once you're ready to submit your code, create a pull request, and one of our |
| 212 | +maintainers will review it. Once your PR has passed review, a maintainer will |
| 213 | +merge the request and you're done! 🎉 |
| 214 | + |
| 215 | +## Where do I start? |
| 216 | + |
| 217 | +If this is your first contribution to the project, we recommend taking a look |
| 218 | +at one of the [open issues][] we've marked for new contributors. |
| 219 | + |
| 220 | +[open issues]: https://github.com/ruma/synapse-admin-api/issues?q=is%3Aissue+is%3Aopen+label%3A"help+wanted" |
| 221 | + |
| 222 | +# Testing |
| 223 | + |
| 224 | +Before committing, run `cargo check` to make sure that your changes can build, |
| 225 | +as well as running the formatting and linting tools |
| 226 | +[mentioned above](#code-formatting-and-linting). |
| 227 | + |
| 228 | +# LLM Contributions |
| 229 | + |
| 230 | +Contributions must not include content generated by large language models |
| 231 | +or other probabilistic tools like ChatGPT, Claude, and Copilot. |
| 232 | + |
| 233 | +This policy exists due to |
| 234 | + |
| 235 | +- ethical concerns about the data gathering for training these models |
| 236 | +- the disproportionate use of electricity and water of building / running them |
| 237 | +- the potential negative influence of LLM-generated content on quality |
| 238 | +- potential copyright violations |
| 239 | + |
| 240 | +This ban of LLM-generated content applies to all parts of the projects, |
| 241 | +including, but not limited to, code, documentation, issues, and artworks. |
| 242 | +An exception applies for purely translating texts for issues and comments to |
| 243 | +English. We may make more exceptions for other accessibility-related uses. |
| 244 | + |
| 245 | +## Project-related use of LLMs |
| 246 | + |
| 247 | +We heavily discourage the use of LLM chat bots as a replacement for reading |
| 248 | +Ruma's documentation and API reference. |
| 249 | + |
| 250 | +Support requests referencing misleading or false LLM output relating to the |
| 251 | +project may be ignored, since it is a waste of time for us to "debug" where |
| 252 | +things went wrong based on this output before human support was sought. |
0 commit comments