Skip to content

support Deno auto installation#968

Merged
j178 merged 15 commits intoj178:denofrom
janosh:deno
Oct 28, 2025
Merged

support Deno auto installation#968
j178 merged 15 commits intoj178:denofrom
janosh:deno

Conversation

@janosh
Copy link
Copy Markdown
Contributor

@janosh janosh commented Oct 26, 2025

deno language support for pre-commit hooks with automatic version management from GitHub releases.

Features:

  • Auto-downloads requested Deno versions or uses system installation (if version matches)
  • Supports language_version (exact, semver ranges) and additional_dependencies (npm:, jsr:)
  • Creates isolated DENO_DIR for dependency caching
  • Cross-platform support (Linux, macOS, Windows)

Changes:

  • Add DenoInstaller, DenoVersion, and DenoRequest for version management
  • Add Deno to storage buckets and language registry
  • Add 8 comprehensive tests
  • Update documentation

Mirrors Node.js/Go installation patterns for consistency.

j178 and others added 6 commits October 25, 2025 01:24
- Implement Deno language handler with dependency isolation
- Support npm packages via `additional_dependencies`
- Add 8 tests covering basic usage, dependencies, and error cases
- example config showing deno fmt, lint, and npm eslint hook usage
Implement full-fledged Deno language support with automatic version management,
mirroring the installation patterns used for Node.js and Go.

