Skip to content

fix: reuse installers cached in the tool cache - #298

Open
dhensby wants to merge 3 commits into
tediousjs:masterfrom
dhensby:fix/tool-cache-semver-version
Open

dhensby wants to merge 3 commits into
tediousjs:masterfrom
dhensby:fix/tool-cache-semver-version

Conversation

@dhensby

@dhensby dhensby commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

Problem

@actions/tool-cache's find() only does an exact lookup when the version is an explicit semver. For anything else (e.g. '2022') it treats the version as a range and resolves it via findAllVersions(), which only returns cache directories whose names are explicit semver versions. Every installer was cached under a bare version (sqlserver/2022, sqlupdate/2019, msodbcsql/18, sqlncli/11), so find() always returned '' — the cache was written but never read, even on self-hosted runners. The unit tests didn't catch it because they mock tc.find.

This was noticed while reviewing #296.

Reproduced against the real @actions/tool-cache 4.0.0:

cacheDir(sqlserver, 2022)     -> <cache>/sqlserver/2022/arm64
  find(sqlserver, 2022)       -> ""
cacheDir(sqlserver, 2025.0.0) -> <cache>/sqlserver/2025.0.0/arm64
  find(sqlserver, 2025.0.0)   -> "<cache>/sqlserver/2025.0.0/arm64"

The MSI installer (ODBC / Native Client) also used inconsistent arch: find() was given getArch() (x64/x86) while cacheFile() fell back to os.arch(), which differ on arm64 runners.

Changes

  • fix: reuse cached SQL Server installers and updates — adds src/tool-cache.ts, a thin wrapper (findCachedTool, cacheToolDir, cacheToolFile) that pads versions to an explicit semver ('2022' → '2022.0.0') for both writes and lookups. install.ts and utils.ts go through it. New test/tool-cache.ts runs against the real @actions/tool-cache (only @actions/core logging is silenced) and round-trips every supported SQL Server version; it fails without the mapping. Mocked tests now assert the semver-shaped version passed to tool-cache. README gains a "Caching" section.
  • fix: reuse cached ODBC and Native Client installers — the MSI installer uses the wrapper and passes the same arch to lookup and cache.
  • docs: document the tool-cache wrapper in agent instructions — records in .github/copilot-instructions.md that cache access must go through the wrapper, and that CU caching per SQL Server version is intentional.

Behaviour notes

  • Hosted runners: no practical change; each job starts with a fresh tool cache.
  • Self-hosted runners with a persistent tool cache: installers are now reused. Cumulative updates are cached per SQL Server version, so the first CU downloaded is reused until sqlupdate is removed from the tool cache (documented in the README). This is intentional.
  • Migration: none needed. Entries under the old non-semver directory names were never read and are left untouched; they can be deleted to reclaim disk space. Older releases of this action on the same runner will also match the new 2022.0.0-style entries (their bare '2022' is treated as a satisfiable range); the cached layout is identical, so this is harmless.

Testing

  • npm run lint, npm test (171 passing) and npm run build with a clean git diff-files -w, verified on each commit individually.

🤖 Generated with Claude Code

dhensby and others added 3 commits October 9, 2026 09:53
@actions/tool-cache only does an exact lookup in find() for explicit
semver versions. Installers and cumulative updates were cached under
bare SQL Server versions such as '2022', which find() treats as a range
and only matches against semver-named cache directories, so the cache
was written but never read.

Cache and look up tools through a small wrapper that maps versions to
an explicit semver version (e.g. '2022.0.0') so cached media is reused
by later runs on the same runner. Entries previously cached under the
old directory names were never read and are left untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ODBC and Native Client MSI installers were cached under bare major
versions such as '18', which @actions/tool-cache's find() never matches,
so they were downloaded on every run. The lookup also used the
installer's own arch (x64/x86) while caching used the host arch, which
differ on arm64 runners.

Use the semver-mapping tool-cache wrapper and pass the same arch when
looking up and caching the installer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Record that all tool-cache access must go through src/tool-cache.ts
because find() only matches explicit semver versions, and that cached
cumulative updates are intentionally reused per SQL Server version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant