* ci: modernize workflows to match mdterm CI pattern
Replace monolithic build.yml with split ci.yml (parallel fmt, clippy,
build+test jobs). Update all actions to modern versions (checkout@v4,
dtolnay/rust-toolchain, rust-cache@v2). Overhaul release workflow with
more build targets (musl, aarch64), simpler changelog, and crates.io
publish step.
* ci: fix broken cross-compilation targets and workspace publish
It turns out that the release workflow had a couple of targets that
were never going to work on GitHub-hosted runners.
The aarch64-pc-windows-msvc target needs ARM64 MSVC build tools
that simply aren't installed on windows-latest runners. And the
aarch64-unknown-linux-musl target was configured with
aarch64-linux-gnu-gcc as its linker — which is a *glibc* linker,
not a musl one. The resulting binaries would silently be linked
against glibc, completely defeating the point of a musl build.
Remove both broken targets rather than papering over them with
increasingly fragile cross-compilation hacks. The remaining six
targets are all either native builds or well-supported cross-
compilation (aarch64-linux-gnu with the correct gnu linker).
While at it, fix cargo publish — a bare `cargo publish` from a
workspace root doesn't know how to publish crates in dependency
order. Use cargo-workspaces which actually handles this correctly.
Also restore workflow_dispatch to CI so it can be triggered
manually when needed.
* ci: fix review issues in modernized workflows
The CI and release workflows from the previous modernization had a
few things that were just *not right*.
The CI build job was running `cargo build --release` which is
pointless in CI — we care about correctness and fast feedback, not
optimized binaries. It was also missing `--workspace` on both build
and test, so we were only checking whatever the root workspace
defaults resolved to. Clippy had the same problem — only linting
default features of default members, blissfully ignoring everything
else.
The release workflow had three issues: `git log HEAD` for first
releases only shows a single commit instead of the full history,
`--allow-dirty` on cargo publish silently masks unexpected checkout
state, and the workflow_dispatch trigger got dropped so there's no
way to manually re-run a failed release without pushing a new tag.
Fix all of it. Add --workspace and --all-features where they belong,
drop --release from CI build, fix the changelog range for first
releases, remove --allow-dirty, and restore workflow_dispatch.
* ci(release): harden release workflow against manual dispatch footguns
The release workflow had a bare workflow_dispatch trigger with no
inputs, which means manually re-running a failed release would use
the *branch name* as the tag. The changelog would be wrong, the
release would be named after a branch, and the publish job would
cheerfully push to crates.io regardless. Not great.
Three fixes:
Require a tag input on workflow_dispatch so manual re-runs actually
know what they're releasing. The changelog and release creation now
use inputs.tag || github.ref_name so both paths resolve correctly.
Guard the publish job with an if: startsWith(github.ref,
'refs/tags/v') check, because publishing to crates.io is
irreversible and "oops" is not an acceptable rollback strategy.
While at it, replace the cd-into-directory-and-back tar pattern
with tar -C, because changing directories in a shell script and
hoping you cd back correctly is the kind of thing that works right
up until it doesn't.
* ci: fix workflow_dispatch releasing into the void
The release workflow happily accepts a manual dispatch with any tag
string, then passes it to git log and softprops/action-gh-release
without ever checking if the tag actually *exists* as a git ref.
Confusion ensues — changelog generation silently produces garbage
and the release gets created pointing at nothing useful.
Add a tag validation step that fails fast with a clear error before
any downstream jobs run. Since both build and release already depend
on the changelog job via `needs`, this acts as a proper gate.
While at it, add --all-features to the CI build and test steps so
feature-gated code actually gets compiled and tested, not just
linted by clippy. Having clippy check code that never gets built
is the kind of false confidence that bites you on release day.
* ci(release): tighten tag validation and deduplicate tag resolution
The tag validation step was using `git rev-parse`, which happily
accepts *any* git ref — branches, commit SHAs, you name it. So if
someone created a branch called `v1.0.0` (don't ask), it would
sail right through validation and produce a release pointing at a
branch. Not great.
Switch to `git tag -l` so we only accept actual tags. That's the
whole point of a *tag* validation step.
While at it, hoist the `inputs.tag || github.ref_name` expression
into a workflow-level RELEASE_TAG env var instead of repeating it
in four different places. Also add a comment on the publish job's
`if` guard explaining that excluding manual dispatch is intentional
— because some future maintainer *will* look at that and think
it's a bug.
* ci(release): fix three lurking bugs in release workflow
The release workflow had a few issues that were just waiting to
bite someone at the worst possible time:
The prev_tag selection was grabbing *any* tag sorted by version,
not just version tags. If someone ever pushed a non-v* tag (say,
a test tag or a label), the changelog range would silently use
that as the baseline. Filter for "^v" prefixed tags first.
The cargo-workspaces install was unpinned, which means a breaking
release of that tool would break *our* release pipeline. In a
release workflow. The irony writes itself. Pin to 0.4.2.
While at it, fix the .cargo/config.toml creation for
aarch64-linux-gnu cross-compilation to use > instead of >> for
the first line, so we don't append duplicate entries if the file
somehow already exists.
* ci(release): fix three review issues in release workflow
The release workflow had a few things that would bite you at
exactly the wrong moment:
The prev_tag selection was using grep -v to exclude the current
tag, then grabbing the first result from a descending version
sort. Problem is, if you're doing a backport release for v1.0.1
and v2.0.0 already exists, you'd get v2.0.0 as your "previous"
tag. The changelog range would then be backwards and produce
garbage. Use sed to find the current tag's position in the sorted
list and grab the one *after* it instead.
The build job had no dependency on the changelog job, which means
tag validation could fail and six runners would still happily
churn away building binaries that nobody will ever use. Waste of
perfectly good CI minutes. Add needs: [changelog] so builds are
gated behind validation.
While at it, cap the first-release changelog to 100 commits. An
unbounded git log dumped into a GitHub release body is the kind
of thing that works fine until your repo has a thousand commits
and the API starts having opinions about payload size.
* ci(release): parallelize build, validate tag format, cache cargo-workspaces
Three things that should have been caught earlier:
The build job had a `needs: [changelog]` dependency for absolutely
no reason — it doesn't use any changelog outputs. All it did was
serialize the pipeline and add ~20s of dead time before the actual
builds started. The release and publish jobs already depend on both,
so the ordering was always preserved where it matters. Remove it.
The RELEASE_TAG env var comes from user input on workflow_dispatch,
and we were feeding it straight into sed patterns and git log range
expressions without validating the format first. Add a regex check
for vX.Y.Z *before* any shell interpolation happens. Defense in
depth — the trust boundary is already at repo write access, but
let's not be sloppy about it.
While at it, cache the cargo-workspaces binary in the publish job.
Compiling it from source on every single release is the kind of
waste that's easy to ignore until you don't.
* ci: harden CI permissions and fix release tag validation
The CI workflow was running with default token permissions, which
is more access than a read-only lint-and-build pipeline should ever
have. Add an explicit `permissions: { contents: read }` because
least-privilege is not optional.
The tag format regex in the release workflow was unanchored — it
matched *prefixes*, so `v1.0.0garbage` sailed right through. Anchor
it with `$` and add an optional pre-release suffix group so tags
like `v1.0.0-beta.1` still work. Please don't ship unanchored
validation regexes.
While at it, replace the sed-based prev-tag lookup with `grep -F -x`
for exact matching. The old sed pipeline treated dots in the tag as
regex wildcards, which is the kind of thing that works fine until it
doesn't. The new approach does literal matching and handles the
no-previous-tag edge case explicitly.
* ci(release): add --locked to builds and guard changelog tag lookup
The release builds were running without --locked, which means cargo
is free to re-resolve dependencies however it pleases. For a release
binary, that's *not great* — you want reproducible builds from the
exact Cargo.lock that was committed, not whatever cargo feels like
doing today.
While at it, the changelog generation was silently falling through
to the "list all commits" path if the release tag wasn't found in
the tag list. Now it emits a ::warning annotation so you at least
know something went sideways instead of staring at a suspiciously
long changelog wondering where it all came from.
* feat(ui): make TUI optional behind a cargo feature flag
The TUI is great for interactive use, but if you want to run wrkflw
as a headless CI runner, dragging in ratatui and crossterm is
pointless baggage. Issue #41 asked for this, and honestly the code
was already well-isolated enough that it *should* have been optional
from the start.
Add a `tui` feature flag (default-on) to both the `wrkflw-ui` crate
and the main binary crate. When disabled via `--no-default-features`,
ratatui/crossterm are gone, the `tui` subcommand disappears, and
running with no args prints help instead of launching the TUI. All
CLI subcommands (validate, run, trigger, list) remain fully
functional.
While at it, removed the direct crossterm/ratatui deps from the
binary crate — it never imported them, they were just coming through
transitively anyway.
* refactor(ui): feature-gate models and utils, clean up cfg imports
The previous commit gated the TUI behind a feature flag but left the
models and utils modules unconditionally compiled. It turns out that
*every single consumer* of those modules is TUI-gated code — they
were compiling to dead code when building with --no-default-features.
Gate models and utils behind cfg(feature = "tui") where they belong.
While at it, consolidate the five separate #[cfg(feature = "tui")]
annotations on imports in workflow.rs into a single grouped use block,
because repeating the same attribute five times in a row is not my
idea of readability.
Also add a cargo check --no-default-features step to CI so this
kind of thing doesn't silently regress.
* ci(build): drop archived actions-rs/cargo, add --workspace to feature check
The actions-rs/cargo@v1 action has been archived for a while now,
and wrapping every cargo invocation in a GitHub Action that just...
calls cargo... was never exactly adding value. Replace all five
uses with plain `run: cargo <cmd>` steps.
While at it, add --workspace to the --no-default-features check so
it actually verifies *all* crates compile without the tui feature,
not just the default workspace member. The previous version would
happily miss breakage in any non-default crate.
- Add windows-latest to OS matrix with x86_64-pc-windows-msvc target
- Add dedicated Windows integration test job
- Verify Windows executable functionality
- Ensure cross-platform compatibility testing
This ensures Windows build issues are caught early in CI/CD pipeline.
- Extracted functionality from the `src/` directory into individual crates within the `crates/` directory. This improves modularity, organization, and separation of concerns.
- Migrated modules include: models, evaluator, ui, gitlab, utils, logging, github, matrix, executor, runtime, parser, and validators.
- Removed the original source files and directories from `src/` after successful migration.
- This change sets the stage for better code management and potentially independent development/versioning of workspace members.
Add ability to trigger GitHub workflows with workflow_dispatch event from CLI.
This enables manual workflow triggering without using GitHub UI or custom bash
scripts.
Add trigger subcommand with branch and input parameters
Add list subcommand to show available workflows
Create GitHub API client for workflow dispatch events
Implement repo detection from git remote
Add User-Agent header for GitHub API requests
Update documentation with usage examples