• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Nu-hin / remote_ruby / 13530671338

25 Feb 2025 08:49PM UTC coverage: 89.697% (-0.6%) from 90.336%
13530671338

push

github

Nu-hin
Handle non-zero exit status or remote Ruby process

3 of 12 new or added lines in 3 files covered. (25.0%)

888 of 990 relevant lines covered (89.7%)

59.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

18.46
/lib/remote_ruby/ssh_adapter.rb
1
# frozen_string_literal: true
2

3
require 'net/ssh'
16✔
4
require 'remote_ruby/pipes'
16✔
5

6
module RemoteRuby
16✔
7
  # An adapter for executing Ruby code on a remote host via SSH
8
  class SSHAdapter < ConnectionAdapter
16✔
9
    UnableToExecuteError = Class.new(StandardError)
16✔
10

11
    attr_reader :host, :user, :config, :working_dir
16✔
12

13
    def initialize(host:, user: nil, working_dir: nil)
16✔
14
      super
×
15
      @host = host
×
16
      @working_dir = working_dir
×
17
      @config = Net::SSH.configuration_for(@host, true)
×
18
      @user = user || @config[:user]
×
19
    end
20

21
    def open(code)
16✔
22
      Net::SSH.start(host, user, config) do |ssh|
×
23
        with_temp_file(code, ssh) do |fname|
×
24
          Pipes.with_pipes do |p|
×
25
            t = Thread.new do
×
NEW
26
              res = run_code(ssh, fname, p.in_r, p.out_w, p.err_w)
×
NEW
27
              get_result(ssh, fname, p.res_w, res)
×
28
            end
29

30
            yield p.in_w, p.out_r, p.err_r, p.res_r
×
31
            t.join
×
32
          end
33
        end
34
      end
35
    end
36

37
    def run_code(ssh, fname, stdin_r, stdout_w, stderr_w)
16✔
NEW
38
      res = nil
×
39
      ssh.open_channel do |channel|
×
40
        channel.exec("cd '#{working_dir}' && ruby #{fname}") do |ch, success|
×
41
          raise UnableToExecuteError unless success
×
42

43
          ssh.listen_to(stdin_r) do |io|
×
44
            data = io.read_nonblock(4096)
×
45
            ch.send_data(data)
×
46
          rescue EOFError
47
            ch.eof!
×
48
          end
49

50
          ch.on_data do |_, data|
×
51
            stdout_w << data
×
52
          end
53

54
          ch.on_extended_data do |_, _, data|
×
55
            stderr_w << data
×
56
          end
57

NEW
58
          ch.on_request('exit-status') do |_, data|
×
NEW
59
            res = data.read_long
×
60
          end
61

62
          ch.on_close do |_|
×
63
            stdout_w.close
×
64
            stderr_w.close
×
65
          end
66
        end
67
      end.wait
NEW
68
      res
×
69
    end
70

71
    def get_result(ssh, fname, res_w, process_status)
16✔
NEW
72
      unless process_status.zero?
×
NEW
73
        res_w.close
×
NEW
74
        raise "Process exited with code #{process_status}"
×
75
      end
76

77
      ssh.open_channel do |channel|
×
78
        channel.exec("cat #{fname}") do |ch, success|
×
79
          raise UnableToExecuteError unless success
×
80

81
          ch.on_data do |_, data|
×
82
            res_w << data
×
83
          end
84

85
          ch.on_close do |_|
×
86
            res_w.close
×
87
          end
88
        end
89
      end.wait
90
    end
91

92
    def connection_name
16✔
93
      "#{user}@#{host}:#{working_dir || '~'}> "
×
94
    end
95

96
    def with_temp_file(code, ssh)
16✔
97
      fname = String.new
×
98
      code_channel = ssh.open_channel do |channel|
×
99
        channel.exec('f=$(mktemp remote_ruby.rb.XXXXXX) && cat > $f && echo $f') do |ch, success|
×
100
          raise UnableToExecuteError unless success
×
101

102
          ch.on_data do |_, data|
×
103
            fname << data
×
104
          end
105

106
          ch.send_data(code)
×
107
          ch.eof!
×
108
        end
109
      end
110

111
      code_channel.wait
×
112

113
      yield fname
×
114
    ensure
115
      ssh.exec!("rm #{fname}")
×
116
    end
117
  end
118
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc