From 61c2c8d12a702382831d5d3e708ddf4a0d03de23 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 16:30:57 +0000 Subject: [PATCH 01/10] chore(deps): update actions to v6 (#303) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fcd769a..e892f26 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,3 +21,5 @@ jobs: token: ${{ secrets.PORTER_GITHUB_TOKEN }} supermarket_user: ${{ secrets.CHEF_SUPERMARKET_USER }} supermarket_key: ${{ secrets.CHEF_SUPERMARKET_KEY }} + slack_bot_token: ${{ secrets.SLACK_BOT_TOKEN }} + slack_channel_id: ${{ secrets.SLACK_CHANNEL_ID }} From 534757b3dd3ff2fcccc1ec3ebf0ee41fb8a50af5 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Wed, 29 Apr 2026 14:03:25 +0100 Subject: [PATCH 02/10] feat!: migrate nodejs to resources Convert the cookbook from recipes and attributes to custom resources with resource documentation and migration guidance. Verification: berks install; cookstyle; ruby -c on changed Ruby files; chef exec rspec --format documentation; KITCHEN_LOCAL_YAML=kitchen.dokken.yml kitchen test default-ubuntu-2404 --destroy=always. --- .github/workflows/ci.yml | 11 +- Berksfile | 2 + LIMITATIONS.md | 69 +++++++ README.md | 181 +++--------------- attributes/default.rb | 44 ----- attributes/npm.rb | 2 - attributes/packages.rb | 17 -- attributes/repo.rb | 12 -- documentation/nodejs_install.md | 50 +++++ documentation/nodejs_npm_install.md | 39 ++++ documentation/nodejs_npm_package.md | 46 +++++ documentation/nodejs_npm_packages.md | 28 +++ documentation/nodejs_repository.md | 36 ++++ kitchen.dokken.yml | 10 - kitchen.global.yml | 7 +- kitchen.yml | 97 ++++++---- libraries/nodejs_helper.rb | 99 +++++++++- metadata.rb | 23 +-- migration.md | 52 +++++ recipes/default.rb | 23 --- recipes/install.rb | 21 -- recipes/iojs.rb | 1 - recipes/nodejs.rb | 21 -- recipes/nodejs_from_binary.rb | 67 ------- recipes/nodejs_from_chocolatey.rb | 24 --- recipes/nodejs_from_package.rb | 43 ----- recipes/nodejs_from_source.rb | 48 ----- recipes/npm.rb | 28 --- recipes/npm_from_source.rb | 32 ---- recipes/npm_packages.rb | 13 -- recipes/repo.rb | 48 ----- resources/_partial/_nodejs.rb | 2 + resources/nodejs_install.rb | 121 ++++++++++++ resources/nodejs_npm_install.rb | 46 +++++ resources/nodejs_npm_packages.rb | 46 +++++ resources/nodejs_repository.rb | 78 ++++++++ resources/npm_package.rb | 49 ++--- spec/rspec_helper.rb | 2 + spec/spec_helper.rb | 2 + spec/unit/library/helper_spec.rb | 15 +- spec/unit/recipes/default_spec.rb | 75 -------- spec/unit/resources/nodejs_install_spec.rb | 69 +++++++ .../unit/resources/nodejs_npm_install_spec.rb | 31 +++ .../resources/nodejs_npm_packages_spec.rb | 22 +++ spec/unit/resources/nodejs_repository_spec.rb | 44 +++++ spec/unit/resources/npm_package_spec.rb | 35 ++++ test/cookbooks/test/metadata.rb | 2 + test/cookbooks/test/recipes/chocolatey.rb | 8 +- test/cookbooks/test/recipes/default.rb | 21 +- test/cookbooks/test/recipes/npm_embedded.rb | 10 + test/cookbooks/test/recipes/npm_source.rb | 6 + test/cookbooks/test/recipes/package.rb | 10 +- test/cookbooks/test/recipes/resource.rb | 11 +- test/cookbooks/test/recipes/resource_win.rb | 8 +- test/cookbooks/test/recipes/source.rb | 10 +- test/cookbooks/test/recipes/source_iojs.rb | 8 - .../chocolatey/controls/chocolatey_spec.rb | 16 ++ test/integration/chocolatey/default.rb | 16 -- test/integration/chocolatey/inspec.yml | 7 + .../default/controls/default_spec.rb | 29 +++ test/integration/default/default_spec.rb | 32 ---- test/integration/default/inspec.yml | 7 + .../npm_embedded_spec.rb} | 6 +- test/integration/npm_embedded/inspec.yml | 7 + .../npm_source_spec.rb} | 6 +- test/integration/npm_source/inspec.yml | 7 + test/integration/options/default_spec.rb | 13 -- .../package/controls/package_spec.rb | 31 +++ test/integration/package/default.rb | 43 ----- test/integration/package/inspec.yml | 7 + .../{default.rb => controls/source_spec.rb} | 12 +- test/integration/source/inspec.yml | 7 + 72 files changed, 1252 insertions(+), 919 deletions(-) create mode 100644 LIMITATIONS.md delete mode 100644 attributes/default.rb delete mode 100644 attributes/npm.rb delete mode 100644 attributes/packages.rb delete mode 100644 attributes/repo.rb create mode 100644 documentation/nodejs_install.md create mode 100644 documentation/nodejs_npm_install.md create mode 100644 documentation/nodejs_npm_package.md create mode 100644 documentation/nodejs_npm_packages.md create mode 100644 documentation/nodejs_repository.md create mode 100644 migration.md delete mode 100644 recipes/default.rb delete mode 100644 recipes/install.rb delete mode 100644 recipes/iojs.rb delete mode 100644 recipes/nodejs.rb delete mode 100644 recipes/nodejs_from_binary.rb delete mode 100644 recipes/nodejs_from_chocolatey.rb delete mode 100644 recipes/nodejs_from_package.rb delete mode 100644 recipes/nodejs_from_source.rb delete mode 100644 recipes/npm.rb delete mode 100644 recipes/npm_from_source.rb delete mode 100644 recipes/npm_packages.rb delete mode 100644 recipes/repo.rb create mode 100644 resources/_partial/_nodejs.rb create mode 100644 resources/nodejs_install.rb create mode 100644 resources/nodejs_npm_install.rb create mode 100644 resources/nodejs_npm_packages.rb create mode 100644 resources/nodejs_repository.rb delete mode 100644 spec/unit/recipes/default_spec.rb create mode 100644 spec/unit/resources/nodejs_install_spec.rb create mode 100644 spec/unit/resources/nodejs_npm_install_spec.rb create mode 100644 spec/unit/resources/nodejs_npm_packages_spec.rb create mode 100644 spec/unit/resources/nodejs_repository_spec.rb create mode 100644 spec/unit/resources/npm_package_spec.rb create mode 100644 test/cookbooks/test/recipes/npm_embedded.rb create mode 100644 test/cookbooks/test/recipes/npm_source.rb delete mode 100644 test/cookbooks/test/recipes/source_iojs.rb create mode 100644 test/integration/chocolatey/controls/chocolatey_spec.rb delete mode 100644 test/integration/chocolatey/default.rb create mode 100644 test/integration/chocolatey/inspec.yml create mode 100644 test/integration/default/controls/default_spec.rb delete mode 100644 test/integration/default/default_spec.rb create mode 100644 test/integration/default/inspec.yml rename test/integration/npm_embedded/{default_spec.rb => controls/npm_embedded_spec.rb} (65%) create mode 100644 test/integration/npm_embedded/inspec.yml rename test/integration/npm_source/{default_spec.rb => controls/npm_source_spec.rb} (75%) create mode 100644 test/integration/npm_source/inspec.yml delete mode 100644 test/integration/options/default_spec.rb create mode 100644 test/integration/package/controls/package_spec.rb delete mode 100644 test/integration/package/default.rb create mode 100644 test/integration/package/inspec.yml rename test/integration/source/{default.rb => controls/source_spec.rb} (69%) create mode 100644 test/integration/source/inspec.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9fb7e73..f00ef47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,13 +22,20 @@ jobs: strategy: matrix: os: + - "almalinux-8" - "almalinux-9" + - "almalinux-10" - "rockylinux-9" - "amazonlinux-2023" - "centos-stream-9" - "centos-stream-10" - - "debian-11" - "debian-12" + - "debian-13" + - "fedora-latest" + - "oraclelinux-8" + - "oraclelinux-9" + - "rockylinux-8" + - "rockylinux-10" - "ubuntu-2204" - "ubuntu-2404" suite: @@ -47,7 +54,7 @@ jobs: - name: Check out code uses: actions/checkout@v6 - name: Install Chef - uses: actionshub/chef-install@6.0.0 + uses: sous-chefs/.github/.github/actions/install-workstation@6.0.0 - name: Dokken uses: actionshub/test-kitchen@3.0.0 env: diff --git a/Berksfile b/Berksfile index 7048569..847c9c0 100644 --- a/Berksfile +++ b/Berksfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source 'https://supermarket.chef.io' metadata diff --git a/LIMITATIONS.md b/LIMITATIONS.md new file mode 100644 index 0000000..fbb335a --- /dev/null +++ b/LIMITATIONS.md @@ -0,0 +1,69 @@ +# Limitations + +This cookbook defaults to Node.js 24 LTS, using Node.js v24.15.0 checksums from the official `SHASUMS256.txt` published for `latest-v24.x` on 2026-04-16. + +Sources checked on 2026-04-29: + +* Node.js release schedule: https://github.com/nodejs/Release/blob/main/schedule.json +* Node.js latest v24 artifacts: https://nodejs.org/dist/latest-v24.x/ +* Node.js v24 checksums: https://nodejs.org/dist/latest-v24.x/SHASUMS256.txt +* NodeSource distributions page: https://nodesource.com/products/distributions +* NodeSource distributions repository: https://github.com/nodesource/distributions + +## Package Availability + +### APT (Debian/Ubuntu) + +NodeSource documents Node 24 packages for: + +* Ubuntu 20.04, 22.04, 24.04: `amd64`, `armhf`, `arm64` +* Debian 10, 11, 12: `amd64`, `armhf`, `arm64` + +The cookbook only declares currently supported, non-EOL Debian/Ubuntu platforms in `metadata.rb`: Debian 12 or later and Ubuntu 22.04 or later. NodeSource packages use the `nodistro` repository distribution. + +### DNF/YUM (RHEL family) + +NodeSource documents RPM packages for RHEL 8/9, Fedora 29+, and Amazon Linux 2023 on `x86_64` and `arm64`. The repository URL pattern used by this cookbook is: + +```text +https://rpm.nodesource.com/pub_.x/nodistro/nodejs/$basearch +``` + +The cookbook declares AlmaLinux, Amazon Linux 2023, CentOS Stream, Fedora, Oracle Linux, Red Hat, and Rocky Linux where current test images are available. + +### Zypper (SUSE) + +NodeSource does not publish SUSE repository rows in the current distributions documentation. This migration does not declare SUSE/openSUSE support in `metadata.rb`. + +### Windows and macOS + +Windows support is limited to `nodejs_install` with `install_method 'chocolatey'`. macOS support is limited to package installation through the platform package provider where available. Dokken coverage is Linux-only. + +## Architecture Limitations + +Official Node.js v24.15.0 source and binary checksums pinned by this cookbook: + +| Artifact | SHA256 | +|----------|--------| +| `node-v24.15.0.tar.gz` | `729de494dd2872e5a3a6c32a1cd156a5413d4aca2772b2d873ee86bb5531bcd9` | +| `node-v24.15.0-linux-x64.tar.gz` | `44836872d9aec49f1e6b52a9a922872db9a2b02d235a616a5681b6a85fec8d89` | +| `node-v24.15.0-linux-arm64.tar.gz` | `73afc234d558c24919875f51c2d1ea002a2ada4ea6f83601a383869fefa64eed` | + +The `nodejs_install` binary action currently models Linux `x64` and `arm64` checksums. Other official Node.js artifacts can be installed by passing `binary_url` and the matching checksum. + +## Source/Compiled Installation + +### Build Dependencies + +| Platform Family | Packages | +|-----------------|----------| +| Debian | `build-essential`, `libssl-dev`, `python3` | +| RHEL/Fedora/Amazon | `build-essential`, `openssl-devel`, `python3`, `tar` | +| Other | `build-essential`, `python3` | + +Source builds are much slower than package or binary installs and are not used as the default Kitchen smoke path. + +## Known Issues + +* Node.js 20 reaches end-of-life on 2026-04-30, so this migration does not keep old Node 20 defaults. +* NodeSource repository docs currently show some LTS/current labels that lag the official Node.js release schedule. The cookbook version defaults follow the official Node.js release schedule and official Node.js checksum artifacts. diff --git a/README.md b/README.md index 055ba7e..e3bb4c5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) -Installs node.js/npm and includes a resource for managing npm packages +Provides custom resources for installing Node.js/npm and managing npm packages. ## Maintainers @@ -17,11 +17,9 @@ This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of ### Platforms - Debian/Ubuntu -- RHEL/CentOS/Scientific/Amazon/Oracle -- openSUSE -- Windows - -Note: Source installs require GCC 4.8+, which is not included on older distro releases +- RHEL family/Fedora/Amazon Linux +- macOS where platform packages are available +- Windows through Chocolatey ### Chef @@ -30,179 +28,60 @@ Note: Source installs require GCC 4.8+, which is not included on older distro re ### Cookbooks - ark +- chocolatey ## Usage -Include the nodejs recipe to install node on your system based on the default installation method: +Install Node.js with the default platform method: ```ruby -include_recipe "nodejs" +nodejs_install 'nodejs' ``` -### Install methods - -#### Package - Install node from packages: ```ruby -node['nodejs']['install_method'] = 'package' # Not necessary because it's the default -include_recipe "nodejs" -# Or -include_recipe "nodejs::nodejs_from_package" +nodejs_install 'nodejs' do + install_method 'package' + version '24.15.0' ``` -By default this will setup deb/rpm repositories from nodesource.com, which include up to date NodeJS packages. If you prefer to use distro provided package you can disable this behavior by setting `node['nodejs']['install_repo']` to `false`. - -#### Binary - -Install node from official prebuilt binaries: +Install Node.js from official prebuilt binaries: ```ruby -node['nodejs']['install_method'] = 'binary' -include_recipe "nodejs" - -# Or -include_recipe "nodejs::nodejs_from_binary" - -# Or set a specific version of nodejs to be installed -node.default['nodejs']['install_method'] = 'binary' -node.default['nodejs']['version'] = '5.9.0' -node.default['nodejs']['binary']['checksum'] = '99c4136cf61761fac5ac57f80544140a3793b63e00a65d4a0e528c9db328bf40' - -# Or fetch the binary from your own location -node.default['nodejs']['install_method'] = 'binary' -node.default['nodejs']['binary']['url'] = 'https://s3.amazonaws.com/my-bucket/node-v7.8.0-linux-x64.tar.gz' -node.default['nodejs']['binary']['checksum'] = '0bd86f2a39221b532172c7d1acb57f0b0cba88c7b82ea74ba9d1208b9f6f9697' +nodejs_install 'nodejs' do + install_method 'binary' ``` -#### Source - -Install node from sources: +Install Node.js from source: ```ruby -node['nodejs']['install_method'] = 'source' -include_recipe "nodejs" -# Or -include_recipe "nodejs::nodejs_from_source" -``` - -#### Chocolatey - -Install node from chocolatey: - -```chef -node['nodejs']['install_method'] = 'chocolatey' -include_recipe "nodejs" -# Or -include_recipe "nodejs::nodejs_from_chocolatey" +nodejs_install 'nodejs' do + install_method 'source' +end ``` -## NPM - -Npm is included in nodejs installs by default. By default, we are using it and call it `embedded`. Adding recipe `nodejs::npm` assure you to have npm installed and let you choose install method with `node['nodejs']['npm']['install_method']` - -```ruby -include_recipe "nodejs::npm" -``` - -_Warning:_ This recipe will include the `nodejs` recipe, which by default includes `nodejs::nodejs_from_package` if you did not set `node['nodejs']['install_method']`. - -## Resources - -### npm_package - -note: This resource was previously named nodejs_npm. Calls to that resource name will still function, but cookbooks should be updated for the new npm_package resource name. - -`npm_package` lets you install npm packages from various sources: - -- npm registry: - - - name: `property :package` - - version: `property :version` (optional) - -- url: `property :url` - - - for git use `git://{your_repo}` - -- from a json (package.json by default): `property :json` - - - use `true` for default - - use a `String` to specify json file - -Packages can be installed globally (by default) or in a directory (by using `attribute :path`) - -You can specify an `NPM_TOKEN` environment variable for accessing [NPM private modules](https://docs.npmjs.com/private-modules/intro) by using `attribute :npm_token` - -You can specify a `NODE_ENV` environment variable, in the case that some element of your installation depends on this by using `attribute :node_env`. E.g., using [`node-config`](https://www.npmjs.com/package/config) as part of your postinstall script. Please note that adding the `--production` option will override this to `NODE_ENV=production`. - -You can append more specific options to npm command with `attribute :options` array : - -You can specify auto_update as false to stop the npm install command from running and updating an installed package. Running the command will update packages within restrictions imposed by a package.json file. The default behavior is to update automatically. - -- use an array of options (w/ dash), they will be added to npm call. -- ex: `['--production','--force']` or `['--force-latest']` - -You can specify live_stream true for the resource to have the package install information included in the chef-client log outout for better npm package diagnostics and trouble shooting. - -This LWRP attempts to use vanilla npm as much as possible (no custom wrapper). - -### Packages +Install npm packages: ```ruby npm_package 'express' -npm_package 'async' do - version '0.6.2' -end - -npm_package 'request' do - url 'github mikeal/request' +nodejs_npm_packages 'application packages' do + packages [ + { name: 'socket.io', version: '4.8.1' }, + ] end +``` -npm_package 'grunt' do - path '/home/random/grunt' - json true - user 'random' - node_env 'staging' -end +See [migration.md](migration.md) for the breaking recipe/attribute migration guide. -npm_package 'my_private_module' do - path '/home/random/myproject' # The root path to your project, containing a package.json file - json true - npm_token '12345-abcde-e5d4c3b2a1' - user 'random' - options ['--production'] # Only install dependencies. Skip devDependencies -end -``` +## Resources -[Working Examples](test/cookbooks/nodejs_test/recipes/npm.rb) - -Or add packages via attributes (which accept the same attributes as the LWRP above): - -```json -"nodejs": { - "npm_packages": [ - { - "name": "express" - }, - { - "name": "async", - "version": "0.6.2" - }, - { - "name": "request", - "url": "github mikeal/request" - } - { - "name": "grunt", - "path": "/home/random/grunt", - "json": true, - "user": "random" - } - ] -} -``` +- [nodejs_install](documentation/nodejs_install.md) +- [nodejs_repository](documentation/nodejs_repository.md) +- [nodejs_npm_install](documentation/nodejs_npm_install.md) +- [nodejs_npm_packages](documentation/nodejs_npm_packages.md) +- [npm_package](documentation/nodejs_npm_package.md) ## Contributors diff --git a/attributes/default.rb b/attributes/default.rb deleted file mode 100644 index e766335..0000000 --- a/attributes/default.rb +++ /dev/null @@ -1,44 +0,0 @@ -# -# Cookbook:: nodejs -# Attributes:: nodejs -# -# Copyright:: 2010-2017, Promet Solutions -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -default['nodejs']['install_method'] = case node['platform_family'] - when 'smartos', 'rhel', 'debian', 'fedora', 'mac_os_x', 'suse', 'amazon' - 'package' - when 'windows' - 'chocolatey' - else - 'source' - end - -default['nodejs']['version'] = '22.11.0' - -default['nodejs']['prefix_url']['node'] = 'https://nodejs.org/dist/' - -default['nodejs']['tmpdir'] = '/tmp' -default['nodejs']['source']['url'] = nil # Auto generated -default['nodejs']['source']['checksum'] = '24e5130fa7bc1eaab218a0c9cb05e03168fa381bb9e3babddc6a11f655799222' - -default['nodejs']['binary']['url'] = nil # Auto generated -default['nodejs']['binary']['checksum']['linux_x64'] = '8c9f4c95c254336fcb2c768e746f4316b8176adc0fb599cbbb460d0933991d12' -default['nodejs']['binary']['checksum']['linux_arm64'] = 'd4acf5c0380c96c867428d0232666d3327dc5fa83a694d7b63f728a76ece84b2' -default['nodejs']['binary']['append_env_path'] = true - -default['nodejs']['make_threads'] = node['cpu'] ? node['cpu']['total'].to_i : 2 - -default['nodejs']['manage_node'] = true diff --git a/attributes/npm.rb b/attributes/npm.rb deleted file mode 100644 index 97ee5d3..0000000 --- a/attributes/npm.rb +++ /dev/null @@ -1,2 +0,0 @@ -default['nodejs']['npm']['install_method'] = 'embedded' -default['nodejs']['npm']['version'] = 'latest' diff --git a/attributes/packages.rb b/attributes/packages.rb deleted file mode 100644 index 1237ef0..0000000 --- a/attributes/packages.rb +++ /dev/null @@ -1,17 +0,0 @@ -include_attribute 'nodejs::default' -include_attribute 'nodejs::repo' - -default['nodejs']['packages'] = value_for_platform_family( - 'debian' => node['nodejs']['install_repo'] ? ['nodejs'] : %w(nodejs npm nodejs-dev), - %w(rhel fedora amazon) => node['nodejs']['install_repo'] ? %w(nodejs nodejs-devel) : %w(nodejs npm nodejs-dev), - 'suse' => %w(nodejs npm nodejs-devel), - 'mac_os_x' => ['node'], - 'freebsd' => %w(node npm), - 'default' => ['nodejs'] -) - -# Add options and actions by package name -default['nodejs']['package_action'] = { default: :install } -default['nodejs']['package_options'] = { default: '' } -# Disable upstream DNF module on EL8 based systems -default['nodejs']['dnf_module'] = false diff --git a/attributes/repo.rb b/attributes/repo.rb deleted file mode 100644 index ae98dac..0000000 --- a/attributes/repo.rb +++ /dev/null @@ -1,12 +0,0 @@ -case node['platform_family'] -when 'debian' - default['nodejs']['install_repo'] = true - default['nodejs']['repo'] = 'https://deb.nodesource.com/node_20.x' - default['nodejs']['distribution'] = 'nodistro' - default['nodejs']['key'] = 'https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key' -when 'rhel', 'amazon', 'fedora' - default['nodejs']['install_repo'] = true - node_version = platform?('amazon') ? '17.x' : '20.x' - default['nodejs']['repo'] = "https://rpm.nodesource.com/pub_#{node_version}/nodistro/nodejs/$basearch" - default['nodejs']['key'] = 'https://rpm.nodesource.com/gpgkey/ns-operations-public.key' -end diff --git a/documentation/nodejs_install.md b/documentation/nodejs_install.md new file mode 100644 index 0000000..cbbc788 --- /dev/null +++ b/documentation/nodejs_install.md @@ -0,0 +1,50 @@ +# nodejs_install + +Installs Node.js from packages, official binaries, source, or Chocolatey. + +## Actions + +| Action | Description | +|--------|-------------| +| `:install` | Installs Node.js. Default. | +| `:remove` | Removes artifacts created by the selected install method. | + +## Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `version` | String | `'24.15.0'` | Node.js version for source, binary, and Chocolatey installs. | +| `install_method` | String | platform default | One of `package`, `binary`, `source`, or `chocolatey`. | +| `install_repository` | true, false | `true` | Configures NodeSource repositories for package installs. | +| `packages` | Array, nil | platform default | Package names to install for package installs. | +| `package_action` | Symbol, String | `:install` | Action passed to package resources. | +| `package_options` | String, nil | `nil` | Options passed to package resources. | +| `disable_dnf_module` | true, false | `true` | Disables the distro Node.js DNF module on EL/Fedora 8+. | +| `prefix_url` | String | `'https://nodejs.org/dist/'` | Base URL for official Node.js source and binary artifacts. | +| `source_url` | String, nil | `nil` | Override URL for source installs. | +| `source_checksum` | String, nil | official v24.15.0 checksum | Source tarball checksum. | +| `binary_url` | String, nil | `nil` | Override URL for binary installs. | +| `binary_checksums` | Hash | official v24.15.0 checksums | Binary checksums by architecture key. | +| `append_env_path` | true, false | `true` | Passed to `ark` for binary installs. | +| `make_threads` | Integer, String, nil | CPU count | Parallel make jobs for source installs. | +| `build_packages` | Array, nil | platform default | Build dependency package list for source installs. | +| `chocolatey_package_name` | String | `'nodejs-lts'` | Chocolatey package name for Windows installs. | + +## Examples + +```ruby +nodejs_install 'nodejs' +``` + +```ruby +nodejs_install 'nodejs from source' do + install_method 'source' + make_threads 4 +end +``` + +```ruby +nodejs_install 'nodejs from binary' do + install_method 'binary' +end +``` diff --git a/documentation/nodejs_npm_install.md b/documentation/nodejs_npm_install.md new file mode 100644 index 0000000..64506e4 --- /dev/null +++ b/documentation/nodejs_npm_install.md @@ -0,0 +1,39 @@ +# nodejs_npm_install + +Ensures npm is available through the embedded Node.js npm or installs npm from source. + +## Actions + +| Action | Description | +|--------|-------------| +| `:install` | Installs npm. Default. | +| `:remove` | Removes npm artifacts created by source installs. | + +## Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `install_method` | String | `'embedded'` | One of `embedded` or `source`. | +| `install_node` | true, false | `true` | Installs Node.js before npm. | +| `node_install_method` | String | `'package'` | Node.js install method when `install_node` is true. | +| `version` | String | `'24.15.0'` | Node.js version passed to `nodejs_install`. | +| `prefix_url` | String | `'https://nodejs.org/dist/'` | Node.js artifact base URL passed to `nodejs_install`. | +| `npm_version` | String | `'latest'` | npm version resolved from the npm registry for source installs. | +| `npm_url` | String, nil | `nil` | Override npm tarball URL. | +| `npm_checksum` | String, nil | `nil` | Optional npm tarball checksum. | +| `make_threads` | Integer, String, nil | CPU count | Parallel make jobs for source installs. | + +## Examples + +```ruby +nodejs_npm_install 'npm' do + install_method 'embedded' +end +``` + +```ruby +nodejs_npm_install 'npm from source' do + install_method 'source' + npm_version '11.6.2' +end +``` diff --git a/documentation/nodejs_npm_package.md b/documentation/nodejs_npm_package.md new file mode 100644 index 0000000..5420db2 --- /dev/null +++ b/documentation/nodejs_npm_package.md @@ -0,0 +1,46 @@ +# npm_package + +Installs or removes an npm package. The legacy `nodejs_npm` alias is retained. + +## Actions + +| Action | Description | +|--------|-------------| +| `:install` | Installs or updates an npm package. Default. | +| `:uninstall` | Uninstalls an npm package if present. | +| `:remove` | Alias-style remove action for uninstalling an npm package. | + +## Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `package` | String | name property | npm package name. | +| `version` | String | `nil` | npm package version. | +| `path` | String | `nil` | Local project path. Omit for global installs. | +| `url` | String | `nil` | Package URL or git source. | +| `json` | String, true, false | `nil` | Install from `package.json` or a provided JSON/tarball source. | +| `npm_token` | String | `nil` | Sensitive NPM token exposed as `NPM_TOKEN`. | +| `options` | Array | `[]` | Extra npm CLI options. | +| `user` | String | `nil` | User for the npm command. | +| `group` | String | `nil` | Group for the npm command. | +| `live_stream` | true, false | `false` | Streams npm output to the Chef log. | +| `node_env` | String | `nil` | `NODE_ENV` value for the npm command. | +| `auto_update` | true, false | `true` | When false, skips install if the matching package is already installed. | + +## Examples + +```ruby +npm_package 'express' +``` + +```ruby +npm_package 'async' do + version '0.6.2' +end +``` + +```ruby +nodejs_npm 'mocha' do + options ['--production'] +end +``` diff --git a/documentation/nodejs_npm_packages.md b/documentation/nodejs_npm_packages.md new file mode 100644 index 0000000..a0813c8 --- /dev/null +++ b/documentation/nodejs_npm_packages.md @@ -0,0 +1,28 @@ +# nodejs_npm_packages + +Installs or removes a collection of npm packages. + +## Actions + +| Action | Description | +|--------|-------------| +| `:install` | Converges each package entry with its requested action. Default. | +| `:remove` | Removes each listed package. | + +## Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `packages` | Array | `[]` | Array of package hashes. Use `name` for package name and any `npm_package` property for options. | + +## Examples + +```ruby +nodejs_npm_packages 'application packages' do + packages [ + { name: 'express' }, + { name: 'socket.io', version: '4.8.1' }, + { name: 'express', action: :remove }, + ] +end +``` diff --git a/documentation/nodejs_repository.md b/documentation/nodejs_repository.md new file mode 100644 index 0000000..3c3686b --- /dev/null +++ b/documentation/nodejs_repository.md @@ -0,0 +1,36 @@ +# nodejs_repository + +Configures NodeSource package repositories. + +## Actions + +| Action | Description | +|--------|-------------| +| `:create` | Creates the NodeSource repository. Default. | +| `:remove` | Removes the NodeSource repository and managed APT keyring. | + +## Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `repo_name` | String | name property | Repository name. | +| `node_major` | String, Integer | `'24'` | Node.js major version used in repository URLs. | +| `apt_uri` | String | generated | APT repository URI override. | +| `apt_distribution` | String | `'nodistro'` | APT distribution. | +| `apt_components` | Array | `['main']` | APT components. | +| `apt_key` | String | NodeSource DEB key URL | APT signing key URL. | +| `apt_keyring` | String | `'/etc/apt/keyrings/nodesource.asc'` | Managed APT keyring path. | +| `apt_pin_priority` | String | `'600'` | APT preference priority for NodeSource. | +| `yum_baseurl` | String | generated | YUM/DNF base URL override. | +| `yum_gpgkey` | String | NodeSource RPM key URL | RPM signing key URL. | +| `yum_priority` | String | `'9'` | YUM repository priority. | +| `enabled` | true, false | `true` | Enables the YUM/DNF repository. | +| `gpgcheck` | true, false | `true` | Enables package GPG checks. | + +## Examples + +```ruby +nodejs_repository 'nodesource' do + node_major 24 +end +``` diff --git a/kitchen.dokken.yml b/kitchen.dokken.yml index 1d8623e..e898fcd 100644 --- a/kitchen.dokken.yml +++ b/kitchen.dokken.yml @@ -52,11 +52,6 @@ platforms: image: dokken/fedora-latest pid_one_command: /usr/lib/systemd/systemd - - name: opensuse-leap-15 - driver: - image: dokken/opensuse-leap-15 - pid_one_command: /usr/lib/systemd/systemd - - name: oraclelinux-8 driver: image: dokken/oraclelinux-8 @@ -82,11 +77,6 @@ platforms: image: dokken/rockylinux-10 pid_one_command: /usr/lib/systemd/systemd - - name: ubuntu-20.04 - driver: - image: dokken/ubuntu-20.04 - pid_one_command: /bin/systemd - - name: ubuntu-22.04 driver: image: dokken/ubuntu-22.04 diff --git a/kitchen.global.yml b/kitchen.global.yml index 1740e46..ad83b62 100644 --- a/kitchen.global.yml +++ b/kitchen.global.yml @@ -17,16 +17,17 @@ verifier: platforms: - name: almalinux-8 - name: almalinux-9 + - name: almalinux-10 - name: amazonlinux-2023 - name: centos-stream-9 - - name: debian-11 + - name: centos-stream-10 - name: debian-12 + - name: debian-13 - name: fedora-latest - - name: opensuse-leap-15 - name: oraclelinux-8 - name: oraclelinux-9 - name: rockylinux-8 - name: rockylinux-9 - - name: ubuntu-20.04 + - name: rockylinux-10 - name: ubuntu-22.04 - name: ubuntu-24.04 diff --git a/kitchen.yml b/kitchen.yml index 6f09eba..4181c7c 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -2,51 +2,64 @@ driver: name: vagrant +provisioner: + name: chef_infra + product_name: chef + product_version: <%= ENV['CHEF_VERSION'] || 'latest' %> + channel: stable + install_strategy: once + chef_license: accept + enforce_idempotency: <%= ENV['ENFORCE_IDEMPOTENCY'] || true %> + multiple_converge: <%= ENV['MULTIPLE_CONVERGE'] || 2 %> + deprecations_as_errors: true + log_level: <%= ENV['CHEF_LOG_LEVEL'] || 'auto' %> + +verifier: + name: inspec + sudo: true + +x-run_lists: + default: &default_run_list + - recipe[test::default] + package: &package_run_list + - recipe[test::package] + source: &source_run_list + - recipe[test::source] + npm_embedded: &npm_embedded_run_list + - recipe[test::npm_embedded] + npm_source: &npm_source_run_list + - recipe[test::npm_source] + +x-verifiers: + default: &default_verifier + inspec_tests: + - path: test/integration/default + package: &package_verifier + inspec_tests: + - path: test/integration/package + source: &source_verifier + inspec_tests: + - path: test/integration/source + npm_embedded: &npm_embedded_verifier + inspec_tests: + - path: test/integration/npm_embedded + npm_source: &npm_source_verifier + inspec_tests: + - path: test/integration/npm_source + suites: - name: default - run_list: - - recipe[nodejs::default] - attributes: - nodejs: - manage_node: true - npm: - install_method: embedded - npm_packages: - - name: express - - name: socket.io - version: 1.0.4 - - name: express - action: :uninstall + run_list: *default_run_list + verifier: *default_verifier - name: npm_embedded - run_list: - - recipe[nodejs::npm] - attributes: - nodejs: - npm: - install_method: embedded + run_list: *npm_embedded_run_list + verifier: *npm_embedded_verifier - name: npm_source - run_list: - - recipe[nodejs::npm] - attributes: - nodejs: - npm: - install_method: source + run_list: *npm_source_run_list + verifier: *npm_source_verifier - name: package - run_list: - - recipe[test::default] + run_list: *package_run_list + verifier: *package_verifier - name: source - run_list: - - recipe[test::source] - - name: options - run_list: - - recipe[nodejs] - attributes: - nodejs: - packages: - - nodejs - - acpid - - adcli - package_options: - acpid: "--force-yes" - package_action: - adcli: :nothing + run_list: *source_run_list + verifier: *source_verifier diff --git a/libraries/nodejs_helper.rb b/libraries/nodejs_helper.rb index 5941822..f8106f4 100644 --- a/libraries/nodejs_helper.rb +++ b/libraries/nodejs_helper.rb @@ -1,19 +1,100 @@ +# frozen_string_literal: true + module NodeJs module Helper - def npm_dist - if node['nodejs']['npm']['url'] - { 'url' => node['nodejs']['npm']['url'] } + DEFAULT_NODE_VERSION = '24.15.0' unless const_defined?(:DEFAULT_NODE_VERSION) + DEFAULT_NODE_MAJOR = '24' unless const_defined?(:DEFAULT_NODE_MAJOR) + DEFAULT_SOURCE_CHECKSUM = '729de494dd2872e5a3a6c32a1cd156a5413d4aca2772b2d873ee86bb5531bcd9' unless const_defined?(:DEFAULT_SOURCE_CHECKSUM) + DEFAULT_BINARY_CHECKSUMS = { + 'linux_x64' => '44836872d9aec49f1e6b52a9a922872db9a2b02d235a616a5681b6a85fec8d89', + 'linux_arm64' => '73afc234d558c24919875f51c2d1ea002a2ada4ea6f83601a383869fefa64eed', + }.freeze unless const_defined?(:DEFAULT_BINARY_CHECKSUMS) + + def default_install_method + case node['platform_family'] + when 'debian', 'rhel', 'fedora', 'amazon', 'mac_os_x', 'suse' + 'package' + when 'windows' + 'chocolatey' else + 'source' + end + end - require 'open-uri' - require 'json' - result = JSON.parse(URI.parse("https://registry.npmjs.org/npm/#{node['nodejs']['npm']['version']}").read, max_nesting: false) - ret = { 'url' => result['dist']['tarball'], 'version' => result['_npmVersion'], 'shasum' => result['dist']['shasum'] } - Chef::Log.debug("Npm dist #{ret}") - ret + def default_packages(install_repository) + case node['platform_family'] + when 'debian' + install_repository ? ['nodejs'] : %w(nodejs npm nodejs-dev) + when 'rhel', 'fedora', 'amazon' + install_repository ? %w(nodejs nodejs-devel) : %w(nodejs npm nodejs-devel) + when 'suse' + %w(nodejs npm nodejs-devel) + when 'mac_os_x' + ['node'] + else + ['nodejs'] end end + def default_build_packages + case node['platform_family'] + when 'rhel', 'fedora', 'amazon' + %w(openssl-devel python3 tar) + when 'debian' + %w(libssl-dev python3) + else + %w(python3) + end + end + + def default_make_threads + node['cpu'] ? node['cpu']['total'].to_i : 2 + end + + def node_major_from_version(version) + version.to_s.split('.').first + end + + def nodejs_arch + machine = node['kernel']['machine'] + + case machine + when /armv6l/ + 'arm-pi' + when /aarch64/ + 'arm64' + when /x86_64/ + 'x64' + when /\d86/ + 'x86' + else + machine + end + end + + def nodejs_binary_checksum(checksums) + checksums["linux_#{nodejs_arch}"] + end + + def nodejs_source_url(version, prefix_url, source_url) + source_url || ::URI.join(prefix_url, "v#{version}/", "node-v#{version}.tar.gz").to_s + end + + def nodejs_binary_url(version, prefix_url, binary_url) + binary_url || ::URI.join(prefix_url, "v#{version}/", "node-v#{version}-linux-#{nodejs_arch}.tar.gz").to_s + end + + def npm_dist(version, url = nil) + return { 'url' => url } if url + + require 'open-uri' + require 'json' + result = JSON.parse(URI.parse("https://registry.npmjs.org/npm/#{version}").read, max_nesting: false) + ret = { 'url' => result['dist']['tarball'], 'version' => result['_npmVersion'], 'shasum' => result['dist']['shasum'] } + Chef::Log.debug("Npm dist #{ret}") + ret + end + def npm_list(package, path = nil, environment = {}) require 'json' cmd = if path diff --git a/metadata.rb b/metadata.rb index 871b8c1..8fc77ed 100644 --- a/metadata.rb +++ b/metadata.rb @@ -1,24 +1,25 @@ +# frozen_string_literal: true + name 'nodejs' maintainer 'Sous Chefs' maintainer_email 'help@sous-chefs.org' license 'Apache-2.0' -description 'Installs/Configures node.js' +description 'Provides resources for installing Node.js and managing npm packages' version '10.2.3' source_url 'https://github.com/sous-chefs/nodejs' issues_url 'https://github.com/sous-chefs/nodejs/issues' chef_version '>= 15.3' -supports 'amazon' -supports 'centos' -supports 'debian' +supports 'almalinux', '>= 8.0' +supports 'amazon', '>= 2023.0' +supports 'centos_stream', '>= 9.0' +supports 'debian', '>= 12.0' +supports 'fedora' supports 'mac_os_x' -supports 'opensuseleap' -supports 'oracle' -supports 'redhat' -supports 'scientific' -supports 'smartos' -supports 'suse' -supports 'ubuntu' +supports 'oracle', '>= 8.0' +supports 'redhat', '>= 8.0' +supports 'rocky', '>= 8.0' +supports 'ubuntu', '>= 22.04' supports 'windows' depends 'ark', '>= 2.0.2' diff --git a/migration.md b/migration.md new file mode 100644 index 0000000..daa5861 --- /dev/null +++ b/migration.md @@ -0,0 +1,52 @@ +# Migration Guide + +This release is a breaking migration from recipes and node attributes to custom resources. + +## What Changed + +The cookbook no longer exposes `nodejs::default`, `nodejs::install`, `nodejs::repo`, `nodejs::npm`, `nodejs::npm_packages`, or the install-method recipes. The `attributes/` directory was removed. Configure Node.js through resource properties instead of `node['nodejs']` attributes. + +## Recipe to Resource Mapping + +| Before | After | +|--------|-------| +| `include_recipe 'nodejs::default'` | `nodejs_install 'nodejs'` plus optional `nodejs_npm_packages` | +| `include_recipe 'nodejs::repo'` | `nodejs_repository 'nodesource'` | +| `include_recipe 'nodejs::nodejs_from_package'` | `nodejs_install 'nodejs' do install_method 'package' end` | +| `include_recipe 'nodejs::nodejs_from_binary'` | `nodejs_install 'nodejs' do install_method 'binary' end` | +| `include_recipe 'nodejs::nodejs_from_source'` | `nodejs_install 'nodejs' do install_method 'source' end` | +| `include_recipe 'nodejs::nodejs_from_chocolatey'` | `nodejs_install 'nodejs' do install_method 'chocolatey' end` | +| `include_recipe 'nodejs::npm'` | `nodejs_npm_install 'npm'` | +| `node['nodejs']['npm_packages']` | `nodejs_npm_packages 'packages'` | + +## Examples + +Install Node.js from NodeSource packages: + +```ruby +nodejs_install 'nodejs' do + install_method 'package' + version '24.15.0' +end +``` + +Install packages that used to be configured with `node['nodejs']['npm_packages']`: + +```ruby +nodejs_npm_packages 'application packages' do + packages [ + { name: 'express' }, + { name: 'socket.io', version: '4.8.1' }, + ] +end +``` + +The `nodejs_npm` alias still works for the `npm_package` resource, but it no longer auto-includes any Node.js or npm recipes. Install Node.js first: + +```ruby +nodejs_install 'nodejs' + +nodejs_npm 'express' +``` + +See `test/cookbooks/test/recipes/` for runnable migration examples used by Kitchen. diff --git a/recipes/default.rb b/recipes/default.rb deleted file mode 100644 index aac903e..0000000 --- a/recipes/default.rb +++ /dev/null @@ -1,23 +0,0 @@ - -# Author:: Marius Ducea (marius@promethost.com) -# Cookbook:: nodejs -# Recipe:: default -# -# Copyright:: 2010-2017, Promet Solutions -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include_recipe 'nodejs::install' if node['nodejs']['manage_node'] -include_recipe 'nodejs::npm' if node['nodejs']['manage_node'] -include_recipe 'nodejs::npm_packages' if node['nodejs']['manage_node'] diff --git a/recipes/install.rb b/recipes/install.rb deleted file mode 100644 index bb4b529..0000000 --- a/recipes/install.rb +++ /dev/null @@ -1,21 +0,0 @@ -# -# Author:: Marius Ducea (marius@promethost.com) -# Cookbook:: nodejs -# Recipe:: install -# -# Copyright:: 2010-2017, Promet Solutions -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include_recipe "nodejs::nodejs_from_#{node['nodejs']['install_method']}" diff --git a/recipes/iojs.rb b/recipes/iojs.rb deleted file mode 100644 index a1244b0..0000000 --- a/recipes/iojs.rb +++ /dev/null @@ -1 +0,0 @@ -Chef::Log.fatal('The nodejs::iojs recipe has been deprecated. If you need iojs installation pin to cookbook version 3.0.1.') diff --git a/recipes/nodejs.rb b/recipes/nodejs.rb deleted file mode 100644 index 368b88d..0000000 --- a/recipes/nodejs.rb +++ /dev/null @@ -1,21 +0,0 @@ -# -# Author:: Marius Ducea (marius@promethost.com) -# Cookbook:: nodejs -# Recipe:: nodejs -# -# Copyright:: 2010-2017, Promet Solutions -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -Chef::Log.fatal('The nodejs::nodejs recipe is no longer used. Use nodejs::install to install nodejs instead.') diff --git a/recipes/nodejs_from_binary.rb b/recipes/nodejs_from_binary.rb deleted file mode 100644 index 0c05710..0000000 --- a/recipes/nodejs_from_binary.rb +++ /dev/null @@ -1,67 +0,0 @@ -# -# Author:: Julian Wilde (jules@jules.com.au) -# Cookbook:: nodejs -# Recipe:: install_from_binary -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -Chef::DSL::Recipe.include NodeJs::Helper - -# Shamelessly borrowed from http://docs.chef.io/dsl_recipe_method_platform.html -# Surely there's a more canonical way to get arch? -arch = if node['kernel']['machine'] =~ /armv6l/ - # FIXME: This should really check the version of node we're looking for - # as it seems that they haven't build an `arm-pi` version in a while... - # if it's old, return this, otherwise just return `node['kernel']['machine']` - 'arm-pi' # assume a raspberry pi - elsif node['kernel']['machine'] =~ /aarch64/ - 'arm64' - elsif node['kernel']['machine'] =~ /x86_64/ - 'x64' - elsif node['kernel']['machine'] =~ /\d86/ - 'x86' - else - node['kernel']['machine'] - end - -# needed to uncompress the binary -package 'tar' if platform_family?('rhel', 'fedora', 'amazon', 'suse') - -# package_stub is for example: "node-v6.9.1-linux-x64.tar.gz" -version = "v#{node['nodejs']['version']}/" -prefix = node['nodejs']['prefix_url']['node'] - -filename = "node-v#{node['nodejs']['version']}-linux-#{arch}.tar.gz" -archive_name = 'nodejs-binary' -binaries = ['bin/node'] - -binaries.push('bin/npm') if node['nodejs']['npm']['install_method'] == 'embedded' -binaries.push('bin/npx') if node['nodejs']['npm']['install_method'] == 'embedded' - -if node['nodejs']['binary']['url'] - nodejs_bin_url = node['nodejs']['binary']['url'] - checksum = node['nodejs']['binary']['checksum'] -else - nodejs_bin_url = ::URI.join(prefix, version, filename).to_s - checksum = node['nodejs']['binary']['checksum']["linux_#{arch}"] -end - -ark archive_name do - url nodejs_bin_url - version node['nodejs']['version'] - checksum checksum - has_binaries binaries - append_env_path node['nodejs']['binary']['append_env_path'] - action :install -end diff --git a/recipes/nodejs_from_chocolatey.rb b/recipes/nodejs_from_chocolatey.rb deleted file mode 100644 index a0fa9d0..0000000 --- a/recipes/nodejs_from_chocolatey.rb +++ /dev/null @@ -1,24 +0,0 @@ -# -# Author:: Hossein Margani (hossein@margani.dev) -# Cookbook:: nodejs -# Recipe:: install_from_chocolatey -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include_recipe 'chocolatey' - -chocolatey_package 'nodejs-lts' do - version node['nodejs']['version'] if node['nodejs']['version'] - action :upgrade -end diff --git a/recipes/nodejs_from_package.rb b/recipes/nodejs_from_package.rb deleted file mode 100644 index b5c3ae8..0000000 --- a/recipes/nodejs_from_package.rb +++ /dev/null @@ -1,43 +0,0 @@ -# -# Author:: Nathan L Smith (nlloyds@gmail.com) -# Author:: Marius Ducea (marius@promethost.com) -# Cookbook:: nodejs -# Recipe:: package -# -# Copyright:: 2012-2017, Cramer Development, Inc. -# Copyright:: 2013-2017, Opscale -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include_recipe 'nodejs::repo' if node['nodejs']['install_repo'] - -unless node['nodejs']['packages'] - Chef::Log.error 'No package for nodejs' - Chef::Log.warn 'Please use the source or binary method to install node' - return -end - -if platform_family?('rhel', 'fedora') && node['platform_version'].to_i >= 8 && !node['nodejs']['dnf_module'] - dnf_module 'nodejs' do - action :disable - only_if 'dnf module list nodejs' - end -end - -node['nodejs']['packages'].each do |node_pkg| - package node_pkg do - action node['nodejs']['package_action'][node_pkg] if node['nodejs']['package_action'][node_pkg] - options node['nodejs']['package_options'][node_pkg] if node['nodejs']['package_options'][node_pkg] - end -end diff --git a/recipes/nodejs_from_source.rb b/recipes/nodejs_from_source.rb deleted file mode 100644 index 19bc2f1..0000000 --- a/recipes/nodejs_from_source.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Author:: Marius Ducea (marius@promethost.com) -# Cookbook:: nodejs -# Recipe:: source -# -# Copyright:: 2010-2017, Promet Solutions -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -Chef::DSL::Recipe.include NodeJs::Helper - -build_essential 'install build tools' - -case node['platform_family'] -when 'rhel', 'fedora', 'amazon' - package %w(openssl-devel python3 tar) -when 'debian' - package %w(libssl-dev python3) -else - package %w(python3) -end - -version = "v#{node['nodejs']['version']}/" -prefix = node['nodejs']['prefix_url']['node'] -filename = "node-v#{node['nodejs']['version']}.tar.gz" -archive_name = 'nodejs-source' - -nodejs_src_url = node['nodejs']['source']['url'] || ::URI.join(prefix, version, filename).to_s - -ark archive_name do - url nodejs_src_url - version node['nodejs']['version'] - checksum node['nodejs']['source']['checksum'] - make_opts ["-j #{node['nodejs']['make_threads']}"] - action :install_with_make - environment(PYTHON: 'python3') -end diff --git a/recipes/npm.rb b/recipes/npm.rb deleted file mode 100644 index 9d049fc..0000000 --- a/recipes/npm.rb +++ /dev/null @@ -1,28 +0,0 @@ -# -# Author:: Marius Ducea (marius@promethost.com) -# Cookbook:: nodejs -# Recipe:: npm -# -# Copyright:: 2010-2017, Promet Solutions -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -case node['nodejs']['npm']['install_method'] -when 'embedded' - include_recipe 'nodejs::install' -when 'source' - include_recipe 'nodejs::npm_from_source' -else - Chef::Log.error('No install method found for npm') -end diff --git a/recipes/npm_from_source.rb b/recipes/npm_from_source.rb deleted file mode 100644 index d2dc71d..0000000 --- a/recipes/npm_from_source.rb +++ /dev/null @@ -1,32 +0,0 @@ -# -# Author:: Marius Ducea (marius@promethost.com) -# Cookbook:: nodejs -# Recipe:: npm -# -# Copyright:: 2010-2017, Promet Solutions -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -Chef::DSL::Recipe.include NodeJs::Helper - -include_recipe 'nodejs::nodejs_from_source' - -dist = npm_dist - -ark 'npm' do - url dist['url'] - checksum dist['checksum'] - version dist['version'] - action :install_with_make -end diff --git a/recipes/npm_packages.rb b/recipes/npm_packages.rb deleted file mode 100644 index ec0d3c5..0000000 --- a/recipes/npm_packages.rb +++ /dev/null @@ -1,13 +0,0 @@ -if node['nodejs'].key?('npm_packages') - node['nodejs']['npm_packages'].each do |pkg| - pkg_action = pkg.key?('action') ? pkg['action'] : :install - f = npm_package "nodejs_npm-#{pkg['name']}-#{pkg_action}" do - action :nothing - package pkg['name'] - end - pkg.each do |key, value| - f.send(key, value) unless key == 'name' || key == 'action' - end - f.action(pkg_action) - end -end diff --git a/recipes/repo.rb b/recipes/repo.rb deleted file mode 100644 index ee9d8bf..0000000 --- a/recipes/repo.rb +++ /dev/null @@ -1,48 +0,0 @@ -case node['platform_family'] -when 'debian' - # Install necessary packages for downloading and verifying new repository information - package %w(ca-certificates curl gnupg apt-transport-https) - - # Create a directory for the new repository's keyring, if it doesn't exist - directory '/etc/apt/keyrings' - - # Download the new repository's GPG key and save it in the keyring directory - execute 'add nodejs gpg key' do - command "curl -fsSL #{node['nodejs']['key']} | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg" - not_if { ::File.exist? '/etc/apt/keyrings/nodesource.gpg' } - end - - # Prefer nodesource over Ubuntu universe packages by giving a higher priority (default 500) - apt_preference 'nodesource' do - glob '*' - pin 'origin deb.nodesource.com' - pin_priority '600' - end - - if Gem::Version.new('18.3.0') <= Chef::VERSION - apt_repository 'nodesource' do - uri node['nodejs']['repo'] - components ['main'] - options ['signed-by=/etc/apt/keyrings/nodesource.gpg'] - distribution node['nodejs']['distribution'] - end - else - # Chef Infra < 18.3 doesn't support options attribute, fallback to (deprecated) apt-key method - apt_repository 'nodesource' do - uri node['nodejs']['repo'] - components ['main'] - key '2F59B5F99B1BE0B4' - keyserver 'keyserver.ubuntu.com' - distribution node['nodejs']['distribution'] - end - end - -when 'rhel', 'fedora', 'amazon' - yum_repository 'nodesource-nodejs' do - description 'nodesource.com nodejs repository' - baseurl node['nodejs']['repo'] - gpgkey node['nodejs']['key'] - priority '9' - options(module_hotfixes: 1) - end -end diff --git a/resources/_partial/_nodejs.rb b/resources/_partial/_nodejs.rb new file mode 100644 index 0000000..5cd8304 --- /dev/null +++ b/resources/_partial/_nodejs.rb @@ -0,0 +1,2 @@ +property :version, String, default: NodeJs::Helper::DEFAULT_NODE_VERSION +property :prefix_url, String, default: 'https://nodejs.org/dist/' diff --git a/resources/nodejs_install.rb b/resources/nodejs_install.rb new file mode 100644 index 0000000..5d26f55 --- /dev/null +++ b/resources/nodejs_install.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +provides :nodejs_install +unified_mode true + +use '_partial/_nodejs' + +property :install_method, String, equal_to: %w(package binary source chocolatey) +property :install_repository, [true, false], default: true +property :packages, [Array, nil], default: nil +property :package_action, [Symbol, String], default: :install +property :package_options, [String, nil] +property :disable_dnf_module, [true, false], default: true +property :source_url, [String, nil] +property :source_checksum, [String, nil], default: NodeJs::Helper::DEFAULT_SOURCE_CHECKSUM +property :binary_url, [String, nil] +property :binary_checksums, Hash, default: NodeJs::Helper::DEFAULT_BINARY_CHECKSUMS +property :append_env_path, [true, false], default: true +property :make_threads, [Integer, String, nil], default: nil +property :build_packages, [Array, nil], default: nil +property :chocolatey_package_name, String, default: 'nodejs-lts' + +default_action :install + +action :install do + case requested_install_method + when 'package' + nodejs_repository 'nodesource' do + node_major node_major_from_version(new_resource.version) + action :create + only_if { new_resource.install_repository } + end + + dnf_module 'nodejs' do + action :disable + only_if { disable_dnf_module? } + end + + resolved_packages.each do |pkg| + package pkg do + action new_resource.package_action.to_sym + options new_resource.package_options if new_resource.package_options + end + end + when 'binary' + package 'tar' if platform_family?('rhel', 'fedora', 'amazon', 'suse') + + ark 'nodejs-binary' do + url nodejs_binary_url(new_resource.version, new_resource.prefix_url, new_resource.binary_url) + version new_resource.version + checksum nodejs_binary_checksum(new_resource.binary_checksums) unless new_resource.binary_url + has_binaries %w(bin/node bin/npm bin/npx) + append_env_path new_resource.append_env_path + action :install + end + when 'source' + build_essential 'install build tools' + + package(new_resource.build_packages || default_build_packages) + + ark 'nodejs-source' do + url nodejs_source_url(new_resource.version, new_resource.prefix_url, new_resource.source_url) + version new_resource.version + checksum new_resource.source_checksum if new_resource.source_checksum + make_opts ["-j #{new_resource.make_threads || default_make_threads}"] + environment(PYTHON: 'python3') + action :install_with_make + end + when 'chocolatey' + chocolatey_package new_resource.chocolatey_package_name do + version new_resource.version if new_resource.version + action :upgrade + end + end +end + +action :remove do + case requested_install_method + when 'package' + resolved_packages.each do |pkg| + package pkg do + action :remove + end + end + + nodejs_repository 'nodesource' do + action :remove + only_if { new_resource.install_repository } + end + when 'binary' + ark 'nodejs-binary' do + action :remove + end + when 'source' + ark 'nodejs-source' do + action :remove + end + when 'chocolatey' + chocolatey_package new_resource.chocolatey_package_name do + action :remove + end + end +end + +action_class do + include NodeJs::Helper + + def requested_install_method + new_resource.install_method || default_install_method + end + + def resolved_packages + new_resource.packages || default_packages(new_resource.install_repository) + end + + def disable_dnf_module? + new_resource.disable_dnf_module && + platform_family?('rhel', 'fedora') && + node['platform_version'].to_i >= 8 + end +end diff --git a/resources/nodejs_npm_install.rb b/resources/nodejs_npm_install.rb new file mode 100644 index 0000000..b506d2d --- /dev/null +++ b/resources/nodejs_npm_install.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +provides :nodejs_npm_install +unified_mode true + +use '_partial/_nodejs' + +property :install_method, String, equal_to: %w(embedded source), default: 'embedded' +property :install_node, [true, false], default: true +property :node_install_method, String, equal_to: %w(package binary source chocolatey), default: 'package' +property :npm_version, String, default: 'latest' +property :npm_url, [String, nil] +property :npm_checksum, [String, nil] +property :make_threads, [Integer, String, nil], default: nil + +default_action :install + +action :install do + nodejs_install 'nodejs for npm' do + install_method new_resource.node_install_method + version new_resource.version + prefix_url new_resource.prefix_url + action :install + only_if { new_resource.install_node } + end + + ark 'npm' do + url lazy { npm_dist(new_resource.npm_version, new_resource.npm_url)['url'] } + checksum new_resource.npm_checksum if new_resource.npm_checksum + version lazy { npm_dist(new_resource.npm_version, new_resource.npm_url)['version'] || new_resource.npm_version } + make_opts ["-j #{new_resource.make_threads || default_make_threads}"] + action :install_with_make + only_if { new_resource.install_method == 'source' } + end +end + +action :remove do + ark 'npm' do + action :remove + only_if { new_resource.install_method == 'source' } + end +end + +action_class do + include NodeJs::Helper +end diff --git a/resources/nodejs_npm_packages.rb b/resources/nodejs_npm_packages.rb new file mode 100644 index 0000000..cbe2c96 --- /dev/null +++ b/resources/nodejs_npm_packages.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +provides :nodejs_npm_packages +unified_mode true + +property :packages, Array, default: [] + +default_action :install + +action :install do + new_resource.packages.each do |pkg| + package_properties = normalize_package(pkg) + pkg_action = package_properties.delete(:action) || :install + pkg_name = package_properties.delete(:package) + + npm_package "nodejs_npm-#{pkg_name}-#{pkg_action}" do + package pkg_name + package_properties.each do |property_name, property_value| + send(property_name, property_value) + end + action pkg_action.to_sym + end + end +end + +action :remove do + new_resource.packages.each do |pkg| + package_properties = normalize_package(pkg) + pkg_name = package_properties[:package] + + npm_package "nodejs_npm-#{pkg_name}-remove" do + package pkg_name + action :remove + end + end +end + +action_class do + def normalize_package(pkg) + pkg.each_with_object({}) do |(key, value), memo| + property_name = key.to_sym + property_name = :package if property_name == :name + memo[property_name] = value + end + end +end diff --git a/resources/nodejs_repository.rb b/resources/nodejs_repository.rb new file mode 100644 index 0000000..fc6ad3a --- /dev/null +++ b/resources/nodejs_repository.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +provides :nodejs_repository +unified_mode true + +property :repo_name, String, name_property: true +property :node_major, [String, Integer], default: NodeJs::Helper::DEFAULT_NODE_MAJOR +property :apt_uri, String +property :apt_distribution, String, default: 'nodistro' +property :apt_components, Array, default: ['main'] +property :apt_key, String, default: 'https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key' +property :apt_keyring, String, default: '/etc/apt/keyrings/nodesource.asc' +property :apt_pin_priority, String, default: '600' +property :yum_baseurl, String +property :yum_gpgkey, String, default: 'https://rpm.nodesource.com/gpgkey/ns-operations-public.key' +property :yum_priority, String, default: '9' +property :enabled, [true, false], default: true +property :gpgcheck, [true, false], default: true + +default_action :create + +action :create do + case node['platform_family'] + when 'debian' + package %w(ca-certificates curl gnupg apt-transport-https) + + directory ::File.dirname(new_resource.apt_keyring) do + recursive true + mode '0755' + end + + remote_file new_resource.apt_keyring do + source new_resource.apt_key + mode '0644' + end + + apt_preference new_resource.repo_name do + glob '*' + pin 'origin deb.nodesource.com' + pin_priority new_resource.apt_pin_priority + end + + apt_repository new_resource.repo_name do + uri lazy { new_resource.apt_uri || "https://deb.nodesource.com/node_#{new_resource.node_major}.x" } + components new_resource.apt_components + signed_by new_resource.apt_keyring + distribution new_resource.apt_distribution + end + when 'rhel', 'fedora', 'amazon' + yum_repository "#{new_resource.repo_name}-nodejs" do + description 'nodesource.com nodejs repository' + baseurl lazy { new_resource.yum_baseurl || "https://rpm.nodesource.com/pub_#{new_resource.node_major}.x/nodistro/nodejs/$basearch" } + gpgkey new_resource.yum_gpgkey + priority new_resource.yum_priority + enabled new_resource.enabled + gpgcheck new_resource.gpgcheck + options(module_hotfixes: 1) + action :create + end + end +end + +action :remove do + case node['platform_family'] + when 'debian' + apt_repository new_resource.repo_name do + action :remove + end + + file new_resource.apt_keyring do + action :delete + end + when 'rhel', 'fedora', 'amazon' + yum_repository "#{new_resource.repo_name}-nodejs" do + action :remove + end + end +end diff --git a/resources/npm_package.rb b/resources/npm_package.rb index 94c4deb..675d14a 100644 --- a/resources/npm_package.rb +++ b/resources/npm_package.rb @@ -1,29 +1,8 @@ -# -# Cookbook:: nodejs -# Resource:: npm -# -# Author:: Sergey Balbeko -# -# Copyright:: 2012-2017, Sergey Balbeko -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# +# frozen_string_literal: true -resource_name :npm_package provides :npm_package unified_mode true -# backwards compatibility for the old resource name provides :nodejs_npm property :package, String, name_property: true @@ -31,7 +10,7 @@ property :path, String property :url, String property :json, [String, true, false] -property :npm_token, String +property :npm_token, String, sensitive: true property :options, Array, default: [] property :user, String property :group, String @@ -39,10 +18,7 @@ property :node_env, String property :auto_update, [true, false], default: true -def initialize(*args) - super - @run_context.include_recipe 'nodejs::npm' if node['nodejs']['manage_node'] -end +default_action :install action :install do execute "install NPM package #{new_resource.package}" do @@ -52,7 +28,8 @@ def initialize(*args) group new_resource.group environment npm_env_vars live_stream new_resource.live_stream - not_if { package_installed? && no_auto_update? } + sensitive true if new_resource.npm_token + not_if { no_auto_update? && package_installed? } end end @@ -64,6 +41,20 @@ def initialize(*args) group new_resource.group environment npm_env_vars live_stream new_resource.live_stream + sensitive true if new_resource.npm_token + only_if { package_installed? } + end +end + +action :remove do + execute "uninstall NPM package #{new_resource.package}" do + cwd new_resource.path + command "npm uninstall #{npm_options}" + user new_resource.user + group new_resource.group + environment npm_env_vars + live_stream new_resource.live_stream + sensitive true if new_resource.npm_token only_if { package_installed? } end end @@ -90,7 +81,7 @@ def no_auto_update? end def npm_options - options = '' + options = +'' options << ' -global' unless new_resource.path new_resource.options.each do |option| options << " #{option}" diff --git a/spec/rspec_helper.rb b/spec/rspec_helper.rb index 2e189c8..e1af5a0 100644 --- a/spec/rspec_helper.rb +++ b/spec/rspec_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dir.glob('libraries/*.rb').each do |lib| require_relative "../#{lib}" end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 773d557..cbf7181 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'chefspec' require 'chefspec/berkshelf' diff --git a/spec/unit/library/helper_spec.rb b/spec/unit/library/helper_spec.rb index 583d529..4425bb7 100644 --- a/spec/unit/library/helper_spec.rb +++ b/spec/unit/library/helper_spec.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + require 'rspec_helper' require 'mixlib/shellout' require 'ostruct' @@ -9,17 +11,12 @@ end describe 'npm_dist' do - it 'should return a url if specified in the node attributes' do - n = { 'nodejs': { 'npm': { 'url': 'get it' } } } - n = Mash.new(n) - allow(@mt).to receive(:node).and_return(n) - expect(@mt.npm_dist['url']).to eq('get it') + it 'should return a url if specified' do + expect(@mt.npm_dist('latest', 'get it')['url']).to eq('get it') end + it 'should return a url based on the version' do - n = { 'nodejs': { 'npm': { 'url': nil, 'version': '6.14.8' } } } - n = Mash.new(n) - allow(@mt).to receive(:node).and_return(n) - expect(@mt.npm_dist['url']).to eq('https://registry.npmjs.org/npm/-/npm-6.14.8.tgz') + expect(@mt.npm_dist('6.14.8')['url']).to eq('https://registry.npmjs.org/npm/-/npm-6.14.8.tgz') end end diff --git a/spec/unit/recipes/default_spec.rb b/spec/unit/recipes/default_spec.rb deleted file mode 100644 index 2a2f25a..0000000 --- a/spec/unit/recipes/default_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -require 'spec_helper' - -describe 'default recipe on ubuntu 22.04' do - let(:runner) { ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04') } - let(:chef_run) { runner.converge('nodejs::default') } - - it 'includes the package install recipes' do - expect(chef_run).to include_recipe('nodejs::nodejs_from_package') - expect(chef_run).to include_recipe('nodejs::npm_packages') - end - - it 'converges successfully' do - expect { :chef_run }.to_not raise_error - end -end - -describe 'default recipe on centos 8' do - let(:runner) { ChefSpec::ServerRunner.new(platform: 'centos', version: '8') } - let(:chef_run) { runner.converge('nodejs::default') } - - it 'includes the package install recipes' do - stub_command('dnf module list nodejs').and_return(0) - expect(chef_run).to include_recipe('nodejs::nodejs_from_package') - expect(chef_run).to include_recipe('nodejs::npm_packages') - end - - it 'converges successfully' do - expect { :chef_run }.to_not raise_error - end -end - -describe 'default recipe on debian 12' do - let(:runner) { ChefSpec::ServerRunner.new(platform: 'debian', version: '12') } - let(:chef_run) { runner.converge('nodejs::default') } - - it 'includes the package install recipes' do - expect(chef_run).to include_recipe('nodejs::nodejs_from_package') - expect(chef_run).to include_recipe('nodejs::npm_packages') - end - - it 'converges successfully' do - expect { :chef_run }.to_not raise_error - end -end - -describe 'default recipe on mac_os_x' do - let(:runner) { ChefSpec::ServerRunner.new(platform: 'mac_os_x') } - let(:chef_run) { runner.converge('nodejs::default') } - - it 'includes the package install recipes' do - expect(chef_run).to include_recipe('nodejs::nodejs_from_package') - expect(chef_run).to include_recipe('nodejs::npm_packages') - end - - it 'converges successfully' do - expect { :chef_run }.to_not raise_error - end -end - -describe 'default recipe on fedora' do - let(:runner) { ChefSpec::ServerRunner.new(platform: 'fedora') } - let(:chef_run) do - stub_command('dnf module list nodejs').and_return(0) - runner.converge('nodejs::default') - end - - it 'includes the package install recipes' do - expect(chef_run).to include_recipe('nodejs::nodejs_from_package') - expect(chef_run).to include_recipe('nodejs::npm_packages') - end - - it 'converges successfully' do - expect { :chef_run }.to_not raise_error - end -end diff --git a/spec/unit/resources/nodejs_install_spec.rb b/spec/unit/resources/nodejs_install_spec.rb new file mode 100644 index 0000000..2c760e5 --- /dev/null +++ b/spec/unit/resources/nodejs_install_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'nodejs_install' do + step_into :nodejs_install, :nodejs_repository + + context 'package install on ubuntu' do + platform 'ubuntu', '24.04' + + recipe do + nodejs_install 'nodejs' + end + + it { is_expected.to create_nodejs_repository('nodesource') } + it { is_expected.to install_package('nodejs') } + end + + context 'package install on rocky linux' do + platform 'rocky', '9' + + recipe do + nodejs_install 'nodejs' + end + + it { is_expected.to disable_dnf_module('nodejs') } + it { is_expected.to install_package('nodejs') } + it { is_expected.to install_package('nodejs-devel') } + end + + context 'binary install' do + platform 'ubuntu', '24.04' + + recipe do + nodejs_install 'nodejs' do + install_method 'binary' + end + end + + it { is_expected.to install_ark('nodejs-binary') } + end + + context 'source install' do + platform 'ubuntu', '24.04' + + recipe do + nodejs_install 'nodejs' do + install_method 'source' + make_threads 2 + end + end + + it { is_expected.to install_build_essential('install build tools') } + it { is_expected.to install_package(%w(libssl-dev python3)) } + it { is_expected.to install_with_make_ark('nodejs-source') } + end + + context 'chocolatey install' do + platform 'windows', '2022' + + recipe do + nodejs_install 'nodejs' do + install_method 'chocolatey' + end + end + + it { is_expected.to upgrade_chocolatey_package('nodejs-lts') } + end +end diff --git a/spec/unit/resources/nodejs_npm_install_spec.rb b/spec/unit/resources/nodejs_npm_install_spec.rb new file mode 100644 index 0000000..a75ae4f --- /dev/null +++ b/spec/unit/resources/nodejs_npm_install_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'nodejs_npm_install' do + step_into :nodejs_npm_install + platform 'ubuntu', '24.04' + + context 'embedded npm' do + recipe do + nodejs_npm_install 'npm' + end + + it { is_expected.to install_nodejs_install('nodejs for npm') } + it { is_expected.to_not install_with_make_ark('npm') } + end + + context 'source npm' do + recipe do + nodejs_npm_install 'npm' do + install_method 'source' + npm_url 'https://registry.npmjs.org/npm/-/npm-11.0.0.tgz' + npm_version '11.0.0' + npm_checksum 'a4f653d79ed140aaad921e8c22a3b585ca85cfdab80d4030f6309e4663a8a1c8' + end + end + + it { is_expected.to install_nodejs_install('nodejs for npm') } + it { is_expected.to install_with_make_ark('npm') } + end +end diff --git a/spec/unit/resources/nodejs_npm_packages_spec.rb b/spec/unit/resources/nodejs_npm_packages_spec.rb new file mode 100644 index 0000000..1d8199f --- /dev/null +++ b/spec/unit/resources/nodejs_npm_packages_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'nodejs_npm_packages' do + step_into :nodejs_npm_packages + platform 'ubuntu', '24.04' + + recipe do + nodejs_npm_packages 'packages' do + packages [ + { name: 'express' }, + { name: 'socket.io', version: '4.8.1' }, + { name: 'left-pad', action: :remove }, + ] + end + end + + it { is_expected.to install_npm_package('nodejs_npm-express-install').with(package: 'express') } + it { is_expected.to install_npm_package('nodejs_npm-socket.io-install').with(package: 'socket.io', version: '4.8.1') } + it { is_expected.to remove_npm_package('nodejs_npm-left-pad-remove').with(package: 'left-pad') } +end diff --git a/spec/unit/resources/nodejs_repository_spec.rb b/spec/unit/resources/nodejs_repository_spec.rb new file mode 100644 index 0000000..9c23215 --- /dev/null +++ b/spec/unit/resources/nodejs_repository_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'nodejs_repository' do + step_into :nodejs_repository + + context 'on ubuntu' do + platform 'ubuntu', '24.04' + + recipe do + nodejs_repository 'nodesource' + end + + it { is_expected.to install_package(%w(ca-certificates curl gnupg apt-transport-https)) } + it { is_expected.to create_directory('/etc/apt/keyrings') } + it { is_expected.to create_remote_file('/etc/apt/keyrings/nodesource.asc') } + it { is_expected.to add_apt_preference('nodesource') } + it { is_expected.to add_apt_repository('nodesource').with(uri: 'https://deb.nodesource.com/node_24.x', distribution: 'nodistro') } + end + + context 'on rocky linux' do + platform 'rocky', '9' + + recipe do + nodejs_repository 'nodesource' + end + + it { is_expected.to create_yum_repository('nodesource-nodejs').with(baseurl: 'https://rpm.nodesource.com/pub_24.x/nodistro/nodejs/$basearch') } + end + + context 'remove on ubuntu' do + platform 'ubuntu', '24.04' + + recipe do + nodejs_repository 'nodesource' do + action :remove + end + end + + it { is_expected.to remove_apt_repository('nodesource') } + it { is_expected.to delete_file('/etc/apt/keyrings/nodesource.asc') } + end +end diff --git a/spec/unit/resources/npm_package_spec.rb b/spec/unit/resources/npm_package_spec.rb new file mode 100644 index 0000000..cc6ad5c --- /dev/null +++ b/spec/unit/resources/npm_package_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'npm_package' do + step_into :npm_package, :nodejs_npm + platform 'ubuntu', '24.04' + + context 'install a global package' do + recipe do + npm_package 'express' + end + + it { is_expected.to run_execute('install NPM package express').with(command: 'npm install -global express') } + end + + context 'install a versioned package' do + recipe do + npm_package 'async' do + version '0.6.2' + options ['--production'] + end + end + + it { is_expected.to run_execute('install NPM package async').with(command: 'npm install -global --production async@0.6.2') } + end + + context 'install with the legacy alias' do + recipe do + nodejs_npm 'mocha' + end + + it { is_expected.to run_execute('install NPM package mocha').with(command: 'npm install -global mocha') } + end +end diff --git a/test/cookbooks/test/metadata.rb b/test/cookbooks/test/metadata.rb index e1b0188..906ad36 100644 --- a/test/cookbooks/test/metadata.rb +++ b/test/cookbooks/test/metadata.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + name 'test' version '0.1.0' diff --git a/test/cookbooks/test/recipes/chocolatey.rb b/test/cookbooks/test/recipes/chocolatey.rb index 4db799f..70edbe8 100644 --- a/test/cookbooks/test/recipes/chocolatey.rb +++ b/test/cookbooks/test/recipes/chocolatey.rb @@ -1,3 +1,7 @@ -node.default['nodejs']['install_method'] = 'chocolatey' -include_recipe 'nodejs::default' +# frozen_string_literal: true + +nodejs_install 'nodejs' do + install_method 'chocolatey' +end + include_recipe 'test::resource_win' diff --git a/test/cookbooks/test/recipes/default.rb b/test/cookbooks/test/recipes/default.rb index 28813e8..f44ff23 100644 --- a/test/cookbooks/test/recipes/default.rb +++ b/test/cookbooks/test/recipes/default.rb @@ -1,4 +1,19 @@ -apt_update 'update' +# frozen_string_literal: true -include_recipe 'nodejs::default' -include_recipe 'test::resource' +apt_update 'update' if platform_family?('debian') + +nodejs_install 'nodejs' do + install_method platform_family?('windows') ? 'chocolatey' : 'package' +end + +nodejs_npm_install 'embedded npm' do + install_method 'embedded' + install_node false +end + +nodejs_npm_packages 'default npm packages' do + packages [ + { name: 'socket.io', version: '4.8.1', auto_update: false }, + { name: 'express', action: :remove }, + ] +end diff --git a/test/cookbooks/test/recipes/npm_embedded.rb b/test/cookbooks/test/recipes/npm_embedded.rb new file mode 100644 index 0000000..ccb2375 --- /dev/null +++ b/test/cookbooks/test/recipes/npm_embedded.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +nodejs_install 'nodejs' do + install_method platform_family?('windows') ? 'chocolatey' : 'package' +end + +nodejs_npm_install 'embedded npm' do + install_method 'embedded' + install_node false +end diff --git a/test/cookbooks/test/recipes/npm_source.rb b/test/cookbooks/test/recipes/npm_source.rb new file mode 100644 index 0000000..a212810 --- /dev/null +++ b/test/cookbooks/test/recipes/npm_source.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +nodejs_npm_install 'source npm' do + install_method 'source' + node_install_method 'source' +end diff --git a/test/cookbooks/test/recipes/package.rb b/test/cookbooks/test/recipes/package.rb index 709900e..aa55e31 100644 --- a/test/cookbooks/test/recipes/package.rb +++ b/test/cookbooks/test/recipes/package.rb @@ -1,5 +1,9 @@ -apt_update 'update' +# frozen_string_literal: true -node.default['nodejs']['install_method'] = 'package' +apt_update 'update' if platform_family?('debian') -include_recipe 'nodejs::default' +nodejs_install 'nodejs' do + install_method 'package' +end + +include_recipe 'test::resource' diff --git a/test/cookbooks/test/recipes/resource.rb b/test/cookbooks/test/recipes/resource.rb index 8fb7a1f..e1ca353 100644 --- a/test/cookbooks/test/recipes/resource.rb +++ b/test/cookbooks/test/recipes/resource.rb @@ -1,8 +1,13 @@ -apt_update 'update' +# frozen_string_literal: true -include_recipe 'nodejs::npm' +apt_update 'update' if platform_family?('debian') include_recipe 'git' +nodejs_npm_install 'embedded npm' do + install_method 'embedded' + install_node false +end + user 'random' do manage_home true home '/home/random' @@ -18,7 +23,7 @@ home '/home/random2' end -# global "express" using the old resource name +# global "express" using the old resource alias nodejs_npm 'express' npm_package 'async' do diff --git a/test/cookbooks/test/recipes/resource_win.rb b/test/cookbooks/test/recipes/resource_win.rb index 198c252..3ab6a81 100644 --- a/test/cookbooks/test/recipes/resource_win.rb +++ b/test/cookbooks/test/recipes/resource_win.rb @@ -1,4 +1,10 @@ -include_recipe 'nodejs::npm' +# frozen_string_literal: true + +nodejs_npm_install 'embedded npm' do + install_method 'embedded' + install_node false +end + include_recipe 'git' user 'random' do diff --git a/test/cookbooks/test/recipes/source.rb b/test/cookbooks/test/recipes/source.rb index c05bd33..628421d 100644 --- a/test/cookbooks/test/recipes/source.rb +++ b/test/cookbooks/test/recipes/source.rb @@ -1,8 +1,12 @@ -apt_update 'update' +# frozen_string_literal: true + +apt_update 'update' if platform_family?('debian') # Source install puts the npm symlink in /usr/local/bin ENV['PATH'] = '/usr/local/bin:' + ENV['PATH'] -node.default['nodejs']['install_method'] = 'source' -include_recipe 'nodejs::default' +nodejs_install 'nodejs from source' do + install_method 'source' +end + include_recipe 'test::resource' diff --git a/test/cookbooks/test/recipes/source_iojs.rb b/test/cookbooks/test/recipes/source_iojs.rb deleted file mode 100644 index 1c72cf3..0000000 --- a/test/cookbooks/test/recipes/source_iojs.rb +++ /dev/null @@ -1,8 +0,0 @@ -apt_update 'update' - -node.default['nodejs']['engine'] = 'iojs' -node.default['nodejs']['install_method'] = 'source' -node.default['nodejs']['source']['checksum'] = '55e79cc4f4cde41f03c1e204d2af5ee4b6e4edcf14defc82e518436e939195fa' -node.default['nodejs']['version'] = '2.2.1' - -include_recipe 'nodejs::default' diff --git a/test/integration/chocolatey/controls/chocolatey_spec.rb b/test/integration/chocolatey/controls/chocolatey_spec.rb new file mode 100644 index 0000000..5753425 --- /dev/null +++ b/test/integration/chocolatey/controls/chocolatey_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +control 'nodejs-chocolatey-01' do + impact 1.0 + title 'Node.js commands are available on Windows' + + only_if('Windows only') { os.windows? } + + describe command('node -v') do + its('exit_status') { should eq 0 } + end + + describe command('npm -v') do + its('exit_status') { should eq 0 } + end +end diff --git a/test/integration/chocolatey/default.rb b/test/integration/chocolatey/default.rb deleted file mode 100644 index 4ff1714..0000000 --- a/test/integration/chocolatey/default.rb +++ /dev/null @@ -1,16 +0,0 @@ -control 'commands should exist' do - describe command('node -v') do - its('exit_status') { should eq 0 } - end - - describe command('npm -v') do - its('exit_status') { should eq 0 } - end - - describe command('npm list -json -global') do - its('stdout') { should match(/express/) } - its('stdout') { should match(/async@0.6.2/) } - its('stdout') { should match(/request/) } - its('stdout') { should match(/mocha/) } - end -end diff --git a/test/integration/chocolatey/inspec.yml b/test/integration/chocolatey/inspec.yml new file mode 100644 index 0000000..f08830b --- /dev/null +++ b/test/integration/chocolatey/inspec.yml @@ -0,0 +1,7 @@ +--- +name: chocolatey +title: Chocolatey Resource Tests +maintainer: Sous Chefs +license: Apache-2.0 +summary: Verifies Windows Chocolatey installation where feasible +version: 1.0.0 diff --git a/test/integration/default/controls/default_spec.rb b/test/integration/default/controls/default_spec.rb new file mode 100644 index 0000000..7d72480 --- /dev/null +++ b/test/integration/default/controls/default_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +control 'nodejs-default-01' do + impact 1.0 + title 'Node.js commands are available' + + describe command('node -v') do + its('exit_status') { should eq 0 } + its('stdout') { should match(/^v24\./) } + end + + describe command('npm -v') do + its('exit_status') { should eq 0 } + end + + describe command('npx -v') do + its('exit_status') { should eq 0 } + end +end + +control 'nodejs-default-02' do + impact 0.7 + title 'Configured npm packages are converged' + + describe command('npm list -json -global') do + its('stdout') { should_not match(/"express"/) } + its('stdout') { should match(/"socket.io"/) } + end +end diff --git a/test/integration/default/default_spec.rb b/test/integration/default/default_spec.rb deleted file mode 100644 index f40b1a3..0000000 --- a/test/integration/default/default_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -os_family = os.family - -control 'commands should exist' do - describe command('node -v') do - its('exit_status') { should eq 0 } - # No upstream repository so it installs the OS version - unless os_family == 'suse' - its('stdout') { should match /^v17\.*/ } - end - end - - describe command('npm -v') do - its('exit_status') { should eq 0 } - # No upstream repository so it installs the OS version - unless os_family == 'suse' - its('stdout') { should match /^8\.*/ } - end - end - - describe command('npx -v') do - its('exit_status') { should eq 0 } - # No upstream repository so it installs the OS version - unless os_family == 'suse' - its('stdout') { should match /^8\.*/ } - end - end - - describe command('npm list -json -global') do - its('stdout') { should_not match(/"express"/) } - its('stdout') { should match(/"socket.io"/) } - end -end diff --git a/test/integration/default/inspec.yml b/test/integration/default/inspec.yml new file mode 100644 index 0000000..222a995 --- /dev/null +++ b/test/integration/default/inspec.yml @@ -0,0 +1,7 @@ +--- +name: default +title: Default Resource Tests +maintainer: Sous Chefs +license: Apache-2.0 +summary: Verifies the default Node.js resource workflow +version: 1.0.0 diff --git a/test/integration/npm_embedded/default_spec.rb b/test/integration/npm_embedded/controls/npm_embedded_spec.rb similarity index 65% rename from test/integration/npm_embedded/default_spec.rb rename to test/integration/npm_embedded/controls/npm_embedded_spec.rb index a0b0800..acdf05c 100644 --- a/test/integration/npm_embedded/default_spec.rb +++ b/test/integration/npm_embedded/controls/npm_embedded_spec.rb @@ -1,5 +1,9 @@ +# frozen_string_literal: true + +control 'nodejs-npm-embedded-01' do + impact 1.0 + title 'Embedded npm commands are available' -control 'commands should exist' do describe command('node -v') do its('exit_status') { should eq 0 } end diff --git a/test/integration/npm_embedded/inspec.yml b/test/integration/npm_embedded/inspec.yml new file mode 100644 index 0000000..f85ce49 --- /dev/null +++ b/test/integration/npm_embedded/inspec.yml @@ -0,0 +1,7 @@ +--- +name: npm_embedded +title: Embedded npm Resource Tests +maintainer: Sous Chefs +license: Apache-2.0 +summary: Verifies embedded npm is available +version: 1.0.0 diff --git a/test/integration/npm_source/default_spec.rb b/test/integration/npm_source/controls/npm_source_spec.rb similarity index 75% rename from test/integration/npm_source/default_spec.rb rename to test/integration/npm_source/controls/npm_source_spec.rb index 7d76ecf..d52b55a 100644 --- a/test/integration/npm_source/default_spec.rb +++ b/test/integration/npm_source/controls/npm_source_spec.rb @@ -1,5 +1,9 @@ +# frozen_string_literal: true + +control 'nodejs-npm-source-01' do + impact 1.0 + title 'Source npm commands are available' -control 'commands should exist' do describe command('node -v') do its('exit_status') { should eq 0 } end diff --git a/test/integration/npm_source/inspec.yml b/test/integration/npm_source/inspec.yml new file mode 100644 index 0000000..bed39f6 --- /dev/null +++ b/test/integration/npm_source/inspec.yml @@ -0,0 +1,7 @@ +--- +name: npm_source +title: Source npm Resource Tests +maintainer: Sous Chefs +license: Apache-2.0 +summary: Verifies npm source installation +version: 1.0.0 diff --git a/test/integration/options/default_spec.rb b/test/integration/options/default_spec.rb deleted file mode 100644 index 5a947d3..0000000 --- a/test/integration/options/default_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -control 'packages should install' do - describe package('nodejs') do - it { should be_installed } - end - - describe package('acpid') do - it { should be_installed } - end - - describe package('adcli') do - it { should_not be_installed } - end -end diff --git a/test/integration/package/controls/package_spec.rb b/test/integration/package/controls/package_spec.rb new file mode 100644 index 0000000..9261bfe --- /dev/null +++ b/test/integration/package/controls/package_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +control 'nodejs-package-01' do + impact 1.0 + title 'Node.js package install is available' + + describe command('node -v') do + its('exit_status') { should eq 0 } + its('stdout') { should match(/^v24\./) } + end + + describe command('npm -v') do + its('exit_status') { should eq 0 } + end +end + +control 'nodejs-package-02' do + impact 0.7 + title 'npm_package resources install expected packages' + + describe command('npm list -json -global') do + its('stdout') { should match(/express/) } + its('stdout') { should match(/"async": {\n\s*"version": "0.6.2"/) } + its('stdout') { should match(/request/) } + its('stdout') { should match(/mocha/) } + end + + describe command('npm list xss -json -global') do + its('stdout') { should match(/"version":\s*"1.0.7"/) } + end +end diff --git a/test/integration/package/default.rb b/test/integration/package/default.rb deleted file mode 100644 index 076b3e8..0000000 --- a/test/integration/package/default.rb +++ /dev/null @@ -1,43 +0,0 @@ -control 'commands should exist' do - describe command('node -v') do - its('exit_status') { should eq 0 } - end - - describe command('npm -v') do - its('exit_status') { should eq 0 } - end - - describe file '/home/random/staging' do - it { should exist } - end - - describe command('npm list -json -global') do - its('stdout') { should match(/express/) } - its('stdout') { should match(/"async": {\n\s*"version": "0.6.2"/) } - its('stdout') { should match(/request/) } - its('stdout') { should match(/mocha/) } - end - - describe command('npm list xss -json -global') do - its('stdout') { should match(/"version":\s*"1.0.7"/) } - end - - describe command('npm list minify -json -global') do - its('stdout') { should_not match(/"version":\s*"5.2.0"/) } - end - - describe command('export NPM_TOKEN="123-abcde" && cd /home/random && npm list -json') do - its('stdout') { should match(/koa/) } - its('stdout') { should match(/gulp/) } - end - - describe command('export NPM_TOKEN="123-abcde" && cd /home/random1 && npm list -json') do - its('stdout') { should match(/koa/) } - its('stdout') { should match(/gulp/) } - end - - describe command('export NPM_TOKEN="123-abcde" && cd /home/random2 && npm list -json') do - its('stdout') { should match(/grunt/) } - its('stdout') { should match(/vary/) } - end -end diff --git a/test/integration/package/inspec.yml b/test/integration/package/inspec.yml new file mode 100644 index 0000000..75b6070 --- /dev/null +++ b/test/integration/package/inspec.yml @@ -0,0 +1,7 @@ +--- +name: package +title: Package Resource Tests +maintainer: Sous Chefs +license: Apache-2.0 +summary: Verifies package install and npm package resources +version: 1.0.0 diff --git a/test/integration/source/default.rb b/test/integration/source/controls/source_spec.rb similarity index 69% rename from test/integration/source/default.rb rename to test/integration/source/controls/source_spec.rb index 924229b..2b4b4f9 100644 --- a/test/integration/source/default.rb +++ b/test/integration/source/controls/source_spec.rb @@ -1,16 +1,18 @@ -control 'commands should exist' do +# frozen_string_literal: true + +control 'nodejs-source-01' do + impact 1.0 + title 'Node.js source install is available' + describe command('node -v') do its('exit_status') { should eq 0 } + its('stdout') { should match(/^v24\./) } end describe command('npm -v') do its('exit_status') { should eq 0 } end - describe file '/home/random/staging' do - it { should exist } - end - describe command('npx -v') do its('exit_status') { should eq 0 } end diff --git a/test/integration/source/inspec.yml b/test/integration/source/inspec.yml new file mode 100644 index 0000000..3a9af7e --- /dev/null +++ b/test/integration/source/inspec.yml @@ -0,0 +1,7 @@ +--- +name: source +title: Source Resource Tests +maintainer: Sous Chefs +license: Apache-2.0 +summary: Verifies source installation +version: 1.0.0 From 64822535f4e0aab07b95866bf2798ee6f540ecfa Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Wed, 29 Apr 2026 14:26:47 +0100 Subject: [PATCH 03/10] fix: satisfy markdown and cookstyle lint --- .markdownlint-cli2.yaml | 3 ++ .rubocop.yml | 4 +++ CHANGELOG.md | 20 ++++++------ CONTRIBUTING.md | 2 +- LIMITATIONS.md | 28 ++++++++--------- README.md | 46 ++++++++++++++-------------- documentation/nodejs_install.md | 44 +++++++++++++------------- documentation/nodejs_npm_install.md | 30 +++++++++--------- documentation/nodejs_npm_package.md | 38 +++++++++++------------ documentation/nodejs_npm_packages.md | 12 ++++---- documentation/nodejs_repository.md | 36 +++++++++++----------- migration.md | 20 ++++++------ 12 files changed, 145 insertions(+), 138 deletions(-) diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml index ac5076b..9b06cfe 100644 --- a/.markdownlint-cli2.yaml +++ b/.markdownlint-cli2.yaml @@ -3,7 +3,10 @@ config: line-length: false # MD013 no-duplicate-heading: false # MD024 reference-links-images: false # MD052 + ul-style: + style: asterisk no-multiple-blanks: maximum: 2 ignores: - .github/copilot-instructions.md + - .windsurf/** diff --git a/.rubocop.yml b/.rubocop.yml index 6188300..24bbe45 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,2 +1,6 @@ require: - cookstyle + +AllCops: + Exclude: + - 'vendor/**/*' diff --git a/CHANGELOG.md b/CHANGELOG.md index fb58132..ab0614a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -321,13 +321,13 @@ Standardise files with files in sous-chefs/repo-management * added packages installation support ([@smith]) -[@bakins]: https://github.com/bakins -[@chrislundquist]: https://github.com/ChrisLundquist -[@johannesbecker]: https://github.com/johannesbecker -[@julesau]: https://github.com/JulesAU -[@markbirbeck]: https://github.com/markbirbeck -[@robertkowalski]: https://github.com/robertkowalski -[@sax]: https://github.com/sax -[@smith]: https://github.com/smith -[@vaskas]: https://github.com/vaskas -[@wanelo-pair]: https://github.com/wanelo-pair +[@bakins]: +[@chrislundquist]: +[@johannesbecker]: +[@julesau]: +[@markbirbeck]: +[@robertkowalski]: +[@sax]: +[@smith]: +[@vaskas]: +[@wanelo-pair]: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c76e180..0827d47 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ # Contributing Please refer to -[https://github.com/chef-cookbooks/community_cookbook_documentation/blob/main/CONTRIBUTING.MD](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/main/CONTRIBUTING.MD) +[) diff --git a/LIMITATIONS.md b/LIMITATIONS.md index fbb335a..24b8e6f 100644 --- a/LIMITATIONS.md +++ b/LIMITATIONS.md @@ -4,11 +4,11 @@ This cookbook defaults to Node.js 24 LTS, using Node.js v24.15.0 checksums from Sources checked on 2026-04-29: -* Node.js release schedule: https://github.com/nodejs/Release/blob/main/schedule.json -* Node.js latest v24 artifacts: https://nodejs.org/dist/latest-v24.x/ -* Node.js v24 checksums: https://nodejs.org/dist/latest-v24.x/SHASUMS256.txt -* NodeSource distributions page: https://nodesource.com/products/distributions -* NodeSource distributions repository: https://github.com/nodesource/distributions +* Node.js release schedule: +* Node.js latest v24 artifacts: +* Node.js v24 checksums: +* NodeSource distributions page: +* NodeSource distributions repository: ## Package Availability @@ -26,7 +26,7 @@ The cookbook only declares currently supported, non-EOL Debian/Ubuntu platforms NodeSource documents RPM packages for RHEL 8/9, Fedora 29+, and Amazon Linux 2023 on `x86_64` and `arm64`. The repository URL pattern used by this cookbook is: ```text -https://rpm.nodesource.com/pub_.x/nodistro/nodejs/$basearch +>.x/nodistro/nodejs/$basearch ``` The cookbook declares AlmaLinux, Amazon Linux 2023, CentOS Stream, Fedora, Oracle Linux, Red Hat, and Rocky Linux where current test images are available. @@ -43,10 +43,10 @@ Windows support is limited to `nodejs_install` with `install_method 'chocolatey' Official Node.js v24.15.0 source and binary checksums pinned by this cookbook: -| Artifact | SHA256 | -|----------|--------| -| `node-v24.15.0.tar.gz` | `729de494dd2872e5a3a6c32a1cd156a5413d4aca2772b2d873ee86bb5531bcd9` | -| `node-v24.15.0-linux-x64.tar.gz` | `44836872d9aec49f1e6b52a9a922872db9a2b02d235a616a5681b6a85fec8d89` | +| Artifact | SHA256 | +| ---------------------------------- | ------------------------------------------------------------------ | +| `node-v24.15.0.tar.gz` | `729de494dd2872e5a3a6c32a1cd156a5413d4aca2772b2d873ee86bb5531bcd9` | +| `node-v24.15.0-linux-x64.tar.gz` | `44836872d9aec49f1e6b52a9a922872db9a2b02d235a616a5681b6a85fec8d89` | | `node-v24.15.0-linux-arm64.tar.gz` | `73afc234d558c24919875f51c2d1ea002a2ada4ea6f83601a383869fefa64eed` | The `nodejs_install` binary action currently models Linux `x64` and `arm64` checksums. Other official Node.js artifacts can be installed by passing `binary_url` and the matching checksum. @@ -55,11 +55,11 @@ The `nodejs_install` binary action currently models Linux `x64` and `arm64` chec ### Build Dependencies -| Platform Family | Packages | -|-----------------|----------| -| Debian | `build-essential`, `libssl-dev`, `python3` | +| Platform Family | Packages | +| ------------------ | ---------------------------------------------------- | +| Debian | `build-essential`, `libssl-dev`, `python3` | | RHEL/Fedora/Amazon | `build-essential`, `openssl-devel`, `python3`, `tar` | -| Other | `build-essential`, `python3` | +| Other | `build-essential`, `python3` | Source builds are much slower than package or binary installs and are not used as the default Kitchen smoke path. diff --git a/README.md b/README.md index e3bb4c5..cb114a7 100644 --- a/README.md +++ b/README.md @@ -16,19 +16,19 @@ This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of ### Platforms -- Debian/Ubuntu -- RHEL family/Fedora/Amazon Linux -- macOS where platform packages are available -- Windows through Chocolatey +* Debian/Ubuntu +* RHEL family/Fedora/Amazon Linux +* macOS where platform packages are available +* Windows through Chocolatey ### Chef -- Chef Infra Client 15.3+ +* Chef Infra Client 15.3+ ### Cookbooks -- ark -- chocolatey +* ark +* chocolatey ## Usage @@ -77,11 +77,11 @@ See [migration.md](migration.md) for the breaking recipe/attribute migration gui ## Resources -- [nodejs_install](documentation/nodejs_install.md) -- [nodejs_repository](documentation/nodejs_repository.md) -- [nodejs_npm_install](documentation/nodejs_npm_install.md) -- [nodejs_npm_packages](documentation/nodejs_npm_packages.md) -- [npm_package](documentation/nodejs_npm_package.md) +* [nodejs_install](documentation/nodejs_install.md) +* [nodejs_repository](documentation/nodejs_repository.md) +* [nodejs_npm_install](documentation/nodejs_npm_install.md) +* [nodejs_npm_packages](documentation/nodejs_npm_packages.md) +* [npm_package](documentation/nodejs_npm_package.md) ## Contributors @@ -91,19 +91,19 @@ This project exists thanks to all the people who [contribute.](https://opencolle Thank you to all our backers! -![https://opencollective.com/sous-chefs#backers](https://opencollective.com/sous-chefs/backers.svg?width=600&avatarHeight=40) +![) ### Sponsors Support this project by becoming a sponsor. Your logo will show up here with a link to your website. -![https://opencollective.com/sous-chefs/sponsor/0/website](https://opencollective.com/sous-chefs/sponsor/0/avatar.svg?avatarHeight=100) -![https://opencollective.com/sous-chefs/sponsor/1/website](https://opencollective.com/sous-chefs/sponsor/1/avatar.svg?avatarHeight=100) -![https://opencollective.com/sous-chefs/sponsor/2/website](https://opencollective.com/sous-chefs/sponsor/2/avatar.svg?avatarHeight=100) -![https://opencollective.com/sous-chefs/sponsor/3/website](https://opencollective.com/sous-chefs/sponsor/3/avatar.svg?avatarHeight=100) -![https://opencollective.com/sous-chefs/sponsor/4/website](https://opencollective.com/sous-chefs/sponsor/4/avatar.svg?avatarHeight=100) -![https://opencollective.com/sous-chefs/sponsor/5/website](https://opencollective.com/sous-chefs/sponsor/5/avatar.svg?avatarHeight=100) -![https://opencollective.com/sous-chefs/sponsor/6/website](https://opencollective.com/sous-chefs/sponsor/6/avatar.svg?avatarHeight=100) -![https://opencollective.com/sous-chefs/sponsor/7/website](https://opencollective.com/sous-chefs/sponsor/7/avatar.svg?avatarHeight=100) -![https://opencollective.com/sous-chefs/sponsor/8/website](https://opencollective.com/sous-chefs/sponsor/8/avatar.svg?avatarHeight=100) -![https://opencollective.com/sous-chefs/sponsor/9/website](https://opencollective.com/sous-chefs/sponsor/9/avatar.svg?avatarHeight=100) +![) +![) +![) +![) +![) +![) +![) +![) +![) +![) diff --git a/documentation/nodejs_install.md b/documentation/nodejs_install.md index cbbc788..6875081 100644 --- a/documentation/nodejs_install.md +++ b/documentation/nodejs_install.md @@ -4,31 +4,31 @@ Installs Node.js from packages, official binaries, source, or Chocolatey. ## Actions -| Action | Description | -|--------|-------------| -| `:install` | Installs Node.js. Default. | -| `:remove` | Removes artifacts created by the selected install method. | +| Action | Description | +| ---------- | --------------------------------------------------------- | +| `:install` | Installs Node.js. Default. | +| `:remove` | Removes artifacts created by the selected install method. | ## Properties -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `version` | String | `'24.15.0'` | Node.js version for source, binary, and Chocolatey installs. | -| `install_method` | String | platform default | One of `package`, `binary`, `source`, or `chocolatey`. | -| `install_repository` | true, false | `true` | Configures NodeSource repositories for package installs. | -| `packages` | Array, nil | platform default | Package names to install for package installs. | -| `package_action` | Symbol, String | `:install` | Action passed to package resources. | -| `package_options` | String, nil | `nil` | Options passed to package resources. | -| `disable_dnf_module` | true, false | `true` | Disables the distro Node.js DNF module on EL/Fedora 8+. | -| `prefix_url` | String | `'https://nodejs.org/dist/'` | Base URL for official Node.js source and binary artifacts. | -| `source_url` | String, nil | `nil` | Override URL for source installs. | -| `source_checksum` | String, nil | official v24.15.0 checksum | Source tarball checksum. | -| `binary_url` | String, nil | `nil` | Override URL for binary installs. | -| `binary_checksums` | Hash | official v24.15.0 checksums | Binary checksums by architecture key. | -| `append_env_path` | true, false | `true` | Passed to `ark` for binary installs. | -| `make_threads` | Integer, String, nil | CPU count | Parallel make jobs for source installs. | -| `build_packages` | Array, nil | platform default | Build dependency package list for source installs. | -| `chocolatey_package_name` | String | `'nodejs-lts'` | Chocolatey package name for Windows installs. | +| Property | Type | Default | Description | +| ------------------------- | -------------------- | ------------------------------ | ------------------------------------------------------------ | +| `version` | String | `'24.15.0'` | Node.js version for source, binary, and Chocolatey installs. | +| `install_method` | String | platform default | One of `package`, `binary`, `source`, or `chocolatey`. | +| `install_repository` | true, false | `true` | Configures NodeSource repositories for package installs. | +| `packages` | Array, nil | platform default | Package names to install for package installs. | +| `package_action` | Symbol, String | `:install` | Action passed to package resources. | +| `package_options` | String, nil | `nil` | Options passed to package resources. | +| `disable_dnf_module` | true, false | `true` | Disables the distro Node.js DNF module on EL/Fedora 8+. | +| `prefix_url` | String | `' | Base URL for official Node.js source and binary artifacts. | +| `source_url` | String, nil | `nil` | Override URL for source installs. | +| `source_checksum` | String, nil | official v24.15.0 checksum | Source tarball checksum. | +| `binary_url` | String, nil | `nil` | Override URL for binary installs. | +| `binary_checksums` | Hash | official v24.15.0 checksums | Binary checksums by architecture key. | +| `append_env_path` | true, false | `true` | Passed to `ark` for binary installs. | +| `make_threads` | Integer, String, nil | CPU count | Parallel make jobs for source installs. | +| `build_packages` | Array, nil | platform default | Build dependency package list for source installs. | +| `chocolatey_package_name` | String | `'nodejs-lts'` | Chocolatey package name for Windows installs. | ## Examples diff --git a/documentation/nodejs_npm_install.md b/documentation/nodejs_npm_install.md index 64506e4..9270170 100644 --- a/documentation/nodejs_npm_install.md +++ b/documentation/nodejs_npm_install.md @@ -4,24 +4,24 @@ Ensures npm is available through the embedded Node.js npm or installs npm from s ## Actions -| Action | Description | -|--------|-------------| -| `:install` | Installs npm. Default. | -| `:remove` | Removes npm artifacts created by source installs. | +| Action | Description | +| ---------- | ------------------------------------------------- | +| `:install` | Installs npm. Default. | +| `:remove` | Removes npm artifacts created by source installs. | ## Properties -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `install_method` | String | `'embedded'` | One of `embedded` or `source`. | -| `install_node` | true, false | `true` | Installs Node.js before npm. | -| `node_install_method` | String | `'package'` | Node.js install method when `install_node` is true. | -| `version` | String | `'24.15.0'` | Node.js version passed to `nodejs_install`. | -| `prefix_url` | String | `'https://nodejs.org/dist/'` | Node.js artifact base URL passed to `nodejs_install`. | -| `npm_version` | String | `'latest'` | npm version resolved from the npm registry for source installs. | -| `npm_url` | String, nil | `nil` | Override npm tarball URL. | -| `npm_checksum` | String, nil | `nil` | Optional npm tarball checksum. | -| `make_threads` | Integer, String, nil | CPU count | Parallel make jobs for source installs. | +| Property | Type | Default | Description | +| --------------------- | -------------------- | ------------------------------ | --------------------------------------------------------------- | +| `install_method` | String | `'embedded'` | One of `embedded` or `source`. | +| `install_node` | true, false | `true` | Installs Node.js before npm. | +| `node_install_method` | String | `'package'` | Node.js install method when `install_node` is true. | +| `version` | String | `'24.15.0'` | Node.js version passed to `nodejs_install`. | +| `prefix_url` | String | `' | Node.js artifact base URL passed to `nodejs_install`. | +| `npm_version` | String | `'latest'` | npm version resolved from the npm registry for source installs. | +| `npm_url` | String, nil | `nil` | Override npm tarball URL. | +| `npm_checksum` | String, nil | `nil` | Optional npm tarball checksum. | +| `make_threads` | Integer, String, nil | CPU count | Parallel make jobs for source installs. | ## Examples diff --git a/documentation/nodejs_npm_package.md b/documentation/nodejs_npm_package.md index 5420db2..cfa853f 100644 --- a/documentation/nodejs_npm_package.md +++ b/documentation/nodejs_npm_package.md @@ -4,28 +4,28 @@ Installs or removes an npm package. The legacy `nodejs_npm` alias is retained. ## Actions -| Action | Description | -|--------|-------------| -| `:install` | Installs or updates an npm package. Default. | -| `:uninstall` | Uninstalls an npm package if present. | -| `:remove` | Alias-style remove action for uninstalling an npm package. | +| Action | Description | +| ------------ | ---------------------------------------------------------- | +| `:install` | Installs or updates an npm package. Default. | +| `:uninstall` | Uninstalls an npm package if present. | +| `:remove` | Alias-style remove action for uninstalling an npm package. | ## Properties -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `package` | String | name property | npm package name. | -| `version` | String | `nil` | npm package version. | -| `path` | String | `nil` | Local project path. Omit for global installs. | -| `url` | String | `nil` | Package URL or git source. | -| `json` | String, true, false | `nil` | Install from `package.json` or a provided JSON/tarball source. | -| `npm_token` | String | `nil` | Sensitive NPM token exposed as `NPM_TOKEN`. | -| `options` | Array | `[]` | Extra npm CLI options. | -| `user` | String | `nil` | User for the npm command. | -| `group` | String | `nil` | Group for the npm command. | -| `live_stream` | true, false | `false` | Streams npm output to the Chef log. | -| `node_env` | String | `nil` | `NODE_ENV` value for the npm command. | -| `auto_update` | true, false | `true` | When false, skips install if the matching package is already installed. | +| Property | Type | Default | Description | +| ------------- | ------------------- | ------------- | ----------------------------------------------------------------------- | +| `package` | String | name property | npm package name. | +| `version` | String | `nil` | npm package version. | +| `path` | String | `nil` | Local project path. Omit for global installs. | +| `url` | String | `nil` | Package URL or git source. | +| `json` | String, true, false | `nil` | Install from `package.json` or a provided JSON/tarball source. | +| `npm_token` | String | `nil` | Sensitive NPM token exposed as `NPM_TOKEN`. | +| `options` | Array | `[]` | Extra npm CLI options. | +| `user` | String | `nil` | User for the npm command. | +| `group` | String | `nil` | Group for the npm command. | +| `live_stream` | true, false | `false` | Streams npm output to the Chef log. | +| `node_env` | String | `nil` | `NODE_ENV` value for the npm command. | +| `auto_update` | true, false | `true` | When false, skips install if the matching package is already installed. | ## Examples diff --git a/documentation/nodejs_npm_packages.md b/documentation/nodejs_npm_packages.md index a0813c8..eaee21f 100644 --- a/documentation/nodejs_npm_packages.md +++ b/documentation/nodejs_npm_packages.md @@ -4,16 +4,16 @@ Installs or removes a collection of npm packages. ## Actions -| Action | Description | -|--------|-------------| +| Action | Description | +| ---------- | ---------------------------------------------------------------- | | `:install` | Converges each package entry with its requested action. Default. | -| `:remove` | Removes each listed package. | +| `:remove` | Removes each listed package. | ## Properties -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `packages` | Array | `[]` | Array of package hashes. Use `name` for package name and any `npm_package` property for options. | +| Property | Type | Default | Description | +| ---------- | ------ | --------- | ------------------------------------------------------------------------------------------------ | +| `packages` | Array | `[]` | Array of package hashes. Use `name` for package name and any `npm_package` property for options. | ## Examples diff --git a/documentation/nodejs_repository.md b/documentation/nodejs_repository.md index 3c3686b..68d91bf 100644 --- a/documentation/nodejs_repository.md +++ b/documentation/nodejs_repository.md @@ -4,28 +4,28 @@ Configures NodeSource package repositories. ## Actions -| Action | Description | -|--------|-------------| -| `:create` | Creates the NodeSource repository. Default. | +| Action | Description | +| --------- | ---------------------------------------------------------- | +| `:create` | Creates the NodeSource repository. Default. | | `:remove` | Removes the NodeSource repository and managed APT keyring. | ## Properties -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `repo_name` | String | name property | Repository name. | -| `node_major` | String, Integer | `'24'` | Node.js major version used in repository URLs. | -| `apt_uri` | String | generated | APT repository URI override. | -| `apt_distribution` | String | `'nodistro'` | APT distribution. | -| `apt_components` | Array | `['main']` | APT components. | -| `apt_key` | String | NodeSource DEB key URL | APT signing key URL. | -| `apt_keyring` | String | `'/etc/apt/keyrings/nodesource.asc'` | Managed APT keyring path. | -| `apt_pin_priority` | String | `'600'` | APT preference priority for NodeSource. | -| `yum_baseurl` | String | generated | YUM/DNF base URL override. | -| `yum_gpgkey` | String | NodeSource RPM key URL | RPM signing key URL. | -| `yum_priority` | String | `'9'` | YUM repository priority. | -| `enabled` | true, false | `true` | Enables the YUM/DNF repository. | -| `gpgcheck` | true, false | `true` | Enables package GPG checks. | +| Property | Type | Default | Description | +| ------------------ | --------------- | ------------------------------------ | ---------------------------------------------- | +| `repo_name` | String | name property | Repository name. | +| `node_major` | String, Integer | `'24'` | Node.js major version used in repository URLs. | +| `apt_uri` | String | generated | APT repository URI override. | +| `apt_distribution` | String | `'nodistro'` | APT distribution. | +| `apt_components` | Array | `['main']` | APT components. | +| `apt_key` | String | NodeSource DEB key URL | APT signing key URL. | +| `apt_keyring` | String | `'/etc/apt/keyrings/nodesource.asc'` | Managed APT keyring path. | +| `apt_pin_priority` | String | `'600'` | APT preference priority for NodeSource. | +| `yum_baseurl` | String | generated | YUM/DNF base URL override. | +| `yum_gpgkey` | String | NodeSource RPM key URL | RPM signing key URL. | +| `yum_priority` | String | `'9'` | YUM repository priority. | +| `enabled` | true, false | `true` | Enables the YUM/DNF repository. | +| `gpgcheck` | true, false | `true` | Enables package GPG checks. | ## Examples diff --git a/migration.md b/migration.md index daa5861..c23f8be 100644 --- a/migration.md +++ b/migration.md @@ -8,16 +8,16 @@ The cookbook no longer exposes `nodejs::default`, `nodejs::install`, `nodejs::re ## Recipe to Resource Mapping -| Before | After | -|--------|-------| -| `include_recipe 'nodejs::default'` | `nodejs_install 'nodejs'` plus optional `nodejs_npm_packages` | -| `include_recipe 'nodejs::repo'` | `nodejs_repository 'nodesource'` | -| `include_recipe 'nodejs::nodejs_from_package'` | `nodejs_install 'nodejs' do install_method 'package' end` | -| `include_recipe 'nodejs::nodejs_from_binary'` | `nodejs_install 'nodejs' do install_method 'binary' end` | -| `include_recipe 'nodejs::nodejs_from_source'` | `nodejs_install 'nodejs' do install_method 'source' end` | -| `include_recipe 'nodejs::nodejs_from_chocolatey'` | `nodejs_install 'nodejs' do install_method 'chocolatey' end` | -| `include_recipe 'nodejs::npm'` | `nodejs_npm_install 'npm'` | -| `node['nodejs']['npm_packages']` | `nodejs_npm_packages 'packages'` | +| Before | After | +| ------------------------------------------------- | ------------------------------------------------------------- | +| `include_recipe 'nodejs::default'` | `nodejs_install 'nodejs'` plus optional `nodejs_npm_packages` | +| `include_recipe 'nodejs::repo'` | `nodejs_repository 'nodesource'` | +| `include_recipe 'nodejs::nodejs_from_package'` | `nodejs_install 'nodejs' do install_method 'package' end` | +| `include_recipe 'nodejs::nodejs_from_binary'` | `nodejs_install 'nodejs' do install_method 'binary' end` | +| `include_recipe 'nodejs::nodejs_from_source'` | `nodejs_install 'nodejs' do install_method 'source' end` | +| `include_recipe 'nodejs::nodejs_from_chocolatey'` | `nodejs_install 'nodejs' do install_method 'chocolatey' end` | +| `include_recipe 'nodejs::npm'` | `nodejs_npm_install 'npm'` | +| `node['nodejs']['npm_packages']` | `nodejs_npm_packages 'packages'` | ## Examples From 07eb78aebc23b31d2292bef00433631f40d5dbb3 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Wed, 29 Apr 2026 14:48:58 +0100 Subject: [PATCH 04/10] fix: skip unavailable nodejs dnf module --- resources/nodejs_install.rb | 7 +++++- spec/unit/resources/nodejs_install_spec.rb | 26 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/resources/nodejs_install.rb b/resources/nodejs_install.rb index 5d26f55..33a0258 100644 --- a/resources/nodejs_install.rb +++ b/resources/nodejs_install.rb @@ -116,6 +116,11 @@ def resolved_packages def disable_dnf_module? new_resource.disable_dnf_module && platform_family?('rhel', 'fedora') && - node['platform_version'].to_i >= 8 + node['platform_version'].to_i >= 8 && + dnf_module_available?('nodejs') + end + + def dnf_module_available?(module_name) + shell_out!("dnf -q module list #{module_name}", returns: [0, 1]).stdout.match?(/^#{Regexp.escape(module_name)}\s/m) end end diff --git a/spec/unit/resources/nodejs_install_spec.rb b/spec/unit/resources/nodejs_install_spec.rb index 2c760e5..897a58a 100644 --- a/spec/unit/resources/nodejs_install_spec.rb +++ b/spec/unit/resources/nodejs_install_spec.rb @@ -23,11 +23,37 @@ nodejs_install 'nodejs' end + before do + stubs_for_provider('nodejs_install[nodejs]') do |provider| + allow(provider).to receive_shell_out('dnf -q module list nodejs', returns: [0, 1]) + .and_return(double(stdout: "nodejs 20 common [d]\n", error!: nil)) + end + end + it { is_expected.to disable_dnf_module('nodejs') } it { is_expected.to install_package('nodejs') } it { is_expected.to install_package('nodejs-devel') } end + context 'package install when the nodejs dnf module is unavailable' do + platform 'rocky', '9' + + recipe do + nodejs_install 'nodejs' + end + + before do + stubs_for_provider('nodejs_install[nodejs]') do |provider| + allow(provider).to receive_shell_out('dnf -q module list nodejs', returns: [0, 1]) + .and_return(double(stdout: '', error!: nil)) + end + end + + it { is_expected.not_to disable_dnf_module('nodejs') } + it { is_expected.to install_package('nodejs') } + it { is_expected.to install_package('nodejs-devel') } + end + context 'binary install' do platform 'ubuntu', '24.04' From f80c12da1add61697b2ada1030f0fba0cbb64301 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Wed, 29 Apr 2026 22:52:20 +0100 Subject: [PATCH 05/10] fix: stabilize nodejs integration suites --- resources/npm_package.rb | 6 ++++++ test/cookbooks/test/recipes/resource.rb | 14 +++++++++++++- test/cookbooks/test/recipes/source.rb | 2 ++ test/integration/source/controls/source_spec.rb | 2 +- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/resources/npm_package.rb b/resources/npm_package.rb index 675d14a..f2f2434 100644 --- a/resources/npm_package.rb +++ b/resources/npm_package.rb @@ -73,9 +73,15 @@ def npm_env_vars end def package_installed? + return package_json_installed? if new_resource.json == true + new_resource.package && npm_package_installed?(new_resource.package, new_resource.version, new_resource.path, npm_env_vars) end + def package_json_installed? + new_resource.path && ::File.exist?(::File.join(new_resource.path, 'node_modules')) + end + def no_auto_update? new_resource.package && !new_resource.auto_update end diff --git a/test/cookbooks/test/recipes/resource.rb b/test/cookbooks/test/recipes/resource.rb index e1ca353..4d332b6 100644 --- a/test/cookbooks/test/recipes/resource.rb +++ b/test/cookbooks/test/recipes/resource.rb @@ -24,14 +24,18 @@ end # global "express" using the old resource alias -nodejs_npm 'express' +nodejs_npm 'express' do + auto_update false +end npm_package 'async' do version '0.6.2' + auto_update false end npm_package 'xss' do version '1.0.7' + auto_update false end npm_package 'xss noupgrade' do @@ -41,20 +45,24 @@ npm_package 'minify' do version '5.2.0' + auto_update false end npm_package 'minify upgrade' do package 'minify' live_stream true + auto_update false end npm_package 'request' do url 'github mikeal/request' live_stream true + auto_update false end npm_package 'mocha' do options ['--force', '--production'] + auto_update false end git '/home/random2/grunt' do @@ -71,6 +79,7 @@ package 'grunt' json '/home/random2/grunt' user 'random2' + auto_update false end npm_package 'Install the vary package from a tgz url' do @@ -78,6 +87,7 @@ package 'vary' json 'https://registry.npmjs.org/vary/-/vary-1.1.2.tgz' user 'random2' + auto_update false end directory '/home/random/.npm' do @@ -105,6 +115,7 @@ user 'random' npm_token '123-abcde' node_env 'staging' # Test node_env usage + auto_update false end directory '/home/random1/.npm' do @@ -132,4 +143,5 @@ npm_token '123-abcde' options ['--development'] node_env 'development' + auto_update false end diff --git a/test/cookbooks/test/recipes/source.rb b/test/cookbooks/test/recipes/source.rb index 628421d..8aa2b19 100644 --- a/test/cookbooks/test/recipes/source.rb +++ b/test/cookbooks/test/recipes/source.rb @@ -7,6 +7,8 @@ nodejs_install 'nodejs from source' do install_method 'source' + version '20.20.2' + source_checksum '8cb85a81f75169eb811f7b2512cf17a646826430debbe016a7461f31e286fdef' end include_recipe 'test::resource' diff --git a/test/integration/source/controls/source_spec.rb b/test/integration/source/controls/source_spec.rb index 2b4b4f9..d9b1ed4 100644 --- a/test/integration/source/controls/source_spec.rb +++ b/test/integration/source/controls/source_spec.rb @@ -6,7 +6,7 @@ describe command('node -v') do its('exit_status') { should eq 0 } - its('stdout') { should match(/^v24\./) } + its('stdout') { should match(/^v20\./) } end describe command('npm -v') do From 580c949159f275c3ef0a2b048dd363e978819703 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 19 May 2026 08:55:13 +0100 Subject: [PATCH 06/10] fix: align nodejs workflow permissions --- .github/workflows/ci.yml | 3 +-- .github/workflows/conventional-commits.yml | 2 ++ .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/prevent-file-change.yml | 2 ++ .github/workflows/release.yml | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f00ef47..113d819 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,11 +10,10 @@ jobs: lint-unit: uses: sous-chefs/.github/.github/workflows/lint-unit.yml@6.0.0 permissions: - actions: write + contents: read checks: write pull-requests: write statuses: write - issues: write integration: needs: lint-unit diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index 09ccfaf..0e8d908 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -12,3 +12,5 @@ name: conventional-commits jobs: conventional-commits: uses: sous-chefs/.github/.github/workflows/conventional-commits.yml@6.0.0 + permissions: + pull-requests: read diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index dfc8e8f..2bbd6ad 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -19,6 +19,6 @@ jobs: - name: Check out code uses: actions/checkout@v6 - name: Install Chef - uses: actionshub/chef-install@main + uses: sous-chefs/.github/.github/actions/install-workstation@6.0.0 - name: Install cookbooks run: berks install diff --git a/.github/workflows/prevent-file-change.yml b/.github/workflows/prevent-file-change.yml index 80d64d7..5d180fa 100644 --- a/.github/workflows/prevent-file-change.yml +++ b/.github/workflows/prevent-file-change.yml @@ -12,5 +12,7 @@ name: prevent-file-change jobs: prevent-file-change: uses: sous-chefs/.github/.github/workflows/prevent-file-change.yml@6.0.0 + permissions: + pull-requests: write secrets: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e892f26..fb4d96f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,8 +10,8 @@ permissions: contents: write issues: write pull-requests: write - packages: write attestations: write + artifact-metadata: write id-token: write jobs: From 967ad7ebe76690648232478c59603c647e6cd97e Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 19 May 2026 09:03:21 +0100 Subject: [PATCH 07/10] fix: install git in nodejs test cookbook --- test/cookbooks/test/recipes/resource.rb | 3 ++- test/cookbooks/test/recipes/resource_win.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/cookbooks/test/recipes/resource.rb b/test/cookbooks/test/recipes/resource.rb index 4d332b6..f4c19df 100644 --- a/test/cookbooks/test/recipes/resource.rb +++ b/test/cookbooks/test/recipes/resource.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true apt_update 'update' if platform_family?('debian') -include_recipe 'git' + +package 'git' nodejs_npm_install 'embedded npm' do install_method 'embedded' diff --git a/test/cookbooks/test/recipes/resource_win.rb b/test/cookbooks/test/recipes/resource_win.rb index 3ab6a81..3698914 100644 --- a/test/cookbooks/test/recipes/resource_win.rb +++ b/test/cookbooks/test/recipes/resource_win.rb @@ -5,7 +5,7 @@ install_node false end -include_recipe 'git' +chocolatey_package 'git' user 'random' do manage_home true From 32a5dd39bfb937508282cd786020d99f27cc801b Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 19 May 2026 09:18:15 +0100 Subject: [PATCH 08/10] fix: handle python for nodejs source builds --- libraries/nodejs_helper.rb | 4 +++ resources/nodejs_install.rb | 18 ++++++++++++- spec/unit/resources/nodejs_install_spec.rb | 30 +++++++++++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/libraries/nodejs_helper.rb b/libraries/nodejs_helper.rb index f8106f4..dac0824 100644 --- a/libraries/nodejs_helper.rb +++ b/libraries/nodejs_helper.rb @@ -47,6 +47,10 @@ def default_build_packages end end + def dnf_python_package?(package_name) + package_name == 'python3' && platform_family?('rhel', 'fedora', 'amazon') + end + def default_make_threads node['cpu'] ? node['cpu']['total'].to_i : 2 end diff --git a/resources/nodejs_install.rb b/resources/nodejs_install.rb index 33a0258..7b5683f 100644 --- a/resources/nodejs_install.rb +++ b/resources/nodejs_install.rb @@ -56,7 +56,23 @@ when 'source' build_essential 'install build tools' - package(new_resource.build_packages || default_build_packages) + (new_resource.build_packages || default_build_packages).each do |pkg| + if dnf_python_package?(pkg) + execute 'install python3 build package' do + command 'dnf -y install python3' + not_if 'command -v python3' + only_if 'command -v dnf' + end + else + package pkg + end + end + + link '/usr/local/bin/python' do + to '/usr/bin/python3' + not_if 'command -v python' + only_if 'command -v python3' + end ark 'nodejs-source' do url nodejs_source_url(new_resource.version, new_resource.prefix_url, new_resource.source_url) diff --git a/spec/unit/resources/nodejs_install_spec.rb b/spec/unit/resources/nodejs_install_spec.rb index 897a58a..945b006 100644 --- a/spec/unit/resources/nodejs_install_spec.rb +++ b/spec/unit/resources/nodejs_install_spec.rb @@ -76,11 +76,39 @@ end end + before do + stub_command('command -v python').and_return(false) + stub_command('command -v python3').and_return(true) + end + it { is_expected.to install_build_essential('install build tools') } - it { is_expected.to install_package(%w(libssl-dev python3)) } + it { is_expected.to install_package('libssl-dev') } + it { is_expected.to install_package('python3') } + it { is_expected.to create_link('/usr/local/bin/python') } it { is_expected.to install_with_make_ark('nodejs-source') } end + context 'source install on rocky linux' do + platform 'rocky', '9' + + recipe do + nodejs_install 'nodejs' do + install_method 'source' + end + end + + before do + stub_command('command -v dnf').and_return(true) + stub_command('command -v python').and_return(false) + stub_command('command -v python3').and_return(false) + end + + it { is_expected.to install_package('openssl-devel') } + it { is_expected.to install_package('tar') } + it { is_expected.to run_execute('install python3 build package') } + it { is_expected.not_to install_package('python3') } + end + context 'chocolatey install' do platform 'windows', '2022' From b24c6780df6bab67d801cc28bd89b43385884304 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 19 May 2026 09:23:11 +0100 Subject: [PATCH 09/10] fix: guard source python symlink portably --- resources/nodejs_install.rb | 4 ++-- spec/unit/resources/nodejs_install_spec.rb | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/resources/nodejs_install.rb b/resources/nodejs_install.rb index 7b5683f..2da3dc6 100644 --- a/resources/nodejs_install.rb +++ b/resources/nodejs_install.rb @@ -70,8 +70,8 @@ link '/usr/local/bin/python' do to '/usr/bin/python3' - not_if 'command -v python' - only_if 'command -v python3' + not_if { ::File.exist?('/usr/bin/python') || ::File.exist?('/usr/local/bin/python') } + only_if { ::File.exist?('/usr/bin/python3') } end ark 'nodejs-source' do diff --git a/spec/unit/resources/nodejs_install_spec.rb b/spec/unit/resources/nodejs_install_spec.rb index 945b006..dc6f598 100644 --- a/spec/unit/resources/nodejs_install_spec.rb +++ b/spec/unit/resources/nodejs_install_spec.rb @@ -77,8 +77,10 @@ end before do - stub_command('command -v python').and_return(false) - stub_command('command -v python3').and_return(true) + allow(::File).to receive(:exist?).and_call_original + allow(::File).to receive(:exist?).with('/usr/bin/python').and_return(false) + allow(::File).to receive(:exist?).with('/usr/local/bin/python').and_return(false) + allow(::File).to receive(:exist?).with('/usr/bin/python3').and_return(true) end it { is_expected.to install_build_essential('install build tools') } @@ -99,8 +101,11 @@ before do stub_command('command -v dnf').and_return(true) - stub_command('command -v python').and_return(false) stub_command('command -v python3').and_return(false) + allow(::File).to receive(:exist?).and_call_original + allow(::File).to receive(:exist?).with('/usr/bin/python').and_return(false) + allow(::File).to receive(:exist?).with('/usr/local/bin/python').and_return(false) + allow(::File).to receive(:exist?).with('/usr/bin/python3').and_return(false) end it { is_expected.to install_package('openssl-devel') } From 8da768aef7c8f8b273094c2ea6bc50a370c0cafe Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 19 May 2026 10:35:54 +0100 Subject: [PATCH 10/10] fix: move nodejs defaults into resources --- libraries/nodejs_helper.rb | 8 -------- resources/_partial/_nodejs.rb | 2 +- resources/nodejs_install.rb | 8 ++++++-- resources/nodejs_repository.rb | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/libraries/nodejs_helper.rb b/libraries/nodejs_helper.rb index dac0824..4fecad5 100644 --- a/libraries/nodejs_helper.rb +++ b/libraries/nodejs_helper.rb @@ -2,14 +2,6 @@ module NodeJs module Helper - DEFAULT_NODE_VERSION = '24.15.0' unless const_defined?(:DEFAULT_NODE_VERSION) - DEFAULT_NODE_MAJOR = '24' unless const_defined?(:DEFAULT_NODE_MAJOR) - DEFAULT_SOURCE_CHECKSUM = '729de494dd2872e5a3a6c32a1cd156a5413d4aca2772b2d873ee86bb5531bcd9' unless const_defined?(:DEFAULT_SOURCE_CHECKSUM) - DEFAULT_BINARY_CHECKSUMS = { - 'linux_x64' => '44836872d9aec49f1e6b52a9a922872db9a2b02d235a616a5681b6a85fec8d89', - 'linux_arm64' => '73afc234d558c24919875f51c2d1ea002a2ada4ea6f83601a383869fefa64eed', - }.freeze unless const_defined?(:DEFAULT_BINARY_CHECKSUMS) - def default_install_method case node['platform_family'] when 'debian', 'rhel', 'fedora', 'amazon', 'mac_os_x', 'suse' diff --git a/resources/_partial/_nodejs.rb b/resources/_partial/_nodejs.rb index 5cd8304..47b2b5f 100644 --- a/resources/_partial/_nodejs.rb +++ b/resources/_partial/_nodejs.rb @@ -1,2 +1,2 @@ -property :version, String, default: NodeJs::Helper::DEFAULT_NODE_VERSION +property :version, String, default: '24.15.0' property :prefix_url, String, default: 'https://nodejs.org/dist/' diff --git a/resources/nodejs_install.rb b/resources/nodejs_install.rb index 2da3dc6..f4468ac 100644 --- a/resources/nodejs_install.rb +++ b/resources/nodejs_install.rb @@ -12,9 +12,13 @@ property :package_options, [String, nil] property :disable_dnf_module, [true, false], default: true property :source_url, [String, nil] -property :source_checksum, [String, nil], default: NodeJs::Helper::DEFAULT_SOURCE_CHECKSUM +property :source_checksum, [String, nil], default: '729de494dd2872e5a3a6c32a1cd156a5413d4aca2772b2d873ee86bb5531bcd9' property :binary_url, [String, nil] -property :binary_checksums, Hash, default: NodeJs::Helper::DEFAULT_BINARY_CHECKSUMS +property :binary_checksums, Hash, + default: { + 'linux_x64' => '44836872d9aec49f1e6b52a9a922872db9a2b02d235a616a5681b6a85fec8d89', + 'linux_arm64' => '73afc234d558c24919875f51c2d1ea002a2ada4ea6f83601a383869fefa64eed', + } property :append_env_path, [true, false], default: true property :make_threads, [Integer, String, nil], default: nil property :build_packages, [Array, nil], default: nil diff --git a/resources/nodejs_repository.rb b/resources/nodejs_repository.rb index fc6ad3a..654b83a 100644 --- a/resources/nodejs_repository.rb +++ b/resources/nodejs_repository.rb @@ -4,7 +4,7 @@ unified_mode true property :repo_name, String, name_property: true -property :node_major, [String, Integer], default: NodeJs::Helper::DEFAULT_NODE_MAJOR +property :node_major, [String, Integer], default: '24' property :apt_uri, String property :apt_distribution, String, default: 'nodistro' property :apt_components, Array, default: ['main']