Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
version: 2
updates:
# Check for major GitHub Actions updates
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
interval: "weekly"
day: "monday"
groups:
actions:
patterns:
- "*"
cooldown:
default-days: 7

# Check for Go module updates
- package-ecosystem: "gomod"
directory: "/" # adjust this if your go.mod file is in a subdirectory
directory: "/"
schedule:
interval: "daily"
interval: "weekly"
day: "monday"
groups:
all-minor-patch:
update-types:
- "minor"
- "patch"
cooldown:
default-days: 7
31 changes: 31 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Lint

permissions: {}

on:
push:
branches: [master]
pull_request:

jobs:
lint:
permissions:
contents: read
name: Run on Ubuntu
runs-on: ubuntu-latest
steps:
- name: Clone the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false

- name: Setup Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod

- name: Check linter configuration
run: make lint-config
- name: Run linter
run: make lint
9 changes: 7 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ on:
schedule:
- cron: '14 14 * * *'

permissions: {}

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}

Expand All @@ -21,10 +23,13 @@ jobs:

steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v6.0.2
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false

- name: Set up Go
uses: actions/setup-go@v6
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: 'go.mod'

Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Workflow Security Lint

permissions: {}

on:
push:
branches: [master]
paths: ['.github/**']
pull_request:
paths: ['.github/**']

jobs:
zizmor:
permissions:
actions: read
contents: read
security-events: write
name: zizmor
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Run zizmor
uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.idea/
/vendor/
bin/
97 changes: 97 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
version: "2"
run:
allow-parallel-runners: true
build-tags:
- integration
linters:
default: none
enable:
- asasalint # warns about passing []any to func(...any) without expanding it
- asciicheck # non ascii symbols
- copyloopvar # copying loop variables
- errcheck # unchecked errors
- exhaustive # exhaustiveness of enum switch statements
- ginkgolinter # ginkgo and gomega - only if ginkgo/gomega is used
- gocritic # bugs, performance, style
- gocyclo # cyclomatic complexity of functions
- godoclint # go documentation linting against best practices
- gosec # potential security problems
- govet # basically 'go vet'
- importas # enforces consistent import aliases.
- ineffassign # ineffectual assignments
- loggercheck # check for even key/value pairs in logger calls
- modernize # suggest simplifications to Go code, using modern language and library features
- misspell # spelling checks
- nakedret # naked returns (named return parameters and an empty return)
- noctx # http requests without context.Context
- nolintlint # badly formatted nolint directives
- predeclared # shadowing predeclared identifiers
- promlinter # only if prom is used for creating metrics
- revive # better version of golint
- spancheck # only if OpenTelemetry is used
- staticcheck # many static checks
- thelper # test helpers not starting with t.Helper()
- unconvert # unnecessary type conversions
- unparam # unused function parameters
- unused # unused constants, variables,functions, types
- usestdlibvars # using variables/constants from the standard library
- usetesting # reports uses of functions with replacement inside the testing package
- whitespace # unnecessary newlines
settings:
loggercheck:
kitlog: false
slog: false
zap: false
require-string-key: true
no-printf-like: true
modernize:
disable:
- omitzero
gocritic:
disabled-checks:
- ifElseChain # disabled ifElseChain because this is purely stylistic
revive:
rules:
# The following rules are recommended https://github.com/mgechev/revive#recommended-configuration
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: error-return
- name: error-strings
- name: error-naming
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unreachable-code
- name: redefines-builtin-id
staticcheck:
dot-import-whitelist:
- fmt
- github.com/onsi/gomega
- github.com/onsi/ginkgo/v2
exclusions:
generated: lax
warn-unused: true
formatters:
enable:
- goimports # ensures imports are organized
- gofmt # Check if the code is formatted according to 'gofmt' command.
settings:
goimports:
# A list of prefixes, which, if set, checks import paths
# with the given prefixes are grouped after 3rd-party packages.
# Default: []
local-prefixes:
- github.com/cloudscale-ch/cloudscale-go-sdk
exclusions:
generated: lax
warn-unused: true
76 changes: 76 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# AGENTS.md
Comment thread
mweibel marked this conversation as resolved.

