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
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED BY KRES, PLEASE DO NOT EDIT.
#
# Generated on 2026-05-26T16:46:25Z by kres c267185-dirty.
# Generated on 2026-05-28T15:40:14Z by kres 80fec4e.

# common variables

Expand Down Expand Up @@ -214,7 +214,7 @@ lint-gofumpt: ## Runs gofumpt linter.

.PHONY: fmt
fmt: ## Formats the source code
@docker run --rm -it -v $(PWD):/src -w /src golang:$(GO_VERSION) \
@docker run --rm -v $(PWD):/src -w /src golang:$(GO_VERSION) \
bash -c "export GOTOOLCHAIN=local; \
export GO111MODULE=on; export GOPROXY=https://proxy.golang.org; \
go install mvdan.cc/gofumpt@$(GOFUMPT_VERSION) && \
Expand Down Expand Up @@ -335,7 +335,7 @@ release-notes: $(ARTIFACTS)
.PHONY: conformance
conformance:
@docker pull $(CONFORMANCE_IMAGE)
@docker run --rm -it -v $(PWD):/src -w /src $(CONFORMANCE_IMAGE) enforce
@docker run --rm -v $(PWD):/src -w /src $(CONFORMANCE_IMAGE) enforce

.PHONY: renovate-local
renovate-local: ## runs renovate locally to check syntax and test configuration
Expand Down
2 changes: 2 additions & 0 deletions cmd/kres/cmd/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/siderolabs/kres/internal/output/github"
"github.com/siderolabs/kres/internal/output/gitignore"
"github.com/siderolabs/kres/internal/output/golangci"
"github.com/siderolabs/kres/internal/output/lefthook"
"github.com/siderolabs/kres/internal/output/license"
"github.com/siderolabs/kres/internal/output/makefile"
"github.com/siderolabs/kres/internal/output/markdownlint"
Expand Down Expand Up @@ -91,6 +92,7 @@ func runGen() error {
output.Wrap(release.NewOutput()),
output.Wrap(markdownlint.NewOutput()),
output.Wrap(template.NewOutput()),
output.Wrap(lefthook.NewOutput()),
)
}

Expand Down
6 changes: 3 additions & 3 deletions internal/output/codecov/codecov.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

const (
filename = ".codecov.yml"
configFile = ".codecov.yml"
)

//go:embed codecov.yml
Expand Down Expand Up @@ -60,13 +60,13 @@ func (o *Output) Filenames() []string {
return nil
}

return []string{filename}
return []string{configFile}
}

// GenerateFile implements output.FileWriter interface.
func (o *Output) GenerateFile(filename string, w io.Writer) error {
switch filename {
case filename:
case configFile:
return o.config(w)
default:
panic("unexpected filename: " + filename)
Expand Down
6 changes: 3 additions & 3 deletions internal/output/conform/conform.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
)

const (
filename = ".conform.yaml"
configFile = ".conform.yaml"
)

// Output implements .conform.yaml generation.
Expand Down Expand Up @@ -96,13 +96,13 @@ func (o *Output) Filenames() []string {
return nil
}

return []string{filename}
return []string{configFile}
}

