From 0aa9ac568243cc819b91544266dfd987dad5dbfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Kar=C3=A9kinian?= Date: Fri, 22 Jan 2016 22:26:17 +0000 Subject: [PATCH] Update nodejs cookbook --- cookbooks/nodejs/CHANGELOG.md | 35 ++++++++++++++- cookbooks/nodejs/README.md | 14 +++++- cookbooks/nodejs/attributes/default.rb | 7 +-- cookbooks/nodejs/attributes/packages.rb | 2 +- cookbooks/nodejs/attributes/repo.rb | 9 ++++ cookbooks/nodejs/libraries/nodejs_helper.rb | 23 +++++++--- cookbooks/nodejs/metadata.json | 43 +------------------ cookbooks/nodejs/providers/npm.rb | 15 +++++-- .../nodejs/recipes/nodejs_from_binary.rb | 9 ++-- .../nodejs/recipes/nodejs_from_source.rb | 3 +- cookbooks/nodejs/resources/npm.rb | 1 + 11 files changed, 97 insertions(+), 64 deletions(-) diff --git a/cookbooks/nodejs/CHANGELOG.md b/cookbooks/nodejs/CHANGELOG.md index a159124..5623870 100644 --- a/cookbooks/nodejs/CHANGELOG.md +++ b/cookbooks/nodejs/CHANGELOG.md @@ -1,4 +1,34 @@ -## v2.0.0 (unreleased) +## 2.4.4 + * Use HTTPS prefix URLs for node download #98 + * Update NPM symlink when installing from source #105 + * Add support for NPM private modules #107 + +## v2.4.2 + * Fix check version + * Support iojs package install + +## v2.4.0 + * Move `npm_packages` to his own recipe + * Fix different race conditions when using direct recipe call + * Fix npm recipe + +## v2.3.2 + * Fix package recipe + +## v2.3.0 + * Support io.js. Use node['nodejs']['engine']. + * Add MacOS support via homebrew + +## v2.2.0 + * Add node['nodejs']['keyserver'] + * Update arm checksum + * Fix `npm_packages` JSON + +## v2.1.0 + * Use official nodesource repository + * Add node['nodejs']['npm_packages'] to install npm package with `default` recipe + +## v2.0.0 * Travis integration * Gems updated * Rewrite cookbook dependencies @@ -64,3 +94,6 @@ [@vaskas]: https://github.com/vaskas [@robertkowalski]: https://github.com/robertkowalski [@wanelo-pair]: https://github.com/wanelo-pair +[@predominant]: https://github.com/predominant +[@sjlu]: https://github.com/sjlu +[@gmccue]: https://github.com/gmccue diff --git a/cookbooks/nodejs/README.md b/cookbooks/nodejs/README.md index 42b86d0..45890b3 100644 --- a/cookbooks/nodejs/README.md +++ b/cookbooks/nodejs/README.md @@ -13,7 +13,7 @@ Include the nodejs recipe to install node on your system based on the default in include_recipe "nodejs" ``` -### Engine +### Engine You can select different engine by setting `node['nodejs']['engine']` ``` @@ -84,11 +84,13 @@ _Warning:_ This recipe will include the `nodejs` recipe, which by default includ 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 append more specific options to npm command with `attribute :options` array : * use an array of options (w/ dash), they will be added to npm call. * ex: `['--production','--force']` or `['--force-latest']` -This LWRP try to use npm bare as much as possible (no custom wrapper). +This LWRP attempts to use vanilla npm as much as possible (no custom wrapper). ### Packages @@ -108,6 +110,14 @@ nodejs_npm "grunt" do json true user "random" end + +nodejs_npm "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 ``` [Working Examples](test/cookbooks/nodejs_test/recipes/npm.rb) diff --git a/cookbooks/nodejs/attributes/default.rb b/cookbooks/nodejs/attributes/default.rb index da31cce..e5d33f6 100644 --- a/cookbooks/nodejs/attributes/default.rb +++ b/cookbooks/nodejs/attributes/default.rb @@ -28,11 +28,8 @@ default['nodejs']['engine'] = 'node' # or iojs default['nodejs']['version'] = '0.10.26' -if node['nodejs']['engine'] == 'iojs' - default['nodejs']['prefix_url'] = 'http://iojs.org/dist/' -else - default['nodejs']['prefix_url'] = 'http://nodejs.org/dist/' -end +default['nodejs']['prefix_url']['node'] = 'https://nodejs.org/dist/' +default['nodejs']['prefix_url']['iojs'] = 'https://iojs.org/dist/' default['nodejs']['source']['url'] = nil # Auto generated default['nodejs']['source']['checksum'] = 'ef5e4ea6f2689ed7f781355012b942a2347e0299da0804a58de8e6281c4b1daa' diff --git a/cookbooks/nodejs/attributes/packages.rb b/cookbooks/nodejs/attributes/packages.rb index 0152692..64442e8 100644 --- a/cookbooks/nodejs/attributes/packages.rb +++ b/cookbooks/nodejs/attributes/packages.rb @@ -10,5 +10,5 @@ when 'node' 'default' => ['nodejs'] ) when 'iojs' - default['nodejs']['packages'] = nil + default['nodejs']['packages'] = ['iojs'] end diff --git a/cookbooks/nodejs/attributes/repo.rb b/cookbooks/nodejs/attributes/repo.rb index 596509c..64f7aa0 100644 --- a/cookbooks/nodejs/attributes/repo.rb +++ b/cookbooks/nodejs/attributes/repo.rb @@ -10,4 +10,13 @@ when 'node' when 'rhel' default['nodejs']['install_repo'] = true end +when 'iojs' + case node['platform_family'] + when 'debian' + default['nodejs']['install_repo'] = true + + default['nodejs']['repo'] = 'https://deb.nodesource.com/iojs_2.x' + default['nodejs']['keyserver'] = 'keyserver.ubuntu.com' + default['nodejs']['key'] = '1655a0ab68576280' + end end diff --git a/cookbooks/nodejs/libraries/nodejs_helper.rb b/cookbooks/nodejs/libraries/nodejs_helper.rb index 46964a0..8848972 100644 --- a/cookbooks/nodejs/libraries/nodejs_helper.rb +++ b/cookbooks/nodejs/libraries/nodejs_helper.rb @@ -14,20 +14,31 @@ module NodeJs end end - def npm_list(path = nil) + def npm_list(path = nil, environment = {}) require 'json' if path - cmd = Mixlib::ShellOut.new('npm list -json', :cwd => path) + cmd = Mixlib::ShellOut.new('npm list -json', :cwd => path, :environment => environment) else - cmd = Mixlib::ShellOut.new('npm list -global -json') + cmd = Mixlib::ShellOut.new('npm list -global -json', :environment => environment) end + JSON.parse(cmd.run_command.stdout, :max_nesting => false) end - def npm_package_installed?(package, version = nil, path = nil) - list = npm_list(path)['dependencies'] + def url_valid?(list, package) + list.fetch(package, {}).fetch('resolved', '').include?('url') + end + + def version_valid?(list, package, version) + (version ? list[package]['version'] == version : true) + end + + def npm_package_installed?(package, version = nil, path = nil, npm_token = nil) + environment = { 'NPM_TOKEN' => npm_token } if npm_token + + list = npm_list(path, environment)['dependencies'] # Return true if package installed and installed to good version - (!list.nil?) && list.key?(package) && (version ? list[package]['version'] == version : true) + (!list.nil?) && list.key?(package) && version_valid?(list, package, version) && url_valid?(list, package) end end end diff --git a/cookbooks/nodejs/metadata.json b/cookbooks/nodejs/metadata.json index 07de793..6cf03a4 100644 --- a/cookbooks/nodejs/metadata.json +++ b/cookbooks/nodejs/metadata.json @@ -1,42 +1 @@ -{ - "name": "nodejs", - "version": "2.4.0", - "description": "Installs/Configures node.js & io.js", - "long_description": "# [nodejs-cookbook](https://github.com/redguide/nodejs)\n[![CK Version](http://img.shields.io/cookbook/v/nodejs.svg)](https://supermarket.getchef.com/cookbooks/nodejs) [![Build Status](https://img.shields.io/travis/redguide/nodejs.svg)](https://travis-ci.org/redguide/nodejs)\n[![Gitter chat](https://badges.gitter.im/redguide/nodejs.png)](https://gitter.im/redguide/nodejs)\n\n## DESCRIPTION\n\nInstalls node.js/io.js and manage npm\n\n## USAGE\n\nInclude the nodejs recipe to install node on your system based on the default installation method:\n```chef\ninclude_recipe \"nodejs\"\n```\n\n### Engine\n\nYou can select different engine by setting `node['nodejs']['engine']`\n```\nnode['nodejs']['engine'] => 'node' # default\nnode['nodejs']['engine'] => 'iojs'\n```\n\nYou can also use recipes `nodejs::nodejs` or `nodejs::iojs`.\n\n### Install methods\n\n#### Package\n\nInstall node from packages:\n\n```chef\nnode['nodejs']['install_method'] = 'package' # Not necessary because it's the default\ninclude_recipe \"nodejs\"\n# Or\ninclude_recipe \"nodejs::nodejs_from_package\"\n```\nNote that only apt (Ubuntu, Debian) appears to have up to date packages available. \nCentos, RHEL, etc are non-functional (try `nodejs_from_binary` for those).\n\n#### Binary\n\nInstall node from official prebuilt binaries:\n```chef\nnode['nodejs']['install_method'] = 'binary'\ninclude_recipe \"nodejs\"\n# Or\ninclude_recipe \"nodejs::nodejs_from_binary\"\n```\n\n#### Source\n\nInstall node from sources:\n```chef\nnode['nodejs']['install_method'] = 'source'\ninclude_recipe \"nodejs\"\n# Or\ninclude_recipe \"nodejs::nodejs_from_source\"\n```\n\n## NPM\n\nNpm is included in nodejs installs by default.\nBy default, we are using it and call it `embedded`.\nAdding recipe `nodejs::npm` assure you to have npm installed and let you choose install method with `node['nodejs']['npm']['install_method']`\n```chef\ninclude_recipe \"nodejs::npm\"\n```\n_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']`.\n\n## LWRP\n\n### nodejs_npm\n\n`nodejs_npm` let you install npm packages from various sources:\n* npm registry:\n * name: `attribute :package`\n * version: `attribute :version` (optionnal)\n* url: `attribute :url`\n * for git use `git://{your_repo}`\n* from a json (packages.json by default): `attribute :json`\n * use `true` for default\n * use a `String` to specify json file\n \nPackages can be installed globally (by default) or in a directory (by using `attribute :path`)\n\nYou can append more specific options to npm command with `attribute :options` array : \n * use an array of options (w/ dash), they will be added to npm call.\n * ex: `['--production','--force']` or `['--force-latest']`\n \nThis LWRP try to use npm bare as much as possible (no custom wrapper).\n\n### Packages\n\n```ruby\nnodejs_npm \"express\"\n\nnodejs_npm \"async\" do\n version \"0.6.2\"\nend\n\nnodejs_npm \"request\" do\n url \"github mikeal/request\"\nend\n\nnodejs_npm \"grunt\" do\n path \"/home/random/grunt\"\n json true\n user \"random\"\nend\n```\n[Working Examples](test/cookbooks/nodejs_test/recipes/npm.rb)\n\nOr add packages via attributes (which accept the same attributes as the LWRP above):\n\n```json\n\"nodejs\": {\n \"npm_packages\": [\n {\n \"name\": \"express\"\n },\n {\n \"name\": \"async\",\n \"version\": \"0.6.2\"\n },\n {\n \"name\": \"request\",\n \"url\": \"github mikeal/request\"\n }\n {\n \"name\": \"grunt\",\n \"path\": \"/home/random/grunt\",\n \"json\": true,\n \"user\": \"random\"\n }\n ]\n}\n```\n\n## AUTHORS\n\n* Marius Ducea (marius@promethost.com)\n* Nathan L Smith (nlloyds@gmail.com)\n* Guilhem Lettron (guilhem@lettron.fr)\n* Barthelemy Vessemont (bvessemont@gmail.com)\n", - "maintainer": "redguide", - "maintainer_email": "guilhem@lettron.fr", - "license": "Apache 2.0", - "platforms": { - "debian": ">= 0.0.0", - "ubuntu": ">= 0.0.0", - "centos": ">= 0.0.0", - "redhat": ">= 0.0.0", - "smartos": ">= 0.0.0", - "mac_os_x": ">= 0.0.0" - }, - "dependencies": { - "yum-epel": ">= 0.0.0", - "build-essential": ">= 0.0.0", - "ark": ">= 0.0.0", - "apt": ">= 0.0.0", - "homebrew": ">= 0.0.0" - }, - "recommendations": { - }, - "suggestions": { - "application_nodejs": ">= 0.0.0" - }, - "conflicting": { - "node": ">= 0.0.0" - }, - "providing": { - }, - "replacing": { - }, - "attributes": { - }, - "groupings": { - }, - "recipes": { - } -} \ No newline at end of file +{"name":"nodejs","version":"2.4.4","description":"Installs/Configures node.js & io.js","long_description":"# [nodejs-cookbook](https://github.com/redguide/nodejs)\n[![CK Version](http://img.shields.io/cookbook/v/nodejs.svg)](https://supermarket.getchef.com/cookbooks/nodejs) [![Build Status](https://img.shields.io/travis/redguide/nodejs.svg)](https://travis-ci.org/redguide/nodejs)\n[![Gitter chat](https://badges.gitter.im/redguide/nodejs.png)](https://gitter.im/redguide/nodejs)\n\n## DESCRIPTION\n\nInstalls node.js/io.js and manage npm\n\n## USAGE\n\nInclude the nodejs recipe to install node on your system based on the default installation method:\n```chef\ninclude_recipe \"nodejs\"\n```\n\n### Engine\n\nYou can select different engine by setting `node['nodejs']['engine']`\n```\nnode['nodejs']['engine'] => 'node' # default\nnode['nodejs']['engine'] => 'iojs'\n```\n\nYou can also use recipes `nodejs::nodejs` or `nodejs::iojs`.\n\n### Install methods\n\n#### Package\n\nInstall node from packages:\n\n```chef\nnode['nodejs']['install_method'] = 'package' # Not necessary because it's the default\ninclude_recipe \"nodejs\"\n# Or\ninclude_recipe \"nodejs::nodejs_from_package\"\n```\nNote that only apt (Ubuntu, Debian) appears to have up to date packages available. \nCentos, RHEL, etc are non-functional (try `nodejs_from_binary` for those).\n\n#### Binary\n\nInstall node from official prebuilt binaries:\n```chef\nnode['nodejs']['install_method'] = 'binary'\ninclude_recipe \"nodejs\"\n# Or\ninclude_recipe \"nodejs::nodejs_from_binary\"\n```\n\n#### Source\n\nInstall node from sources:\n```chef\nnode['nodejs']['install_method'] = 'source'\ninclude_recipe \"nodejs\"\n# Or\ninclude_recipe \"nodejs::nodejs_from_source\"\n```\n\n## NPM\n\nNpm is included in nodejs installs by default.\nBy default, we are using it and call it `embedded`.\nAdding recipe `nodejs::npm` assure you to have npm installed and let you choose install method with `node['nodejs']['npm']['install_method']`\n```chef\ninclude_recipe \"nodejs::npm\"\n```\n_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']`.\n\n## LWRP\n\n### nodejs_npm\n\n`nodejs_npm` let you install npm packages from various sources:\n* npm registry:\n * name: `attribute :package`\n * version: `attribute :version` (optionnal)\n* url: `attribute :url`\n * for git use `git://{your_repo}`\n* from a json (packages.json by default): `attribute :json`\n * use `true` for default\n * use a `String` to specify json file\n \nPackages can be installed globally (by default) or in a directory (by using `attribute :path`)\n\nYou can specify an `NPM_TOKEN` environment variable for accessing [NPM private modules](https://docs.npmjs.com/private-modules/intro) by using `attribute :npm_token`\n\nYou can append more specific options to npm command with `attribute :options` array : \n * use an array of options (w/ dash), they will be added to npm call.\n * ex: `['--production','--force']` or `['--force-latest']`\n \nThis LWRP attempts to use vanilla npm as much as possible (no custom wrapper).\n\n### Packages\n\n```ruby\nnodejs_npm \"express\"\n\nnodejs_npm \"async\" do\n version \"0.6.2\"\nend\n\nnodejs_npm \"request\" do\n url \"github mikeal/request\"\nend\n\nnodejs_npm \"grunt\" do\n path \"/home/random/grunt\"\n json true\n user \"random\"\nend\n\nnodejs_npm \"my_private_module\" do\n path \"/home/random/myproject\" # The root path to your project, containing a package.json file\n json true\n npm_token \"12345-abcde-e5d4c3b2a1\"\n user \"random\"\n options ['--production'] # Only install dependencies. Skip devDependencies\nend\n```\n[Working Examples](test/cookbooks/nodejs_test/recipes/npm.rb)\n\nOr add packages via attributes (which accept the same attributes as the LWRP above):\n\n```json\n\"nodejs\": {\n \"npm_packages\": [\n {\n \"name\": \"express\"\n },\n {\n \"name\": \"async\",\n \"version\": \"0.6.2\"\n },\n {\n \"name\": \"request\",\n \"url\": \"github mikeal/request\"\n }\n {\n \"name\": \"grunt\",\n \"path\": \"/home/random/grunt\",\n \"json\": true,\n \"user\": \"random\"\n }\n ]\n}\n```\n\n## AUTHORS\n\n* Marius Ducea (marius@promethost.com)\n* Nathan L Smith (nlloyds@gmail.com)\n* Guilhem Lettron (guilhem@lettron.fr)\n* Barthelemy Vessemont (bvessemont@gmail.com)\n","maintainer":"redguide","maintainer_email":"guilhem@lettron.fr","license":"Apache 2.0","platforms":{"debian":">= 0.0.0","ubuntu":">= 0.0.0","centos":">= 0.0.0","redhat":">= 0.0.0","smartos":">= 0.0.0","mac_os_x":">= 0.0.0"},"dependencies":{"yum-epel":">= 0.0.0","build-essential":">= 0.0.0","ark":">= 0.0.0","apt":">= 0.0.0","homebrew":">= 0.0.0"},"recommendations":{},"suggestions":{"application_nodejs":">= 0.0.0"},"conflicting":{"node":">= 0.0.0"},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}} \ No newline at end of file diff --git a/cookbooks/nodejs/providers/npm.rb b/cookbooks/nodejs/providers/npm.rb index b5ca1c1..02742a8 100644 --- a/cookbooks/nodejs/providers/npm.rb +++ b/cookbooks/nodejs/providers/npm.rb @@ -8,7 +8,7 @@ action :install do command "npm install #{npm_options}" user new_resource.user group new_resource.group - environment 'HOME' => ::Dir.home(new_resource.user), 'USER' => new_resource.user if new_resource.user + environment npm_env_vars not_if { package_installed? } end end @@ -19,13 +19,22 @@ action :uninstall do command "npm uninstall #{npm_options}" user new_resource.user group new_resource.group - environment 'HOME' => ::Dir.home(new_resource.user), 'USER' => new_resource.user if new_resource.user + environment npm_env_vars only_if { package_installed? } end end +def npm_env_vars + env_vars = {} + env_vars['HOME'] = ::Dir.home(new_resource.user) if new_resource.user + env_vars['USER'] = new_resource.user if new_resource.user + env_vars['NPM_TOKEN'] = new_resource.npm_token if new_resource.npm_token + + env_vars +end + def package_installed? - new_resource.package && npm_package_installed?(new_resource.package, new_resource.version, new_resource.path) + new_resource.package && npm_package_installed?(new_resource.package, new_resource.version, new_resource.path, new_resource.npm_token) end def npm_options diff --git a/cookbooks/nodejs/recipes/nodejs_from_binary.rb b/cookbooks/nodejs/recipes/nodejs_from_binary.rb index 23fb9d9..3ae5c50 100644 --- a/cookbooks/nodejs/recipes/nodejs_from_binary.rb +++ b/cookbooks/nodejs/recipes/nodejs_from_binary.rb @@ -30,22 +30,25 @@ end # package_stub is for example: "node-v0.8.20-linux-x64.tar.gz" version = "v#{node['nodejs']['version']}/" +prefix = node['nodejs']['prefix_url'][node['nodejs']['engine']] if node['nodejs']['engine'] == 'iojs' filename = "iojs-v#{node['nodejs']['version']}-linux-#{arch}.tar.gz" archive_name = 'iojs-binary' - binaries = ['bin/iojs', 'bin/node', 'bin/npm'] + binaries = ['bin/iojs', 'bin/node'] else filename = "node-v#{node['nodejs']['version']}-linux-#{arch}.tar.gz" archive_name = 'nodejs-binary' - binaries = ['bin/node', 'bin/npm'] + binaries = ['bin/node'] end +binaries.push('bin/npm') 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(node['nodejs']['prefix_url'], version, filename).to_s + nodejs_bin_url = ::URI.join(prefix, version, filename).to_s checksum = node['nodejs']['binary']['checksum']["linux_#{arch}"] end diff --git a/cookbooks/nodejs/recipes/nodejs_from_source.rb b/cookbooks/nodejs/recipes/nodejs_from_source.rb index eef1924..e8eb94d 100644 --- a/cookbooks/nodejs/recipes/nodejs_from_source.rb +++ b/cookbooks/nodejs/recipes/nodejs_from_source.rb @@ -32,6 +32,7 @@ when 'debian' end version = "v#{node['nodejs']['version']}/" +prefix = node['nodejs']['prefix_url'][node['nodejs']['engine']] if node['nodejs']['engine'] == 'iojs' filename = "iojs-v#{node['nodejs']['version']}.tar.gz" @@ -41,7 +42,7 @@ else archive_name = 'nodejs-source' end -nodejs_src_url = node['nodejs']['source']['url'] || ::URI.join(node['nodejs']['prefix_url'], version, filename).to_s +nodejs_src_url = node['nodejs']['source']['url'] || ::URI.join(prefix, version, filename).to_s ark archive_name do url nodejs_src_url diff --git a/cookbooks/nodejs/resources/npm.rb b/cookbooks/nodejs/resources/npm.rb index f873f93..3d5e034 100644 --- a/cookbooks/nodejs/resources/npm.rb +++ b/cookbooks/nodejs/resources/npm.rb @@ -27,6 +27,7 @@ attribute :version, :kind_of => String attribute :path, :kind_of => String attribute :url, :kind_of => String attribute :json, :kind_of => [String, TrueClass] +attribute :npm_token, :kind_of => String attribute :options, :kind_of => Array, :default => [] attribute :user, :kind_of => String