This file is a supplement for AI agents working on the cloudscale SDK (cloudscale-go-sdk).

## What this is

A Go client library for the cloudscale.ch API, imported as
`github.com/cloudscale-ch/cloudscale-go-sdk/v9`. It is source-only: there is no `main` package and nothing to build or
ship, so consumers just `go get` it.

## What to run after a change

| Change | Command |
|-------------------------------------------------------------|---------------------------------------------------------------|
| Edited any `.go` file | `make fmt`, then `make vet` |
| Before committing | `make lint` (or `make lint-fix` to apply fixes automatically) |
| Changed logic | `make test`, unit tests, run with `-race`, no network calls |
| Touched a service and want to check it against the real API | `make integration` or `make integration-short` |

`make vet` also vets the integration tests under the `integration` build tag, so run it even when you only touched files
in `test/integration`.

## Where things live

| Path | Contents |
|---------------------------|-----------------------------------------------------------------------------------------------------------|
| root package `cloudscale` | one file per API resource (`servers.go`, `servers.go`, `volumes.go`, …) plus its `*_test.go` |
| `cloudscale.go` | the `Client`, service wiring in `NewClient`, `NewRequest`/`Do`, error handling, and `libraryVersion` |
| `generic_service.go` | generic CRUD operations and `WaitFor`, shared by most services |
| `ctxutil.go` | `WithOperationPath` / `OperationPath`, the endpoint template carried on the context for metrics and spans |
| `instrumentation/` | optional transport wrapper adding Prometheus metrics and OpenTelemetry spans |
| `test/integration/` | tests that hit the live API, behind the `//go:build integration` tag |

## Adding or changing a service

Most services are just an instance of the generics in `generic_service.go`. Look at `servers.go`
next to `cloudscale.go` for a full example, including the case where a resource needs extra methods on top of the
generic ones. The usual steps:

1. Define the resource struct and its request structs with `json` tags. Embed `ZonalResource` /
`TaggedResource` (and the matching `ZonalResourceRequest` / `TaggedResourceRequest`) when the resource is zonal or
taggable.
2. Declare a `XService` interface built from the `Generic…Service[...]` interfaces, listing only the operations the API
actually supports.
3. Wire it up in `NewClient` in `cloudscale.go`. Use a bare
`GenericServiceOperations[Resource, CreateRequest, UpdateRequest]{client, path}` when the generic operations are
enough, or a wrapper struct that embeds it when you need custom methods (see `ServerServiceOperations` and its
`CreateInterface` / `DeleteInterface`).
4. For custom endpoints, set the operation path before making the request, e.g.
`ctx = WithOperationPath(ctx, serverBasePath+"/:id/reboot")`, so metrics and spans get a stable template instead
of a URL with a UUID baked in.
5. If callers need to wait on a status, add status constants and a condition function in the style of `XIsRunning`
for use with `WaitFor`.

## Conventions

- Linting is golangci-lint v2, configured in `.golangci.yml`. Imports are grouped with `goimports`
using the local prefix `github.com/cloudscale-ch/cloudscale-go-sdk`.
- Unit tests are table-driven and use an `httptest` mock server. They must not make real network calls, which is why
`make test` stays fast.
- Every request method takes a `context.Context` as its first argument. API errors come back as
`*ErrorResponse`.

## Integration tests

These run against a real cloudscale account, so they cost money and create real resources. Resources are named
`go-sdk-<random>` and cleaned up automatically after each test. The README's "Testing" section documents how to run them.

## Releasing

Releasing is a manual process. Consult the README's "Releasing" section for instructions on how to release.

## References

- `README.md` — usage, instrumentation, testing, and release steps.
- API docs: <https://pkg.go.dev/github.com/cloudscale-ch/cloudscale-go-sdk/v9>
Loading