Formatting

GolangCI-Lint

Where possible these rules have been codified in the .golangci.yml file below.

This file will be used in the pipelines to lint PRs and minion will use it to check code changes ahead of committing them.

Config
version: "2"
run:
  issues-exit-code: 1
  tests: true
  allow-parallel-runners: true
linters:
  default: none
  enable:
    - bodyclose
    - copyloopvar
    - errcheck
    - govet
    - ineffassign
    - misspell
    - nakedret
    - nolintlint
    - staticcheck
    - tparallel
    - unconvert
    - whitespace
  settings:
    staticcheck:
      checks:
        - all
        - -SA1029
        - -ST1000
        - -ST1003
        - -ST1016
        - -ST1020
        - -ST1021
        - -ST1022
        - -ST1023
      initialisms:
        - ACL
        - API
        - ASCII
        - CPU
        - CSS
        - DNS
        - EOF
        - GUID
        - HTML
        - HTTP
        - HTTPS
        - ID
        - IP
        - JSON
        - QPS
        - RAM
        - RPC
        - SLA
        - SMTP
        - SQL
        - SSH
        - TCP
        - TLS
        - TTL
        - UDP
        - UI
        - GID
        - UID
        - UUID
        - URI
        - URL
        - UTF8
        - VM
        - XML
        - XMPP
        - XSRF
        - XSS
        - SIP
        - RTP
        - AMQP
        - DB
        - TS
      dot-import-whitelist:
        - github.com/mmcloughlin/avo/build
        - github.com/mmcloughlin/avo/operand
        - github.com/mmcloughlin/avo/reg
      http-status-code-whitelist:
        - "200"
        - "400"
        - "404"
        - "500"
  exclusions:
    generated: lax
    paths:
      - ^\.(.*)$
      - Dockerfile|Readme.md
      - tmp
      - doc
      - .buildkite
      - third_party$
      - builtin$
      - examples$
issues:
  fix: true
formatters:
  enable:
    - gofmt
    - goimports
  exclusions:
    generated: lax
    paths:
      - ^\.(.*)$
      - Dockerfile|Readme.md
      - tmp
      - doc
      - .buildkite
      - third_party$
      - builtin$
      - examples$
output:
  formats:
    text:
      colors: true
      print-issued-lines: true
      print-linter-name: true

File Termination ProposedCF02010

In accordance with the POSIX standard, the last line of a file should be empty - that is, the file should have a new-line character appended to the last line.

Why? The POSIX standard is intended to provide compatibility with many command line tools, such as `cat`.

If you use cat on a file that does not have th final new-line character and you haven’t configured your shell to allow for that, you may find your prompt appearing on the same line as the last line of the output of cat.

file1
1File1Line12File1Line2
$ cat file1 file2
File1Line1
File1Line2$

If you use cat on two files and the first one does not have the final new-line character, the first line of the second file will be appended to the last line of the first file.

file2
1File2Line12File2Line23  
$ cat file1 file2
File1Line1
File1Line2File2Line1
File2Line2
$

Swapping the order of the files so the file with the final new-line character is first will output each line on it’s own, but your prompt may still end up on the same line as the last line of the output.

$ cat file2 file1
File2Line1
File2Line2
File1Line1
File1Line2$ 
IDE Configuration

This can be achieved auto-magically by configuring your IDE.

For VS Code the settings are:

settings.json
1{
2    "editor.renderFinalNewline": "off",
3    "files.insertFinalNewline": true,
4}

Sorting Imports CanonicalCF02110

Packages can be divided in to three types, standard library, our own packages, and third party packages.

Imports should be grouped accordingly, with the standard library packages first, followed by packages starting with github.com/cirruscomms/ and then third party packages.

Examples
imports.go
 1package main
 2
 3import (
 4	"context"
 5	"flag"
 6	"fmt"
 7	"net/http"
 8
 9	"github.com/cirruscomms/go-common/pkg/db/migrations"
10	"github.com/cirruscomms/go-common/pkg/env/config"
11	"github.com/cirruscomms/go-logging"
12	etc "github.com/cirruscomms/optus-service/etc/migrations"
13	"github.com/cirruscomms/optus-service/internal/api"
14	"github.com/cirruscomms/optus-service/internal/api/base"
15	"github.com/cirruscomms/optus-service/internal/optus"
16	actions "github.com/cirruscomms/optus-service/internal/optusActions"
17
18	"github.com/joho/godotenv"
19	"github.com/sirupsen/logrus"
20)
IDE Configuration

This can be achieved auto-magically by configuring your IDE and/or Go’s language server to use gofumpts as the formatter for Go files.

For VS Code with formatting handled by gopls the settings are:

settings.json
 1{
 2    "gopls": {
 3        "analyses": {
 4            "nilness": true,
 5            "shadow": false,
 6            "unusedvariable": true,
 7            "useany": true,
 8        },
 9        "codelenses": {
10            "run_govulncheck": false
11        },
12        "formatting.gofumpt": true,
13        "formatting.local": "github.com/cirruscomms/",
14        "staticcheck": true,
15        "ui.semanticTokens": true
16    },
17}

Renaming Imports NormativeCF02120

Naming Packages NormativeCF02210

Package names should be camelCase, with the exception of _test packages, which should just be camelCase package names with the _test suffix appended to them.

Examples
packages.go
1package simple // okay
2package simpleBrands // okay
3package simpleBrands_test // okay
4
5package simple_brands // not okay
6package simplebrands // not okay

Naming Types ProposedCF02215

Naming Constants ProposedCF02220

Naming Variables ProposedCF02225

Naming Interfaces ProposedCF02230

Naming Mock Structs ProposedCF02235

Naming Functions ProposedCF02240

Naming Methods ProposedCF02245

Initialisms - Never Mixed Case ProposedCF02250

Initialisms should be written either in all upper or all lower case, never mixed.

If the initialism is the prefix of an unexported function, method, variable, constant, or type (thing), it the initialism should be written in all lower case, otherwise it should be all uppercase.

Try to name the thing to avoid having two adjacent initialisms, but if you can’t, the rules above apply to them independently.

Examples
initialisms.go
 1var nbnClient       = "okay" // not exported with initialism as prefix should be lower case
 2var NBNClient       = "okay" // exported with initialism as prefix should be upper case
 3var NbnClient       = "not okay" // exported with initialism as prefix should not be mixed case
 4var mobileSIMSerial = "okay" // not exported with initialisms in middle should be upper case
 5var mobileSimSerial = "not okay" // not exported with initialisms in middle should be not be mixed case
 6
 7var NBNTC4Client    = "okay" // exported with adjacent initialisms as prefix should have  mixed case
 8var nbnTC4Client    = "okay" // not exported with adjacent initialisms as prefix should have the first in lower and subsequent in upper case
 9var nbntc4Client    = "not okay" // prefix, adjacent, not exported  lower + lower case
10
11var requestID       = "okay" // not exported with initialism outside the prefix should be upper case
12var RequestID       = "okay" // exported with initialism outside the prefix should be upper case
13var RequestId       = "no okay" // exported with initialism outside the prefix should not be mixed case
14var requestId       = "no okay" // not exported with initialism outside the prefix should not be mixed case
15var requestid       = "no okay" // not exported with initialism outside the prefix should not lower case
16var Requestid       = "no okay" // exported with initialism outside the prefix should not lower case

Ordering Struct Fields IdiomaticCF02270

Naming Struct Fields ProposedCF02275

Ordering Struct Tags ProposedCF02280

Naming Struct Tags - Env NormativeCF02285

Naming Struct Tags - JSON NormativeCF02290

GoDoc Package Comments CanonicalCF02310

GoDoc Package Examples CanonicalCF02312

GoDoc Function Comments CanonicalCF02314

GoDoc Function Examples CanonicalCF02316

Comments Explain Why, Not What CanonicalCF02320

Inner Function Heading Comments CanonicalCF02330

Functions & Methods - Ordering Contract Parameters NormativeCF02410

Functions & Methods - Formatting Contract Signatures NormativeCF02411

Keep them on a single line unless the line exceeds 120 characters, at which point they should be wrapped between 80 and 120 characters, preferably with one parameter per line.

Examples
signatures.go
 1// MustRepeatSomething needs a GoDoc comment
 2func MustRepeatSomething(ctx context.Context, repeats int) {
 3    // ...
 4}
 5
 6// MustRepeatManyThings needs a GoDoc comment
 7func MustRepeatManyThings(
 8    ctx context.Context,
 9    repeats int,
10    param1 map[string]string,
11    param2 map[string]string,
12    param2 map[string]string,
13    param2 map[string]string,
14) {
15    // ...
16}
17
18// RepeatManyThings needs a GoDoc comment
19func RepeatManyThings(
20    ctx context.Context,
21    repeats int,
22    param1 map[string]string,
23    param2 map[string]string,
24    param2 map[string]string,
25    param2 map[string]string,
26) (fault error) {
27    // ...
28}

Functions & Methods - Named Contract Returns NormativeCF02420

Functions & Methods - Ordering Contract Returns NormativeCF02430

Functions & Methods - Using Naked Return Statements NormativeCF02440

Don’t.

API - Routes NormativeCF02510

API - Methods NormativeCF02520

API - Status Codes NormativeCF02530