fastlane-plugin-dynatrace 0.1.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f927981645e0ccc0e64b0140474e3ee4013b530fb8d3feed6222f73b45fa4f12
4
- data.tar.gz: c178b4f934268c0d1499fdd33ab59a0e2e35fb1e4411c5c35095b4bd110686c3
3
+ metadata.gz: b1e38a109d92db2380ea11d2f46c22bf47d51089244fb4bea5d80b5e61ba99a6
4
+ data.tar.gz: 12544e3125d0150b485fd3a8b09b0dd23e456c3806e9418f0c50c578b96e7374
5
5
  SHA512:
6
- metadata.gz: 24197bea9f72df02426714998845f266b2b3cb19ffe51a4e9ae6d91940d0ea1d97b298084b49e7d0fd327c7151439d96520b16963a40a6294129d4c116a6576d
7
- data.tar.gz: 3ac487931a3829562ad22d98921e59196ac7a987574ced78bc8dee4ce31a5c4003dc3d37691356cd6b0dccb0d69b0aed03c50d90e2753ed4b40903488b85e386
6
+ metadata.gz: c332f1b61211ebe151c790e9402bdafae21606925b38acad64132d049046d22ae11a17f6f8fefb392f0501bc609c030f8f88f9742b9bfc3e8383742b942dda8f
7
+ data.tar.gz: 60724f36ca0fd22fd1b879c2ba6de2f42d954681907aad98084b4ee510d8e86603ee6ebfc3550c5e97f8c6e233c6a56676d10e6545c95aa82148a653f9b28398
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # dynatrace plugin
1
+ # Dynatrace Fastlane plugin
2
2
 
3
3
  [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-dynatrace)
4
4
 
@@ -10,127 +10,97 @@ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To
10
10
  fastlane add_plugin dynatrace
11
11
  ```
12
12
 
13
- ## About dynatrace
13
+ ### Dynatrace Managed
14
+ If the installation is on version 1.195 or earlier the Symbolication Client has to be manually download and specified (`dtxDssClientPath`), else it's fetched and updated automatically. A matching version can be downloaded manually with this link [https://api.mobileagent.downloads.dynatrace.com/sprint-latest-dss-client/xyz](https://api.mobileagent.downloads.dynatrace.com/sprint-latest-dss-client/xyz) by replacing `xyz` with the 3-digit sprint version of your Dynatrace Managed installation.
14
15
 
15
- This plugin allows you to decode and upload symbolication files to Dynatrace. You can also use it to first download your latest dSym files from AppStore Connect if you use Bitcode.
16
+ ## About the Dynatrace fastlane plugin
17
+ This plugin allows you to decode and upload symbol files (iOS) or just upload obfuscation mapping files (Android) to Dynatrace. You can also use it to first download your latest dSYM files from App Store Connect if you use Bitcode.
16
18
 
17
19
  ## Action: `dynatrace_process_symbols`
18
20
 
19
21
  | Supported Platforms | ios, android |
20
22
  |---------------------|--------------|
21
- | Author | @MANassar |
22
-
23
-
24
- ## Parameters
25
-
26
- | Key | Description | default value |
27
- |------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|
28
- | downloadDsyms | Boolean variable that enables downloading the Dsyms from AppStore Connect (iOS only) | false |
29
- | username | The username or the AppleID to use to download the Dsyms. You can also store this in your AppFile as "apple_id and it will be automatically retrieved." | |
30
- | dtxDssClientPath | The full path to your DTXDssClient. For example, it could be `./ios/agent/DTXDssClient` | `./DTXDssClient` |
31
- | action | The action to perform. upload/decode | `upload` |
32
- | appID | The app ID you get from your Dynatrace WebUI | |
33
- | os | The OperatingSystem of the symbol files. Either "ios" or "android" | |
34
- | apitoken | The Dynatrace API token. It should have the correct permissions. | |
35
- | bundleId | The CFBundlebundleId (iOS) / package (Android) of the Application. Usually in reverse com notation. Ex. com.your_company.your_app. This can also be stored in the AppFile as "app_identifier" and it will be automatically retrieved. | |
36
- | bundleName | The CFBundleName of the Application (iOS only) | |
37
- | versionStr | The CFBundleShortVersionString (iOS) / versionName (Android | |
38
- | version | The CFBundleVersion (iOS) / versionCode (Android). This will also be used for dsym download. | |
39
- | symbolsfile | The path to a local symbol files to be processed and uploaded. You do not need to specify that if you use downloadDsyms. | |
40
- | server | The API endpoint for the Dynatrace environment. For example https://environmentID.live.dynatrace.com or https://dynatrace-managed.com/e/environmentID | |
41
- | debugMode | Debug logging enabled | false |
42
23
 
43
- ## Example
44
-
45
- Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
46
-
47
- ##Example
24
+ ## Is your app Bitcode enabled?
25
+ > Only applies for apps distributed via the AppStore or TestFlight.
48
26
 
49
- In your *fastfile*
27
+ If your app is bitcode enabled, then the dSYMs that are generated during the Xcode build are **_not_** the dSYMs you want to upload to Dynatrace. This is because Apple recompiles the application on their servers, generating new dSYM files in the process. These newly generated dSYM files need to be downloaded from *App Store Connect*, then processed and uploaded to Dynatrace.
50
28
 
51
- ### Supplying all parameters locally
52
-
53
- ```ruby
54
- dynatrace_process_symbols(
55
- dtxDssClientPath:"<path>/DTXDssClient",
56
- appId: "your DT appID",
57
- apitoken: "your DT API token",
58
- os: "<ios> or <android>",
59
- bundleId: "com.yourcompany.yourApp",
60
- bundleName: "MyApp",
61
- versionStr: "1.0",
62
- version: "1",
63
- symbolsfile: "<path to my app>.app.dSYM",
64
- server: "https://<environmentID.live.dynatrace.com",
65
- debugMode: true)
29
+ ### Important
30
+ There is a time gap between the application being uploaded to App Store Connect and the dSYM files to be ready. So **_we have to introduce some "wait" time in the CI to accomodate for this_**. You can do this by setting the `waitForDsymProcessing` to true. Unfortunately, Apple does not specify how long this time is. We recommend 1800 seconds (30 mins) as this is usually enough for the symbols are ready for download. You can increase this timeout if needed (`waitForDsymProcessingTimeout`).
66
31
 