- **installer.rs**: New DenoInstaller that downloads and installs Deno versions
  - Downloads from GitHub releases (https://github.com/denoland/deno/releases)
  - Searches installed versions in $PREK_HOME/tools/deno
  - Falls back to system Deno if version matches
  - Supports all platforms: Linux, macOS, Windows (x86_64, aarch64)
  - Uses file locking to prevent concurrent installations
  - Implements proper binary extraction and permission setup

- **version.rs**: New DenoVersion and DenoRequest types
  - Supports version specifications: exact (1.40.0), major (1), major.minor (1.40)
  - Supports semver ranges: ">= 1.40, < 1.50"
  - Handles "deno", "deno@version", "latest", "system" formats
  - Supports local path specifications
  - Comprehensive unit tests for version parsing

- **deno.rs**: Updated to use DenoInstaller
  - Removed manual system-only detection
  - Integrated with DenoInstaller for automatic downloads
  - Simplified installation flow
  - Proper health checks with version validation
@janosh janosh changed the base branch from master to deno October 26, 2025 09:45
@codecov
Copy link
Copy Markdown

codecov bot commented Oct 26, 2025

Codecov Report

❌ Patch coverage is 79.62185% with 97 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.59%. Comparing base (987923c) to head (4c5e205).
⚠️ Report is 1 commits behind head on deno.

Files with missing lines Patch % Lines
src/languages/deno/installer.rs 75.78% 46 Missing ⚠️
src/languages/deno/version.rs 78.64% 22 Missing ⚠️
src/languages/deno/deno.rs 85.88% 12 Missing ⚠️
src/languages/mod.rs 81.53% 12 Missing ⚠️
src/languages/version.rs 0.00% 3 Missing ⚠️
src/languages/python/uv.rs 90.90% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             deno     #968      +/-   ##
==========================================
+ Coverage   83.58%   89.59%   +6.00%     
==========================================
  Files          67       69       +2     
  Lines       12352    12680     +328     
==========================================
+ Hits        10325    11361    +1036     
+ Misses       2027     1319     -708     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@j178
Copy link
Copy Markdown
Owner

j178 commented Oct 26, 2025

wow!

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Oct 26, 2025

📦 Cargo Bloat Comparison

Binary size change: +0.62% (16.1 MiB → 16.2 MiB)

Expand for cargo-bloat output

PR Branch Results

 File  .text     Size          Crate Name
 0.6%   1.3% 101.1KiB          prek? <prek::cli::Command as clap_builder::derive::Subcommand>::augment_subcommands
 0.6%   1.3%  97.2KiB           prek prek::languages::<impl prek::config::Language>::run::{{closure}}
 0.5%   1.1%  85.8KiB           prek prek::builtin::pre_commit_hooks::Implemented::run::{{closure}}
 0.4%   0.9%  70.0KiB           prek prek::run::{{closure}}
 0.4%   0.8%  63.8KiB           prek prek::archive::unpack::{{closure}}
 0.3%   0.6%  46.8KiB           prek prek::languages::<impl prek::config::Language>::install::{{closure}}
 0.2%   0.5%  40.9KiB regex_automata regex_automata::meta::strategy::new
 0.2%   0.5%  40.1KiB          prek? <prek::cli::RunArgs as clap_builder::derive::Args>::augment_args
 0.2%   0.5%  38.5KiB           prek prek::identify::by_extension::{{closure}}
 0.2%   0.4%  32.9KiB           prek prek::workspace::Workspace::discover
 0.2%   0.4%  32.8KiB           prek prek::cli::run::run::run::{{closure}}
 0.2%   0.4%  31.8KiB             h2 h2::proto::connection::DynConnection<B>::recv_frame
 0.2%   0.4%  31.7KiB             h2 h2::proto::connection::Connection<T,P,B>::poll
 0.2%   0.4%  30.4KiB           prek prek::languages::node::installer::NodeInstaller::install::{{closure}}
 0.2%   0.4%  27.0KiB           prek prek::languages::deno::installer::DenoInstaller::install::{{closure}}
 0.2%   0.3%  26.2KiB     hyper_util hyper_util::client::legacy::client::Client<C,B>::send_request::{{closure}}
 0.2%   0.3%  25.8KiB     hyper_util hyper_util::client::legacy::client::Client<C,B>::connect_to::{{closure}}::{{closure}}::{{closure}}
 0.2%   0.3%  25.0KiB        globset globset::GlobSetBuilder::build
 0.2%   0.3%  25.0KiB           prek prek::main
 0.1%   0.3%  24.2KiB           prek prek::languages::golang::installer::GoInstaller::install::{{closure}}
39.7%  87.2%   6.4MiB                And 10220 smaller methods. Use -n N to show more.
45.5% 100.0%   7.4MiB                .text section size, the file size is 16.2MiB

Base Branch Results

 File  .text     Size          Crate Name
 0.6%   1.3% 101.1KiB          prek? <prek::cli::Command as clap_builder::derive::Subcommand>::augment_subcommands
 0.6%   1.3%  96.2KiB           prek prek::languages::<impl prek::config::Language>::run::{{closure}}
 0.5%   1.1%  85.8KiB           prek prek::builtin::pre_commit_hooks::Implemented::run::{{closure}}
 0.4%   0.9%  70.0KiB           prek prek::run::{{closure}}
 0.4%   0.9%  63.8KiB           prek prek::archive::unpack::{{closure}}
 0.3%   0.6%  45.5KiB           prek prek::languages::<impl prek::config::Language>::install::{{closure}}
 0.2%   0.5%  40.9KiB regex_automata regex_automata::meta::strategy::new
 0.2%   0.5%  40.1KiB          prek? <prek::cli::RunArgs as clap_builder::derive::Args>::augment_args
 0.2%   0.5%  38.5KiB           prek prek::identify::by_extension::{{closure}}
 0.2%   0.4%  32.9KiB           prek prek::workspace::Workspace::discover
 0.2%   0.4%  32.8KiB           prek prek::cli::run::run::run::{{closure}}
 0.2%   0.4%  32.7KiB           prek prek::languages::node::installer::NodeInstaller::install::{{closure}}
 0.2%   0.4%  31.8KiB             h2 h2::proto::connection::DynConnection<B>::recv_frame
 0.2%   0.4%  31.7KiB             h2 h2::proto::connection::Connection<T,P,B>::poll
 0.2%   0.3%  26.2KiB     hyper_util hyper_util::client::legacy::client::Client<C,B>::send_request::{{closure}}
 0.2%   0.3%  25.8KiB     hyper_util hyper_util::client::legacy::client::Client<C,B>::connect_to::{{closure}}::{{closure}}::{{closure}}
 0.2%   0.3%  25.0KiB        globset globset::GlobSetBuilder::build
 0.2%   0.3%  25.0KiB           prek prek::main
 0.1%   0.3%  24.6KiB           prek prek::languages::golang::installer::GoInstaller::install::{{closure}}
 0.1%   0.3%  23.7KiB          hyper hyper::proto::h1::dispatch::Dispatcher<D,Bs,I,T>::poll_loop
39.6%  87.1%   6.4MiB                And 10145 smaller methods. Use -n N to show more.
45.4% 100.0%   7.3MiB                .text section size, the file size is 16.1MiB

fs_err::tokio::copy(repo_deno_json, &deno_json).await?;
needs_deno_json = false;
}
// Deno can run scripts directly from the repo without installation
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to cache dependencies from deno.json (by deno install?). The idea is that install should set up everything needed for the hooks to run, so when we call run, it can work completely offline.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not an expert of deno, just a user. but i think deno maintains it's own global cache of every package that was ever imported in an executed script (be it from NPM, JSR or directly via URL from GitHub)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess we can call deno cache during hook installation. subtle benefit of that:

  • with deno cache: Dependencies are downloaded during prek install (slower install, faster first run, can detect dependency issues early)
  • without deno cache: Dependencies are downloaded on first hook run (faster install, slightly slower first run)

"#);
}

/// Test that when deno is not available, a helpful error is shown.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deno will be installed automatically, right?

