Prepare a change in this repository (branch, code, docs, PR) so it satisfies the pull request checklist before it's opened for review.
See also:
- unit-tests.md for how to write the unit tests this checklist requires.
- mocks.md for generating/using mocks referenced by the checklist.
- code-quality.md for what
make lintenforces and the SOLID patterns to follow in any non-test Go code touched by the change.
Apply every item below that is relevant to the change being made — the PR checklist itself is opt-in per item ("check ONLY IF APPLIED"), but if an item applies, follow it; don't skip it because it's inconvenient.
Name the branch after the kind of change:
feature/<name>for new functionality.fix/<name>for bug fixes.
Every method on a struct uses the struct's first letter (lowercase) as the receiver name:
func (c *Checkbox) Render(provider core.Provider, cell *entity.Cell) {(see pkg/components/checkbox/checkbox.go). Do not use this, self, or the full struct name.
A few existing types don't follow the literal first-letter rule (e.g. internal/providers/gofpdf/font.go
uses s for Font) — that's pre-existing, not a pattern to copy; for new code, use the struct's
actual first letter.
- Write unit tests for every new or changed exported function/method.
- Follow unit-tests.md for naming (
when <condition>, should <outcome>), AAA comments, parallelism, and thesutvariable name. - Follow mocks.md for constructing mocks (
m := mocks.NewConstructor(t)) and setting expectations (m.EXPECT().MethodName(...)).
Every new exported struct, interface, or method gets a comment above it explaining its
responsibility, starting with the identifier name. This is required because these comments are
what godoc/pkg.go.dev renders as the package documentation (see make godoc and the
GoDoc badge in README.md) — undocumented
exported identifiers show up blank there:
// NewFont create a Font.
func NewFont(...) *Font { ... }
// GetFamily return the currently Font family configured.
func (s *Font) GetFamily() string { ... }(see internal/providers/gofpdf/font.go).
docs/ is a docsify site. Run make docs to preview it locally.
- Feature pages live at
docs/v2/features/<name>.md, one per component/config option, and are listed indocs/v2/features/_sidebar.md— a new feature page must be added there too, or it will exist but be unreachable from the site nav. - Follow the structure of existing pages, e.g.
docs/v2/features/checkbox.md:# <Title>and a short description of the component/feature.## Props (<props.Type>)— a table of every prop field, its type, default, and description (skip this section for features with no props).## Usage notes— constraints, clamping behavior, gotchas.## GoDoc— links tohttps://pkg.go.dev/...for the constructor(s), props, and component.## Code Example— a docsify include of the runnable example:[filename](../../assets/examples/<name>/v2/main.go ':include :type=code')## PDF Generated/## Time Execution— includes of the generatedassets/pdf/<name>v2.pdfandassets/text/<name>v2.txt.## Test File— a docsify include of the matching fixture undertest/maroto/examples/.
- The runnable example referenced above lives at
docs/assets/examples/<name>/v2/main.go(plus amain_test.goif it's also used as a unit test fixture). It must calldocument.Save(...)anddocument.GetReport().Save(...)to producedocs/assets/pdf/<name>v2.pdfanddocs/assets/text/<name>v2.txt, and must be added to theexamplestarget in theMakefile(go run docs/assets/examples/<name>/v2/main.go) somake examplesregenerates it. - If the change affects behavior documented on an existing page instead of adding a new
feature, update that page (and its example under
docs/assets/examples/) in place rather than creating a new one.
If the change adds or changes a public entry point that's useful to demonstrate, add or update an
Example<Type>_<Method> function in example_test.go:
// ExampleMaroto_AddPages demonstrates how to add a new page in maroto.
func ExampleMaroto_AddPages() {
...
}Update README.md if the change affects installation, the make command table, or anything else
described there.
Before opening the PR, run:
make dod
which runs, in order: make build, make test, make fmt, make lint (the last of which also
runs make mock-lint to verify mocks/ is up to date with mockery), then make codecov. Fix
every issue golangci-lint points out — the PR checklist requires this to have zero issues. See
code-quality.md for exactly what this repo's .golangci.yml enforces (and
deliberately doesn't) and for the SOLID principles to check non-test code against beyond what the
linter alone catches. make test runs with -race, so a genuine data race also fails the build
here, not just a wrong result. make codecov is warning-only: it runs shell/codecov.sh,
which lists every function with 0% test coverage (excluding internal/fixture, which is
test-support code with no test file of its own) and always exits 0 — it flags gaps without
blocking the commit.
A make codecov warning is not optional busywork — treat it as highly recommended to fix
before opening the PR, not after. Reviewers on this project routinely ask for missing tests on
exactly these functions, so a PR that ships with unaddressed make codecov output is very likely
to get a review comment asking for the same tests anyway. Writing them upfront (following
unit-tests.md) avoids a review round-trip. If an agent is doing the work and
make codecov reports functions touched by the change, it should write tests for them as part of
the same change rather than leaving it for review to catch — only skip a specific function if
there's a concrete reason it can't reasonably be tested, and say so in the PR description.
If the pre-commit git hook is installed (make install or make install-hooks, see
.githooks/pre-commit), make dod already runs automatically
before every commit and blocks it on failure — a commit that succeeded locally has already
satisfied this item.
make fmt, make lint, make mocks, and make godoc don't rely on globally installed
binaries. goimports, gofumpt, golangci-lint, mockery, and godoc are declared as tool
dependencies in a separate tools/go.mod (a nested module, isolated so its
~200 extra transitive dependencies — mostly from golangci-lint's linter engine — never touch the
main module's go.sum, which every consumer of this library downloads). The Makefile invokes them
with go tool -modfile=tools/go.mod <name>, which builds and runs the exact version pinned in
tools/go.sum on first use — no go install/sudo cp needed. If you need to add or upgrade one
of these tools, run go get -tool <module>@<version> from inside tools/, never from the
repo root (that would add it to the main go.mod instead).
When opening the PR, fill in:
- Description: how the PR is useful, and any tricky technical detail.
- Related Issue: a reference to the issue it closes/relates to, if any.
Full checklist for reference: pull_request_template.md