67
- ```
32
+ > Notice that this timeout is only the **maximum** waiting time. If the symbol files are ready sooner, it will continue processing and will not wait for the whole duration of the timeout.
68
33
 
69
- ### Downloading dsyms and using AppFile
34
+ ### Automatically downloading dSYMs and using AppFile for authentication
70
35
 
71
36
  #### AppFile
72
-
73
37
  ```ruby
74
- app_identifier("com.yourcompany.yourappID") # The bundle identifier of your app
75
- apple_id("user@email.com") # Your Apple email address
38
+ app_identifier("com.yourcompany.yourappID") # bundle identifier of your app
39
+ apple_id("user@email.com")
76
40
  ```
77
41
 
78
42
  #### Fastfile
79
-
80
43
  ```ruby
81
44
  dynatrace_process_symbols(
82
- downloadDsyms: true,
83
- dtxDssClientPath:"<path>/DTXDssClient",
84
- appId: "your DT appID",
85
- apitoken: "your DT API token",
86
- os: "<ios> or <android>",
87
- bundleName: "MyApp",
88
- versionStr: "1.0",
89
- version: "1",
90
- server: "https://<environmentID.live.dynatrace.com",
91
- debugMode: true)
92
-
45
+ appId: "<Dynatrace application ID>",
46
+ apitoken: "<Dynatrace API token>",
47
+ os: "ios",
48
+ bundleId: "<CFBundlebundleId (iOS) / package (Android)>",
49
+ versionStr: "<Build Number (CFBundleVersion)>",
50
+ version: "<App Version (CFBundleShortVersionString)>",
51
+ server: "<Dynatrace Environment URL>",
52
+ downloadDsyms: true
53
+ )
93
54
  ```
94
55
 
95
- ### Downloading dsyms, using AppFile - Only decoding them
96
56
 
97
- #### AppFile
57
+ ## If you are NOT using Bitcode, or if you have already downloaded your new symbols from App Store Connect manually.
98
58
 
59
+ ### Supply all parameters locally
99
60
  ```ruby
100
- app_identifier("com.yourcompany.yourappID") # The bundle identifier of your app
101
- apple_id("user@email.com") # Your Apple email address
61
+ dynatrace_process_symbols(
62
+ appId: "<Dynatrace application ID>",
63
+ apitoken: "<Dynatrace API Token>",
64
+ os: "<ios> or <android>",
65
+ bundleId: "<CFBundlebundleId (iOS) / package (Android)>",
66
+ versionStr: "<CFBundleShortVersionString (iOS) / versionName (Android)>",
67
+ version: "<CFBundleVersion (iOS) / versionCode (Android)>",
68
+ server: "<Dynatrace Environment URL>",
69
+ symbolsfile: "<Symbols File Path>"
70
+ )
102
71
  ```
103
72
 
104
- #### Fastfile
73
+ ## List of all Parameters
74
+ | Key | Description | default value |
75
+ |------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|
76
+ | action | *(iOS only)* Action to be performed by DTXDssClient (`upload` or `decode`). | `upload` |
77
+ | downloadDsyms | *(iOS only)* Download the dSYMs from App Store Connect. | `false` |
78
+ | waitForDsymProcessing | *(iOS only)* Wait for dSYM processing to be finished. | `true` |
79
+ | waitForDsymProcessingTimeout | *(iOS only)* Timeout in seconds to wait for the dSYMs be downloadable. | `1800` |
80
+ | username | *(iOS only)* The username/AppleID to use to download the dSYMs. Alternatively you can specify this in your AppFile as `apple_id`. | |
81
+ | os | The type of the symbol files, either `ios` or `android`. | |
82
+ | apitoken | Dynatrace API token with mobile symbolication permissions. | |
83
+ | dtxDssClientPath | **(DEPRECATED)** The path to your DTXDssClient. The DTXDssClient is downloaded and updated automatically, unless this key is set. | |
84
+ | appID | The application ID you get from your Dynatrace environment. | |
85
+ | bundleId | The CFBundlebundleId (iOS) / package (Android) of the application. Alternatively you can specify this in your AppFile as `app_identifier`. | |
86
+ | versionStr | The CFBundleShortVersionString (iOS) / versionName (Android) | |
87
+ | version | The CFBundleVersion (iOS) / versionCode (Android). Is also used for the dSYM download. | |
88
+ | symbolsfile | Path to the dSYM file to be processed. If downloadDsyms is set, this is only a fallback. | |
89
+ | server | The API endpoint for the Dynatrace environment (e.g. `https://environmentID.live.dynatrace.com` or `https://dynatrace-managed.com/e/environmentID`). | |
90
+ | debugMode | Enable debug logging. | false |
105
91
 
