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
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25.1'

- name: Install dependencies
run: go mod download

- name: Run fmt-check
run: make fmt-check

- name: Run lint
run: make lint

- name: Run tests
run: make test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ coverage.html

# Build
dist/

# Dev tools
.tools/
168 changes: 168 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
version: "2"

linters:
default: none
enable:
- asciicheck
- bidichk
- bodyclose
- containedctx
- contextcheck
- cyclop
- depguard
- dupword
- dupl
- err113
- errcheck
- errorlint
- forbidigo
- goconst
- gocritic
- gocyclo
- gosec
- govet
- ineffassign
- makezero
- misspell
- nilerr
- nilnil
- noctx
- nolintlint
- paralleltest
- prealloc
- predeclared
- revive
- rowserrcheck
- sqlclosecheck
- staticcheck
- tagliatelle
- thelper
- tparallel
- durationcheck
- unparam
- unused
- wastedassign
- whitespace
- wrapcheck
- wsl_v5

settings:
cyclop:
max-complexity: 50
dupl:
threshold: 150
depguard:
rules:
main:
list-mode: lax
files:
- $all
deny:
- pkg: io/ioutil
desc: "deprecated; use io or os"
goconst:
min-len: 3
min-occurrences: 4
gocyclo:
min-complexity: 50
forbidigo:
forbid:
- pattern: "^log\\."
msg: "avoid std log; use slog"
revive:
rules:
- name: blank-imports
- name: empty-lines
- name: errorf
- name: import-shadowing
- name: range
- name: unnecessary-stmt
tagliatelle:
case:
rules:
json: snake
yaml: snake
wsl_v5:
allow-first-in-block: true
allow-whole-block: false
branch-max-lines: 2
disable:
- assign
- decl
govet:
enable-all: true
disable:
- fieldalignment

exclusions:
presets:
- std-error-handling
rules:
- path: _test\.go
linters:
- errcheck
- cyclop
- gocyclo
- gosec
- dupl
- goconst
- tagliatelle
- paralleltest
- err113
- errorlint
- wsl_v5
- noctx
- unparam
- path: internal/cmd/.*\.go
linters:
- err113
- wrapcheck
- dupl
- wsl_v5
- tagliatelle
- gocritic
- gosec
- govet
- nilerr
- predeclared
- staticcheck
- unparam
- path: cmd/.*\.go
linters:
- wsl_v5
- path: internal/(adapter|batch|cache|config|outfmt|registry|safety|scripts|ssh|wpcli)/.*\.go
linters:
- err113
- wrapcheck
- wsl_v5
- noctx
- gosec
- nilerr
- nilnil
- govet
- errorlint
- unparam
- tagliatelle
- gocritic
- predeclared
- staticcheck
- revive
- rowserrcheck
- linters:
- errcheck
text: "Error return value of `fmt\\.Fprint"
- linters:
- errcheck
text: "Error return value of .*.Close"
- linters:
- errcheck
text: "Error return value of .*.Signal"

formatters:
enable:
- gofumpt
- goimports
settings:
goimports:
local-prefixes:
- github.com/builtbyrobben/wpssh
44 changes: 44 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
version: 2

project_name: wpssh

changelog:
disable: true

builds:
- id: wpgo
main: ./cmd/wpgo
binary: wpgo
ldflags: >-
-s -w
-X main.version={{ .Tag }}
-X main.commit={{ .ShortCommit }}
-X main.date={{ .Date }}
env:
- CGO_ENABLED=0
targets:
- linux_amd64
- linux_arm64
- darwin_amd64
- darwin_arm64

archives:
- builds:
- wpgo
format: tar.gz
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"

checksum:
name_template: checksums.txt

brews:
- repository:
owner: builtbyrobben
name: homebrew-tap
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
folder: Formula
homepage: "https://github.com/builtbyrobben/wpssh"
description: "WordPress management over SSH"
license: "MIT"
test: |
system "#{bin}/wpgo", "--version"
47 changes: 47 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Repository Guidelines

## Project Structure

- `cmd/wpgo/`: CLI entrypoint
- `internal/`: implementation packages
- `cmd/`: Kong CLI commands
- `ssh/`: SSH client
- `cache/`: Caching
- `wpcli/`: WP-CLI wrapper
- `config/`: Configuration
- `outfmt/`: JSON/plain output formatting
- `errfmt/`: User-friendly error formatting
- `safety/`: Safety checks
- `scripts/`: Script management
- `adapter/`: Adapters
- `batch/`: Batch operations
- `registry/`: Registry

