diff --git a/.github/workflows/pymarkdownlnt.yml b/.github/workflows/pymarkdownlnt.yml index eecd632..5be7c5d 100644 --- a/.github/workflows/pymarkdownlnt.yml +++ b/.github/workflows/pymarkdownlnt.yml @@ -10,7 +10,7 @@ on: branches: - trunk -permissions: # added using https://github.com/step-security/secure-workflows +permissions: # added using https://github.com/step-security/secure-workflows contents: read jobs: @@ -27,4 +27,6 @@ jobs: - name: Install and run linter run: |- python3 -m pip install --require-hashes -r tools/requirements.txt - pymarkdownlnt -s 'plugins.md024.siblings_only=$!True' scan */*.md + pymarkdownlnt -s 'plugins.md024.siblings_only=$!True' \ + -s 'plugins.md012.maximum=$#2' \ + scan */*.md diff --git a/decisions/2024-09-format-and-lint-tooling.md b/decisions/2024-09-format-and-lint-tooling.md new file mode 100644 index 0000000..68c17fe --- /dev/null +++ b/decisions/2024-09-format-and-lint-tooling.md @@ -0,0 +1,93 @@ +# Format and Lint Tooling + + + +- **Status:** Draft +- **Last Updated:** 2024-09-05 +- **Objective:** Standardize formatting and linting to consistent code styles + +## Context & Problem Statement + +Members of the team use various markup / code styles / formatters outside of +Dart which results in some problematic code reviews containing lots of quote +changes, white space changes, etc. + +## Goals + +- Create a list of formatters for common file types we use to format and lint + code to ensure consistency across the team +- Try to keep the list short and reasonable +- Try to pick tools formatters which are widely available + +### Non-goals + +## Other considerations + +- It is typically a wise and sane choice to pick the native option whenever + available. +- Do the same for linters, and lint ignores. + +> Note: I have brought linters into the equation because they can be affected by +> formatters. For example, I have yet to find a formatter that works with the +> linter we use for the at_protocol specification... thus I think we should +> change that to markdownlint or something that follows the same rules as +> markdownlint. The reason that the linter for the at_protocol specification +> fails is due to whitespace around comments. The linter ignores comments, but +> not whitespace around comments. Every formatter that I've seen pads all +> comments with whitespace, thus the linter sees a double blank line and doesn't +> like it. - @xavierchanth + +## Considered Options + +- ### Option 1 (@xavierchanth's proposal) + +> Not tied to any of these, but these are what I am using as they work well and +> seem to be popular. + + + +| Formatter | Description | Language(s) | +| ------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------- | +| dart format | Native | Dart | +| rustfmt | Native | Rust | +| [gofumpt](https://github.com/mvdan/gofumpt) | Native gofmt with some stricter rules | Go | +| markdownlint-cli2 | Markdown linter/formatter with similar rules to our current linter | Markdown | +| shfmt | Shell formatter | shell | +| gersemi | Cmake formatter | cmake | +| clangd | C family formatter, which supports configuration | C | +| prettier | A formatter for webdev which supports several file types | HTML, CSS, JavaScript, JSON, YAML, (Markdown available) | + +> Note on clangd: we currently have at_c configured to be more like dart format +> +> Note on markdownlint-cli2: pymarkdownlnt (our linter) is based off the rules +> in this linter/formatter +> +> Note on prettier: I think it is a good catch-all for languages where we don't +> care very much about styling but should have something. +> +> Note on missing languages: I don't have a Java or C# formatter currently +> installed, thus I have not recommended formatters for them, but we do have +> some code written in these languages so it would be nice to have +> recommendations. We could also use clangd, but there are probably better +> options. + +- ### Option 2 + +## Proposal Summary + +Proposed a list of formatters for the team to use for various languages. + +## Proposal in Detail + +- After discussing in architecture, @cpswan noted that we chose pymarkdownlnt + because it was easy to get up and running +- Having messed around with pymarkdownlnt locally, I was able to change MD012, + the rule causing issues to allow a maximum of two lines instead of one which + means it works well in most scenarios + - occasionally, we will have to disable MD022 if a pyml comment is next to a + header (only one instance in the at_protocol spec) + +### Expected Consequences + +Less styling changes in our Pull Requests, easier times reviewing. diff --git a/specification/at_protocol_specification.md b/specification/at_protocol_specification.md index 2a4a1d1..54eeaef 100644 --- a/specification/at_protocol_specification.md +++ b/specification/at_protocol_specification.md @@ -167,7 +167,8 @@ in an atServer is bound by the config parameter "maxBufferSize". Metadata of a key should describe the following properties of the value being inserted. - + + | **Meta Attribute** | **Auto create?** | **Description** | | ------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------ | | createdOn | Yes | Date and time when the key has been created. | @@ -221,6 +222,7 @@ and size. An atServer should honor the following configuration parameters. + | **Key** | **Valid Values** | **Description** | | ----------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **autoNotify** | true/false | If set to true, an atServer should automatically notify another atSign user when a key has been shared with them. Please refer to the _notify_ verb spec for details. | @@ -242,6 +244,7 @@ atSign owner using the `from` verb. An atServer should have the following standard keys: + | **Key** | **Description** | | ------------------------- | ------------------------------------------------------------- | | public:publickey@ | Public key used by other atSigns for encryption. | @@ -289,6 +292,7 @@ If the user who is trying to connect is the owner of the atServer, then the e.g: + `data:_4af24c03-d732-48f8-a9a2-570e8fb6a01c@alice:d6cac849-9c29-42b0-b0c5-493db62728b9` If the user who is trying to connect is not the owner of the atServer, then the @@ -459,7 +463,8 @@ The scan verb is used to see the keys in an atSign's secondary server. Following regex represents the syntax of the `scan` verb: - + + `r'^scan$|scan(:showhidden:(?true|false))?(:(?@[^:@\s]+))?( (?\S+))?$'` **Response:** @@ -492,7 +497,8 @@ can only be run by the owner of an atServer on his/her own atServer. Following regex represents the syntax of the `update` verb: - + + `r'^update:(?:ttl:(?\d+):)?(?:ttb:(?\d+):)?(?:ttr:(?(-?)\d+):)?(ccd:(?true|false):)?((?:public:)|(@(?[^@:\s]-):))?(?[^:@]((?!:{2})[^@])+)(?:@(?<@sign>[^@\s]-))? (?.+$)'` **Example:** @@ -537,7 +543,8 @@ If a key has been created for another atSign user, the atServer should honor **Options:** - + + | Option | Required | Description | | ------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `` | No | Time to live in milliseconds | @@ -559,7 +566,8 @@ user without having to send or save the value again. Following is the regex for the `update:meta` verb - + + `^update:meta:((?:public:)|((?@?[^@\s]-):))?(?((?!:{2})[^@])+)@(?[^@:\s]-)(:ttl:(?\d+))?(:ttb:(?\d+))?(:ttr:(?\d+))?(:ccd:(?true|false))?(:isBinary:(?true|false))?(:isEncrypted:(?true|false))?$` **Example:** @@ -599,7 +607,8 @@ configuration parameter. **OPTIONS:** - + + | Option | Required | Description | | ------------ | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `` | No | Time to live in milliseconds | @@ -729,7 +738,8 @@ otherwise the public key has to be returned. **Options:** - + + | Option | Required | Description | | ------------- | -------- | ------------------------------------------------------------------------------------------------------- | | `` | No | `meta` - returns the metadata of the AtKey, `all` - returns both the data and the metadata of the AtKey | @@ -795,7 +805,8 @@ another atSign user. **Options:** - + + | Option | Required | Description | | ------------- | -------- | ------------------------------------------------------------------------------------------------------- | | `` | No | `meta` - returns the metadata of the AtKey, `all` - returns both the data and the metadata of the AtKey | @@ -813,7 +824,8 @@ return the value as is (i.e. without any resolution). The Following is the regex of the `llookup` verb: - + + `^llookup:((?meta|all):)?(?:cached:)?((?:public:)|(@(?[^@:\s]-):))?(?[^:]((?!:{2})[^@])+)@(?<@sign>[^@\s]+)$` **Example:** @@ -857,7 +869,8 @@ llookup should return the value as is. **Options:** - + + | Option | Required | Description | | ------------- | -------- | ------------------------------------------------------------------------------------------------------- | | `` | No | `meta` - returns the metadata of the AtKey, `all` - returns both the data and the metadata of the AtKey | @@ -875,7 +888,8 @@ authenticated atSigns can use the `delete` verb. The following is the regex of the `delete` verb: - + + `^delete(:priority:(?low|medium|high))?(:cached)?(:((?public)|(@(?[^:@\s]+))))?:(?(([^:@\s]+)|(at_secret)))(@(?[^:@\s]+))?$` **Example:** @@ -900,7 +914,8 @@ exist will still respond with a commit id. **Options:** - + + | Option | Required | Description | | ------------ | -------- | ------------------------------------------------------------------------- | | `:cached:` | No | Include `:cached:` if the key you are deleting is cached in your atServer | @@ -928,7 +943,8 @@ The `sync` verb returns a json array of the commit entries from the given commit id to the current commit id. Further, The `sync` verb accepts -1 as argument which returns all the commit entries. - + + ```json data:[{"atKey":"@bob:phone@alice","operation":"+","opTime":"2020-10-26 11:57:43.732","commitId":0,"value":"12345","metadata":{"ttr":"36000000","ccd":"false"}}, {"atKey":"@bob:shared_key@alice","operation":"-","opTime":"2020-10-26 09:44:54.382219Z","commitId":1}] @@ -946,14 +962,16 @@ The `notify` verb enables us to notify the atSign user of some data event. The Following is the regex for the `notify` verb - + + ```text notify:((?update|delete):)?(ttl:(?\d+):)?(ttb:(?\d+):)?(ttr:(?(-)?\d+):)?(ccd:(?true|false):)?(@(?[^@:\s]-)):(?[^:]((?!:{2})[^@])+)@(?[^@:\s]+)(:(?.+))? ``` **Example:** - + + ```json notify:update:ttr:-1:@{RECIPIENT}:{KEY}.{NAMESPACE}@{SENDER}:{BASE64ENCODED_CYPHERTEXT} ``` @@ -1010,7 +1028,8 @@ Following is the regex If the user is the owner, returns a list of received notifications. If a user is pol authenticated user, returns a list of sent notifications - + + `data:[{"id":"0e5e9e89-c9cb-423b-8972-8c5487215990","from":"@alice","to":"@bob","key":"@bob:phone@alice","value":12345,"operation":"update","epochMillis":1603714122636}]` #### The `notify:remove` verb @@ -1072,7 +1091,8 @@ Following is the regex Returns a stream of notifications. - + + ```json @alice@monitor notification: {"id":"773e226d-dac2-4269-b1ee-64d7ce93a42f","from":"@bob","to":"@alice","key":"@alice:phone@bob","value":null,"operation":"update","epochMillis":1603714720965} @@ -1085,7 +1105,8 @@ passing filter criteria as regex to `monitor` verb. **Options:** - + + | Option | Required | Description | | --------- | -------- | ---------------------------------------------------------------- | | `` | No | The regex to filter the notificaitons during the monitor session | @@ -1122,7 +1143,8 @@ statistics are provided: **Example:** - + + `data: [{"id":"1","name":"activeInboundConnections","value":"1"}, {"id":"2","name":"activeOutboundConnections","value":"0"}, {"id":"3","name":"lastCommitID","value":"1"}, {"id":"4","name":"secondaryStorageSize","value":12560}, {"id":"5","name":"topAtSigns","value":{"@bob":1}}, {"id":"6","name":"topKeys","value":{"publickey@alice":1}}]` Individual statistics can be retrieved using the respective Id. @@ -1144,7 +1166,8 @@ Regex: `^info(:brief)?$` `info` - + + ```json data:{"version":"3.0.28","uptimeAsWords":"1 hours 35 minutes 29 seconds","features":[{"name":"noop:","status":"Beta","description":"The No-Op verb simply does nothing for the requested number of milliseconds. The requested number of milliseconds may not be greater than 5000. Upon completion, the noop verb sends 'ok' as a response to the client.","syntax":"^noop:(?\\d+)$"},{"name":"info:","status":"Beta","description":"The Info verb returns some information about the server including uptime and some info about available features. ","syntax":"^info(:brief)?$"}]} ``` @@ -1174,14 +1197,18 @@ After 123ms: `noop:5001` - + + ```text error:AT0022-Exception: noop: where the duration maximum is 5000 milliseconds ``` + + ## Error Codes + | **Error Code** | **Error Message** | **Description** | | -------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | AT0001 | Server exception | Exception occurs when there is an issue while starting the server. |