106
- ```ruby
107
- dynatrace_process_symbols(
108
- action = "decode",
109
- downloadDsyms: true,
110
- dtxDssClientPath:"<path>/DTXDssClient",
111
- appId: "your DT appID",
112
- apitoken: "your DT API token",
113
- os: "<ios> or <android>",
114
- bundleName: "MyApp",
115
- versionStr: "1.0",
116
- version: "1",
117
- server: "https://dynatrace-managed.com/e/environmentID",
118
- debugMode: true)
119
92
 
120
- ```
93
+ ## Example
94
+ Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
121
95
 
122
96
  ## Issues and Feedback
123
-
124
- For any other issues and feedback about this plugin, please submit it to this repository or contact Dynatrace Support.
97
+ For any other issues and feedback about this plugin, please submit it to this repository or contact [Dynatrace Support](https://support.dynatrace.com).
125
98
 
126
99
  ## Troubleshooting
127
-
128
100
  If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
129
101
 
130
102
  ## Using _fastlane_ Plugins
131
-
132
103
  For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
133
104
 
134
105
  ## About _fastlane_
135
-
136
106
  _fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
@@ -1,4 +1,8 @@
1
1
  require 'fastlane/action'
2
+ require 'net/http'
3
+ require 'open-uri'
4
+ require 'zip'
5
+ require "fileutils"
2
6
  require_relative '../helper/dynatrace_helper'
3
7
 
4
8
  module Fastlane
@@ -6,244 +10,245 @@ module Fastlane
6
10
  class DynatraceProcessSymbolsAction < Action
7
11
 
8
12
  def self.run(params)
9
- # fastlane will take care of reading in the parameter and fetching the environment variable:
10
13
  UI.message "DTXDssClientPath: #{params[:dtxDssClientPath]}"
11
14
  UI.message "Parameter API Token: #{params[:apitoken]}"
12
15
  UI.message "OS: #{params[:os]}"
13
- UI.message "Bundle name: #{params[:bundleName]}" if params[:os] == "ios"
14
16
  UI.message "Version string: #{params[:versionStr]}"
15
17
  UI.message "Version: #{params[:version]}"
16
18
  UI.message "Server URL: #{params[:server]}"
17
19
 
18
- UI.message("Checking AppFile for possible AppID")
20
+ UI.message "Checking AppFile for possible AppID"
19
21
  bundleId = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
20
- UI.message("Using #{bundleId} from your AppFile")
22
+ if bundleId
23
+ UI.message "Using #{bundleId} from your AppFile"
24
+ else
25
+ bundleId = params[:bundleId]
26
+ UI.message "BundleID: #{bundleId}"
27
+ end
21
28
 
22
- if !(bundleId)
23
- UI.message "BundleID: #{params[:bundleId]}"
29
+ UI.message "Checking AppFile for possible username/AppleID"
30
+ username = CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
31
+ if username
32
+ UI.message "Using #{username} from your AppFile"
33
+ else
34
+ username = params[:username]
35
+ UI.message "Didn't find a username in AppFile, using passed username parameter: #{params[:username]}"
24
36
  end
25
37
 
38
+ dtxDssClientPath = Helper::DynatraceHelper.get_dss_client(params)
26
39
 
27
40
  dsym_paths = []
28
-
29
- if (params[:os] == "ios")
30
- begin
31
- if (params[:versionStr])
32
- version = params[:versionStr]
33
- else
34
- version = 'latest'
41
+ symbolFilesKey = "symbolsfile" # default to iOS
42
+
43
+ if params[:os] == "ios"
44
+ if params[:downloadDsyms] == true
45
+ UI.message "Downloading dSYMs from App Store Connect"
46
+ startTime = Time.now
47
+
48
+ # it takes a couple of minutes until the new build is available through the API
49
+ # -> retry until available
50
+ while params[:waitForDsymProcessing] and # wait is active
51
+ !lane_context[SharedValues::DSYM_PATHS] and # has dsym path
52
+ (Time.now - startTime) < params[:waitForDsymProcessingTimeout] # is in time
53
+
54
+ Actions::DownloadDsymsAction.run(wait_for_dsym_processing: params[:waitForDsymProcessing],
55
+ wait_timeout: (params[:waitForDsymProcessingTimeout] - (Time.now - startTime)).round(0), # remaining timeout
56
+ app_identifier: bundleId,
57
+ username: username,
58
+ version: params[:version],
59
+ build_number: params[:versionStr],
60
+ platform: :ios) # should be optional (Hint: it's not)
61
+
62
+ if !lane_context[SharedValues::DSYM_PATHS] and (Time.now - startTime) < params[:waitForDsymProcessingTimeout]
63
+ UI.message "Version #{params[:version]} (Build #{params[:versionStr]}) isn't listed yet, retrying in 60 seconds (timeout in #{(params[:waitForDsymProcessingTimeout] - (Time.now - startTime)).round(0)} seconds)."
64
+ sleep(60)
65
+ end
35
66
  end
36
67
 
37
- if (params[:downloadDsyms] == true)
38
- UI.message("Checking AppFile for possible username/AppleID")
39
- username = CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
40
- UI.message("Using #{username} from your AppFile")
41
-
42
- if !(username)
43
- UI.message "Username: #{params[:username]}"
44
- end
45
-
46
- UI.message("Downloading Dsyms from AppStore Connect")
47
- Fastlane::Actions::DownloadDsymsAction.run(app_identifier: bundleId,
48
- username: username,
49
- version: version)
50
- dsym_paths += Actions.lane_context[SharedValues::DSYM_PATHS] if Actions.lane_context[SharedValues::DSYM_PATHS]
51
-
52
- if dsym_paths.count > 0
53
- UI.message("Downloaded the Dsyms from AppStore Connect. Paths #{dsym_paths}")
68
+ if (Time.now - startTime) > params[:waitForDsymProcessingTimeout]
69
+ UI.user_error!("Timeout during dSYM download. Try increasing :waitForDsymProcessingTimeout.")
70
+ end
54
71
 
55
- else
56
- raise 'No dsyms found error'
57
- end
58
- end
72
+ dsym_paths += Actions.lane_context[SharedValues::DSYM_PATHS] if Actions.lane_context[SharedValues::DSYM_PATHS]
59
73
 
60
- rescue
61
- UI.error("Couldn't download Dsyms. Checking if we have a local path")
74
+ if dsym_paths.count > 0
75
+ UI.message "Downloaded the dSYMs from App Store Connect. Paths: #{dsym_paths}"
76
+ else
77
+ raise 'No dSYM paths found!'
78
+ end
79
+ else
80
+ UI.error "dSYM download disabled, using local path (#{params[:symbolsfile]})"
62
81
  dsym_paths << params[:symbolsfile] if params[:symbolsfile]
63
- end #end the begin-rescue block
82
+ end
64
83
 
65
- else #android
66
- dsym_paths << params[:symbolsfile] if params[:symbolsfile]
67
- end
84
+ else # android
85
+ dsym_paths << params[:symbolsfile] if params[:symbolsfile]
86
+ symbolFilesKey = "file"
87
+ end
68
88
 
69
- #check if we have dsyms to proceed with
70
- if (dsym_paths.count == 0)
71
- UI.message "Symbol file path: #{params[:symbolsfile]}" #Ask the user for the symbolFiles path
72
- dsym_paths = params[:symbolsfile]
73
- symbolFilesCommandSnippet = "symbolsfile=\"#{dsym_paths}\""
74
- else
75
- symbolFilesCommandSnippet = "symbolsfile=\"#{dsym_paths[0]}\""
76
- end
89
+ # check if we have dSYMs to proceed with
90
+ if dsym_paths.count == 0
91
+ UI.message "Symbol file path: #{params[:symbolsfile]}"
92
+ dsym_paths = params[:symbolsfile]
93
+ symbolFilesCommandSnippet = "#{symbolFilesKey}=\"#{dsym_paths}\""
94
+ else
95
+ symbolFilesCommandSnippet = "#{symbolFilesKey}=\"#{dsym_paths[0]}\""
96
+ end
77
97
 
78
- #Start constructing the command that will trigger the DTXDssClient
98
+ # start constructing the command that will trigger the DTXDssClient
79
99
  command = []
80
- command << "#{params[:dtxDssClientPath]}"
100
+ command << "#{dtxDssClientPath}"
81
101
  command << "-#{params[:action]}" #"-upload"
82
102
  command << "appid=\"#{params[:appId]}\""
83
103
  command << "apitoken=\"#{params[:apitoken]}\""
84
104
  command << "os=#{params[:os]}"
85
105
  command << "bundleId=\"#{bundleId}\""
86
- command << "bundleName=\"#{params[:bundleName]}\""
87
- command << "versionStr=\"#{version}\""
106
+ command << "versionStr=\"#{params[:versionStr]}\""
88
107
  command << "version=\"#{params[:version]}\""
89
108
  command << symbolFilesCommandSnippet
90
- command << "server=\"#{params[:server]}\""
109
+ command << "server=\"#{Helper::DynatraceHelper.get_server_base_url(params)}\""
91
110
  command << "DTXLogLevel=ALL -verbose" if params[:debugMode] == true
92
- command << "forced=1" #So that we do not waste time with errors if the file already exists
111
+ command << "forced=1" # if the file already exists
93
112
 
94
113
  # Create the full shell command to trigger the DTXDssClient
95
114
  shell_command = command.join(' ')
96
115
 
116
+ UI.message "dSYM path: #{dsym_paths[0]}"
117
+ UI.message "#{shell_command}"
97
118
 
98
- UI.message("Dsym paths: #{dsym_paths[0]}")
99
- UI.message("#{shell_command}")
100
-
101
- # Execute the shell command
102
- sh "#{shell_command}"
119
+ sh("#{shell_command}", error_callback: ->(result) {
120
+ # ShAction doesn't return any reference to the return value -> parse it from the output
121
+ result_groups = result.match /(?:ERROR: Execution failed, rc=)(-?\d*)(?:\sreason=)(.*)/
122
+ if result_groups and result_groups.length() >= 2
123
+ if result_groups[1] == "413"
124
+ UI.user_error!("DTXDssClient: #{result_groups[2]} See https://www.dynatrace.com/support/help/shortlink/mobile-symbolication#manage-the-uploaded-symbol-files for more information.")
125
+ else
126
+ UI.user_error!("DTXDssClient: #{result_groups[2]}")
127
+ end
128
+ else
129
+ UI.user_error!("DTXDssClient finished with errors.")
130
+ end
131
+ })
103
132
 
104
- UI.message("Cleaning build artifacts")
133
+ UI.message "Cleaning build artifacts"
105
134
  Fastlane::Actions::CleanBuildArtifactsAction.run(exclude_pattern: nil)
106
-
107
- end #end the run functions
135
+ end
108
136
 
109
137
  def self.description
110
- "This action processes and uploads your symbol files to Dynatrace"
138
+ "This action processes and uploads your symbol files to Dynatrace."
111
139
  end
112
140
 
113
141
  def self.details
114
- "This action allows you to process and upload symbol files to Dynatrace. You can also use it to first download your latest dSym files from AppStore Connect if you use Bitcode"
142
+ "This action allows you to process and upload symbol files to Dynatrace. If you use Bitcode you can also use it to download the latest dSYM files from App Store Connect."
115
143
  end
116
144
 
117
145
  def self.available_options
118
- # Define all options your action supports.
119
146
  [
120
147
  FastlaneCore::ConfigItem.new(key: :action,
121
148
  env_name: "FL_UPLOAD_TO_DYNATRACE_ACTION",
122
- description: "The action you need to perform. For example upload/decode",
149
+ description: "(iOS only) Action to be performed by DTXDssClient (\"upload\" or \"decode\")",
123
150
  default_value: "upload",
124
151
  is_string: true,
125
152
  verify_block: proc do |value|
126
- UI.user_error!("Action needs to either be upload or decode") unless (value and value == "upload" or value == "decode")
127
- # UI.user_error!("Couldn't find file at path '#{value}'") unless File.exist?(value)
153
+ UI.user_error!("Action needs to either be \"upload\" or \"decode\"") unless (value and value == "upload" or value == "decode")
128
154
  end),
129
155
 
130
156
  FastlaneCore::ConfigItem.new(key: :downloadDsyms,
131
- env_name: "FL_UPLOAD_TO_DYNATRACE_DOWNLOAD_DSYMS", # The name of the environment variable
157
+ env_name: "FL_UPLOAD_TO_DYNATRACE_DOWNLOAD_DSYMS",
132
158
  default_value: false,
133
159
  is_string: false,
134
- description: "Boolean variable that enables downloading the Dsyms from AppStore Connect (iOS only)", # a short description of this parameter
135
- ),
160
+ description: "(iOS only) Download the dSYMs from App Store Connect"),
161
+
162
+ FastlaneCore::ConfigItem.new(key: :waitForDsymProcessing,
163
+ env_name: "FL_UPLOAD_TO_DYNATRACE_DOWNLOAD_DSYMS_WAIT_PROCESSING",
164
+ default_value: true,
165
+ is_string: false,
166
+ description: "(iOS only) Wait for dSYM processing to be finished"),
167
+
168
+ FastlaneCore::ConfigItem.new(key: :waitForDsymProcessingTimeout,
169
+ env_name: "FL_UPLOAD_TO_DYNATRACE_DOWNLOAD_DSYMS_WAIT_TIMEOUT",
170
+ default_value: 1800,
171
+ is_string: false,
172
+ description: "(iOS only) Timeout in seconds to wait for the dSYMs be downloadable"),
136
173
 
137
174
  FastlaneCore::ConfigItem.new(key: :username,
138
- env_name: "FL_UPLOAD_TO_DYNATRACE_DOWNLOAD_DSYMS_USERNAME", # The name of the environment variable
139
- description: "The username or the AppleID to use to download the Dsyms", # a short description of this parameter
140
- ),
141
-
142
- FastlaneCore::ConfigItem.new(key: :os,
143
- env_name: "FL_UPLOAD_TO_DYNATRACE_OS", # The name of the environment variable
144
- description: "The OperatingSystem of the symbol files. Either \"ios\" or \"android\"",
145
- sensitive: false,
146
- optional: false,
147
- verify_block: proc do |value|
148
- UI.user_error!("Please specify the OperatingSystem of the symbol files. Possible values are \"ios\" or \"android\"") unless (value and not value.empty? and (value == "ios" || value =="android"))
149
- end),
175
+ env_name: "FL_UPLOAD_TO_DYNATRACE_DOWNLOAD_DSYMS_USERNAME",
176
+ description: "(iOS only) The username/AppleID to use to download the dSYMs"),
177
+
178
+ FastlaneCore::ConfigItem.new(key: :os,
179
+ env_name: "FL_UPLOAD_TO_DYNATRACE_OS",
180
+ description: "The type of the symbol files, either \"ios\" or \"android\"",
181
+ sensitive: false,
182
+ optional: false,
183
+ verify_block: proc do |value|
184
+ UI.user_error!("Please specify the type of the symbol files. Possible values are \"ios\" or \"android\".") unless (value and not value.empty? and (value == "ios" || value =="android"))
185
+ end),
150
186
 