// GenerateFile implements output.FileWriter interface.
func (o *Output) GenerateFile(filename string, w io.Writer) error {
switch filename {
case filename:
case configFile:
return o.config(w)
default:
panic("unexpected filename: " + filename)
Expand Down
8 changes: 4 additions & 4 deletions internal/output/dockerfile/dockerfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import (
)

const (
filename = "Dockerfile"
syntax = "docker/dockerfile-upstream:" + config.DockerfileFrontendImageVersion
configFile = "Dockerfile"
syntax = "docker/dockerfile-upstream:" + config.DockerfileFrontendImageVersion
)

// Output implements Dockerfile and .dockerignore generation.
Expand Down Expand Up @@ -55,13 +55,13 @@ func (o *Output) Filenames() []string {
return nil
}

return []string{filename}
return []string{configFile}
}

// GenerateFile implements output.FileWriter interface.
func (o *Output) GenerateFile(filename string, w io.Writer) error {
switch filename {
case filename:
case configFile:
return o.dockerfile(w)
default:
panic("unexpected filename: " + filename)
Expand Down
6 changes: 3 additions & 3 deletions internal/output/dockerignore/dockerignore.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

const (
filename = ".dockerignore"
configFile = ".dockerignore"
)

// Output implements .dockerignore generation.
Expand All @@ -39,7 +39,7 @@ func (o *Output) Compile(compiler Compiler) error {

// Filenames implements output.FileWriter interface.
func (o *Output) Filenames() []string {
return []string{filename}
return []string{configFile}
}

// AllowLocalPath adds path to the list of paths to be copied into the context.
Expand All @@ -52,7 +52,7 @@ func (o *Output) AllowLocalPath(paths ...string) *Output {
// GenerateFile implements output.FileWriter interface.
func (o *Output) GenerateFile(filename string, w io.Writer) error {
switch filename {
case filename:
case configFile:
return o.dockerignore(w)
default:
panic("unexpected filename: " + filename)
Expand Down
6 changes: 3 additions & 3 deletions internal/output/gitignore/gitignore.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

const (
filename = ".gitignore"
configFile = ".gitignore"
)

// Output implements .gitignore generation.
Expand Down Expand Up @@ -44,13 +44,13 @@ func (o *Output) IgnorePath(paths ...string) {

// Filenames implements output.FileWriter interface.
func (o *Output) Filenames() []string {
return []string{filename}
return []string{configFile}
}

// GenerateFile implements output.FileWriter interface.
func (o *Output) GenerateFile(filename string, w io.Writer) error {
switch filename {
case filename:
case configFile:
return o.gitignore(w)
default:
panic("unexpected filename: " + filename)
Expand Down
81 changes: 81 additions & 0 deletions internal/output/lefthook/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package lefthook

// Command represents a single named command under a hook's commands: map.
type Command struct { //nolint:govet
Run string `yaml:"run"`
Tags []string `yaml:"tags,omitempty"`
Glob string `yaml:"glob,omitempty"`
Files string `yaml:"files,omitempty"`
Skip []string `yaml:"skip,omitempty"`
Only []string `yaml:"only,omitempty"`
Interactive bool `yaml:"interactive,omitempty"`
StageFixed bool `yaml:"stage_fixed,omitempty"`
Priority int `yaml:"priority,omitempty"`
}

// WithRun sets the shell command lefthook executes for this command.
func (c *Command) WithRun(run string) *Command {
c.Run = run

return c
}

// WithTags attaches tags used for selective hook execution (lefthook --tags ...).
func (c *Command) WithTags(tags ...string) *Command {
c.Tags = tags

return c
}

// WithGlob restricts the command to files matching the given glob.
func (c *Command) WithGlob(glob string) *Command {
c.Glob = glob

return c
}

// WithFiles overrides the default file source (e.g. "git diff --name-only ...").
func (c *Command) WithFiles(files string) *Command {
c.Files = files

return c
}

// WithSkip lists git states or refs where the command should be skipped (e.g. "merge", "rebase").
func (c *Command) WithSkip(skip ...string) *Command {
c.Skip = skip

return c
}

// WithOnly is the inverse of WithSkip: command runs only in the listed states.
func (c *Command) WithOnly(only ...string) *Command {
c.Only = only

return c
}

// WithInteractive marks the command as needing a TTY (stdin/stdout passthrough).
func (c *Command) WithInteractive() *Command {
c.Interactive = true

return c
}

// WithStageFixed re-stages files modified by the command (useful for formatters).
func (c *Command) WithStageFixed() *Command {
c.StageFixed = true

return c
}

// WithPriority sets the command's run order within its hook (lower runs first).
func (c *Command) WithPriority(priority int) *Command {
c.Priority = priority

return c
}
78 changes: 78 additions & 0 deletions internal/output/lefthook/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package lefthook

// Config is a declarative description of lefthook.yml contributions, suitable
// for unmarshalling from a kres.yaml block.
//
// Hooks reuse the very same builder types (Hook, Command, Job, Group) that
// serialize lefthook.yml, so the config is authored in lefthook's native schema
// and there is a single definitive set of types for both serializing the output
// and deserializing the config.
type Config struct {
Hooks map[string]*Hook `yaml:"hooks"`
Enabled bool `yaml:"enabled"`
}

// Compile merges the configured hooks into the output. It is a no-op when the
// config is disabled.
func (c Config) Compile(output *Output) error {
if !c.Enabled {
return nil
}

for name, cfgHook := range c.Hooks {
if cfgHook == nil {
continue
}

hook := output.Hook(name)

if cfgHook.Parallel != nil {
hook.WithParallel(*cfgHook.Parallel)
}

if cfgHook.Piped {
hook.WithPiped(true)
}

for cmdName, cmd := range cfgHook.Commands {
if cmd == nil {
continue
}

*hook.Command(cmdName) = *cmd
}
Comment thread
majabojarska marked this conversation as resolved.

for _, job := range cfgHook.Jobs {
if job == nil {
continue
}

// A named job wrapping a group is merged into the hook's group of
// the same name, so a config can extend the shared fix/lint groups
// emitted by the standard blocks instead of forking a new one.
if job.Group != nil && job.Name != "" {
group := hook.Group(job.Name)

if job.Group.Parallel != nil {
group.WithParallel(*job.Group.Parallel)
}

if job.Group.Piped {
group.WithPiped(true)
}

group.Jobs = append(group.Jobs, job.Group.Jobs...)

continue
}

hook.Jobs = append(hook.Jobs, job)
}
Comment thread
majabojarska marked this conversation as resolved.
}

return nil
}
39 changes: 39 additions & 0 deletions internal/output/lefthook/group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package lefthook

// Group is a container for nested Jobs with its own parallel/piped semantics.
// Used to express "run these in parallel, then those sequentially" without
// touching the hook-level execution model.
type Group struct { //nolint:govet
// Parallel is a pointer so an explicit `parallel: false` can be emitted
// (the bool zero value would otherwise be suppressed by omitempty).
Parallel *bool `yaml:"parallel,omitempty"`
Piped bool `yaml:"piped,omitempty"`
Jobs []*Job `yaml:"jobs,omitempty"`
}

// WithParallel toggles parallel execution of this group's jobs.
func (g *Group) WithParallel(parallel bool) *Group {
g.Parallel = &parallel

return g
}

// WithPiped enables piped (sequential, fail-fast, stdout-chained) execution.
func (g *Group) WithPiped(piped bool) *Group {
g.Piped = piped

return g
}

// Job appends a new job to the group and returns it for further configuration.
func (g *Group) Job() *Job {
j := &Job{}

g.Jobs = append(g.Jobs, j)

return j
}
Loading