Skip to content

v1.1.0

Latest

Choose a tag to compare

@jorgemoralespou jorgemoralespou released this 27 Oct 16:03
67c2be6

educatesenv v1.1.0 reworks how list-remote chooses and shows releases,
takes the GitHub token from your environment or the GitHub CLI instead of
a plain-text config file, verifies every download against the release's
checksums, and adds install latest and uninstall. It also fixes the
download command in these release notes, which returned 404 for v1.0.0.

Three changes can break scripts and habits built on v1.0.0. Read
"Breaking changes" before you upgrade.

Breaking changes

list-remote --all means every stable release

In v1.0.0, --all added pre-releases to the list. It now removes the
limit on how many releases are shown, and pre-releases have a flag of
their own, --pre-releases. To get what --all used to show, every
release including pre-releases, run:

educatesenv list-remote --pre-releases --all

list-remote prints a table of the 10 newest stable releases

v1.0.0 printed an Available versions: line and then the stable
releases it found as - <version> lines, sorted as strings. list-remote now
prints the 10 newest stable releases, highest version first by semver,
as VERSION and RELEASED columns under a header, with each release's
publish date in UTC:

$ educatesenv list-remote
VERSION  RELEASED
3.8.0    2026-08-26
3.7.3    2026-07-17
...
Showing 10 of 66 stable releases. Use --all to see all, --pre-releases to include pre-releases.

The "Showing N of M" line goes to stderr, so a pipe gets only the table.
A script that read the old list needs to skip the header and take the
first column, for example:

educatesenv list-remote --all | awk 'NR > 1 { print $1 }'

config.yaml is no longer read from the working directory

v1.0.0 also looked for config.yaml in the directory you ran it from,
and a file found there replaced your own config, including the
development binary location that decides what runs as educates. A
repository that happened to hold a config.yaml could change which
binary you ran. educatesenv now reads only ~/.educatesenv/config.yaml.
If you relied on a per-directory config, set the EDUCATES_* environment
variables instead, which still override the file.

Deprecations

Both keep working in v1.1.0, with a warning on stderr, and a later
release removes them.

  • list-remote --recents is hidden and changes nothing, since the
    10 newest releases are now the default. Drop it from your scripts.
  • github.token in the config file is still read, but as the last
    of the token sources, and using it prints a warning that names the
    file. Set GH_TOKEN or run gh auth login instead, then delete the
    token line from ~/.educatesenv/config.yaml. init and
    config init no longer write a token key.

New commands and flags

  • install latest installs the highest stable release by semver and
    says which version it resolved to. It takes --use and --overwrite
    like a named version. use takes only installed versions, so
    install latest --use is how to switch to the latest release.
  • uninstall <version>... removes one or more installed versions.
    It checks every version before it removes any, so a typo removes
    nothing. It refuses develop, versions that are not installed, and
    the active version unless you pass --force, which removes the
    educates symlink as well and leaves no version active.
  • list-remote --recent N, or -n N, shows the N newest releases,
    10 by default. It conflicts with --all.
  • list-remote --pre-releases adds release candidates, alphas and
    betas to the list.
  • list-remote --by-date orders the list by publish date instead of
    by version, and combines with every other flag:
    --pre-releases --by-date shows 3.8.1-rc.2 next to 4.0.0-alpha.13.

GitHub token

The token now comes from the first of these sources that has one:

  1. EDUCATES_GITHUB_TOKEN
  2. GH_TOKEN
  3. GITHUB_TOKEN
  4. gh auth token --hostname github.com, when the GitHub CLI is on your
    PATH
  5. github.token in the config file, deprecated

If you are logged in with gh, educatesenv uses that token with no
setup. It never writes a token to disk, and only list-remote,
install, init --download and config view look one up, so list,
use and version never run gh. config view shows where the token
came from, such as <set via GH_TOKEN>, and never any of its
characters.

When GitHub rate-limits a request, the error says when the limit resets,
and without a token, how to authenticate. When GitHub rejects a token,
the error names the source it came from.

Verified downloads

install and init --download check every binary against the SHA-256
checksum in the release's checksums.txt. A mismatch fails the install
and installs nothing, and so does a checksums.txt that does not list
the binary. A release without a checksums.txt installs with a
warning.

Fixes

  • list-remote considers every release. v1.0.0 read only the first 100
    of the 276 Educates releases.
  • Releases and installed versions are ordered by semver, so
    4.0.0-alpha.13 comes above 4.0.0-alpha.2 and 3.10.0 above
    3.9.0. list shows installed versions newest first, with the
    develop entry on top.
  • One rule decides what a pre-release is: a semver pre-release part in
    the tag, or GitHub's pre-release flag. Draft releases are never listed,
    and tags that are not semver are left out.
  • init --download installs the highest stable release by semver. It
    used to take the first stable release among the 10 most recently
    created ones, so it failed during a long run of release candidates,
    as from 2026-08-14 to 2026-08-26, and could pick a backport published
    after a higher release.
  • A binary built with go install reports the version you installed
    instead of develop.
  • An interrupted download no longer leaves a partial binary that a retry
    reports as already installed. Downloads land in a temporary file and
    are renamed into place only once complete and verified.
  • A download times out when the server does not accept the connection,
    finish the TLS handshake or start its response in time, and fails as
    stalled when no data arrives for 60 seconds, instead of waiting
    forever. A slow download that keeps making progress still finishes.
  • use says what went wrong. It reports a version as not installed only
    when its binary is missing, and otherwise passes the cause through.
  • config view no longer prints the token.
  • init and config init create the config file readable only by you.
    An existing file keeps its permissions, so if yours holds a token, run
    chmod 600 ~/.educatesenv/config.yaml.
  • init gives PATH instructions for the shell in $SHELL:
    ~/.zshrc for zsh, ~/.bashrc for bash, fish_user_paths for fish.
    It told zsh users, the macOS default, to edit ~/.bashrc.
  • Only list, use, install and init clean up a leftover symlink to
    a development binary. version, config and list-remote no longer
    touch the educates symlink.
  • The development-symlink check compares directories, so a binary in a
    sibling directory such as bin2 is no longer taken for one in the bin
    directory.
  • The warning about a missing home directory is printed once, not twice.
  • list marks develop as active after use develop. v1.0.0 marked it
    only when the educates symlink held the development binary's
    absolute path, and use develop writes a relative one.
  • A config value or EDUCATES_* variable that should be a boolean but
    is not, such as EDUCATES_DEVELOPMENT_ENABLED=yes, still reads as
    false, as in v1.0.0, and now prints a warning on stderr that names the
    key and file, or the variable.
  • The README documents only the commands and flags that exist.
    install latest and uninstall, which it documented before they
    existed, are now real, and install --force,
    list-remote --skip-pre-releases and make release-test, which never
    existed, are gone from it.

Other changes

These are corrections, but they can turn a command that used to succeed
into one that fails:

  • Commands that take no arguments reject stray ones, so a mistyped flag
    such as list-remote 5 fails instead of being ignored.

Release assets

The binaries are now named educatesenv-<os>-<arch>, and the download
command in the installation instructions works. v1.0.0 named them
educatesenv-<os>-<arch>_<version>_<os>_<arch>, so that command
returned 404.

  • educatesenv-darwin-amd64
  • educatesenv-darwin-arm64
  • educatesenv-linux-amd64
  • educatesenv-linux-arm64
  • checksums.txt, with the SHA-256 checksum of each binary

For example, on macOS on Apple silicon:

curl -fLO https://github.com/educates/educatesenv/releases/download/v1.1.0/educatesenv-darwin-arm64
curl -fLO https://github.com/educates/educatesenv/releases/download/v1.1.0/checksums.txt
shasum -a 256 --ignore-missing -c checksums.txt

On macOS, if you download an unsigned binary in a browser, macOS
quarantines it and refuses to run it. Clear the attribute with
xattr -d com.apple.quarantine <path to the binary>. Downloads made
with curl are not quarantined.

With Go 1.26 or later, you can install it with go install as well:

go install github.com/educates/educatesenv/cmd/educatesenv@v1.1.0

For contributors

  • Go 1.26: go.mod sets go 1.26.0 and toolchain go1.26.10, and every
    workflow reads the version from there.
  • go-github v93, cobra 1.10.2 and testify 1.12.1. golang.org/x/mod
    handles semver. viper gives way to go.yaml.in/yaml/v3 and explicit
    environment lookups, and golang.org/x/oauth2 is gone.
  • golangci-lint is pinned to v2.15.0 and runs on pull requests.
    GoReleaser is pinned to v2.19.0.
  • Every action is pinned by commit SHA, and Dependabot keeps the pins
    current.
  • The release workflow's manual trigger has a skip-signing input that
    releases without signing the macOS binaries, and a MACOS_SIGNING
    repository variable set to false does the same for every release,
    tag pushes included. Every other release signs and notarizes them,
    and fails before creating a release when a signing or notary secret is
    missing, or when signing or the notarization submission fails.
  • A new pkg/releases package holds the release selection rules, and
    the tests run every command in-process against a fake GitHub server,
    with no network, no real gh and no real home directory.