151
187
  FastlaneCore::ConfigItem.new(key: :apitoken,
152
- env_name: "FL_UPLOAD_TO_DYNATRACE_apitoken", # The name of the environment variable
153
- description: "The Dynatrace API token", # a short description of this parameter
188
+ env_name: "FL_UPLOAD_TO_DYNATRACE_apitoken",
189
+ description: "Dynatrace API token with mobile symbolication permissions",
154
190
  verify_block: proc do |value|
155
- UI.user_error!("No API token for UploadToDynatraceAction given, pass using `apitoken: 'token'`") unless (value and not value.empty?)
156
- # UI.user_error!("Couldn't find file at path '#{value}'") unless File.exist?(value)
191
+ UI.user_error!("No Dynatrade API token for specified, pass using `apitoken: 'token'`") unless (value and not value.empty?)
157
192
  end),
158
193
 
159
194
  FastlaneCore::ConfigItem.new(key: :dtxDssClientPath,
160
195
  env_name: "FL_UPLOAD_TO_DYNATRACE_DTXDssClientPath",
161
- description: "The path to your DTXDssClient",
162
- default_value: "./DTXDssClient",
196
+ description: "(DEPRECATED) The path to your DTXDssClient. The DTXDssClient is downloaded and updated automatically, unless this key is set",
197
+ optional: true),
198
+
199
+ FastlaneCore::ConfigItem.new(key: :appId,
200
+ env_name: "FL_UPLOAD_TO_DYNATRACE_APP_ID",
201
+ description: "The app ID you get from your Dynatrace environment",
163
202
  verify_block: proc do |value|
164
- UI.user_error!("We need the path to the DTXDssClient in your iOS agent folder. For example . Pass using `dtxDssClientPath: 'path'`") unless (value and not value.empty?)
165
- # is_string: true # true: verifies the input is a string, false: every kind of value
166
- # default_value: false) # the default value if the user didn't provide one
167
- end),
168
-
169
- FastlaneCore::ConfigItem.new(key: :appId,
170
- env_name: "FL_UPLOAD_TO_DYNATRACE_APP_ID",
171
- description: "The app ID you get from your Dynatrace WebUI",
172
- verify_block: proc do |value|
173
- UI.user_error!("Please provide the appID for your app. Pass using `appId: 'appId'`") unless (value and not value.empty?)
174
- # is_string: true # true: verifies the input is a string, false: every kind of value
175
- # default_value: false) # the default value if the user didn't provide one
176
- end),
203
+ UI.user_error!("Please provide the appID for your application. Pass using `appId: 'appId'`") unless (value and not value.empty?)
204
+ end),
177
205
 
