Skip to content

Commit b21d5d2

Browse files
authored
Merge pull request #1804 from Roasbeef/gemini-config
gemini: add config and style guidelines
2 parents 2c865a0 + e8132e0 commit b21d5d2

File tree

2 files changed

+343
-0
lines changed

2 files changed

+343
-0
lines changed

.gemini/config.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Config for the Gemini Pull Request Review Bot.
2+
# https://github.com/marketplace/gemini-code-assist
3+
have_fun: false
4+
code_review:
5+
disable: false
6+
comment_severity_threshold: MEDIUM
7+
max_review_comments: -1
8+
pull_request_opened:
9+
help: false
10+
summary: true
11+
code_review: true
12+
ignore_patterns: []

.gemini/styleguide.md

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
# tapd Style Guide
2+
3+
## Code Documentation and Commenting
4+
5+
- Always use the Golang code style described below in this document.
6+
- Readable code is the most important requirement for any commit created.
7+
- Comments must not explain the code 1:1 but instead explain the _why_ behind a
8+
certain block of code, in case it requires contextual knowledge.
9+
- Unit tests must always use the `require` library. Either table driven unit
10+
tests or tests using the `rapid` library are preferred.
11+
- The line length MUST NOT exceed 80 characters, this is very important.
12+
You must count the Golang indentation (tabulator character) as 8 spaces when
13+
determining the line length. Use creative approaches or the wrapping rules
14+
specified below to make sure the line length isn't exceeded. HOWEVER: during
15+
code reviews, please leave this check up to the linter and do not comment on
16+
it (why? because gemini is bad at counting characters).
17+
- Every function must be commented with its purpose and assumptions.
18+
- Function comments must begin with the function name.
19+
- Function comments should be complete sentences.
20+
- Exported functions require detailed comments for the caller.
21+
22+
**WRONG**
23+
```go
24+
// generates a revocation key
25+
func DeriveRevocationPubkey(commitPubKey *btcec.PublicKey,
26+
revokePreimage []byte) *btcec.PublicKey {
27+
```
28+
**RIGHT**
29+
```go
30+
// DeriveRevocationPubkey derives the revocation public key given the
31+
// counterparty's commitment key, and revocation preimage derived via a
32+
// pseudo-random-function. In the event that we (for some reason) broadcast a
33+
// revoked commitment transaction, then if the other party knows the revocation
34+
// preimage, then they'll be able to derive the corresponding private key to
35+
// this private key by exploiting the homomorphism in the elliptic curve group.
36+
//
37+
// The derivation is performed as follows:
38+
//
39+
// revokeKey := commitKey + revokePoint
40+
// := G*k + G*h
41+
// := G * (k+h)
42+
//
43+
// Therefore, once we divulge the revocation preimage, the remote peer is able
44+
// to compute the proper private key for the revokeKey by computing:
45+
// revokePriv := commitPriv + revokePreimge mod N
46+
//
47+
// Where N is the order of the sub-group.
48+
func DeriveRevocationPubkey(commitPubKey *btcec.PublicKey,
49+
revokePreimage []byte) *btcec.PublicKey {
50+
```
51+
- In-body comments should explain the *intention* of the code.
52+
53+
**WRONG**
54+
```go
55+
// return err if amt is less than 546
56+
if amt < 546 {
57+
return err
58+
}
59+
```
60+
**RIGHT**
61+
```go
62+
// Treat transactions with amounts less than the amount which is considered dust
63+
// as non-standard.
64+
if amt < 546 {
65+
return err
66+
}
67+
```
68+
69+
## Code Spacing and formatting
70+
71+
- Segment code into logical stanzas separated by newlines.
72+
73+
**WRONG**
74+
```go
75+
witness := make([][]byte, 4)
76+
witness[0] = nil
77+
if bytes.Compare(pubA, pubB) == -1 {
78+
witness[1] = sigB
79+
witness[2] = sigA
80+
} else {
81+
witness[1] = sigA
82+
witness[2] = sigB
83+
}
84+
witness[3] = witnessScript
85+
return witness
86+
```
87+
**RIGHT**
88+
```go
89+
witness := make([][]byte, 4)
90+
91+
// When spending a p2wsh multi-sig script, rather than an OP_0, we add
92+
// a nil stack element to eat the extra pop.
93+
witness[0] = nil
94+
95+
// When initially generating the witnessScript, we sorted the serialized
96+
// public keys in descending order. So we do a quick comparison in order
97+
// to ensure the signatures appear on the Script Virtual Machine stack in
98+
// the correct order.
99+
if bytes.Compare(pubA, pubB) == -1 {
100+
witness[1] = sigB
101+
witness[2] = sigA
102+
} else {
103+
witness[1] = sigA
104+
witness[2] = sigB
105+
}
106+
107+
// Finally, add the preimage as the last witness element.
108+
witness[3] = witnessScript
109+
110+
return witness
111+
```
112+
113+
- Use spacing between `case` and `select` stanzas.
114+
115+
**WRONG**
116+
```go
117+
switch {
118+
case a:
119+
<code block>
120+
case b:
121+
<code block>
122+
case c:
123+
<code block>
124+
case d:
125+
<code block>
126+
default:
127+
<code block>
128+
}
129+
```
130+
**RIGHT**
131+
```go
132+
switch {
133+
// Brief comment detailing instances of this case (repeat below).
134+
case a:
135+
<code block>
136+
137+
case b:
138+
<code block>
139+
140+
case c:
141+
<code block>
142+
143+
case d:
144+
<code block>
145+
146+
default:
147+
<code block>
148+
}
149+
```
150+
151+
## Additional Style Constraints
152+
153+
### 80 character line length
154+
155+
- Wrap columns at 80 characters.
156+
- Tabs are 8 spaces.
157+
158+
**WRONG**
159+
```go
160+
myKey := "0214cd678a565041d00e6cf8d62ef8add33b4af4786fb2beb87b366a2e151fcee7"
161+
```
162+
163+
**RIGHT**
164+
```go
165+
myKey := "0214cd678a565041d00e6cf8d62ef8add33b4af4786fb2beb87b366a2e1" +
166+
"51fcee7"
167+
```
168+
169+
### Wrapping long function calls
170+
171+
- If a function call exceeds the column limit, place the closing parenthesis
172+
on its own line and start all arguments on a new line after the opening
173+
parenthesis.
174+
175+
**WRONG**
176+
```go
177+
value, err := bar(a,
178+
a, b, c)
179+
```
180+
181+
**RIGHT**
182+
```go
183+
value, err := bar(
184+
a, a, b, c,
185+
)
186+
```
187+
188+
- Compact form is acceptable if visual symmetry of parentheses is preserved.
189+
190+
**ACCEPTABLE**
191+
```go
192+
response, err := node.AddInvoice(
193+
ctx, &lnrpc.Invoice{
194+
Memo: "invoice",
195+
ValueMsat: int64(oneUnitMilliSat - 1),
196+
},
197+
)
198+
```
199+
200+
**PREFERRED**
201+
```go
202+
response, err := node.AddInvoice(ctx, &lnrpc.Invoice{
203+
Memo: "invoice",
204+
ValueMsat: int64(oneUnitMilliSat - 1),
205+
})
206+
```
207+
208+
### Exception for log and error message formatting
209+
210+
- Minimize lines for log and error messages, while adhering to the
211+
80-character limit.
212+
213+
**WRONG**
214+
```go
215+
return fmt.Errorf(
216+
"this is a long error message with a couple (%d) place holders",
217+
len(things),
218+
)
219+
220+
log.Debugf(
221+
"Something happened here that we need to log: %v",
222+
longVariableNameHere,
223+
)
224+
```
225+
226+
**RIGHT**
227+
```go
228+
return fmt.Errorf("this is a long error message with a couple (%d) place "+
229+
"holders", len(things))
230+
231+
log.Debugf("Something happened here that we need to log: %v",
232+
longVariableNameHere)
233+
```
234+
235+
### Exceptions and additional styling for structured logging
236+
237+
- **Static messages:** Use key-value pairs instead of formatted strings for the
238+
`msg` parameter.
239+
- **Key-value attributes:** Use `slog.Attr` helper functions.
240+
- **Line wrapping:** Structured log lines are an exception to the 80-character
241+
rule. Use one line per key-value pair for multiple attributes.
242+
243+
**WRONG**
244+
```go
245+
log.DebugS(ctx, fmt.Sprintf("User %d just spent %.8f to open a channel", userID, 0.0154))
246+
```
247+
248+
**RIGHT**
249+
```go
250+
log.InfoS(ctx, "Channel open performed",
251+
slog.Int("user_id", userID),
252+
btclog.Fmt("amount", "%.8f", 0.00154))
253+
```
254+
255+
### Wrapping long function definitions
256+
257+
- If function arguments exceed the 80-character limit, maintain indentation
258+
on following lines.
259+
- Do not end a line with an open parenthesis if the function definition is not
260+
finished.
261+
262+
**WRONG**
263+
```go
264+
func foo(a, b, c,
265+
) (d, error) {
266+
267+
func bar(a, b, c) (
268+
d, error,
269+
) {
270+
271+
func baz(a, b, c) (
272+
d, error) {
273+
```
274+
**RIGHT**
275+
```go
276+
func foo(a, b,
277+
c) (d, error) {
278+
279+
func baz(a, b, c) (d,
280+
error) {
281+
282+
func longFunctionName(
283+
a, b, c) (d, error) {
284+
```
285+
286+
- If a function declaration spans multiple lines, the body should start with an
287+
empty line.
288+
289+
**WRONG**
290+
```go
291+
func foo(a, b, c,
292+
d, e) error {
293+
var a int
294+
}
295+
```
296+
**RIGHT**
297+
```go
298+
func foo(a, b, c,
299+
d, e) error {
300+
301+
var a int
302+
}
303+
```
304+
305+
## Use of Log Levels
306+
307+
- Available levels: `trace`, `debug`, `info`, `warn`, `error`, `critical`.
308+
- Only use `error` for internal errors not triggered by external sources.
309+
310+
## Testing
311+
312+
- To run all tests for a specific package:
313+
`make unit pkg=$pkg`
314+
- To run a specific test case within a package:
315+
`make unit pkg=$pkg case=$case`
316+
317+
## Git Commit Messages
318+
319+
- **Subject Line:**
320+
- Format: `subsystem: short description of changes`
321+
- `subsystem` should be the package primarily affected (e.g., `lnwallet`, `rpcserver`).
322+
- For multiple packages, use `+` or `,` as a delimiter (e.g., `lnwallet+htlcswitch`).
323+
- For widespread changes, use `multi:`.
324+
- Keep it under 50 characters.
325+
- Use the present tense (e.g., "Fix bug", not "Fixed bug").
326+
327+
- **Message Body:**
328+
- Separate from the subject with a blank line.
329+
- Explain the "what" and "why" of the change.
330+
- Wrap text to 72 characters.
331+
- Use bullet points for lists.

0 commit comments

Comments
 (0)