typelevel / typelevel/sbt-typelevel
Public hook for appending commands to the "Check headers and formatting" lint step
Nobody has claimed this yet.
- Dominant language
- Scala
- Stars
- 185
- Forks
- 62
- PR merge metrics
- No merged PRs in 30d
Description
Problem
sbt-typelevel's generated Test job emits a step named "Check headers and formatting" that runs sbt commands like:
sbt '++ ${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck
Plugins and projects that contribute additional lint-style checks (custom formatters, schema validators, license linters, etc.) want to fold their check into this same step so it runs alongside the existing ones — same matrix cell, same conditions, same "lint failures show up here" semantics. There's no first-class way to do that today; the only option is a fragile rewrite of githubWorkflowBuild:
ThisBuild / githubWorkflowBuild ~= {
_.map {
case step: WorkflowStep.Sbt if step.name == Some("Check headers and formatting") =>
step.withCommands(step.commands :+ "myLintCheckAll")
case other => other
}
}
This is nine lines per plugin, repeats the magic step-name string at every call site, and breaks if upstream renames the step or splits it. It also doesn't compose: two plugins both rewriting githubWorkflowBuild need to be careful about order and not stomping each other.
Proposed shape
A public setting that's just a list of extra commands appended into the existing lint step:
val tlCiLintCommands = settingKey[Seq[String]](
"Additional sbt commands appended to the 'Check headers and formatting' step"
)
// existing default rendering becomes something like:
WorkflowStep.Sbt(
List(
s"$$ $${{ matrix.scala }}",
"headerCheckAll",
"scalafmtCheckAll",
"project /",
"scalafmtSbtCheck",
) ++ tlCiLintCommands.value,
name = Some("Check headers and formatting"),
cond = ...,
)
User code becomes one line:
ThisBuild / tlCiLintCommands += "smithyFmtCheckAll"
…and plugins can opt projects in by default:
override def projectSettings = Seq(
tlCiLintCommands += "smithyFmtCheckAll",
)
+='d sequences compose naturally across plugins and project settings, so there's no ordering footgun.
Why it's worth doing
- Removes a copy-paste recipe from documentation. We currently tell
SmithyFormatPluginusers (in polyvariant/smithy-trait-codegen-scala) to write the nine-linegithubWorkflowBuild ~= { … }snippet by hand — every reader has to understand step matching,WorkflowStep.Sbt, andwithCommandsjust to bolt one task onto CI. - Plays nicely with autoplugins. A plugin that wants to opt projects into a check on CI can do so transparently via
projectSettings, with users' explicit additions composing on top. - The current pattern is brittle to upstream changes (step name, step splitting) — a named setting decouples user code from the rendering layout.
Happy to send a PR if the shape lands.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the githubWorkflowBuild rendering and the WorkflowStep.Sbt command construction described in the issue. Add the public tlCiLintCommands setting so its values are appended to the existing "Check headers and formatting" commands, then verify that += additions compose and remain in the generated Test job.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- scala
- Domain
- build-system, ci-cd
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100