178
206
  FastlaneCore::ConfigItem.new(key: :bundleId,
179
207
  env_name: "FL_UPLOAD_TO_DYNATRACE_BUNDLE_ID",
180
- description: "The CFBundlebundleId (iOS) / package (Android) of the Application. Usually in reverse com notation. Ex. com.your_company.your_app",
208
+ description: "The CFBundlebundleId (iOS) / package (Android) of the application",
181
209
  verify_block: proc do |value|
182
210
  UI.user_error!("Please provide the BundleID for your app. Pass using `bundleId: 'bundleId'`") unless (value and not value.empty?)
183
- # is_string: true # true: verifies the input is a string, false: every kind of value
184
- # default_value: false) # the default value if the user didn't provide one
185
- end),
186
-
187
- FastlaneCore::ConfigItem.new(key: :bundleName,
188
- env_name: "FL_UPLOAD_TO_DYNATRACE_BUNDLE_NAME",
189
- description: "The CFBundleName of the Application (iOS only)",
190
- sensitive: false,
191
- verify_block: proc do |value|
192
- UI.user_error!("Please provide the bundleName for your app. Pass using `bundleName: 'bundleName'`") unless (value and not value.empty?)
193
- end),
211
+ end),
194
212
 
195
213
  FastlaneCore::ConfigItem.new(key: :versionStr,
196
214
  env_name: "FL_UPLOAD_TO_DYNATRACE_VERSION_STRING",
197
215
  description: "The CFBundleShortVersionString (iOS) / versionName (Android)",
198
216
  verify_block: proc do |value|
199
217
  UI.user_error!("Please provide the CFBundleShortVersionString for your app. Pass using `versionStr: 'versionStr'`") unless (value and not value.empty?)
200
- # is_string: true # true: verifies the input is a string, false: every kind of value
201
- # default_value: false) # the default value if the user didn't provide one
202
- end),
203
-
204
- FastlaneCore::ConfigItem.new(key: :version,
205
- env_name: "FL_UPLOAD_TO_DYNATRACE_VERSION",
206
- description: "The CFBundleVersion (iOS) / versionCode (Android)",
207
- verify_block: proc do |value|
208
- UI.user_error!("Please provide the version for your app. Pass using `version: 'version'`") unless (value and not value.empty?)
209
- # is_string: true # true: verifies the input is a string, false: every kind of value
210
- # default_value: false) # the default value if the user didn't provide one
211
- end),
218
+ end),
219
+
220
+ FastlaneCore::ConfigItem.new(key: :version,
221
+ env_name: "FL_UPLOAD_TO_DYNATRACE_VERSION",
222
+ description: "The CFBundleVersion (iOS) / versionCode (Android). Is also used for the dSYM download",
223
+ verify_block: proc do |value|
224
+ UI.user_error!("Please provide the version for your app. Pass using `version: 'version'`") unless (value and not value.empty?)
225
+ end),
212
226
 
