diff --git a/plugins/pushes/atlas/config.rb b/plugins/pushes/atlas/config.rb index 9941da455..5c4a1a7cf 100644 --- a/plugins/pushes/atlas/config.rb +++ b/plugins/pushes/atlas/config.rb @@ -1,6 +1,19 @@ module VagrantPlugins module AtlasPush class Config < Vagrant.plugin("2", :config) + # The address of the Atlas server to upload to. By default this will + # be the public Atlas server. + # + # @return [String] + attr_accessor :address + + # The Atlas token to use. If the user has run `vagrant login`, this will + # use that token. If the environment variable `ATLAS_TOKEN` is set, the + # uploader will use this value. By default, this is nil. + # + # @return [String, nil] + attr_accessor :token + # The name of the application to push to. This will be created (with # user confirmation) if it doesn't already exist. # @@ -41,17 +54,12 @@ module VagrantPlugins # @return [String] attr_accessor :uploader_path - # The address of the Atlas server to upload to. By default this will - # be the public Atlas server. - # - # @return [String] - attr_accessor :address - def initialize + @address = UNSET_VALUE + @token = UNSET_VALUE @app = UNSET_VALUE @dir = UNSET_VALUE @vcs = UNSET_VALUE - @address = UNSET_VALUE @includes = [] @excludes = [] @uploader_path = UNSET_VALUE @@ -66,6 +74,7 @@ module VagrantPlugins def finalize! @address = nil if @address == UNSET_VALUE + @token = nil if @token == UNSET_VALUE @app = nil if @app == UNSET_VALUE @dir = "." if @dir == UNSET_VALUE @uploader_path = nil if @uploader_path == UNSET_VALUE @@ -75,6 +84,15 @@ module VagrantPlugins def validate(machine) errors = _detected_errors + if missing?(@token) + token = token_from_vagrant_login(machine.env) || ENV["ATLAS_TOKEN"] + if missing?(token) + errors << I18n.t("atlas_push.errors.missing_token") + else + @token = token + end + end + if missing?(@app) errors << I18n.t("atlas_push.errors.missing_attribute", attribute: "app", @@ -111,6 +129,23 @@ module VagrantPlugins def missing?(obj) obj.to_s.strip.empty? end + + # Attempt to load the token from disk using the vagrant-login plugin. If + # the constant is not defined, that means the user is operating in some + # bespoke and unsupported Ruby environment. + # + # @param [Vagrant::Environment] env + # + # @return [String, nil] + # the token, or nil if it does not exist + def token_from_vagrant_login(env) + if defined?(VagrantPlugins::Login::Client) + client = VagrantPlugins::Login::Client.new(env) + return client.token + end + + nil + end end end end diff --git a/plugins/pushes/atlas/locales/en.yml b/plugins/pushes/atlas/locales/en.yml index c54d59e67..3377f62dd 100644 --- a/plugins/pushes/atlas/locales/en.yml +++ b/plugins/pushes/atlas/locales/en.yml @@ -9,6 +9,11 @@ en: config.push.define "atlas" do |push| push.%{attribute} = "..." end + missing_token: |- + Missing required configuration parameter 'token'. This is required for + Vagrant to securely communicate with your Atlas account. + + To generate an access token, run 'vagrant login'. uploader_not_found: |- Vagrant was unable to find the Atlas uploader CLI. If your Vagrantfile specifies the path explicitly with "uploader_path", then make sure that diff --git a/plugins/pushes/atlas/push.rb b/plugins/pushes/atlas/push.rb index 0b13f1bb3..24a6d28b0 100644 --- a/plugins/pushes/atlas/push.rb +++ b/plugins/pushes/atlas/push.rb @@ -27,6 +27,7 @@ module VagrantPlugins cmd += config.includes.map { |v| ["-include", v] } cmd += config.excludes.map { |v| ["-exclude", v] } cmd += ["-address", config.address] if config.address + cmd += ["-token", config.token] if config.token cmd << config.app cmd << File.expand_path(config.dir, env.root_path) Vagrant::Util::SafeExec.exec(uploader, *cmd.flatten) diff --git a/test/unit/plugins/pushes/atlas/config_test.rb b/test/unit/plugins/pushes/atlas/config_test.rb index 87411c472..e62a5b86e 100644 --- a/test/unit/plugins/pushes/atlas/config_test.rb +++ b/test/unit/plugins/pushes/atlas/config_test.rb @@ -12,6 +12,20 @@ describe VagrantPlugins::AtlasPush::Config do let(:machine) { double("machine") } + describe "#address" do + it "defaults to nil" do + subject.finalize! + expect(subject.address).to be(nil) + end + end + + describe "#token" do + it "defaults to nil" do + subject.finalize! + expect(subject.token).to be(nil) + end + end + describe "#app" do it "defaults to nil" do subject.finalize! @@ -56,6 +70,79 @@ describe VagrantPlugins::AtlasPush::Config do let(:result) { subject.validate(machine) } let(:errors) { result["Atlas push"] } + context "when the token is missing" do + context "when a vagrant-login token exists" do + before do + allow(subject).to receive(:token_from_vagrant_login) + .and_return("token_from_vagrant_login") + + allow(ENV).to receive(:[]).and_call_original + allow(ENV).to receive(:[]) + .with("ATLAS_TOKEN").and_return("token_from_env") + end + + it "uses the token in the Vagrantfile" do + subject.token = "" + subject.finalize! + expect(errors).to be_empty + expect(subject.token).to eq("token_from_vagrant_login") + end + end + + context "when ATLAS_TOKEN is set in the environment" do + before do + allow(subject).to receive(:token_from_vagrant_login) + .and_return(nil) + + allow(ENV).to receive(:[]).and_call_original + allow(ENV).to receive(:[]) + .with("ATLAS_TOKEN").and_return("token_from_env") + end + + it "uses the token in the environment" do + subject.token = "" + subject.finalize! + expect(errors).to be_empty + expect(subject.token).to eq("token_from_env") + end + end + + context "when a token is given in the Vagrantfile" do + before do + allow(subject).to receive(:token_from_vagrant_login) + .and_return("token_from_vagrant_login") + + allow(ENV).to receive(:[]).and_call_original + allow(ENV).to receive(:[]) + .with("ATLAS_TOKEN").and_return("token_from_env") + end + + it "uses the token in the Vagrantfile" do + subject.token = "token_from_vagrantfile" + subject.finalize! + expect(errors).to be_empty + expect(subject.token).to eq("token_from_vagrantfile") + end + end + + context "when no token is given" do + before do + allow(subject).to receive(:token_from_vagrant_login) + .and_return(nil) + + allow(ENV).to receive(:[]).and_call_original + allow(ENV).to receive(:[]) + .with("ATLAS_TOKEN").and_return(nil) + end + + it "returns an error" do + subject.token = "" + subject.finalize! + expect(errors).to include(I18n.t("atlas_push.errors.missing_token")) + end + end + end + context "when the app is missing" do it "returns an error" do subject.app = "" diff --git a/test/unit/plugins/pushes/atlas/push_test.rb b/test/unit/plugins/pushes/atlas/push_test.rb index b93231bb1..e7ffdebd5 100644 --- a/test/unit/plugins/pushes/atlas/push_test.rb +++ b/test/unit/plugins/pushes/atlas/push_test.rb @@ -91,6 +91,14 @@ describe VagrantPlugins::AtlasPush::Push do config.address = "foo" subject.execute("foo") end + + it "sends custom token" do + expect(Vagrant::Util::SafeExec).to receive(:exec). + with("foo", "-vcs", "-token", "atlas_token", app, env.root_path.to_s) + + config.token = "atlas_token" + subject.execute("foo") + end end describe "#uploader_path" do diff --git a/website/docs/source/v2/push/atlas.html.md b/website/docs/source/v2/push/atlas.html.md index f001cfa51..e5679bbf2 100644 --- a/website/docs/source/v2/push/atlas.html.md +++ b/website/docs/source/v2/push/atlas.html.md @@ -35,6 +35,17 @@ The Vagrant Push Atlas strategy supports the following configuration options: - `vcs` - If set to true, Vagrant will automatically use VCS data to determine the files to upload. Uncommitted changes will not be deployed. +Additionally, the following options are exposed for power users of the Vagrant +Atlas push strategy. Most users will not require these options: + +- `address` - The address of the Atlas server to upload to. By default this will + be the public Atlas server. + +- `token` - The Atlas token to use. If the user has run `vagrant login`, this + will the token generated by that command. If the environment variable + `ATLAS_TOKEN` is set, the uploader will use this value. By default, this is + nil. + ### Usage