Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for nvm_verb, update readme #27

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

RulerOf
Copy link

@RulerOf RulerOf commented Mar 12, 2018

So this is the pull request that's just the readme updates and code changes. I think.

I assembled this manually from the full diff so I can't say I actually tested it this way. It looks right to me, though.


Edit: confirmed in #28 that this is functionally identical to #26

@RulerOf
Copy link
Author

RulerOf commented Apr 16, 2018

@koenpunt any thoughts on this patch?

Copy link
Owner

@koenpunt koenpunt left a comment

Choose a reason for hiding this comment

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

Apologies for the late review. Thank you for this PR! I added some remarks, and 1 question.

README.md Outdated
```

If your nvm is located in some custom path, you can use `nvm_custom_path` to set it.
When NVM is installed at the system level:
Copy link
Owner

Choose a reason for hiding this comment

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

NVM is supposed to be written in lowercase.

@@ -1,3 +1,3 @@
module CapistranoNvm
VERSION = '0.0.7'
VERSION = '0.0.9'.freeze
Copy link
Owner

Choose a reason for hiding this comment

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

We can move to 0.1.0 I think.

Copy link
Author

Choose a reason for hiding this comment

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

Heh. I actually had to check the Semver spec before I realized that you're absolutely right about that 😆

README.md Outdated
- `:nvm_map_bins`
- Accepts: Ruby word array
- Default: `%w{node npm yarn}`
- Notes: This is a list of commands that will be executed with NVM support by capistrano.
Copy link
Owner

Choose a reason for hiding this comment

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

The nvm abbreviation is supposed to written in lowercase, Capistrano on the other hand should be capitalized.

Copy link
Author

Choose a reason for hiding this comment

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

Fixed this and the other occurrences of improper capitalization

README.md Outdated

- `:nvm_custom_path`
- Accepts: String
- Default: Unused
Copy link
Owner

Choose a reason for hiding this comment

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

"Not set" or "None" would better define the default value

download! "#{release_path}/.nvmrc", '.nvmrc'
SSHKit.config.default_env[:node_version] = File.read('.nvmrc').strip
end
```
Copy link
Owner

Choose a reason for hiding this comment

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

I don't really get what this is about; you download the .nvmrc and use that for the next commands? Why should the remote version be leading?
Or is this something else and do I not understand this?

Copy link
Author

Choose a reason for hiding this comment

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

This example is to show specifically how to configure your deployment with the .nvmrc file that comes from your release code.

My use case was that our release code contains a .nvmrc file, but reading that file and configuring Capistrano with the value from it required me to download! it to the machine where the Capistrano code was executing.

I will admit that there's definitely a possibility that I'm simply Doing It Wrong™ here and just am not aware, but this seemed like the right solution to set the nvm version with the one from my deployed code.

Copy link
Author

Choose a reason for hiding this comment

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

As an additional note: I'm not 100% certain why I'm setting the :node_version symbol directly instead of setting :nvm_node. It's possible that I made a mistake when I was testing this, then kept it since it worked, but it's also possible that I tried setting :nvm_node which didn't work.... I just don't recall at this point.

Could I possibly lean on your experience with Capistrano to evaluate that?

If you'd like me to verify on my end, I can test with one of my deployment jobs but will need to take the time. Just let me know.

Copy link
Owner

Choose a reason for hiding this comment

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

My use case was that our release code contains a .nvmrc file, but reading that file and configuring Capistrano with the value from it required me to download! it to the machine where the Capistrano code was executing.

If you're running the Capistrano commands from the project directory locally, the same .nvmrc fill should be already present there, right? So I think your example is only relevant for people with a non-standard setup, and for that I would rather leave it out completely.
Let me know if you think it is common use, or if I didn't understand you correctly.

Copy link
Author

@RulerOf RulerOf May 21, 2018

Choose a reason for hiding this comment

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

If you're running the Capistrano commands from the project directory locally, the same .nvmrc fill should be already present there, right?

In our setup, the Capistrano code runs on a Jenkins server, and the release code ends up on our web nodes. Capistrano uses SSHKit to run a bunch of git commands on each of our web servers in turn to fetch precisely the branch that's been configured for deployment. As a result, the .nvmrc file that's in our application code ("release" code in Capistrano parlance) never actually ends up on the Jenkins box where the Capistrano code is running. Hence we download the .nvmrc.

I didn't build this deployment and didn't have any experience with Capistrano prior to this, so I just assumed this was normal. Is the typical deployment case for Capistrano different in some way?

The only thing I can see wrong with it is that it's an awfully redundant procedure if you were to have a very large number of nodes. Downloading the same file from all of them is silly but it would still work.

Edit: I wasn't specific about it, but our Capistrano code and the release code live in different git repos.

end
end
end

task :map_bins do
SSHKit.config.default_env.merge!({ node_version: "#{fetch(:nvm_node)}" })
nvm_prefix = fetch(:nvm_prefix, -> { "#{fetch(:tmp_dir)}/#{fetch(:application)}/nvm-exec.sh" } )
SSHKit.config.default_env[:nvm_verb] = fetch(:nvm_verb).to_s
Copy link
Owner