## Build, Test, and Development Commands

- `make` / `make build`: build `bin/wpgo`
- `make tools`: install pinned dev tools into `.tools/`
- `make fmt` / `make lint` / `make test` / `make ci`: format, lint, test, full local gate
- `make test-integration`: run integration tests
- `make test-all`: run all tests including integration

## Coding Style & Naming Conventions

- Formatting: `make fmt` (`goimports` local prefix `github.com/builtbyrobben/wpssh` + `gofumpt`)
- Output: keep stdout parseable (`--json` / `--plain`); send human hints/progress to stderr

## Testing Guidelines

- Unit tests: stdlib `testing` (and `httptest` where needed)
- Integration tests: use `//go:build integration` tag under `tests/integration/`

## Commit & Pull Request Guidelines

- Follow Conventional Commits + action-oriented subjects (e.g. `feat(cli): add --verbose flag`)
- Group related changes; avoid bundling unrelated refactors
- PRs should summarize scope, note testing performed, and mention user-facing changes

## Security

- Never commit SSH keys, passwords, or credentials
- Use `--stdin` for sensitive input (avoid shell history leaks)
75 changes: 63 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,66 @@
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
LDFLAGS := -ldflags "-X main.version=$(VERSION)"
SHELL := /bin/bash

.PHONY: build test test-integration test-all lint install clean
.DEFAULT_GOAL := build

.PHONY: build wpgo help fmt fmt-check lint test test-integration test-all ci tools install clean

BIN_DIR := $(CURDIR)/bin
BIN := $(BIN_DIR)/wpgo
CMD := ./cmd/wpgo

VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
COMMIT := $(shell git rev-parse --short=12 HEAD 2>/dev/null || echo "")
DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.date=$(DATE)

TOOLS_DIR := $(CURDIR)/.tools
GOFUMPT := $(TOOLS_DIR)/gofumpt
GOIMPORTS := $(TOOLS_DIR)/goimports
GOLANGCI_LINT := $(TOOLS_DIR)/golangci-lint

ifneq ($(filter wpgo,$(MAKECMDGOALS)),)
RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
$(eval $(RUN_ARGS):;@:)
endif

build:
go build $(LDFLAGS) -o bin/wpgo ./cmd/wpgo
@mkdir -p $(BIN_DIR)
@go build -ldflags "$(LDFLAGS)" -o $(BIN) $(CMD)

wpgo: build
@if [ -n "$(RUN_ARGS)" ]; then \
$(BIN) $(RUN_ARGS); \
elif [ -z "$(ARGS)" ]; then \
$(BIN) --help; \
else \
$(BIN) $(ARGS); \
fi

help: build
@$(BIN) --help

tools:
@mkdir -p $(TOOLS_DIR)
@GOBIN=$(TOOLS_DIR) go install mvdan.cc/gofumpt@v0.9.2
@GOBIN=$(TOOLS_DIR) go install golang.org/x/tools/cmd/goimports@v0.41.0
@GOBIN=$(TOOLS_DIR) go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.9.0

fmt: tools
@$(GOIMPORTS) -local github.com/builtbyrobben/wpssh -w .
@$(GOFUMPT) -w .

fmt-check: tools
@UNFMT=$$($(GOIMPORTS) -local github.com/builtbyrobben/wpssh -l .); \
UNFMT="$$UNFMT$$($(GOFUMPT) -l .)"; \
if [ -n "$$UNFMT" ]; then \
echo "Files need formatting:"; echo "$$UNFMT"; exit 1; \
fi

lint: tools
@$(GOLANGCI_LINT) run

test:
go test -race -count=1 ./internal/...
@go test -race -count=1 ./internal/...

test-integration:
@if [ -n "$(shell go list -tags=integration ./tests/integration/... 2>/dev/null)" ]; then \
Expand All @@ -17,14 +70,12 @@ test-integration:
fi

test-all:
go test -race -tags=integration ./...

lint:
go vet ./...
golangci-lint run
@go test -race -tags=integration ./...

install:
go install $(LDFLAGS) ./cmd/wpgo
@go install -ldflags "$(LDFLAGS)" ./cmd/wpgo

clean:
rm -rf bin/ dist/
rm -rf bin/ dist/ .tools/

ci: fmt-check lint test
Loading