Repository navigation
hecatron 0.6.0
-
Detection: dotfiles aren't sources (a
.nvim.luano longer adds
Lua); Lua isn't detected from premake build scripts, nor R from an
Octave package'sDESCRIPTION. -
Default hooks find more layouts: PHP's test and deps hooks use the
nearestcomposer.jsonabove (a root one coveringlang/php, running
its PHPUnit on the directory'sphpunit.xml); Dart's test hook tests the
packages below with atest/(a pub workspace's root,pkgs/*); R's
tests each package below withtests/testthat/(R-package/), and its
deps hook installs aDESCRIPTION's missing dependencies from CRAN
(hct install rnow fetches them); Ruby compiles a gem's native
extension (rake compile) before testing; Racket links sibling packages
(each with itsinfo.rkt) beforeraco test; Elm runs
elm-explorations/test1.x on the last elm-test supporting it, with
Elm 0.19.1. -
Installs: PHP installs the extensions a
composer.jsonor its
dependencies require (ext-curl,ext-mongodb...) where packages
exist; opam installs the system packages dependencies need; Tcl installs
makefor TEA extensions' tests. -
Node.js workspaces built before their tests: when a package in the
workspace a test runs in needs building (a native addon or entry point
not built yet),hct test typescriptandhct test javascriptbuild
the workspace first (pnpm -r run build,npm run build --workspaces,
Yarn'sworkspaces foreach --topological run build), so a roottest
script that runs every package's tests, or a package importing another
one'sdist/, finds them built. -
.NET's
rollForward: latestMajoris a floor: aglobal.jsonasking
for SDK 8.0.100 or later now gets hecatron's default SDK (10), or the
newest of its own major when that is newer than the default, raised to
the newest major the component's projects target (net11.0needs SDK
11). Before, it read as SDK 8, which can't build a project targeting
net10.0. Definitions name such files in the newfloorFileskey. -
hct self: hecatron's own commands take a space, asrustup self
anduv selfdo:hct self update,hct self testandhct self build;hct selflists them.self-testandself-buildstill work. -
hct self update: updates an installation install.sh made to the
latest release (or--version X.Y.Z), its binary checked against the
release'sSHA256SUMSand the new version swapped in whole, so a
failure leaves the old one working; rewritesenvandenv.fishas
install.sh does, so new PATH entries (the toolchains' links) take
effect; refreshes the Agent Skillhct skill installput in place.--checkonly reports (exit 3: a newer release).
Once a day at most, a release binary looks for a newer release in the
background and says so in one line after a command, on a terminal in
human output only (never in CI, agent or JSON output, or with
HECATRON_NO_UPDATE_CHECK=1);hct statusreports it from that check.
Hecatron never updates itself. Needs the binary. -
Detection: a language whose build files are all more than three
levels below the directory the layout gives it (antlr4's Go module in
runtime/Go/antlr/v4, jsii's inpackages/@jsii/...) gets its own
implPathsentry instead, since the hooks look no deeper and failed with
"no go.mod here, below, or above it"; files undervendored/no longer
make a language. -
JVM and .NET builds in real projects: a Java, Kotlin, Scala or
Groovy directory inside a Gradle build that isn't one of its projects
(moshi/src/main/java) runs Gradle from the project it belongs to,
instead of failing as "not part of the build"; a Kotlin Multiplatform
build without atesttask runsjvmTest, elseallTests; a
multi-module Maven build tests through the package phase; Mill builds (build.mill) are tested;
the JVM gets a UTF-8 locale when none is set; Maven, Gradle and sbt are
installed for builds below the language's directory too. .NET tests roll
forward to the installed runtime (a test project targeting net8.0 runs on
.NET 10), and a directory with several projects and no solution tests
each test project. A Clojure project withdeps.ednbut no:test
alias tests with Leiningen when it hasproject.clj. A Gradle build's
toolchain JDK is found from its root and its version catalog
(libs.versions.jdk), so a source directory's build gets it installed,
and a build whosejavais a runtime withoutjavac(a JRE another
package pulled in) runs on the newest installed JDK. -
hct dockerfile: the generated Dockerfile gives curl a config file
(throughCURL_HOME) with the installers' retry policy plus
--retry-all-errors, so a transient download failure, such as a dropped
TLS connection to api.adoptium.net, is retried instead of failing the
build. It applies to everycurlin the build and in the image. -
Python tests in monorepos:
hct test pythonin a directory without
apyproject.toml,setup.pyorsetup.cfgnow tests the Python
projects in the directories below (py-polars/,python-package/),
each in its own environment, instead of running pytest over the whole
tree; with none below, pytest runs there on its own as before. -
Swift: a package that declares no test target (a C library's
Package.swiftfor SwiftPM users) passeshct testinstead of failing
on "no tests found". -
pnpm and Yarn for every language's hooks: Corepack's pnpm and Yarn
shims live in~/.cache/hecatron/corepack-shims, whichhct install
now creates when a package needs them and which is a staticpath
entry of JavaScript and TypeScript, so another language's build or
tests that runpnpm(a Rust test in a pnpm monorepo) find it. -
Bash is detected from a Bats suite: a definition's
detectTests
(Bash's*.bats) count intest/andtests/for a language not
otherwise found, placing it at the directory tested, so bats-core and
Bash-it are Bash projects. Bash's test hook leaves out.batsfiles
under afixtures/directory, which are test data. -
Fixed: a random "Unknown language", skipped dependencies or wrong doctor
result under load. The shell scripts checked list membership by piping
intogrep -q; when grep matched early, the writer was killed and, under
pipefail, the check said "not found". They now use a plain loop (#197). -
A Kotlin JVM target picks the JDK: a Gradle build whose Kotlin sets
jvmTarget(11 or later) and that sets no Java target or toolchain runs on
that JDK, whichhct installinstalls, instead of failing Kotlin's check
that Java and Kotlin target the same JVM. -
JDK 8 installs: a Gradle or Maven toolchain asking for JDK 8 gets
Temurin 8, whose releases are namedjdk8u412-b08. Before,hct install
failed with "No Temurin JDK release matches 8" and installed no other JDK
the build needed either. -
Native builds: C, C++ and Objective-C build with CMake or Meson in
_build/when the project tracks files inbuild/(configuring into it
mixed build output with its sources, andhct cleandeleted them); a CMake
project that never sets up a test passeshct testafter building instead
of failing on "No tests were found"; installers install Meson and Ninja
where a component builds with Meson, pkg-config (which Makefiles call)
with C and C++, and the libraries PCRE2 and cJSON where a CMake build
looks for them. -
Native tests: a CMake project that calls
enable_testing()in a
subdirectory rather than at its top level (Zstandard) runs its CTest tests
from that subdirectory's build directory instead of failing on "No tests
were found"; a Makefile project builds its default target beforemake checkormake test(Redis's tests run programs onlymakebuilds); and
a Meson build directory a failed setup left behind is set up again. -
Rust's system dependencies:
hct install rustinstalls what a
component's crates build with, read from its Cargo.lock files: the
libraries common-syscrates link (OpenSSL, GLib, GTK and WebKitGTK,
D-Bus, ALSA...), Python's headers for PyO3, and the tools build
dependencies run (CMake for thecmakecrate and zlib-ng,protocfor
prost-build unless protoc is vendored, Cap'n Proto, libclang for bindgen),
and therust-srccomponent where ui_test's UI tests need it. -
Python test dependencies in dependency groups:
hct test python
andhct deps pythonnow install every PEP 735 dependency group
(uv run --all-groups,uv sync --all-groups), not onlydev, so
test dependencies kept in atestortestsgroup are there. -
Meson versions: where a
meson.buildasks for a newer Meson
(project(..., meson_version: '>=1.8.3')) than the one installed,hct doctorreports it andhct install c(orcpp,objectivec) installs
the current Meson from PyPI as a uv tool on Linux, whose distribution
Meson lags (Ubuntu 24.04's 1.3 can't build NumPy or SciPy). -
Rust's system dependencies:
hct install rustreads every Cargo.lock
in the project outside the trees detection skips (examples, tests,
vendored code...), not only those of the Rust components, so a crate
another language's build compiles (a Java binding's Maven build running
cargo) gets what it needs too, such asprotoc. -
Rust tests:
hct test rustrunscargo testrather thancargo test --all-targets: Cargo's default targets, now with doctests, and without
running benchmarks as tests (a nightly-only benchmark broke stable builds,
and others fail or run long in test mode). -
A fresh install from
install.shno longer prints git's "is not a commit" warning and its detached HEAD advice. -
hct self uninstallremoves hecatron:~/.hecatron, its lines in
your shell's startup files and fish's conf.d, and its Agent Skill. It
asks first (--yesskips the question). The toolchains it installed
stay;--allalso removes those it unpacked (~/.local/share/hecatron)
and its download cache (~/.cache/hecatron). Run from a checkout, it
keeps the checkout. -
Node.js packages built before their tests:
hct test typescript
andhct test javascriptfirst build a package whose tests need it
built: a native addon (napi-rs, node-gyp) not built yet, or an entry
point (main,exports) the build writes that isn't there. Through
the package's build script, elsenapi build --platformornode-gyp rebuild, instead of failing with "Failed to load native binding" or
"Cannot find module dist/...". A configured test runner that fails now
fails as itself, and npm's placeholder test script counts as none. -
Node.js tests in more layouts:
hct test typescriptandhct test javascriptnow test a workspace root without atestscript through its
packages' scripts, a package with a configured Vitest, Jest or Mocha but
no script through that runner, and a directory without apackage.json
(or a rootpackage.jsonholding only tooling) through the language's
packages below it, where they failed with "no test command". Scripts
that call pnpm or Yarn by name find Corepack's shim on PATH, and tests
run withCI=true(unless it's set), so runners that would otherwise
watch for changes (Create React App's, Vitest's) run once. -
Detection:
hct initno longer proposes components from directories
likesrc/<service>/src/main/<lang>when another language's directory
isn't named for it (TypeScript insrc/frontend), which left that
language, and every other one outside the pattern, with no directory. -
Other languages' tools on PATH: a language's hooks (and
hct env LANG) now also have the project's other added, enabled
languages' staticpathdirectories on PATH, after the language's own,
so a Ruby, OCaml or D build that runscargofinds the Rust that
hct installput in~/.cargo/bin. -
Release downloads as data (#77, stage 2):
install.jsoncan name a
release download, always checked against a SHA-256 (inline, a published
checksum file, or the publisher's index). Gleam and Zig install that way,
at the versionconfig.jsonpins (Zig installed whatever was latest),
into~/.local/share/hecatron/toolchainswithout root, on macOS too
instead of Homebrew, with their commands linked into
~/.local/share/hecatron/bin, which~/.hecatron/envnow puts on PATH.
Downloads are cached in~/.cache/hecatron/downloads; a toolchain that
doesn't work is replaced whole. With"ci": {"cache": true}both are
cached in CI. -
Installs as data (#77, stage 1): with the binary, Bash, COBOL, D,
Erlang, Common Lisp, Octave, Pascal, Prolog, Racket, Raku and Tcl install
from alanguages/<lang>/install.jsoninstead ofinstall.sh: every
step has a check, so a rerun does nothing anddoctor --fixruns only
what fails; the doctor's checks come from the same data; installing
several languages makes oneapt-get install(orbrew install) for all
their packages; receipts record what hecatron installed, and uninstall
removes only that, keeping what another language needs.hct install --planshows what would happen. A project's owninstall.shstill
wins, andHECATRON_INSTALLER=scriptforces the scripts.
tests/docker/parity.shchecks the two ways agree. The prototype's
"install"key moved fromconfig.jsontoinstall.json. Toolchains
the engine downloads go to~/.local/share/hecatron/toolchains(no
root), and"ci": {"cache": true}caches that directory, keyed on what
the engine would install; the eleven languages converted so far come
from apt, which isn't cached, so this grows with the languages moved to
downloads. -
Uninstalling a language leaves shared and system software: an
uninstall.shremoves only what is the language's own and hecatron
installed. A toolchain another language's installer also installs stays,
with a line saying so (Left CMake installed: C, C++, Objective-C, COBOL and Fortran share it.): CMake (C, C++, Fortran), Node.js (TypeScript,
JavaScript), the .NET SDK (C#, F#, VB.NET), Erlang/OTP (Erlang, which now
removes only rebar3), uv (Python) and Homebrew's gcc (Fortran). Python no
longer removes the distribution'spython3(apt-get remove python3
could take much of a Debian or Ubuntu system with it); it removes uv's
Python builds, unless Mojo runs on one. PHP removes only the-cli,
-xmland-mbstringpackages its installer installs, instead of
php*followed byapt-get autoremove. D also removes dub. -
Elixir versions: Elixir installs side by side from builds.hex.pm's
precompiled releases, with a default of 1.20.4 (it was Ubuntu's apt 1.14,
which current libraries warn about), a.tool-versionsormise.toml
pin (1.17.3-otp-27reads as 1.17.3) or theelixir-versiona CI
workflow tests choosing another. Each version runs on an OTP it supports,
linked as<home>/erlang: the Erlang on PATH when it is one, else
builds.hex.pm's OTP build on Ubuntu or Homebrew'serlang@Non macOS. On
Debian, which has no builds there, an Elixir its own Erlang can't run
fails with the reason. Each version has its own Hex (MIX_ARCHIVES), so
one built on a newer OTP doesn't break an older Elixir's.hct doctor elixirnotes which OTP each component's Elixir runs on. -
Doctor notes: a
doctor.shline startingnote:(notein
_common.sh) is shown under the language, like the version notes, without
counting as a problem, for what's worth knowing about a healthy toolchain. -
hct sync: after a pull, rebase or checkout, says in a few lines
what changed for hecatron since whereHEADwas (or a ref): runs
hct depsfor the components whose lock files changed (--no-depsonly
says so), says the toolchain version each changed pin now needs and
whether it's installed (it never installs), and runshct checkwhen the
config, hooks or generated files changed. Never pulls or fetches; needs
the binary (#92). -
Reports every CI reads: with the binary,
HECATRON_REPORT_DIR
receives JUnit XML fromhct test,lintandbuild(a suite per
language and component, with the tools' own test cases where they write
them: Maven Surefire and Failsafe, Gradle, sbt,go test -json, pytest,
and anything a hook leaves inHECATRON_TEST_REPORTS), SARIF 2.1.0 from
hct lintandhct audit(an advisory per rule, at the lock file, for
GitHub code scanning), and GitLab Code Quality JSON fromhct lint,
beside the normal output;--output junitand--output sarifprint one
instead. The generated GitLab pipeline hands JUnit and Code Quality to
the merge request widgets (#100). -
GitHub Actions job summary: with
GITHUB_STEP_SUMMARYset, each run
command appends a table of languages and components with status and
time, then each failure's error lines, log and rerun command;audit,
licensesandadvisoradd their findings (#101). -
hct installandhct uninstallrun in the binary: choosing the
languages, running their installers and fetching the deferred
dependencies no longer goes through manage.py (76 ms to 12 ms around a stub
installer); the installers stay scripts. -
hct version <version>runs in the binary (90 ms to 11 ms around a
stub hook); each language'sversion.shstays a script. -
hct bannerruns in the binary, without Python: 3 ms instead of
51 ms, for generators that call it for every file they write. -
The run commands' help lists
--output,--timeoutand--changed
(hct test help), noting that they need hecatron's binary. -
OSV-Scanner for
hct licenses: every languagehct licensesreads
(TypeScript, JavaScript, Python, Go, Ruby, PHP, C#, F#, VB.NET and
Clojure, besides those whose audit already used it) installs OSV-Scanner
2.7.0 with its toolchain, so a project of only those languages no longer
stops at "OSV-Scanner isn't installed". -
Pin files can drop a suffix: a
pinFilesorsupportFilesentry's
"strip", a regular expression, is removed from the version the file
gives, for ecosystems that write more than the version in it (asdf's and
mise's Elixir1.17.3-otp-27). -
Detection skips more code that isn't the project's:
hct init
leaves out directories it skips in any case (Examples/), hidden
directories (.jenkins/),templates/and test data
(tests_data/,test-data/), so a Jenkinsfile, a code generator's
templates or an example no longer adds a language.