213
227
  FastlaneCore::ConfigItem.new(key: :symbolsfile,
214
228
  env_name: "FL_UPLOAD_TO_DYNATRACE_SYM_FILE_PATH",
215
- description: "The filename/path of the XCode iOS archive or iOS dSYM containing the symbol mappings",
229
+ description: "Path to the dSYM file to be processed. Is only used when downloadDsyms is not set",
216
230
  verify_block: proc do |value|
217
- UI.user_error!("Please provide a value for the symbolFiles. Pass using `symbolsfile: 'symbolsfile'`") unless (value and not value.empty?)
218
- # is_string: true # true: verifies the input is a string, false: every kind of value
219
- # default_value: false) # the default value if the user didn't provide one
220
- end),
221
-
222
- FastlaneCore::ConfigItem.new(key: :server,
223
- env_name: "FL_UPLOAD_TO_DYNATRACE_SERVER_URL",
224
- description: "The API endpoint for the Dynatrace environment. For example https://<environmentID.live.dynatrace.com/api/config/v1",
225
- verify_block: proc do |value|
226
- UI.user_error!("Please provide your environment API endpoint. Pass using `server: 'server'`") unless (value and not value.empty?)
227
- # is_string: true # true: verifies the input is a string, false: every kind of value
228
- # default_value: false) # the default value if the user didn't provide one
229
- end),
231
+ UI.user_error!("Please provide a value for the symbol files. Pass using `symbolsfile: 'symbolsfile'`") unless (value and not value.empty?)
232
+ end),
233
+
234
+ FastlaneCore::ConfigItem.new(key: :server,
235
+ env_name: "FL_UPLOAD_TO_DYNATRACE_SERVER_URL",
236
+ description: "The API endpoint for the Dynatrace environment (e.g. https://environmentID.live.dynatrace.com or https://dynatrace-managed.com/e/environmentID)",
237
+ verify_block: proc do |value|
238
+ UI.user_error!("Please provide your environment API endpoint. Pass using `server: 'server'`") unless (value and not value.empty?)
239
+ end),
230
240
 
