diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77360f32..f73bbe56 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,8 +12,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, windows-2019] - ruby: ['3.0', '3.1', '3.2', '3.3'] + os: [ubuntu-latest, windows-latest] + ruby: ['3.2', '3.3', '3.4', '4.0'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 diff --git a/.rubocop.yml b/.rubocop.yml index fa5031a7..ff6e3c09 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,6 @@ AllCops: - TargetRubyVersion: 3.0 + TargetRubyVersion: 3.2 + NewCops: disable Exclude: - 'appveyor.yml' diff --git a/README.md b/README.md index 52b2e1f7..caa8df66 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ site](http://msdn.microsoft.com/en-us/library/aa384426.aspx). As of version 2.0, this gem retains the WinRM name but all powershell calls use the more modern [Powershell Remoting Protocol (PSRP)](https://msdn.microsoft.com/en-us/library/dd357801.aspx) for initializing runspace pools as well as creating and processing powershell pipelines. ## Supported Ruby Versions -Ruby 3.0 or higher is required. If you need to use an older version of Ruby you'll need to use a previous version of this gem. +Ruby 3.2 or higher is required. If you need to use an older version of Ruby you'll need to use a previous version of this gem. ## Supported WinRM Versions WinRM 1.1 is supported, however 2.0 and higher is recommended. [See MSDN](http://technet.microsoft.com/en-us/library/ff520073.aspx) for information about WinRM versions and supported operating systems. @@ -215,7 +215,7 @@ Perform the following steps to authenticate with a certificate instead of a user See [this post](http://www.hurryupandwait.io/blog/certificate-password-less-based-authentication-in-winrm) for more details on certificate authentication. ## Logging -The `WinRM::Connection` exposes a `logger` attribute and uses the [logging](https://rubygems.org/gems/logging) gem to manage logging behavior. By default this appends to `STDOUT` and has a level of `:warn`, but one can adjust the level or add additional appenders. +The `WinRM::Connection` exposes a `logger` attribute and uses the Ruby standard library [Logger](https://docs.ruby-lang.org/en/master/Logger.html). By default this logs to `STDOUT` with a level of `:warn`, but one can adjust the level or replace the logger entirely. ```ruby conn = WinRM::Connection.new(opts) @@ -223,10 +223,12 @@ conn = WinRM::Connection.new(opts) conn.logger.level = :error # Log to a file -conn.logger.add_appenders(Logging.appenders.file('error.log')) +conn.logger = Logger.new('error.log') ``` -If a consuming application uses its own logger that complies to the logging API, you can simply swap it in: +The default log level can also be set with the `WINRM_LOG` environment variable (`debug`, `info`, `warn`, `error` or `fatal`). + +If a consuming application uses its own logger that complies to the stdlib `Logger` API, you can simply swap it in: ```ruby conn.logger = my_logger ``` diff --git a/appveyor.yml b/appveyor.yml index f566457e..b9afb6d7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ version: "master-{build}" -image: Visual Studio 2019 +image: Visual Studio 2022 platform: - x64 @@ -11,9 +11,9 @@ environment: user_key: c:\projects\winrm\key.pem matrix: - - ruby_version: "31" + - ruby_version: "33-x64" winrm_endpoint: http://localhost:5985/wsman - - ruby_version: "30" + - ruby_version: "32-x64" winrm_endpoint: http://localhost:5985/wsman clone_folder: c:\projects\winrm diff --git a/changelog.md b/changelog.md index f27eebed..c977c60c 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,8 @@ # WinRM Gem Changelog +# Unreleased +* Replace the unmaintained `logging` gem (which depends on `syslog`, no longer a default gem in modern Ruby) with the Ruby standard library `Logger`. Breaking change: `Connection#logger` is now a stdlib `Logger`, so `logging`-specific calls like `add_appenders` no longer work; injecting a custom logger via `conn.logger=` is unchanged. `WINRM_LOG` is still honored. + # 2.3.9 * Fix snakecase `NoMethodError` by @ripa1995 in https://github.com/WinRb/WinRM/pull/347 diff --git a/lib/winrm.rb b/lib/winrm.rb index b8d49238..dd2cf024 100644 --- a/lib/winrm.rb +++ b/lib/winrm.rb @@ -1,37 +1,42 @@ -# Copyright 2010 Dan Wanek -# -# 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. - -require 'logging' -require_relative 'winrm/version' -require_relative 'winrm/connection' -require_relative 'winrm/exceptions' - -# Main WinRM module entry point -module WinRM - # Enable logging if it is requested. We do this before - # anything else so that we can setup the output before - # any logging occurs. - if ENV['WINRM_LOG'] && ENV['WINRM_LOG'] != '' - begin - Logging.logger.root.level = ENV['WINRM_LOG'] - Logging.logger.root.appenders = Logging.appenders.stderr - rescue ArgumentError - # This means that the logging level wasn't valid - warn "Invalid WINRM_LOG level is set: #{ENV['WINRM_LOG']}" - warn '' - warn 'Please use one of the standard log levels: ' \ - 'debug, info, warn, or error' - end - end -end +# Copyright 2010 Dan Wanek +# +# 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. + +require 'logger' +require_relative 'winrm/version' +require_relative 'winrm/connection' +require_relative 'winrm/exceptions' + +# Main WinRM module entry point +module WinRM + LOG_LEVELS = %w[debug info warn error fatal].freeze + + # Default log level used by WinRM loggers, controlled by the + # WINRM_LOG environment variable. Falls back to :warn when unset + # or invalid. + # @return [Symbol] One of :debug, :info, :warn, :error or :fatal + def self.default_log_level + level = ENV.fetch('WINRM_LOG', '').downcase + return :warn if level.empty? + + unless LOG_LEVELS.include?(level) + warn "Invalid WINRM_LOG level is set: #{ENV.fetch('WINRM_LOG', nil)}" + warn '' + warn 'Please use one of the standard log levels: ' \ + 'debug, info, warn, or error' + return :warn + end + + level.to_sym + end +end diff --git a/lib/winrm/connection.rb b/lib/winrm/connection.rb index bed6d880..10d597d6 100644 --- a/lib/winrm/connection.rb +++ b/lib/winrm/connection.rb @@ -65,9 +65,7 @@ def configure_connection_opts(connection_opts) end def configure_logger - @logger = Logging.logger[self] - logger.level = :warn - logger.add_appenders(Logging.appenders.stdout) + @logger = Logger.new($stdout, progname: 'WinRM', level: WinRM.default_log_level) end def shell_factory @@ -77,7 +75,7 @@ def shell_factory def transport @transport ||= begin transport_factory = WinRM::HTTP::TransportFactory.new - transport_factory.create_transport(@connection_opts) + transport_factory.create_transport(@connection_opts.merge(logger: logger)) end end end diff --git a/lib/winrm/http/transport.rb b/lib/winrm/http/transport.rb index cb086dfa..e209e151 100644 --- a/lib/winrm/http/transport.rb +++ b/lib/winrm/http/transport.rb @@ -26,7 +26,8 @@ class HttpTransport def initialize(endpoint, options) @endpoint = endpoint.is_a?(String) ? URI.parse(endpoint) : endpoint @httpcli = HTTPClient.new - @logger = Logging.logger[self] + @logger = options[:logger] || + Logger.new($stdout, progname: 'WinRM', level: WinRM.default_log_level) @httpcli.receive_timeout = options[:receive_timeout] @httpcli.default_header = { 'User-Agent': options[:user_agent] } end diff --git a/tests/integration/issue_59_spec.rb b/tests/integration/issue_59_spec.rb index f63eab89..5aa220b6 100644 --- a/tests/integration/issue_59_spec.rb +++ b/tests/integration/issue_59_spec.rb @@ -3,7 +3,7 @@ describe 'issue 59' do describe 'long running script without output' do let(:logged_output) { StringIO.new } - let(:logger) { Logging.logger(logged_output) } + let(:logger) { Logger.new(logged_output) } before do opts = connection_opts.dup diff --git a/tests/spec/psrp/recieve_response_reader_spec.rb b/tests/spec/psrp/recieve_response_reader_spec.rb index 1818761e..b40c8f22 100644 --- a/tests/spec/psrp/recieve_response_reader_spec.rb +++ b/tests/spec/psrp/recieve_response_reader_spec.rb @@ -33,7 +33,7 @@ subject do described_class.new( transport, - Logging.logger['test'] + Logger.new(IO::NULL) ) end diff --git a/tests/spec/shells/base_spec.rb b/tests/spec/shells/base_spec.rb index 953eab90..e1d67496 100644 --- a/tests/spec/shells/base_spec.rb +++ b/tests/spec/shells/base_spec.rb @@ -52,7 +52,7 @@ def out_streams allow(transport).to receive(:send_request) end - subject { described_class.new(connection_options, transport, Logging.logger['test']) } + subject { described_class.new(connection_options, transport, Logger.new(IO::NULL)) } shared_examples 'retry shell command' do it 'only closes the shell if there are too many' do diff --git a/tests/spec/shells/cmd_spec.rb b/tests/spec/shells/cmd_spec.rb index 1b67817d..04c86134 100644 --- a/tests/spec/shells/cmd_spec.rb +++ b/tests/spec/shells/cmd_spec.rb @@ -30,7 +30,7 @@ .and_return(REXML::Document.new(command_response)) end - subject { described_class.new(connection_options, transport, Logging.logger['test']) } + subject { described_class.new(connection_options, transport, Logger.new(IO::NULL)) } describe '#run' do it 'opens a shell and gets shell id' do diff --git a/tests/spec/shells/powershell_spec.rb b/tests/spec/shells/powershell_spec.rb index ee57e327..32b34912 100644 --- a/tests/spec/shells/powershell_spec.rb +++ b/tests/spec/shells/powershell_spec.rb @@ -105,7 +105,7 @@ .and_return(REXML::Document.new(test_data_xml_template.result(binding))) end - subject { described_class.new(connection_options, transport, Logging.logger['test']) } + subject { described_class.new(connection_options, transport, Logger.new(IO::NULL)) } describe '#run' do it 'opens a shell and gets shell id' do diff --git a/tests/spec/wsmv/receive_response_reader_spec.rb b/tests/spec/wsmv/receive_response_reader_spec.rb index 5c47090a..23b60fb0 100644 --- a/tests/spec/wsmv/receive_response_reader_spec.rb +++ b/tests/spec/wsmv/receive_response_reader_spec.rb @@ -11,7 +11,7 @@ subject do described_class.new( transport, - Logging.logger['test'] + Logger.new(IO::NULL) ) end diff --git a/winrm.gemspec b/winrm.gemspec index fed474ea..e0ef01fe 100644 --- a/winrm.gemspec +++ b/winrm.gemspec @@ -29,20 +29,21 @@ Gem::Specification.new do |s| s.bindir = 'bin' s.executables = ['rwinrm'] - s.required_ruby_version = '>= 3.0' + s.required_ruby_version = '>= 3.2' + s.add_runtime_dependency 'base64', '~> 0.2' s.add_runtime_dependency 'builder', '>= 2.1.2' s.add_runtime_dependency 'erubi', '~> 1.8' s.add_runtime_dependency 'gssapi', '~> 1.2' s.add_runtime_dependency 'gyoku', '~> 1.0' s.add_runtime_dependency 'httpclient', '~> 2.2', '>= 2.2.0.2' - s.add_runtime_dependency 'logging', ['>= 1.6.1', '< 3.0'] + s.add_runtime_dependency 'logger', '~> 1.6' s.add_runtime_dependency 'nori', '~> 2.0', '>= 2.7.1' s.add_runtime_dependency 'rexml', '~> 3.0' s.add_development_dependency 'pry' - s.add_development_dependency 'rake', '>= 10.3', '< 13' + s.add_development_dependency 'rake', '~> 13.0' s.add_development_dependency 'rb-readline' s.add_development_dependency 'rspec', '~> 3.2' - s.add_development_dependency 'rubocop', '~> 1.26.0' + s.add_development_dependency 'rubocop', '~> 1.87' s.add_runtime_dependency 'rubyntlm', '~> 0.6.0', '>= 0.6.3' s.metadata['rubygems_mfa_required'] = 'true'