Comment on lines +145 to +150
// Replace "deno" with the actual path to the installed deno binary
let command = if entry[0] == "deno" {
deno_bin.as_path()
} else {
Path::new(&entry[0])
};
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about symlinking the deno executable into the hook env bin dir and prepending that bin dir to PATH, like we did in the node implementation? That might work better than this approach. For example, it would work for cases like entry: ./run_deno.sh.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you agree, I can take care of it.

…H resolution

- Create bin/ directory in hook environment with symlinked deno executable
- Prepend bin/ to PATH during install and run, matching Node implementation
- Use entry.resolve() to find commands in PATH instead of manual replacement
- Enables shell scripts to call `deno` directly with correct isolated version
- add test verifying deno is available in PATH for shell scripts

addresses #968 (comment)
- Simplify find_script_to_cache() using functional approach
- Fix is_cacheable_script() to only match JS/TS files (prevents caching shell scripts)
- Add support for .mjs, .tsx, .jsx extensions
- Extract deno_bin variable to reduce duplication
- Consolidate PATH setup to single location
- Simplify deno.json creation logic
- Add deno cache call during install for offline hook execution
@janosh
Copy link
Copy Markdown
Contributor Author

janosh commented Oct 27, 2025

btw, feel free to make changes as you see fit in this PR. i'm outside my comfort area here and may have made stupid mistakes so everything is up for scrutiny. also, feel free to merge this PR into the deno branch and continue work there

@j178
Copy link
Copy Markdown
Owner

j178 commented Oct 28, 2025

I'm going to merge this into deno branch and continue there, thank you!

@j178 j178 merged commit be74a68 into j178:deno Oct 28, 2025
18 of 21 checks passed
millord237 pushed a commit to millord237/prek that referenced this pull request Feb 12, 2026
* Do not check for `script` subprocess status (#964)

* Update README

* Allow using system trusted store by `PREK_NATIVE_TLS` (#959)

* Fix compatibility with older luarocks (#967)

* support isolated hook environments for `language: deno`

- Implement Deno language handler with dependency isolation
- Support npm packages via `additional_dependencies`
- Add 8 tests covering basic usage, dependencies, and error cases
- example config showing deno fmt, lint, and npm eslint hook usage

* support Deno auto installation

Implement full-fledged Deno language support with automatic version management,
mirroring the installation patterns used for Node.js and Go.

- **installer.rs**: New DenoInstaller that downloads and installs Deno versions
  - Downloads from GitHub releases (https://github.com/denoland/deno/releases)
  - Searches installed versions in $PREK_HOME/tools/deno
  - Falls back to system Deno if version matches
  - Supports all platforms: Linux, macOS, Windows (x86_64, aarch64)
  - Uses file locking to prevent concurrent installations
  - Implements proper binary extraction and permission setup

- **version.rs**: New DenoVersion and DenoRequest types
  - Supports version specifications: exact (1.40.0), major (1), major.minor (1.40)
  - Supports semver ranges: ">= 1.40, < 1.50"
  - Handles "deno", "deno@version", "latest", "system" formats
  - Supports local path specifications
  - Comprehensive unit tests for version parsing

- **deno.rs**: Updated to use DenoInstaller
  - Removed manual system-only detection
  - Integrated with DenoInstaller for automatic downloads
  - Simplified installation flow
  - Proper health checks with version validation

* Update language support status (#970)

* Update language support status

* Tweak

* Fix DenoRequest parsing

* Generate cli reference

* Fail windows CI when an error occured (#971)

* Fail windows CI when an error occured

* Fix tests

* Use global client

* delete outdated test, deno auto-installs after 2nd commit

addresses j178/prek#968 (comment)

* refactor(deno): symlink deno executable into hook bin dir and use PATH resolution

- Create bin/ directory in hook environment with symlinked deno executable
- Prepend bin/ to PATH during install and run, matching Node implementation
- Use entry.resolve() to find commands in PATH instead of manual replacement
- Enables shell scripts to call `deno` directly with correct isolated version
- add test verifying deno is available in PATH for shell scripts

addresses j178/prek#968 (comment)

* refactor(deno): simplify install logic and add dependency caching

- Simplify find_script_to_cache() using functional approach
- Fix is_cacheable_script() to only match JS/TS files (prevents caching shell scripts)
- Add support for .mjs, .tsx, .jsx extensions
- Extract deno_bin variable to reduce duplication
- Consolidate PATH setup to single location
- Simplify deno.json creation logic
- Add deno cache call during install for offline hook execution

---------

Co-authored-by: Jo <10510431+j178@users.noreply.github.com>
Co-authored-by: Steven Taylor <steven@taylormuff.co.uk>
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.

3 participants