231
241
  FastlaneCore::ConfigItem.new(key: :debugMode,
232
242
  env_name: "FL_UPLOAD_TO_DYNATRACE_DEBUG_MODE",
233
- description: "Debug logging enabled",
243
+ description: "Enable debug logging",
244
+ default_value: false,
234
245
  is_string: false,
235
- optional: true
236
- )
246
+ optional: true)
237
247
  ]
238
248
  end
239
249
 
240
- def self.return_value
241
- # If your method provides a return value, you can describe here what it does
242
- end
243
-
244
250
  def self.authors
245
- # So no one will ever forget your contribution to fastlane :) You are awesome btw!
246
- ["MANassar/@MohamedANassar"]
251
+ ["MANassar/@MohamedANassar", "cynicer"]
247
252
  end
248
253
 
249
254
  def self.is_supported?(platform)
@@ -5,11 +5,70 @@ module Fastlane
5
5
 
6
6
  module Helper
7
7
  class DynatraceHelper
8
- # class methods that you define here become available in your action
9
- # as `Helper::DynatraceHelper.your_method`
10
- #
11
- def self.show_message
12
- UI.message("Hello from the dynatrace plugin helper!")
8
+ def self.get_dss_client(params)
9
+ dynatraceDir = "dynatrace"
10
+ versionFile = "version"
11
+ dtxDssClientBin = "DTXDssClient"
12
+ dtxDssClientPath = "#{dynatraceDir}/#{dtxDssClientBin}"
13
+
14
+ if (params.all_keys.include? :dtxDssClientPath and not params[:dtxDssClientPath].nil?)
15
+ UI.message "DEPRECATION WARNING: DTXDssClientPath doesn't need to be specified anymore, the DTXDssClient is downloaded and updated automatically."
16
+ dtxDssClientPath = params[:dtxDssClientPath]
17
+ else
18
+ # get latest version info
19
+ clientUri = URI("#{self.get_server_base_url(params)}/api/config/v1/symfiles/dtxdss-download?Api-Token=#{params[:apitoken]}")
20
+ response = Net::HTTP.get_response(clientUri)
21
+
22
+ if not response.kind_of? Net::HTTPSuccess
23
+ base_error = "Couldn't update DTXDssClient (invalid response: #{response.message} (#{response.code})) for URL: #{clientUri})"
24
+ if File.exists?("#{dynatraceDir}/#{dtxDssClientBin}")
25
+ UI.important base_error
26
+ UI.important "Using cached DTXDssClient: #{dynatraceDir}/#{dtxDssClientBin}"
27
+ return dtxDssClientPath
28
+ else
29
+ UI.user_error! base_error
30
+ end
31
+ end
32
+
33
+ remoteClientUrl = JSON.parse(response.body)["dssClientUrl"]
34
+ UI.message "Remote DSS client: #{remoteClientUrl}"
35
+
36
+ # check local state
37
+ if (!File.directory?(dynatraceDir))
38
+ Dir.mkdir(dynatraceDir)
39
+ end
40
+
41
+ if (!File.exists?("#{dynatraceDir}/#{versionFile}") or
42
+ !File.exists?("#{dynatraceDir}/#{dtxDssClientBin}") or
43
+ File.read("#{dynatraceDir}/#{versionFile}") != remoteClientUrl)
44
+ # update local state
45
+ UI.message "Found a different remote DTXDssClient client. Updating local version."
46
+ File.delete("#{dynatraceDir}/#{versionFile}") if File.exist?("#{dynatraceDir}/#{versionFile}")
47
+ File.delete("#{dynatraceDir}/#{dtxDssClientBin}") if File.exist?("#{dynatraceDir}/#{dtxDssClientBin}")
48
+
49
+ File.write("#{dynatraceDir}/#{versionFile}", remoteClientUrl)
50
+
51
+ # get client from served archive
52
+ open(remoteClientUrl) do |zipped|
53
+ Zip::InputStream.open(zipped) do |unzipped|
54
+ entry = unzipped.get_next_entry
55
+ if (entry.name == dtxDssClientBin)
56
+ IO.copy_stream(entry.get_input_stream, "#{dynatraceDir}/#{dtxDssClientBin}")
57
+ FileUtils.chmod("+x", "#{dynatraceDir}/#{dtxDssClientBin}")
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ return dtxDssClientPath
64
+ end
65
+
66
+ def self.get_server_base_url(params)
67
+ if params[:server][-1] == '/'
68
+ return params[:server][0..-2]
69
+ else
70
+ return params[:server]
71
+ end
13
72
  end
14
73
  end
15
74
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Dynatrace
3
- VERSION = "0.1.2"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-dynatrace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
- - Mohamed Nassar
8
- autorequire:
7
+ - Dynatrace LLC
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-25 00:00:00.000000000 Z
11
+ date: 2020-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -128,16 +128,16 @@ dependencies:
128
128
  requirements:
129
129
  - - ">="
130
130
  - !ruby/object:Gem::Version
131
- version: 2.119.0
131
+ version: 2.142.0
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
- version: 2.119.0
139
- description:
140
- email: mohamedanassar@gmail.com
138
+ version: 2.142.0
139
+ description:
140
+ email: mobile.agent@dynatrace.com
141
141
  executables: []
142
142
  extensions: []
143
143
  extra_rdoc_files: []
@@ -148,11 +148,11 @@ files:
148
148
  - lib/fastlane/plugin/dynatrace/actions/dynatrace_action.rb
149
149
  - lib/fastlane/plugin/dynatrace/helper/dynatrace_helper.rb
150
150
  - lib/fastlane/plugin/dynatrace/version.rb
151
- homepage: https://github.com/MANassar/fastlane-plugin-dynatrace
151
+ homepage: https://github.com/Dynatrace/fastlane-plugin-dynatrace
152
152
  licenses:
153
153
  - MIT
154
154
  metadata: {}
155
- post_install_message:
155
+ post_install_message:
156
156
  rdoc_options: []
157
157
  require_paths:
158
158
  - lib
@@ -167,8 +167,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
167
  - !ruby/object:Gem::Version
168
168
  version: '0'
169
169
  requirements: []
170
- rubygems_version: 3.0.1
171
- signing_key:
170
+ rubygems_version: 3.1.4
171
+ signing_key:
172
172
  specification_version: 4
173
173
  summary: This action processes and uploads your symbol files to Dynatrace
174
174
  test_files: []