yast-rake 0.2.36 → 0.2.41

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Yast rake
5
+ #
6
+ # Copyright (C) 2021 SUSE LLC
7
+ # This library is free software; you can redistribute it and/or modify
8
+ # it only under the terms of version 2.1 of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14
+ # details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ #++
20
+
21
+ require_relative "../github_actions"
22
+
23
+ module GithubActions
24
+ module Tasks
25
+ # run all supported Github Action jobs locally
26
+ class RunAll
27
+ include Colorizer
28
+
29
+ # run all jobs one by one, continue even if a job fails,
30
+ # print the summary in the end
31
+ def run
32
+ # collect failed jobs
33
+ failed_jobs = []
34
+ workflows = Workflow.read
35
+ # custom Docker image requested?
36
+ image = custom_image(workflows)
37
+
38
+ workflows.each do |workflow|
39
+ workflow.jobs.each do |job|
40
+ # skip unsupported jobs
41
+ next unless valid_job?(job)
42
+
43
+ runner = JobRunner.new(job, image)
44
+ failed_jobs << job.name if !runner.run
45
+ end
46
+ end
47
+
48
+ print_result(failed_jobs)
49
+ end
50
+
51
+ private
52
+
53
+ # check if a custom image can be used for all jobs,
54
+ # if more than one Docker image is used than it's unlikely that
55
+ # a same custom image will work for all jobs, rather abort in that case
56
+ # to avoid some strange errors when using incorrect image
57
+ # @param workflows [GithubActions::Workflow] all defined workflows
58
+ # @return [String,nil] the custom Docker image name or `nil` if not specified
59
+ def custom_image(workflows)
60
+ return nil unless ENV["DOCKER_IMAGE"]
61
+
62
+ images = workflows.each_with_object([]) do |workflow, arr|
63
+ workflow.jobs.each do |job|
64
+ arr << job.container if job.container && !arr.include?(job.container)
65
+ end
66
+ end
67
+
68
+ if images.size > 1
69
+ error("More than one Docker image is used in the workflows,")
70
+ error("DOCKER_IMAGE option cannot be used.")
71
+ puts "Use DOCKER_IMAGE option for each job separately."
72
+ abort
73
+ end
74
+
75
+ ENV["DOCKER_IMAGE"]
76
+ end
77
+
78
+ # print the final result
79
+ # @param failed_jobs [Array<String>] list of failed jobs
80
+ def print_result(failed_jobs)
81
+ if failed_jobs.empty?
82
+ success("Overall result: SUCCESS")
83
+ else
84
+ error("Failed jobs: #{failed_jobs.inspect}")
85
+ error("Overall result: FAILURE!")
86
+ abort
87
+ end
88
+ end
89
+
90
+ # check if the job is valid and can be run locally,
91
+ # if the job cannot be used it prints a warning
92
+ # @return [Boolean] `true` if the job is valid, `false` otherwise
93
+ def valid_job?(job)
94
+ unsupported = job.unsupported_steps
95
+ if !unsupported.empty?
96
+ warning("WARNING: Skipping job \"#{job.name}\", found " \
97
+ "unsupported steps: #{unsupported.inspect}")
98
+ return false
99
+ end
100
+
101
+ if job.container.nil? || job.container.empty?
102
+ warning("WARNING: Skipping job \"#{job.name}\", " \
103
+ "the Docker container in not specified")
104
+ return false
105
+ end
106
+
107
+ true
108
+ end
109
+ end
110
+ end
111
+ end
data/lib/tasks/pot.rake CHANGED
@@ -27,19 +27,36 @@ task :pot do
27
27
  end
28
28
 
29
29
  namespace :check do
30
+
31
+ def interpolation_message
32
+ <<~MSG
33
+ Note: \#{foo} substitution in translatable strings does
34
+ not work properly, use
35
+ _("foo %{bar} baz") % { :bar => bar }
36
+ or
37
+ _("foo %s baz") % bar
38
+ MSG
39
+ end
40
+
41
+ def angle_brackets_message
42
+ <<~MSG
43
+ Note: %<foo> placeholder should not be used in translatable strings
44
+ because GNU Gettext does not support any suitable language format for that,
45
+ use %{foo} instead.
46
+ MSG
47
+ end
48
+
30
49
  # print failed lines and a hint to STDERR
31
- def report_pot_errors(lines)
50
+ def report_pot_errors(lines, message)
51
+ return if lines.empty?
52
+
32
53
  warn "Failed lines:"
33
54
  warn "-" * 30
34
55
  warn lines
35
56
  warn "-" * 30
36
- $stderr.puts
37
- warn "Note: \#{foo} substitution in translatable strings does" \
38
- " not work properly, use"
39
- warn " _(\"foo %{bar} baz\") % { :bar => bar }"
40
- warn "or"
41
- warn " _(\"foo %s baz\") % bar"
42
- $stderr.puts
57
+ warn ""
58
+ warn message
59
+ warn ""
43
60
  end
44
61
 
45
62
  # remove gettext keywords and extra quotes
@@ -53,7 +70,9 @@ namespace :check do
53
70
  end
54
71
 
55
72
  desc "Check translatable strings for common mistakes"
56
- # depends on the global "pot" task defined above
73
+ # depends on the global "pot" task defined above,
74
+ # this scans for the #{} interpolations (do not work in translations)
75
+ # and %<> (no compatible language format in Gettext)
57
76
  task pot: :"rake:pot" do
58
77
  Dir["*.pot"].each do |pot|
59
78
  puts "Checking #{pot}..."
@@ -61,14 +80,18 @@ namespace :check do
61
80
  # remove comments
62
81
  lines.reject! { |line| line.match(/^#/) }
63
82
  # Ruby substitution present?
64
- lines.select! { |line| line.include?("\#{") }
83
+ interpolations = lines.select { |line| line.include?("\#{") }
84
+ angle_brackets = lines.select { |line| line.include?("%<") }
85
+
86
+ next if interpolations.empty? && angle_brackets.empty?
87
+
88
+ clean_pot_lines(interpolations)
89
+ clean_pot_lines(angle_brackets)
65
90
 
66
- clean_pot_lines(lines)
91
+ report_pot_errors(interpolations, interpolation_message)
92
+ report_pot_errors(angle_brackets, angle_brackets_message)
67
93
 
68
- if !lines.empty?
69
- report_pot_errors(lines)
70
- raise "ERROR: Ruby substitution found in a translatable string"
71
- end
94
+ raise "ERROR: Found invalid or unsupported translatable string"
72
95
  end
73
96
  end
74
97
  end
data/lib/tasks/run.rake CHANGED
@@ -18,6 +18,8 @@
18
18
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
19
  #++
20
20
 
21
+ require_relative "container_runner"
22
+
21
23
  def set_y2dir
22
24
  dirs = Dir["**/src"]
23
25
  dirs << ENV["Y2DIR"] if ENV["Y2DIR"] && !ENV["Y2DIR"].empty?
@@ -46,6 +48,15 @@ task :run, :client do |_t, args|
46
48
  sh "/sbin/yast2 #{client}"
47
49
  end
48
50
 
51
+ desc "Run given client in a Docker container"
52
+ task :"run:container", :client do |_t, args|
53
+ args.with_defaults = { client: nil }
54
+ client = args[:client]
55
+
56
+ runner = ContainerRunner.new
57
+ runner.run(client)
58
+ end
59
+
49
60
  desc "Runs console with preloaded module directories"
50
61
  task :console do
51
62
  set_y2dir
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Yast rake
5
+ #
6
+ # Copyright (C) 2020, SUSE LLC
7
+ # This library is free software; you can redistribute it and/or modify
8
+ # it only under the terms of version 2.1 of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14
+ # details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ #++
20
+
21
+ require_relative "../yast/tarball_server"
22
+
23
+ # Rake task for running a source code web server,
24
+ # designed for the `yupdate` script.
25
+ desc "Start an HTTP server providing dynamically generated source code tarball"
26
+ task :server, [:port] do |_task, args|
27
+ server = Yast::TarballServer.new(args[:port])
28
+
29
+ puts "Starting tarball webserver:"
30
+ server.addresses.each { |a| puts " * #{a}" }
31
+ puts
32
+
33
+ server.start
34
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Yast rake
5
+ #
6
+ # Copyright (C) 2020, SUSE LLC
7
+ # This library is free software; you can redistribute it and/or modify
8
+ # it only under the terms of version 2.1 of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14
+ # details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ #++
20
+
21
+ require "webrick"
22
+
23
+ module Yast
24
+ # a webrick servlet which returns a basic HTML info about the server,
25
+ # just to avoid that nasty 404 error page when someone opens the
26
+ # server URL in a web browser
27
+ class IndexServlet < WEBrick::HTTPServlet::AbstractServlet
28
+ INDEX_FILE = File.expand_path("../../data/index.html", __dir__)
29
+
30
+ def do_GET(_request, response)
31
+ response.status = 200
32
+ response.content_type = "text/html"
33
+ response.body = File.read(INDEX_FILE)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Yast rake
5
+ #
6
+ # Copyright (C) 2020, SUSE LLC
7
+ # This library is free software; you can redistribute it and/or modify
8
+ # it only under the terms of version 2.1 of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14
+ # details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ #++
20
+
21
+ require "json"
22
+ require "webrick"
23
+
24
+ module Yast
25
+ # a webrick servlet which lists all rake servers running on this machine
26
+ class ServersServlet < WEBrick::HTTPServlet::AbstractServlet
27
+ def do_GET(_request, response)
28
+ response.status = 200
29
+ response.content_type = "application/json"
30
+ response.body = servers.to_json
31
+ end
32
+
33
+ private
34
+
35
+ # find the locally running "rake server" processes
36
+ def servers
37
+ output = `pgrep -a -f "rake server \\([0-9]+,.*\\)"`
38
+ output.lines.map do |l|
39
+ l.match(/rake server \(([0-9]+),(.*)\)/)
40
+ {
41
+ port: Regexp.last_match[1],
42
+ dir: Regexp.last_match[2]
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Yast rake
5
+ #
6
+ # Copyright (C) 2020, SUSE LLC
7
+ # This library is free software; you can redistribute it and/or modify
8
+ # it only under the terms of version 2.1 of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14
+ # details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ #++
20
+
21
+ require "webrick"
22
+ require "socket"
23
+
24
+ require_relative "index_servlet"
25
+ require_relative "servers_servlet"
26
+ require_relative "tarball_servlet"
27
+
28
+ module Yast
29
+ # a webrick server which provides the source tarballs
30
+ #
31
+ # the server handles these URL paths:
32
+ # - "/archive/current.tar.gz" - the generated source code tarball
33
+ # - "/servers/index.json" - index of the tarball servers running on this machine
34
+ # - "/" - just a simple index page
35
+ #
36
+ # to stop the server press Ctrl+C
37
+ class TarballServer
38
+ # the default port number
39
+ DEFAULT_HTTP_PORT = 8000
40
+
41
+ attr_reader :port
42
+
43
+ # create all URLs valid for this machine, use all network interfaces
44
+ # (except the loop backs, the server will be used only from outside)
45
+ # @return [Array<String>] list of URLs
46
+ def addresses
47
+ # ignore the loopback addresses
48
+ hosts = Socket.ip_address_list.reject { |a| a.ipv4_loopback? || a.ipv6_loopback? }
49
+ # IPv6 addresses need to be closed in square brackets in URLs
50
+ hosts.map! { |a| a.ipv6? ? "[#{a.ip_address}]" : a.ip_address.to_s }
51
+ # include also the hostname to make it easier to write
52
+ hostname = Socket.gethostname
53
+ hosts << hostname if !hostname&.empty?
54
+ hosts.map! { |h| "http://#{h}:#{port}" }
55
+ end
56
+
57
+ # constructor
58
+ #
59
+ # @param port [Integer,nil] the port number, if nil the port will be found automatically
60
+ #
61
+ def initialize(port = nil)
62
+ @port = port || find_port
63
+ end
64
+
65
+ # start the webserver, it can be closed by pressing Ctrl+C or by sending SIGTERM signal
66
+ def start
67
+ dir = File.basename(Dir.pwd)
68
+ # change the process title so we can find the running
69
+ # servers and their ports just by simple grepping the running processes
70
+ Process.setproctitle("rake server (#{port},#{dir})")
71
+
72
+ # Use "*" to bind also the IPv6 addresses
73
+ server = WEBrick::HTTPServer.new(Port: port, BindAddress: "*")
74
+ server.mount("/archive/current.tar.gz", TarballServlet)
75
+ server.mount("/servers/index.json", ServersServlet)
76
+ server.mount("/", IndexServlet)
77
+
78
+ # stop the server when receiving a signal like Ctrl+C
79
+ # (inspired by the "un.rb" from the Ruby stdlib)
80
+ signals = ["TERM", "QUIT"]
81
+ signals.concat(["HUP", "INT"]) if $stdin.tty?
82
+ signals.each do |s|
83
+ trap(s) { server.shutdown }
84
+ end
85
+
86
+ server.start
87
+ end
88
+
89
+ private
90
+
91
+ # is the local port already taken by some other application?
92
+ # @param port [Integer] the port number
93
+ # @return [Boolean] true if the port is taken, false otherwise
94
+ def port_taken?(port)
95
+ # open the port and close it immediately, if that succeeds
96
+ # some other application is already using it
97
+ TCPSocket.new("localhost", port).close
98
+ true
99
+ rescue Errno::ECONNREFUSED
100
+ false
101
+ end
102
+
103
+ # find a free port starting from the default port number
104
+ # @return [Integer] the free port number
105
+ def find_port
106
+ DEFAULT_HTTP_PORT.step.find { |p| !port_taken?(p) }
107
+ end
108
+ end
109
+ end