summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.expeditor/config.yml14
-rw-r--r--.github/CODEOWNERS5
-rw-r--r--.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md (renamed from .github/ISSUE_TEMPLATE.md)10
-rw-r--r--.github/ISSUE_TEMPLATE/DESIGN_PROPOSAL.md40
-rw-r--r--.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md17
-rw-r--r--.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md11
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md3
-rw-r--r--.github/lock.yml1
-rw-r--r--.travis.yml16
-rw-r--r--CHANGELOG.md10
-rw-r--r--CONTRIBUTING.md1
-rw-r--r--README.md3
-rw-r--r--Rakefile2
-rw-r--r--VERSION2
-rw-r--r--lib/mixlib/shellout/version.rb2
-rw-r--r--lib/mixlib/shellout/windows.rb44
-rw-r--r--spec/mixlib/shellout/windows_spec.rb84
17 files changed, 242 insertions, 23 deletions
diff --git a/.expeditor/config.yml b/.expeditor/config.yml
index 2d086d5..75e5e3c 100644
--- a/.expeditor/config.yml
+++ b/.expeditor/config.yml
@@ -2,7 +2,7 @@
---
# Slack channel in Chef Software slack to send notifications about build failures, etc
slack:
- notify_channel: chef-notify
+ notify_channel: chef-found-notify
# This publish is triggered by the `built_in:publish_rubygems` artifact_action.
rubygems:
@@ -16,7 +16,10 @@ github:
version_tag_format: "v{{version}}"
# allow bumping the minor release via label
minor_bump_labels:
- - "Expeditor: Bump Minor Version"
+ - "Expeditor: Bump Version Minor"
+ # allow bumping the major release via label
+ major_bump_labels:
+ - "Expeditor: Bump Version Major"
changelog:
rollup_header: Changes not yet released to rubygems.org
@@ -31,7 +34,7 @@ merge_actions:
only_if: built_in:bump_version
- built_in:update_changelog:
ignore_labels:
- - "Expeditor: Exclude From Changelog"
+ - "Expeditor: Skip Changelog"
- "Expeditor: Skip All"
- built_in:build_gem:
only_if: built_in:bump_version
@@ -40,3 +43,8 @@ promote:
actions:
- built_in:rollover_changelog
- built_in:publish_rubygems
+
+pipelines:
+ - verify:
+ description: Pull Request validation tests
+ public: true
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index fee8d42..9dbcc7b 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,4 +1,5 @@
# Order is important. The last matching pattern has the most precedence.
-* @chef/client-maintainers
-.expeditor/** @chef/jex-team
+* @chef/chef-infra-reviewers
+.expeditor/** @chef/jex-team
+*.md @chef/docs-team
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md
index f229e13..f28915b 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md
@@ -1,8 +1,16 @@
+---
+name: � Bug Report
+about: If something isn't working as expected �.
+labels: "Status: Untriaged"
+---
+
# Version:
[Version of the project installed]
-# Environment: [Details about the environment such as the Operating System, cookbook details, etc...]
+# Environment:
+
+[Details about the environment such as the Operating System, cookbook details, etc...]
# Scenario:
diff --git a/.github/ISSUE_TEMPLATE/DESIGN_PROPOSAL.md b/.github/ISSUE_TEMPLATE/DESIGN_PROPOSAL.md
new file mode 100644
index 0000000..9f4a958
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/DESIGN_PROPOSAL.md
@@ -0,0 +1,40 @@
+---
+name: Design Proposal
+about: I have a significant change I would like to propose and discuss before starting
+labels: "Status: Untriaged"
+---
+
+### When a Change Needs a Design Proposal
+
+A design proposal should be opened any time a change meets one of the following qualifications:
+
+- Significantly changes the user experience of a project in a way that impacts users.
+- Significantly changes the underlying architecture of the project in a way that impacts other developers.
+- Changes the development or testing process of the project such as a change of CI systems or test frameworks.
+
+### Why We Use This Process
+
+- Allows all interested parties (including any community member) to discuss large impact changes to a project.
+- Serves as a durable paper trail for discussions regarding project architecture.
+- Forces design discussions to occur before PRs are created.
+- Reduces PR refactoring and rejected PRs.
+
+---
+
+<!--- Proposal description and rationale. -->
+
+## Motivation
+
+<!---
+ As a <<user_profile>>,
+ I want to <<functionality>>,
+ so that <<benefit>>.
+ -->
+
+## Specification
+
+<!--- A detailed description of the planned implementation. -->
+
+## Downstream Impact
+
+<!--- Which other tools will be impacted by this work? -->
diff --git a/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md b/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..65bf5a0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md
@@ -0,0 +1,17 @@
+---
+name: 🚀 Enhancement Request
+about: I have a suggestion (and may want to implement it 🙂)!
+labels: "Status: Untriaged"
+---
+
+### Describe the Enhancement:
+<!--- What you are trying to achieve that you can't? -->
+
+### Describe the Need:
+<!--- What kind of user do you believe would utilize this enhancement, and how many users might want this functionality -->
+
+### Current Alternative
+<!--- Is there a current alternative that you can utilize to workaround the lack of this enhancement -->
+
+### Can We Help You Implement This?:
+<!--- The best way to ensure your enhancement is built is to help implement the enhancement yourself. If you're interested in helping out we'd love to give you a hand to make this possible. Let us know if there's something you need. -->
diff --git a/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md b/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md
new file mode 100644
index 0000000..921a5f0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md
@@ -0,0 +1,11 @@
+---
+name: 🤗 Support Question
+about: If you have a question 💬, please check out our Slack!
+---
+
+We use GitHub issues to track bugs and feature requests. If you need help please post to our Mailing List or join the Chef Community Slack.
+
+ * Chef Community Slack at http://community-slack.chef.io/.
+ * Chef Mailing List https://discourse.chef.io/
+
+ Support issues opened here will be closed and redirected to Slack or Discourse.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 441965f..0df03f8 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -5,10 +5,11 @@
### Issues Resolved
[List any existing issues this PR resolves, or any Discourse or
-StackOverflow discussion that's relevant]
+StackOverflow discussions that are relevant]
### Check List
- [ ] New functionality includes tests
- [ ] All tests pass
- [ ] All commits have been signed-off for the Developer Certificate of Origin. See <https://github.com/chef/chef/blob/master/CONTRIBUTING.md#developer-certification-of-origin-dco>
+- [ ] PR title is a worthy inclusion in the CHANGELOG \ No newline at end of file
diff --git a/.github/lock.yml b/.github/lock.yml
new file mode 100644
index 0000000..66d5d49
--- /dev/null
+++ b/.github/lock.yml
@@ -0,0 +1 @@
+daysUntilLock: 60
diff --git a/.travis.yml b/.travis.yml
index 5f7875d..bd71bb3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,12 +2,18 @@ language: ruby
cache: bundler
dist: xenial
+before_install:
+ - gem install bundler || true
+ - bundle --version
+ - gem update --system
+ - gem --version
+
matrix:
include:
- rvm: 2.3.8
- rvm: 2.4.5
- - rvm: 2.5.3
- - rvm: 2.6
+ - rvm: 2.5.5
+ - rvm: 2.6.2
- rvm: ruby-head
allow_failures:
- rvm: ruby-head
@@ -16,10 +22,6 @@ branches:
only:
- master
-before_install:
- - gem update --system
- - gem --version
- - gem update bundler
- - bundle --version
+bundler_args: --jobs 7 --without development
script: bundle exec rake
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7f27755..994aea2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,19 @@
# mixlib-shellout Changelog
-<!-- latest_release unreleased -->
-## Unreleased
+<!-- latest_release 3.0.3 -->
+## [v3.0.3](https://github.com/chef/mixlib-shellout/tree/v3.0.3) (2019-06-06)
#### Merged Pull Requests
-- update travis/appveyor, drop ruby 2.2 support, test on 2.6 [#176](https://github.com/chef/mixlib-shellout/pull/176) ([lamont-granquist](https://github.com/lamont-granquist))
+- Support array args on windows WIP [#182](https://github.com/chef/mixlib-shellout/pull/182) ([lamont-granquist](https://github.com/lamont-granquist))
<!-- latest_release -->
<!-- release_rollup since=2.4.4 -->
### Changes not yet released to rubygems.org
#### Merged Pull Requests
+- Support array args on windows WIP [#182](https://github.com/chef/mixlib-shellout/pull/182) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 3.0.3 -->
+- Add BuildKite pipeline [#184](https://github.com/chef/mixlib-shellout/pull/184) ([tas50](https://github.com/tas50)) <!-- 3.0.2 -->
+- Add new github templates and codeowners file [#179](https://github.com/chef/mixlib-shellout/pull/179) ([tas50](https://github.com/tas50)) <!-- 3.0.1 -->
+- Misnamed parameter in README [#178](https://github.com/chef/mixlib-shellout/pull/178) ([martinisoft](https://github.com/martinisoft)) <!-- 3.0.1 -->
- update travis/appveyor, drop ruby 2.2 support, test on 2.6 [#176](https://github.com/chef/mixlib-shellout/pull/176) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 3.0.0 -->
<!-- release_rollup -->
<!-- latest_stable_release -->
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..03fdbfa
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1 @@
+Please refer to https://github.com/chef/chef/blob/master/CONTRIBUTING.md
diff --git a/README.md b/README.md
index 368c113..ffdc112 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@ In addition to the command to run there are other options that can be set to cha
Run a command as the `www` user with no extra ENV settings from `/tmp` with a 1s timeout
```ruby
- cmd = Mixlib::ShellOut.new("apachectl", "start", :user => 'www', :env => nil, :cwd => '/tmp', :timeout => 1)
+ cmd = Mixlib::ShellOut.new("apachectl", "start", :user => 'www', :environment => nil, :cwd => '/tmp', :timeout => 1)
cmd.run_command # etc.
```
@@ -67,6 +67,7 @@ Invoke "whoami.exe" with elevated privileges:
whoami = Mixlib::ShellOut.new("whoami.exe", :user => "username", :domain => "DOMAIN", :password => "password", :elevated => true)
whoami.run_command
```
+
**NOTE:** The user 'admin' must have the 'Log on as a batch job' permission and the user chef is running as must have the 'Replace a process level token' and 'Adjust Memory Quotas for a process' permissions.
## Platform Support
diff --git a/Rakefile b/Rakefile
index dd326ab..40ab182 100644
--- a/Rakefile
+++ b/Rakefile
@@ -3,7 +3,7 @@ require "rspec/core/rake_task"
Bundler::GemHelper.install_tasks name: "mixlib-shellout"
-task default: [:style, :spec]
+task default: [:spec, :style]
desc "Run specs"
RSpec::Core::RakeTask.new(:spec) do |spec|
diff --git a/VERSION b/VERSION
index 4a36342..282895a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.0.0
+3.0.3 \ No newline at end of file
diff --git a/lib/mixlib/shellout/version.rb b/lib/mixlib/shellout/version.rb
index 21b5e5e..d105b77 100644
--- a/lib/mixlib/shellout/version.rb
+++ b/lib/mixlib/shellout/version.rb
@@ -1,5 +1,5 @@
module Mixlib
class ShellOut
- VERSION = "3.0.0".freeze
+ VERSION = "3.0.3".freeze
end
end
diff --git a/lib/mixlib/shellout/windows.rb b/lib/mixlib/shellout/windows.rb
index bd99ef5..db4fe32 100644
--- a/lib/mixlib/shellout/windows.rb
+++ b/lib/mixlib/shellout/windows.rb
@@ -2,7 +2,7 @@
# Author:: Daniel DeLeo (<dan@chef.io>)
# Author:: John Keiser (<jkeiser@chef.io>)
# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
-# Copyright:: Copyright (c) 2011-2016 Chef Software, Inc.
+# Copyright:: Copyright (c) 2011-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -66,7 +66,7 @@ module Mixlib
#
# Set cwd, environment, appname, etc.
#
- app_name, command_line = command_to_run(command)
+ app_name, command_line = command_to_run(combine_args(*command))
create_process_args = {
app_name: app_name,
command_line: command_line,
@@ -198,6 +198,46 @@ module Mixlib
true
end
+ # Use to support array passing semantics on windows
+ #
+ # 1. strings with whitespace or quotes in them need quotes around them.
+ # 2. interior quotes need to get backslash escaped (parser needs to know when it really ends).
+ # 3. random backlsashes in paths themselves remain untouched.
+ # 4. if the argument must be quoted by #1 and terminates in a sequence of backslashes then all the backlashes must themselves
+ # be backslash excaped (double the backslashes).
+ # 5. if an interior quote that must be escaped by #2 has a sequence of backslashes before it then all the backslashes must
+ # themselves be backslash excaped along with the backslash ecape of the interior quote (double plus one backslashes).
+ #
+ # And to restate. We are constructing a string which will be parsed by the windows parser into arguments, and we want those
+ # arguments to match the *args array we are passed here. So call the windows parser operation A then we need to apply A^-1 to
+ # our args to construct the string so that applying A gives windows back our *args.
+ #
+ # And when the windows parser sees a series of backslashes followed by a double quote, it has to determine if that double quote
+ # is terminating or not, and how many backslashes to insert in the args. So what it does is divide it by two (rounding down) to
+ # get the number of backslashes to insert. Then if it is even the double quotes terminate the argument. If it is even the
+ # double quotes are interior double quotes (the extra backslash quotes the double quote).
+ #
+ # We construct the inverse operation so interior double quotes preceeded by N backslashes get 2N+1 backslashes in front of the quote,
+ # while trailing N backslashes get 2N backslashes in front of the quote that terminates the argument.
+ #
+ # see: https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
+ #
+ # @api private
+ # @param args [Array<String>] array of command arguments
+ # @return String
+ def combine_args(*args)
+ return args[0] if args.length == 1
+ args.map do |arg|
+ if arg =~ /[ \t\n\v"]/
+ arg = arg.gsub(/(\\*)"/, '\1\1\"') # interior quotes with N preceeding backslashes need 2N+1 backslashes
+ arg = arg.sub(/(\\+)$/, '\1\1') # trailing N backslashes need to become 2N backslashes
+ "\"#{arg}\""
+ else
+ arg
+ end
+ end.join(" ")
+ end
+
def command_to_run(command)
return run_under_cmd(command) if should_run_under_cmd?(command)
diff --git a/spec/mixlib/shellout/windows_spec.rb b/spec/mixlib/shellout/windows_spec.rb
index d4edabc..1011560 100644
--- a/spec/mixlib/shellout/windows_spec.rb
+++ b/spec/mixlib/shellout/windows_spec.rb
@@ -307,4 +307,88 @@ describe "Mixlib::ShellOut::Windows", :windows_only do
end
end
end
+
+ context "#combine_args" do
+ let(:shell_out) { Mixlib::ShellOut.new }
+ subject { shell_out.send(:combine_args, *largs) }
+
+ def self.with_args(*args, &example)
+ context "with command #{args}" do
+ let(:largs) { args }
+ it(&example)
+ end
+ end
+
+ with_args("echo", "%PATH%") do
+ is_expected.to eql(%q{echo %PATH%})
+ end
+
+ with_args("echo %PATH%") do
+ is_expected.to eql(%q{echo %PATH%})
+ end
+
+ # Note carefully for the following that single quotes in ruby support '\\' as an escape sequence for a single
+ # literal backslash. It is not mandatory to always use this since '\d' does not escape the 'd' and is literally
+ # a backlash followed by an 'd'. However, in the following all backslashes are escaped for consistency. Otherwise
+ # it becomes prohibitively confusing to track when you need and do not need the escape the backslash (particularly
+ # when the literal string has a trailing backslash such that '\\' must be used instead of '\' which would escape
+ # the intended terminating single quote or %q{\} which escapes the terminating delimiter).
+
+ with_args("child.exe", "argument1", "argument 2", '\\some\\path with\\spaces') do
+ is_expected.to eql('child.exe argument1 "argument 2" "\\some\\path with\\spaces"')
+ end
+
+ with_args("child.exe", "argument1", 'she said, "you had me at hello"', '\\some\\path with\\spaces') do
+ is_expected.to eql('child.exe argument1 "she said, \\"you had me at hello\\"" "\\some\\path with\\spaces"')
+ end
+
+ with_args("child.exe", "argument1", 'argument\\\\"2\\\\"', "argument3", "argument4") do
+ is_expected.to eql('child.exe argument1 "argument\\\\\\\\\\"2\\\\\\\\\\"" argument3 argument4')
+ end
+
+ with_args("child.exe", '\\some\\directory with\\spaces\\', "argument2") do
+ is_expected.to eql('child.exe "\\some\\directory with\\spaces\\\\" argument2')
+ end
+
+ with_args("child.exe", '\\some\\directory with\\\\\\spaces\\\\\\', "argument2") do
+ is_expected.to eql('child.exe "\\some\\directory with\\\\\\spaces\\\\\\\\\\\\" argument2')
+ end
+ end
+
+ context "#run_command" do
+ let(:shell_out) { Mixlib::ShellOut.new(*largs) }
+ subject { shell_out.send(:run_command) }
+
+ def self.with_args(*args, &example)
+ context "with command #{args}" do
+ let(:largs) { args }
+ it(&example)
+ end
+ end
+
+ with_args("echo", "FOO") do
+ is_expected.not_to be_error
+ end
+
+ # Test box is going to have to have c:\program files on it, which is perhaps brittle in principle, but
+ # I don't know enough windows to come up with a less brittle test. Fix it if you've got a better idea.
+ # The tests need to fail though if the argument is not quoted correctly so using `echo` would be poor
+ # because `echo FOO BAR` and `echo "FOO BAR"` aren't any different.
+
+ with_args('dir c:\\program files') do
+ is_expected.to be_error
+ end
+
+ with_args('dir "c:\\program files"') do
+ is_expected.not_to be_error
+ end
+
+ with_args("dir", 'c:\\program files') do
+ is_expected.not_to be_error
+ end
+
+ with_args("dir", 'c:\\program files\\') do
+ is_expected.not_to be_error
+ end
+ end
end