Skip to content

task-manager v0.8.0

Choose a tag to compare

@github-actions github-actions released this 28 Aug 14:37
· 45 commits to main since this release
5a373c1

Upgrading from v0.7.1. The SDK module is released alongside as sdk/v0.8.0.

New: taskmgr config

Configuration is now editable from the command line. Two files are addressable: the
resolved store's .tasks/config.yaml, and your per-user ~/.taskmgr/config.yaml with
--global, which needs no store and works in any directory.

taskmgr config keys                  # every supported key, both scopes
taskmgr config list                  # current values, with the file's path
taskmgr config get hook_timeout
taskmgr config set hook_timeout 5m
taskmgr config unset hook_timeout

Hooks are managed with taskmgr config hook, which owns the hooks block:

taskmgr config hook add --event pre-close --run make --run test
taskmgr config hook list             # in run order, with each effective id
taskmgr config hook rm pre-close#0

Global hooks. A hooks block in the per-user config applies to every store on the
machine and runs before the store's own. The per-user file does not travel with a
repository, so it fits personal ergonomics — a reminder, a local lint — and not a rule
the data depends on. Inherited hooks carry a global: prefix on their id wherever they
appear, so a refusal always tells you which file to edit. A store cannot switch them off.

JSON surface: store and health

For anyone driving taskmgr --json across several stores:

  • issueDTO and the create result carry store, the central-registry name of the
    store the issue came from. Omitted for a local store, which has no registry entry.
  • store list rows carry health: ok, dangling (the entry is registered, its
    directory is gone) or broken (a directory with no config.yaml). Classification is
    one stat per entry, so a listing and a resolution never disagree, and a store
    switcher can hide the rows that will not open instead of failing one per selection.

Fixes

  • Concurrent taskmgr config writes no longer discard each other. Twelve at once
    used to leave one edit and report success twelve times. The read now happens inside
    the file lock, and per-user writes take one at all (~/.taskmgr/.config.lock).
  • A malformed hook can be removed again. Two bad entries in the per-user config used
    to fail every write on the machine and refuse config hook rm for both ids, leaving
    a hand edit as the only way out. A write now validates only what it introduces.
  • A central store stays writable when its project directory is deleted. A hook now
    runs in the store directory when the project root is gone, instead of failing the
    spawn and reporting a binary that plainly exists as "could not execute".
  • store list no longer calls an intact store dangling. A stat that fails for
    any reason other than "not found" is reported as itself; only a missing directory is
    dangling. Selecting a dangling store by name also gets its own message, since the
    repair differs from a broken one.
  • taskmgr -C . init derives the ID prefix from the directory's real name rather than
    falling back to task — which mattered, because the prefix cannot be changed later.
  • taskmgr config --global list works, not only taskmgr config list --global.
  • A denied or failed hook writes its log record to the invocation's stderr.

Changes worth checking before you upgrade

  • A declared hook id may no longer contain #. The character is reserved for the
    defaulted <event>#<index> id, so the two sources can never collide. If an existing
    config.yaml declares one — id: pre-close#1 — every write in that store fails
    until it is renamed. Edit the id in the file, or remove the entry with
    taskmgr config hook rm and add it back with a valid id.
  • taskmgr config set <key> "" now exits 1 and points at config unset. It used to
    perform the unset and report success, so a script passing an unset shell variable
    silently reverted the key.
  • taskmgr store list exits 1 when it cannot read a store directory, instead of
    listing it as dangling.

For integrators — sdk/v0.8.0

go get github.com/hk9890/task-manager/sdk@v0.8.0

Breaking

Stores() no longer takes ResolveOptions.

entries, err := tasks.Stores(opts)   // sdk/v0.7.0
entries, err := tasks.Stores()       // sdk/v0.8.0

The registry is global, so a working directory and a store-name override selected
nothing; the parameter was accepted and discarded, which made --dir and --store-name
look as though they filtered store list. This is the only signature change, and it is
why the tag is a minor rather than a patch.

Stores() can now return an error where it previously returned rows. A stat that
fails on a store directory is no longer flattened into StoreDangling. Handle the error;
do not treat a failed listing as an empty one.

Resolution reports a dangling named store differently. Resolve with a StoreName
whose directory is gone returns a message about a missing directory rather than the
"not a finished store (no config.yaml)" text. The sentinels are unchanged — only code
matching on message text is affected.

Added

UpdateConfig, UpdateGlobalConfig, LoadGlobalConfig, SaveGlobalConfig,
GlobalConfigPath, GlobalConfig, HookID, DerivePrefix, StoreHealth,
StoreEntry.Health, Store.Name, Store.Config, Store.SetConfig.
InitWithVFS gained variadic options, which existing calls keep compiling through.

Behaviour to be aware of

  • Prefer UpdateConfig / UpdateGlobalConfig over SetConfig / SaveGlobalConfig.
    The pair taking a mutation function does the read, the change and the write inside one
    hold of the lock. The setters replace the file from a snapshot read outside it, so they
    are last-writer-wins by construction and are documented as such.
  • Store.Config() now returns a deep copy, each hook's Run argv included. It
    previously shared those slices with the compiled hooks, so editing the returned value
    changed the gate the next mutation executed.
  • A hook's working directory falls back to the store directory when the project root
    no longer exists. TASKMGR_STORE always names the data directory.
  • Writing the per-user config creates <home>/.config.lock, a separate advisory lock
    from the central root's .lock.

Verifying the download

The release carries per-archive SBOMs and a keyless cosign signature over the manifest.
Needs cosign 3.x.

sha256sum -c checksums.txt

cosign verify-blob checksums.txt \
  --bundle checksums.txt.bundle \
  --certificate-identity-regexp '^https://github\.com/hk9890/task-manager/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com