Skip to content

hecatron 0.4.0

Choose a tag to compare

@dnf dnf released this 27 Oct 19:01
· 127 commits to main since this release
ce7d1f1
  • A fast binary: installing a release also installs the Go core for
    your machine (macOS and Linux, x86_64 and arm64), checksum-verified, and
    hct runs it: --version and list answer in about a millisecond
    (80 ms before, on a 51-language project), and help, list, env and the
    run commands no longer depend on the system's bash (macOS's 3.2). The
    run commands take --output human|agent|json|ci (or HECATRON_OUTPUT):
    agent output is a summary line and only the failures with their key
    error lines; exit status 3 means a toolchain is missing. The rest still
    runs through the scripts. HECATRON_NO_GO=1 keeps to the scripts.

  • Fixes on macOS's bash 3.2: every run command's help and hct doctor no longer fail with "unbound variable" in a repository with no
    languages (which the binary avoids altogether).

  • .NET runs the SDK it should: a version the project's config names
    runs exactly that SDK, each version in its own view of /opt/dotnet; a
    version a GitHub workflow names is installed but, as setup-dotnet
    does, the newest SDK runs unless a global.json picks one, and
    hecatron doctor now says which. Downloading dotnet-install.sh
    retries a dropped connection.

  • Installing everything fetches dependencies last: with no languages
    named, hecatron install installs every toolchain first, then fetches
    dependencies once, so one language's fetch that needs another's
    toolchain (a prepare script running Ruby) no longer fails.

  • Perl runs a project's own Makefile test target, which may set what
    its tests need (AUTHOR_TESTING): cucumber/tag-expressions runs 169
    tests through it, where hecatron's prove ran 68.

  • hecatron init skips a package with no test script for a JavaScript
    or TypeScript implementation (a JSON-schema package beside the real
    one), saying why.

  • A generated image fails when its PowerShell modules didn't install,
    instead of shipping without Pester.

  • Instructions for AI agents: hct init writes a short section to
    AGENTS.md (and has an existing CLAUDE.md load it); --no-agents skips
    it. hct help agents prints a compact reference written for agents.

  • No setup step: in a git repository without .hecatron/config.json,
    every command works on what hct init would detect, remembered inside
    .git/ until the tracked files change; nothing is written to the working
    tree. hct init saves it, to commit and adjust.

  • hct lint now fails on unformatted code. It runs each language's
    format check (below) after its linter, where the linter doesn't check
    formatting already, so a project whose code isn't formatted the way its
    formatter says will see lint fail. Run hct format once, or turn the
    check off in .hecatron/config.json with "lint": {"format": false} (or
    {"format": {"haskell": false}} for one language). See
    docs/format.md.

  • hecatron outdated: lists each component's direct dependencies that
    have a newer version, from each ecosystem's own report (npm, pnpm, Yarn,
    uv, go list -u -m, Cargo's dry-run update, Bundler, Composer, the .NET
    SDK, Hex, pub, Maven's versions plugin, Gradle's Versions plugin where a
    build applies it, cabal), with current, wanted and latest versions.
    Report-only unless --fail; --json prints one array. See
    docs/outdated.md.

  • hecatron deps: fetches every component's dependencies with its
    ecosystem's tool, held to the lock file where there is one: npm, pnpm,
    Yarn or Bun's frozen install, uv sync --locked, Bundler frozen,
    composer install, dotnet restore --locked-mode, go mod download,
    cargo fetch --locked, mix deps.get, pub get --enforce-lockfile,
    swift package resolve, Maven's dependency:go-offline, Gradle, sbt,
    Stack or cabal, and more. Languages without a dependency manager say so.
    The test, lint and build hooks that install missing dependencies, and the
    installers, now do it the same way, so pnpm, Yarn, Bun, Bundler, Dart
    and Shards installs no longer change a lock file
    : one that's out of
    date fails, as npm ci already did.

  • hecatron format: rewrites every component's code with its
    language's formatter, using the project's own configuration: gofmt,
    rustfmt, Ruff (or Black), dotnet format, mix format, dart format,
    zig fmt, swift-format, elm-format..., and where the project configures
    one, Prettier or Biome, RuboCop or Standard, PHP CS Fixer or Pint,
    Spotless, ktlint or scalafmt through the build, clang-format, StyLua,
    perltidy, Fourmolu or Ormolu, Air, cljfmt, erlfmt, JuliaFormatter and
    ocamlformat. --check changes nothing and lists the files it would
    change. The installers add the formatters a toolchain doesn't ship, at
    pinned versions.

  • hecatron audit: checks every component's dependencies for known
    vulnerabilities with each ecosystem's auditor (npm, pnpm, Yarn, Bun,
    pip-audit, govulncheck, bundler-audit, Composer, the .NET SDK, and
    OSV-Scanner for the rest), fails at --fail-on (default high), and takes
    accepted risks with a reason and an expiry date. See
    docs/audit.md.

  • Old checkouts get the toolchains of their day: when a repository's last
    commit is over a year old, each language's version becomes the release
    that was current then, unless the project pins an exact one. A 2021
    checkout gets the Node.js and JDK it was tested with instead of today's,
    which can no longer build or run it. HECATRON_AS_OF sets the date or
    turns this off; hecatron doctor says when it applies.
    A weekly workflow keeps the release dates this uses current.

  • CI workflows and Maven builds say how new a toolchain may be: with no
    pin file, the versions a project's GitHub Actions setup steps use, and a
    Maven build's Java source level, hold the default back.

  • JavaScript components choose their Node.js version like TypeScript's.

  • Python follows the versions a project supports: with no pin file, a
    component whose classifiers stop at an older Python than the default
    (Avro's at 3.14) gets that line's newest release, since compiled
    dependencies often lag a new Python. hecatron doctor says when.

  • elm-review is on PATH: global npm commands Elm installs are all linked
    onto PATH, now that Node.js comes from its official builds.

  • CMake builds run fewer compile jobs at once: one per CPU (or CPU
    quota) but at most one per 2 GB of memory, so a large C++ project no
    longer has its compilers killed for memory. CMAKE_BUILD_PARALLEL_LEVEL
    still decides when set.

  • A CMake subdirectory is built as part of its project: a component
    whose CMakeLists.txt calls no project() (one a parent's
    add_subdirectory() pulls in) is configured from the nearest directory
    above it that does, and its own tests run.

  • CMake test options are the project's own: the test hook no longer
    turns on a fetched dependency's test options, nor valgrind or
    large-memory ones, and an option whose setup is missing is left off
    instead of failing the configure. A project that registers no CTest
    tests and runs them from a check or tests target gets that target.

  • C and C++ installers find more of what a CMake build needs:
    pkg_check_modules() and pkg_search_module() lookups, headers looked
    for by hand (gtest/gtest.h), files include()d from outside the
    component, the enclosing project's own lookups, and more libraries (GLib,
    RE2, ICU, Jansson, Snappy, zstd, LZ4, libevent, flex, bison...).

  • Perl installs Module::Install and the extensions a Makefile.PL
    written with it names (configure_requires), which a checkout doesn't
    bundle, and installs the CPAN dependencies a Makefile.PL or Build.PL
    declares, as it did a cpanfile's.

  • Dart installs Flutter (3.47.8) where a component is a Flutter package,
    and fetches its packages with flutter pub get; the doctor reports it
    missing. The test hook says so when a package has no test/ directory.

  • JVM builds get the JDKs they ask for: the JVM installers install the
    JDKs a Gradle or Maven toolchain names, and a build whose Gradle wrapper
    (before 9.1) or Kotlin compiler (before 2.3) can't run on the default
    JDK runs on the newest LTS JDK it supports, which they install too.

  • Python installs a C compiler on Linux, for dependencies that build a
    C extension from source.

  • Default hooks find a build that isn't in the language's directory:
    above it in the project (pulumi's sdk/go in the module sdk/go.mod, a
    root Package.swift, CMake project or Gradle build), or in directories
    below it, run in each (several crates under rust/, a solution in
    csharp/src/), or a root Makefile's target named for the directory
    (check_cxx).

  • Node.js uses the project's package manager: the hooks and installers
    run pnpm, Yarn or Bun when packageManager or the lockfile says so (pnpm
    and Yarn through Corepack), so a pnpm or Yarn workspace installs instead of
    failing on workspace:*.

  • Toolchain versions for .NET (C#, F#, VB.NET): a pinned default SDK
    (10.0.403 LTS, the 10.0.4xx feature band), or the one a component's
    global.json asks for, installed side by side with Microsoft's
    dotnet-install.sh into /opt/dotnet (per-user on macOS) rather than the
    distribution's package, which holds one feature band; the runtimes older
    target frameworks need go there too. A newer band's analyzers no longer
    fail with CS9057 on Ubuntu's 10.0.1xx compiler.

  • Toolchain versions for PHP: a pinned default (PHP 8.5), or the line a
    component's .php-version, composer.json config.platform.php,
    .tool-versions or mise asks for, installed side by side from Ondřej
    Surý's packages (his PPA on Ubuntu, packages.sury.org on Debian) or
    Homebrew's shivammathur/php tap, with one Composer for all. The doctor
    reports a component whose PHP is older than its composer.lock needs.

  • Toolchain versions for Ruby: a pinned default (Ruby 4.0.9), or the
    version a component's .ruby-version, .tool-versions or mise asks for,
    built side by side by ruby-build into /opt/ruby/<version> (per-user on
    macOS), each with its own Bundler. Ruby no longer comes from apt, whose
    3.2 is too old for many gems.

  • global.json's rollForward counts: a .NET SDK pin of 8.0.100 with
    latestFeature asks for the newest 8.0 SDK, and with latestMajor the
    newest 8; .php-version and composer.json's config.platform.php pin
    PHP.

  • Rust repairs an interrupted install: a rustup left with no default
    toolchain (an install killed mid-download) is reported by the doctor and
    fixed by the installer.

  • docs/languages.md: every language with a link to
    its home, a one-line description, and the build systems, test runners and
    linters its default hooks use, generated from the definitions.