Choose a reason for hiding this comment

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

Now that I look at this again, there's no need to add an environment variable for nvm_verb. Below you can simply use fetch(:nvm_verb) instead of $NVM_VERB.

@@ -28,7 +32,7 @@ namespace :nvm do
task :wrapper do
on release_roles(fetch(:nvm_roles)) do
execute :mkdir, "-p", "#{fetch(:tmp_dir)}/#{fetch(:application)}/"
upload! StringIO.new("#!/bin/bash -e\nsource \"#{fetch(:nvm_path)}/nvm.sh\"\nnvm use $NODE_VERSION\nexec \"$@\""), "#{fetch(:tmp_dir)}/#{fetch(:application)}/nvm-exec.sh"
upload! StringIO.new("#!/bin/bash -e\nsource \"#{fetch(:nvm_path)}/nvm.sh\"\nnvm $NVM_VERB $NODE_VERSION\nexec \"$@\""), "#{fetch(:tmp_dir)}/#{fetch(:application)}/nvm-exec.sh"
Copy link
Owner

Choose a reason for hiding this comment

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

So here you can replace $NVM_VERB with fetch(:nvm_verb)

Copy link
Author

@RulerOf RulerOf May 21, 2018

Choose a reason for hiding this comment

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

Does the same go for $NODE_VERSION and :nvm_node?

Edit: I expect that the answer is yes, but do appreciate your expertise on this. :)

Copy link
Owner

Choose a reason for hiding this comment

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

Oh crap, I guess I'm wrong here, this is of course the script that is created remotely. I'm sorry, it has been a long time that I worked on this project.

The only thing I'm now thinking is; wouldn't it be better to add a nvm:install task, and let that be idempotent, instead of having side effect when executing a node binary?

Copy link
Author

@RulerOf RulerOf May 21, 2018

Choose a reason for hiding this comment

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

Oh crap, I guess I'm wrong here, this is of course the script that is created remotely.

Hmm... Thinking about it again, my current deploys rely on the destination servers being able to track changes to the $NODE_VERISON environment variable well after the nvm-exec.sh script is created and uploaded to them. So yeah that wouldn't work, at least not for me 😝

The only thing I'm now thinking is; wouldn't it be better to add a nvm:install task, and let that be idempotent, instead of having side effect when executing a node binary?

So like an nvm:install task that I could choose to invoke somewhere in my deploy, and then the wrapper script just runs nvm use before all of my commands?

While I think that this suggestion would probably be more elegant in some respects, nvm install is basically "Install if not installed already, then use." I think it makes sense to leverage the implicit behavior here since we basically get to let nvm worry about version management entirely just by configuring a ruby symbol.


unless test(nvm_node_path.map {|p| "[ -d #{p} ]" }.join(" || "))
error "nvm: #{nvm_node} is not installed or not found in any of #{nvm_node_path.join(" ")}"
exit 1
if nvm_verb == 'use'
Copy link
Owner

Choose a reason for hiding this comment

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

Here you can actually move the verb comparison before the test command, which then omits a remote invocation when the verb is not use.

@@ -9,17 +9,21 @@ namespace :nvm do

nvm_node_path = fetch(:nvm_node_path)
nvm_node_path = [nvm_node_path] unless nvm_node_path.is_a?(Array)
nvm_verb = fetch(:nvm_verb).to_s
Copy link
Owner

@koenpunt koenpunt May 21, 2018

Choose a reason for hiding this comment

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

Can you add validation for the verb, since it can only be :use or :install right?
But then again, if there are only 2 options, maybe it would be better to make it a boolean property, e.g. :nvm_install, which when true causes the "verb" to be install instead of use

Copy link
Author

Choose a reason for hiding this comment

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

Can you add validation for the verb,

Absolutely.

since it can only be :use or :install right?

Effectively yes, but let's discuss your other point...

But then again, if there are only 2 options, maybe it would be better to make it a boolean property, e.g. :nvm_install, which when true causes the "verb" to be install instead of use

Hmm... I'd need to rewrite some things to kind of unify the behavior of this code. For example, when specifying use instead of install, the node version availability check is path based, so the version string has to be exact and must prepend the v, but it really should be running nvm version on the destination machines instead.

I also personally think that :nvm_install behavior should default to true as nvm is just a lot more useful that way, at least from an automation standpoint. That's technically a major version change so I guess if I really think that's the right call I can always submit another PR.

...I've got a good plan for how to handle this, but I suppose I needed to "think out loud" to get the ideas right. LMK if anything doesn't seem right to you, otherwise I'll work on this sometime in the coming days and get that done.

@tiagotex tiagotex mentioned this pull request Aug 9, 2021
@koenpunt
Copy link
Owner

Coming back at this PR once more; I think the verb nomenclature is too ambiguous, so I'd like to suggest a nvm_action option defaulting to "use", or an nvm_install action defaulting to false instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants