highway 0.0.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/highway.rb +8 -4
- data/lib/highway/compiler/analyze/analyzer.rb +249 -0
- data/lib/highway/compiler/analyze/tree/root.rb +95 -0
- data/lib/highway/compiler/analyze/tree/segments/text.rb +36 -0
- data/lib/highway/compiler/analyze/tree/segments/variable.rb +43 -0
- data/lib/highway/compiler/analyze/tree/stage.rb +48 -0
- data/lib/highway/compiler/analyze/tree/step.rb +69 -0
- data/lib/highway/compiler/analyze/tree/values/array.rb +45 -0
- data/lib/highway/compiler/analyze/tree/values/base.rb +67 -0
- data/lib/highway/compiler/analyze/tree/values/hash.rb +45 -0
- data/lib/highway/compiler/analyze/tree/values/primitive.rb +43 -0
- data/lib/highway/compiler/analyze/tree/variable.rb +48 -0
- data/lib/highway/compiler/build/builder.rb +154 -0
- data/lib/highway/compiler/build/output/invocation.rb +70 -0
- data/lib/highway/compiler/build/output/manifest.rb +52 -0
- data/lib/highway/compiler/parse/parser.rb +92 -0
- data/lib/highway/compiler/parse/tree/root.rb +73 -0
- data/lib/highway/compiler/parse/tree/step.rb +62 -0
- data/lib/highway/compiler/parse/tree/variable.rb +48 -0
- data/lib/highway/compiler/parse/versions/v1.rb +110 -0
- data/lib/highway/compiler/suite.rb +56 -0
- data/lib/highway/environment.rb +282 -0
- data/lib/highway/fastlane/action.rb +67 -0
- data/lib/highway/interface.rb +135 -0
- data/lib/highway/main.rb +173 -0
- data/lib/highway/runtime/context.rb +229 -0
- data/lib/highway/runtime/report.rb +80 -0
- data/lib/highway/runtime/runner.rb +286 -0
- data/lib/highway/steps/infrastructure.rb +20 -0
- data/lib/highway/steps/library/action.rb +42 -0
- data/lib/highway/steps/library/appcenter.rb +106 -0
- data/lib/highway/steps/library/appstore.rb +137 -0
- data/lib/highway/steps/library/carthage.rb +67 -0
- data/lib/highway/steps/library/cocoapods.rb +76 -0
- data/lib/highway/steps/library/copy_artifacts.rb +36 -0
- data/lib/highway/steps/library/lane.rb +42 -0
- data/lib/highway/steps/library/sh.rb +36 -0
- data/lib/highway/steps/library/slack.rb +381 -0
- data/lib/highway/steps/library/testflight.rb +105 -0
- data/lib/highway/steps/library/xcode_archive.rb +162 -0
- data/lib/highway/steps/library/xcode_test.rb +264 -0
- data/lib/highway/steps/parameters/base.rb +52 -0
- data/lib/highway/steps/parameters/compound.rb +141 -0
- data/lib/highway/steps/parameters/single.rb +74 -0
- data/lib/highway/steps/registry.rb +92 -0
- data/lib/highway/steps/step.rb +52 -0
- data/lib/highway/steps/types/any.rb +65 -0
- data/lib/highway/steps/types/anyof.rb +64 -0
- data/lib/highway/steps/types/array.rb +44 -0
- data/lib/highway/steps/types/bool.rb +36 -0
- data/lib/highway/steps/types/enum.rb +44 -0
- data/lib/highway/steps/types/hash.rb +45 -0
- data/lib/highway/steps/types/number.rb +38 -0
- data/lib/highway/steps/types/set.rb +39 -0
- data/lib/highway/steps/types/string.rb +47 -0
- data/lib/highway/steps/types/url.rb +35 -0
- data/lib/highway/utilities.rb +51 -0
- data/lib/highway/version.rb +9 -1
- metadata +194 -22
- data/.gitignore +0 -4
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/highway.gemspec +0 -24
@@ -0,0 +1,137 @@
|
|
1
|
+
#
|
2
|
+
# appstore.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "fastlane"
|
7
|
+
|
8
|
+
require "highway/steps/infrastructure"
|
9
|
+
|
10
|
+
module Highway
|
11
|
+
module Steps
|
12
|
+
module Library
|
13
|
+
|
14
|
+
class AppStoreStep < Step
|
15
|
+
|
16
|
+
def self.name
|
17
|
+
"appstore"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.parameters
|
21
|
+
[
|
22
|
+
Parameters::Single.new(
|
23
|
+
name: "app_identifier",
|
24
|
+
required: true,
|
25
|
+
type: Types::String.new()
|
26
|
+
),
|
27
|
+
Parameters::Single.new(
|
28
|
+
name: "build_number",
|
29
|
+
required: false,
|
30
|
+
type: Types::String.new()
|
31
|
+
),
|
32
|
+
Parameters::Single.new(
|
33
|
+
name: "force",
|
34
|
+
required: false,
|
35
|
+
default: true,
|
36
|
+
type: Types::Bool.new()
|
37
|
+
),
|
38
|
+
Parameters::Single.new(
|
39
|
+
name: "metadata_path",
|
40
|
+
required: false,
|
41
|
+
type: Types::String.new()
|
42
|
+
),
|
43
|
+
Parameters::Single.new(
|
44
|
+
name: "password",
|
45
|
+
required: true,
|
46
|
+
type: Types::String.new()
|
47
|
+
),
|
48
|
+
Parameters::Single.new(
|
49
|
+
name: "session",
|
50
|
+
required: false,
|
51
|
+
type: Types::String.new()
|
52
|
+
),
|
53
|
+
Parameters::Single.new(
|
54
|
+
name: "screenshots_path",
|
55
|
+
required: false,
|
56
|
+
type: Types::String.new()
|
57
|
+
),
|
58
|
+
Parameters::Single.new(
|
59
|
+
name: "skip_app_version_update",
|
60
|
+
required: false,
|
61
|
+
default: false,
|
62
|
+
type: Types::Bool.new()
|
63
|
+
),
|
64
|
+
Parameters::Single.new(
|
65
|
+
name: "skip_binary_upload",
|
66
|
+
required: false,
|
67
|
+
default: false,
|
68
|
+
type: Types::Bool.new()
|
69
|
+
),
|
70
|
+
Parameters::Single.new(
|
71
|
+
name: "submit_for_review",
|
72
|
+
required: false,
|
73
|
+
default: false,
|
74
|
+
type: Types::Bool.new()
|
75
|
+
),
|
76
|
+
Parameters::Single.new(
|
77
|
+
name: "team_id",
|
78
|
+
required: false,
|
79
|
+
type: Types::String.new()
|
80
|
+
),
|
81
|
+
Parameters::Single.new(
|
82
|
+
name: "team_name",
|
83
|
+
required: false,
|
84
|
+
type: Types::String.new()
|
85
|
+
),
|
86
|
+
Parameters::Single.new(
|
87
|
+
name: "username",
|
88
|
+
required: true,
|
89
|
+
type: Types::String.regex(/^\S+@\S+\.\S+$/)
|
90
|
+
)
|
91
|
+
]
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.run(parameters:, context:, report:)
|
95
|
+
|
96
|
+
username = parameters["username"]
|
97
|
+
password = parameters["password"]
|
98
|
+
session = parameters["session"]
|
99
|
+
app_identifier = parameters["app_identifier"]
|
100
|
+
metadata_path = parameters["metadata_path"]
|
101
|
+
screenshots_path = parameters["screenshots_path"]
|
102
|
+
skip_app_version_update = parameters["skip_app_version_update"]
|
103
|
+
submit_for_review = parameters["submit_for_review"]
|
104
|
+
team_id = parameters["team_id"]
|
105
|
+
team_name = parameters["team_name"]
|
106
|
+
skip_binary_upload = parameters["skip_binary_upload"]
|
107
|
+
force = parameters["force"]
|
108
|
+
build_number = parameters["build_number"]
|
109
|
+
|
110
|
+
env = {
|
111
|
+
"FASTLANE_PASSWORD" => password,
|
112
|
+
"FASTLANE_SESSION" => session
|
113
|
+
}
|
114
|
+
|
115
|
+
context.with_modified_env(env) {
|
116
|
+
context.run_action("upload_to_app_store", options: {
|
117
|
+
username: username,
|
118
|
+
app_identifier: app_identifier,
|
119
|
+
metadata_path: metadata_path,
|
120
|
+
screenshots_path: screenshots_path,
|
121
|
+
skip_app_version_update: skip_app_version_update,
|
122
|
+
submit_for_review: submit_for_review,
|
123
|
+
team_id: team_id,
|
124
|
+
skip_binary_upload: skip_binary_upload,
|
125
|
+
build_number: build_number,
|
126
|
+
team_name: team_name,
|
127
|
+
force: force
|
128
|
+
})
|
129
|
+
}
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#
|
2
|
+
# carthage.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "highway/steps/infrastructure"
|
7
|
+
|
8
|
+
module Highway
|
9
|
+
module Steps
|
10
|
+
module Library
|
11
|
+
|
12
|
+
class CarthageStep < Step
|
13
|
+
|
14
|
+
def self.name
|
15
|
+
"carthage"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parameters
|
19
|
+
[
|
20
|
+
Parameters::Single.new(
|
21
|
+
name: "command",
|
22
|
+
required: false,
|
23
|
+
type: Types::Enum.new("bootstrap", "update"),
|
24
|
+
default: "bootstrap",
|
25
|
+
),
|
26
|
+
Parameters::Single.new(
|
27
|
+
name: "github_token",
|
28
|
+
required: false,
|
29
|
+
type: Types::String.new(),
|
30
|
+
),
|
31
|
+
Parameters::Single.new(
|
32
|
+
name: "platforms",
|
33
|
+
required: true,
|
34
|
+
type: Types::Set.new(Types::Enum.new("macos", "ios", "tvos", "watchos")),
|
35
|
+
),
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.run(parameters:, context:, report:)
|
40
|
+
|
41
|
+
context.assert_executable_available!("carthage")
|
42
|
+
|
43
|
+
command = parameters["command"]
|
44
|
+
token = parameters["github_token"]
|
45
|
+
|
46
|
+
platform_map = {macos: "Mac", ios: "iOS", tvos: "tvOS", watchos: "watchOS"}
|
47
|
+
platform = parameters["platforms"].to_a.map { |p| platform_map[p.to_sym] }.join(",")
|
48
|
+
|
49
|
+
env = {
|
50
|
+
"GITHUB_ACCESS_TOKEN" => token
|
51
|
+
}
|
52
|
+
|
53
|
+
context.with_modified_env(env) {
|
54
|
+
context.run_action("carthage", options: {
|
55
|
+
cache_builds: true,
|
56
|
+
command: command,
|
57
|
+
platform: platform,
|
58
|
+
})
|
59
|
+
}
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#
|
2
|
+
# cocoapods.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "highway/steps/infrastructure"
|
7
|
+
|
8
|
+
module Highway
|
9
|
+
module Steps
|
10
|
+
module Library
|
11
|
+
|
12
|
+
class CocoaPodsStep < Step
|
13
|
+
|
14
|
+
def self.name
|
15
|
+
"cocoapods"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parameters
|
19
|
+
[
|
20
|
+
Parameters::Single.new(
|
21
|
+
name: "command",
|
22
|
+
required: false,
|
23
|
+
type: Types::Enum.new("install", "update"),
|
24
|
+
default: "install",
|
25
|
+
),
|
26
|
+
Parameters::Single.new(
|
27
|
+
name: "update_specs_repo",
|
28
|
+
required: false,
|
29
|
+
type: Types::Enum.new("always", "never", "on-error"),
|
30
|
+
default: "never",
|
31
|
+
),
|
32
|
+
]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.run(parameters:, context:, report:)
|
36
|
+
|
37
|
+
context.assert_gem_available!("cocoapods")
|
38
|
+
|
39
|
+
command = parameters["command"]
|
40
|
+
update_specs_repo = parameters["update_specs_repo"]
|
41
|
+
|
42
|
+
repo_update_always = update_specs_repo == "always"
|
43
|
+
repo_update_on_error = update_specs_repo == "on-error"
|
44
|
+
|
45
|
+
if command == "install"
|
46
|
+
|
47
|
+
context.run_action("cocoapods", options: {
|
48
|
+
repo_update: repo_update_always,
|
49
|
+
try_repo_update_on_error: repo_update_on_error,
|
50
|
+
use_bundle_exec: context.should_use_bundle_exec?,
|
51
|
+
})
|
52
|
+
|
53
|
+
elsif command == "update"
|
54
|
+
|
55
|
+
invocation = []
|
56
|
+
invocation << "bundle exec" if context.should_use_bundle_exec?
|
57
|
+
invocation << "pod update"
|
58
|
+
invocation << "--repo-update" if repo_update_always
|
59
|
+
|
60
|
+
context.run_sh(invocation.join(" "), on_error: lambda { |error|
|
61
|
+
if repo_update_on_error
|
62
|
+
context.run_sh((invocation + ["--repo-update"]).join(" "))
|
63
|
+
else
|
64
|
+
context.reporter.fatal!(error)
|
65
|
+
end
|
66
|
+
})
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#
|
2
|
+
# copy_artifacts.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "highway/steps/infrastructure"
|
7
|
+
|
8
|
+
module Highway
|
9
|
+
module Steps
|
10
|
+
module Library
|
11
|
+
|
12
|
+
class CopyArtifactsStep < Step
|
13
|
+
|
14
|
+
def self.name
|
15
|
+
"copy_artifacts"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parameters
|
19
|
+
[
|
20
|
+
Parameters::Single.new(
|
21
|
+
name: "path",
|
22
|
+
required: true,
|
23
|
+
type: Types::String.new(),
|
24
|
+
)
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run(parameters:, context:, report:)
|
29
|
+
FileUtils.copy_entry(context.artifacts_dir, parameters["path"], false, false, false)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# lane.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "highway/steps/infrastructure"
|
7
|
+
|
8
|
+
module Highway
|
9
|
+
module Steps
|
10
|
+
module Library
|
11
|
+
|
12
|
+
class LaneStep < Step
|
13
|
+
|
14
|
+
def self.name
|
15
|
+
"lane"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parameters
|
19
|
+
[
|
20
|
+
Parameters::Single.new(
|
21
|
+
name: "name",
|
22
|
+
required: true,
|
23
|
+
type: Types::String.new(),
|
24
|
+
),
|
25
|
+
Parameters::Single.new(
|
26
|
+
name: "options",
|
27
|
+
required: false,
|
28
|
+
type: Types::Hash.new(Types::Any.new()),
|
29
|
+
default: {},
|
30
|
+
),
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.run(parameters:, context:, report:)
|
35
|
+
context.run_lane(parameters["name"], options: parameters["options"])
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#
|
2
|
+
# sh.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "highway/steps/infrastructure"
|
7
|
+
|
8
|
+
module Highway
|
9
|
+
module Steps
|
10
|
+
module Library
|
11
|
+
|
12
|
+
class ShStep < Step
|
13
|
+
|
14
|
+
def self.name
|
15
|
+
"sh"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parameters
|
19
|
+
[
|
20
|
+
Parameters::Single.new(
|
21
|
+
name: "command",
|
22
|
+
required: true,
|
23
|
+
type: Types::String.new(),
|
24
|
+
),
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run(parameters:, context:, report:)
|
29
|
+
context.run_sh(parameters["command"])
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,381 @@
|
|
1
|
+
#
|
2
|
+
# slack.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "fastlane"
|
7
|
+
require "slack-notifier"
|
8
|
+
|
9
|
+
require "highway/steps/infrastructure"
|
10
|
+
|
11
|
+
module Highway
|
12
|
+
module Steps
|
13
|
+
module Library
|
14
|
+
|
15
|
+
class SlackStep < Step
|
16
|
+
|
17
|
+
def self.name
|
18
|
+
"slack"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.parameters
|
22
|
+
[
|
23
|
+
Parameters::Single.new(
|
24
|
+
name: "avatar",
|
25
|
+
required: false,
|
26
|
+
type: Types::AnyOf.new(
|
27
|
+
url: Types::Url.new(),
|
28
|
+
emoji: Types::String.regex(/\:[a-z0-9_-]+\:/),
|
29
|
+
),
|
30
|
+
),
|
31
|
+
Parameters::Single.new(
|
32
|
+
name: "channel",
|
33
|
+
required: true,
|
34
|
+
type: Types::String.regex(/#[a-z0-9_-]+/)
|
35
|
+
),
|
36
|
+
Parameters::Single.new(
|
37
|
+
name: "username",
|
38
|
+
required: false,
|
39
|
+
type: Types::String.new(),
|
40
|
+
default: "Highway",
|
41
|
+
),
|
42
|
+
Parameters::Single.new(
|
43
|
+
name: "webhook",
|
44
|
+
required: true,
|
45
|
+
type: Types::Url.new(),
|
46
|
+
),
|
47
|
+
]
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.run(parameters:, context:, report:)
|
51
|
+
|
52
|
+
username = parameters["username"]
|
53
|
+
webhook = parameters["webhook"].to_s
|
54
|
+
avatar_emoji = parameters["avatar"][:value] if parameters["avatar"]&[:tag] == :emoji
|
55
|
+
avatar_url = parameters["avatar"][:value].to_s if parameters["avatar"]&[:tag] == :url
|
56
|
+
|
57
|
+
attachments = [
|
58
|
+
generate_build_attachments(context),
|
59
|
+
generate_tests_attachments(context),
|
60
|
+
generate_deployment_attachments(context),
|
61
|
+
]
|
62
|
+
|
63
|
+
attachments = attachments.flatten.compact
|
64
|
+
|
65
|
+
attachments.each { |attachment|
|
66
|
+
attachment[:mrkdwn_in] = [:text, :fields]
|
67
|
+
attachment[:fallback] ||= attachment.fetch(:fields, []).reduce([]) { |memo, field| memo + ["#{field[:title]}: #{field[:value]}."] }.join(" ")
|
68
|
+
}
|
69
|
+
|
70
|
+
attachments.each { |attachment|
|
71
|
+
attachment[:fields].each { |field| field[:value] = Slack::Notifier::Util::LinkFormatter.format(field[:value]) }
|
72
|
+
attachment[:fallback] = Slack::Notifier::Util::LinkFormatter.format(attachment[:fallback])
|
73
|
+
}
|
74
|
+
|
75
|
+
notifier = Slack::Notifier.new(webhook)
|
76
|
+
|
77
|
+
notifier.post({
|
78
|
+
username: username,
|
79
|
+
icon_emoji: avatar_emoji,
|
80
|
+
icon_url: avatar_url,
|
81
|
+
attachments: attachments,
|
82
|
+
})
|
83
|
+
|
84
|
+
context.interface.success("Successfully posted a report message on Slack.")
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def self.generate_build_attachments(context)
|
91
|
+
|
92
|
+
# Generate main field containing information about build status
|
93
|
+
# and its identifier.
|
94
|
+
|
95
|
+
main_title = context.reports_any_failed? ? "Build failed" : "Build succeeded"
|
96
|
+
|
97
|
+
if context.env.ci?
|
98
|
+
if context.env.ci_build_number != nil
|
99
|
+
if context.env.ci_build_url != nil
|
100
|
+
main_value = "[#{context.env.ci_build_number}](#{context.env.ci_build_url})"
|
101
|
+
else
|
102
|
+
main_value = "#{context.env.ci_build_number}"
|
103
|
+
end
|
104
|
+
else
|
105
|
+
main_value = "(unknown build)"
|
106
|
+
end
|
107
|
+
else
|
108
|
+
main_value = "(local build)"
|
109
|
+
end
|
110
|
+
|
111
|
+
# Generate duration field, rounding and ceiling it to minutes, if
|
112
|
+
# possible.
|
113
|
+
|
114
|
+
duration_title = "Duration"
|
115
|
+
|
116
|
+
if context.duration_so_far > 60
|
117
|
+
duration_value = "#{(context.duration_so_far.to_f / 60).ceil} minutes"
|
118
|
+
else
|
119
|
+
duration_value = "#{context.duration_so_far} seconds"
|
120
|
+
end
|
121
|
+
|
122
|
+
# Generate pull request field, containing number, title and a URL,
|
123
|
+
# if possible.
|
124
|
+
|
125
|
+
pr_title = "Pull Request"
|
126
|
+
|
127
|
+
if context.env.ci_trigger == :pr && context.env.git_pr_number != nil
|
128
|
+
if context.env.git_pr_url != nil
|
129
|
+
if context.env.git_pr_title != nil
|
130
|
+
pr_value = "[##{context.env.git_pr_number}: #{context.env.git_pr_title}](#{context.env.git_pr_url})"
|
131
|
+
else
|
132
|
+
pr_value = "[##{context.env.git_pr_number}](#{context.env.git_pr_url})"
|
133
|
+
end
|
134
|
+
else
|
135
|
+
if context.env.git_pr_title != nil
|
136
|
+
pr_value = "##{context.env.git_pr_number}: #{context.env.git_pr_title}"
|
137
|
+
else
|
138
|
+
pr_value = "##{context.env.git_pr_number}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Generate commit field, containing hash, message and a URL, if
|
144
|
+
# possible.
|
145
|
+
|
146
|
+
commit_title = "Commit"
|
147
|
+
|
148
|
+
if context.env.git_commit_hash != nil
|
149
|
+
if context.env.git_commit_message != nil
|
150
|
+
commit_value = "#{context.env.git_commit_hash[0,7]}: #{context.env.git_commit_message}"
|
151
|
+
else
|
152
|
+
commit_value = "#{context.env.git_commit_hash}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Infer the attachment color.
|
157
|
+
|
158
|
+
attachment_color = context.reports_any_failed? ? "danger" : "good"
|
159
|
+
|
160
|
+
# Assemble the attachment.
|
161
|
+
|
162
|
+
attachment_fields = []
|
163
|
+
attachment_fields << {title: main_title, value: main_value, short: true} if main_value != nil
|
164
|
+
attachment_fields << {title: duration_title, value: duration_value, short: true} if duration_value != nil
|
165
|
+
attachment_fields << {title: pr_title, value: pr_value, short: false} if pr_value != nil
|
166
|
+
attachment_fields << {title: commit_title, value: commit_value, short: false} if commit_value != nil
|
167
|
+
|
168
|
+
{
|
169
|
+
color: attachment_color,
|
170
|
+
fields: attachment_fields,
|
171
|
+
}
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.generate_tests_attachments(context)
|
176
|
+
|
177
|
+
# Skip if there are no test reports.
|
178
|
+
|
179
|
+
report = prepare_tests_report(context)
|
180
|
+
return nil unless report != nil
|
181
|
+
|
182
|
+
# Prepare variables.
|
183
|
+
|
184
|
+
result = :error if !report[:errors].empty?
|
185
|
+
result ||= :failure if !report[:failures].empty?
|
186
|
+
result ||= :success
|
187
|
+
|
188
|
+
errors = report[:errors]
|
189
|
+
failures = report[:failures]
|
190
|
+
count = report[:count]
|
191
|
+
|
192
|
+
# Generate main field containing the information about the result and
|
193
|
+
# counts of all, successful and failed tests.
|
194
|
+
|
195
|
+
main_title = case result
|
196
|
+
when :success then "Tests succeeded"
|
197
|
+
when :failure, :error then "Tests failed"
|
198
|
+
end
|
199
|
+
|
200
|
+
main_value = "Executed #{count[:all]} tests: #{count[:succeeded]} succeeded, #{count[:failed]} failed."
|
201
|
+
|
202
|
+
# Generate errors field containing first three error locations and
|
203
|
+
# reasons.
|
204
|
+
|
205
|
+
unless errors.empty?
|
206
|
+
|
207
|
+
errors_title = "Compile errors"
|
208
|
+
|
209
|
+
errors_messages = errors.first(3).map { |error|
|
210
|
+
if error[:location]
|
211
|
+
"```#{error[:location]}: #{error[:reason]}```"
|
212
|
+
else
|
213
|
+
"```#{error[:reason]}```"
|
214
|
+
end
|
215
|
+
}
|
216
|
+
|
217
|
+
errors_value = errors_messages.join("\n")
|
218
|
+
errors_value << "\nand #{errors.count - 3} more..." if errors.count > 3
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
# Generate failures field containing first three failure locations and
|
223
|
+
# reasons.
|
224
|
+
|
225
|
+
unless failures.empty?
|
226
|
+
|
227
|
+
failures_title = "Failing test cases"
|
228
|
+
|
229
|
+
failures_messages = failures.first(3).map { |failure|
|
230
|
+
"```#{failure[:location]}: #{failure[:reason]}```"
|
231
|
+
}
|
232
|
+
|
233
|
+
failures_value = failures_messages.join("\n")
|
234
|
+
failures_value << "\nand #{failures.count - 3} more..." if failures.count > 3
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
# Generate the fallback value.
|
239
|
+
|
240
|
+
attachment_fallback = case result
|
241
|
+
when :success then "Tests succeeded. #{main_value}"
|
242
|
+
when :failure then "Tests failed. #{main_value}"
|
243
|
+
when :error then "Tests failed. One or more compiler errors occured."
|
244
|
+
end
|
245
|
+
|
246
|
+
# Infer the attachment color.
|
247
|
+
|
248
|
+
attachment_color = case result
|
249
|
+
when :success then "good"
|
250
|
+
when :failure, :error then "danger"
|
251
|
+
end
|
252
|
+
|
253
|
+
# Assemble the attachment.
|
254
|
+
|
255
|
+
attachment_fields = []
|
256
|
+
attachment_fields << {title: main_title, value: main_value, short: false} if main_value != nil
|
257
|
+
attachment_fields << {title: errors_title, value: errors_value, short: false} if errors_value != nil
|
258
|
+
attachment_fields << {title: failures_title, value: failures_value, short: false} if failures_value != nil
|
259
|
+
|
260
|
+
{
|
261
|
+
color: attachment_color,
|
262
|
+
fields: attachment_fields,
|
263
|
+
fallback: attachment_fallback,
|
264
|
+
}
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
def self.prepare_tests_report(context)
|
269
|
+
|
270
|
+
return nil if context.test_reports.empty?
|
271
|
+
|
272
|
+
zero_report = {
|
273
|
+
errors: [],
|
274
|
+
failures: [],
|
275
|
+
count: {all: 0, failed: 0, succeeded: 0}
|
276
|
+
}
|
277
|
+
|
278
|
+
merged_results = context.test_reports.map { |report|
|
279
|
+
report[:result]
|
280
|
+
}
|
281
|
+
|
282
|
+
merged_report = context.test_reports.reduce(zero_report) { |memo, report|
|
283
|
+
{
|
284
|
+
errors: memo[:errors] + report[:test][:errors],
|
285
|
+
failures: memo[:failures] + report[:test][:failures],
|
286
|
+
count: {
|
287
|
+
all: memo[:count][:all] + report[:test][:count][:all],
|
288
|
+
failed: memo[:count][:failed] + report[:test][:count][:failed],
|
289
|
+
succeeded: memo[:count][:succeeded] + report[:test][:count][:succeeded],
|
290
|
+
}
|
291
|
+
}
|
292
|
+
}
|
293
|
+
|
294
|
+
merged_report[:result] = merged_results.each_cons(2) { |lhs, rhs|
|
295
|
+
if lhs == :error || rhs == :error
|
296
|
+
:error
|
297
|
+
elsif lhs == :failure || rhs == :failure
|
298
|
+
:failure
|
299
|
+
elsif lhs == :succeess && rhs == :success
|
300
|
+
:success
|
301
|
+
else
|
302
|
+
:failure
|
303
|
+
end
|
304
|
+
}
|
305
|
+
|
306
|
+
merged_report
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
def self.generate_deployment_attachments(context)
|
311
|
+
|
312
|
+
# Skip if there are no deployment reports.
|
313
|
+
|
314
|
+
reports = context.deployment_reports
|
315
|
+
return nil if reports.empty?
|
316
|
+
|
317
|
+
# Map reports into attachments.
|
318
|
+
|
319
|
+
attachments = reports.map { |report|
|
320
|
+
prepare_deployment_attachment(report[:deployment])
|
321
|
+
}
|
322
|
+
|
323
|
+
attachments
|
324
|
+
|
325
|
+
end
|
326
|
+
|
327
|
+
def self.prepare_deployment_attachment(report)
|
328
|
+
|
329
|
+
# Generate main field containing the information about deployment
|
330
|
+
# result and information.
|
331
|
+
|
332
|
+
main_title = "Deployment succeeded"
|
333
|
+
|
334
|
+
package_comps = []
|
335
|
+
package_comps << report[:package][:name]
|
336
|
+
package_comps << report[:package][:version]
|
337
|
+
package_comps << "(#{report[:package][:build]})" if report[:package][:build] != nil
|
338
|
+
|
339
|
+
package_value = package_comps.compact.join(" ").strip
|
340
|
+
package_value = "(unknown package)" if package_value.empty?
|
341
|
+
|
342
|
+
main_value = "Successfully deployed #{package_value} to #{report[:service]}."
|
343
|
+
|
344
|
+
# Generate install button pointing to the installation page.
|
345
|
+
|
346
|
+
install_title = "Install"
|
347
|
+
install_url = report[:urls][:install]
|
348
|
+
|
349
|
+
# Generate manage button pointing to the view page.
|
350
|
+
|
351
|
+
view_title = "View"
|
352
|
+
view_url = report[:urls][:view]
|
353
|
+
|
354
|
+
# Generate the attachment fallback value and color.
|
355
|
+
|
356
|
+
attachment_fallback = "Deployment succeeded. #{main_value}"
|
357
|
+
attachment_color = "good"
|
358
|
+
|
359
|
+
# Assemble the attachment.
|
360
|
+
|
361
|
+
attachment_fields = []
|
362
|
+
attachment_fields << {title: main_title, value: main_value, short: false} if main_value != nil
|
363
|
+
|
364
|
+
attachment_actions = []
|
365
|
+
attachment_actions << {type: "button", style: "primary", text: install_title, url: install_url} if install_url != nil
|
366
|
+
attachment_actions << {type: "button", style: "default", text: view_title, url: view_url} if view_url != nil
|
367
|
+
|
368
|
+
{
|
369
|
+
color: attachment_color,
|
370
|
+
fields: attachment_fields,
|
371
|
+
actions: attachment_actions,
|
372
|
+
fallback: attachment_fallback,
|
373
|
+
}
|
374
|
+
|
375
|
+
end
|
376
|
+
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|