fastlane-plugin-buildstash 1.0.3 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ba2835dc2af3fae9a40e7132b7e41e7778e65b02a1304462cda7c47ac3efa80
4
- data.tar.gz: 76069bf392a0d554835535a1eb9795b0f1e7bfc9b38a14a6b56048b7a6d99054
3
+ metadata.gz: 865912b0b34c569272752e0984eeb58bfef8192f1135f83b4516ea2bb29d6c8e
4
+ data.tar.gz: b724cb7648c198a26520918f0c015df43c32788b76d2ad2f5ef226c12f8dc2ce
5
5
  SHA512:
6
- metadata.gz: 4aa058135772962c9793194218405c7c62fc2be57fed53abeb27a0c8e255580b81482b7323f404a879daddbf585587e40f71749dd729c4700bd56ff970173644
7
- data.tar.gz: d794165f479b22864d19ae04c4fc92f59bd76686c4a38ecebfd04692032fd647481b2849330b61882911e300b536b8174aebccfbba15e40ea5cbf96d756e8c9f
6
+ metadata.gz: 4e36e107f079f2badb955736328b0b61baa9d6493fffd18b065aa7de55341df29f3fc2b7b7fb5c0c45c7a0ba085399746ea79475d4ac2579790495b9d21315d4
7
+ data.tar.gz: b5dca4d6c339e86346e208dcb25e528a4b8e42b4ada7d65cd5353fdb361baa441935e3f54a4a49c0fe73fac86f3f35e20d12d11c44be99fa8744f25615004f0a
data/README.md CHANGED
@@ -52,6 +52,7 @@ lane :run_buildstash_upload do |options|
52
52
  structure: 'file',
53
53
  primary_file_path: './path/to/file.apk',
54
54
  platform: 'android',
55
+ custom_target: 'Galaxy Store',
55
56
  stream: 'default',
56
57
  version_component_1_major: 0,
57
58
  version_component_2_minor: 0,
@@ -66,17 +67,47 @@ lane :run_buildstash_upload do |options|
66
67
  ci_pipeline: options[:ci_pipeline],
67
68
  ci_run_id: options[:ci_run_id],
68
69
  ci_run_url: options[:ci_run_url],
70
+ ci_build_duration: '00:05:00',
69
71
  vc_host_type: 'git',
70
72
  vc_host: 'github',
71
73
  vc_repo_name: options[:vc_repo_name],
72
74
  vc_repo_url: options[:vc_repo_url],
73
75
  vc_branch: options[:vc_branch],
74
76
  vc_commit_sha: options[:vc_commit_sha],
75
- vc_commit_url: options[:vc_commit_url]
77
+ vc_commit_url: options[:vc_commit_url],
78
+ metadata_artifacts: [
79
+ { path: './build.log', description: 'Xcode build log' },
80
+ { path: './test-results.xml', description: 'Unit test results' }
81
+ ]
76
82
  )
77
83
  end
78
84
  ```
79
85
 
86
+ ### Uploading metadata artifacts
87
+
88
+ The `metadata_artifacts` parameter lets you attach supplementary files (logs, test results, crash reports, etc.) to a build. Each entry is a Hash with a `:path` key and an optional `:description`:
89
+
90
+ ```ruby
91
+ buildstash_upload(
92
+ api_key: ENV['BUILDSTASH_API_KEY'],
93
+ primary_file_path: './MyApp.ipa',
94
+ platform: 'ios',
95
+ stream: 'nightly',
96
+ version_component_1_major: 2,
97
+ version_component_2_minor: 1,
98
+ version_component_3_patch: 0,
99
+ metadata_artifacts: [
100
+ { path: './build.log', description: 'Build log' },
101
+ { path: './test-results.xml', description: 'Unit test results' },
102
+ { path: './crash-report.txt' }
103
+ ]
104
+ )
105
+ ```
106
+
107
+ **Limits:**
108
+ - Maximum **10** metadata artifacts per upload — if more are provided, only the first 10 are uploaded and a warning is logged for the rest
109
+ - Maximum **5 MB** per file — files exceeding this limit are skipped with a warning
110
+
80
111
  ## Parameters
81
112
  | Parameter | Description | Required |
82
113
  |-----------------------------|--------------------------------------------------------------------------------------------------------------|----------|
@@ -84,6 +115,7 @@ end
84
115
  | `structure` | 'file' for single file, 'file+expansion' to include Android expansion file. will default to 'file' | ✖ |
85
116
  | `primary_file_path` | './path/to/file.apk' | ✅ |
86
117
  | `platform` | 'android' or 'ios' (see [Buildstash docs for full list](https://docs.buildstash.com/integrations/platforms)) | ✅ |
118
+ | `custom_target` | Custom target for this build — must exactly match a target defined in your Buildstash app | ✖️ |
87
119
  | `stream` | Exact name of a build stream in your app | ✅ |
88
120
  | `version_component_1_major` | Semantic version (major component) | ✅ |
89
121
  | `version_component_2_minor` | Semantic version (minor component) | ✅ |
@@ -94,10 +126,13 @@ end
94
126
  | `labels` | Array of labels to attach to build (will be created if they do not already exist) | ✖ |
95
127
  | `architectures` | Array of architectures this build supports (must be supported by platform) | ✖ |
96
128
  | `notes` | Changelog or additional notes | ✖️ |
129
+ | `expansion_file_path` | Path to the expansion file (only used when `structure` is `'file+expansion'`) | ✖️ |
130
+ | `metadata_artifacts` | Array of supplementary files to upload with the build (e.g. logs). See [Metadata artifacts](#uploading-metadata-artifacts) | ✖️ |
97
131
  | `source` | Where build was produced (`ghactions`, `jenkins`, etc) defaults to cli-upload | ✖️ |
98
132
  | `ci_pipeline` | CI pipeline name | ✖️ |
99
133
  | `ci_run_id` | CI run ID | ✖️ |
100
134
  | `ci_run_url` | CI run URL | ✖️ |
135
+ | `ci_build_duration` | CI build duration (e.g. `'00:05:00'`) | ✖️ |
101
136
  | `vc_host_type` | Version control host type (git, svn, hg, perforce, etc) | ✖️ |
102
137
  | `vc_host` | Version control host (github, gitlab, etc) | ✖️ |
103
138
  | `vc_repo_name` | Repository name | ✖️ |
@@ -17,6 +17,7 @@ module Fastlane
17
17
  version_component_meta = params[:version_component_meta]
18
18
  custom_build_number = params[:custom_build_number]
19
19
  platform = params[:platform]
20
+ custom_target = params[:custom_target]
20
21
  stream = params[:stream]
21
22
  notes = params[:notes]
22
23
 
@@ -28,6 +29,7 @@ module Fastlane
28
29
  ci_pipeline = params[:ci_pipeline]
29
30
  ci_run_id = params[:ci_run_id]
30
31
  ci_run_url = params[:ci_run_url]
32
+ ci_build_duration = params[:ci_build_duration]
31
33
 
32
34
  vc_host_type = params[:vc_host_type]
33
35
  vc_host = params[:vc_host]
@@ -37,6 +39,8 @@ module Fastlane
37
39
  vc_commit_sha = params[:vc_commit_sha]
38
40
  vc_commit_url = params[:vc_commit_url]
39
41
 
42
+ metadata_artifacts = params[:metadata_artifacts] || []
43
+
40
44
  if !structure
41
45
  structure = "file"
42
46
  end
@@ -67,12 +71,14 @@ module Fastlane
67
71
  version_component_meta: version_component_meta,
68
72
  custom_build_number: custom_build_number,
69
73
  platform: platform,
74
+ custom_target: custom_target,
70
75
  stream: stream,
71
76
  notes: notes,
72
77
  source: source,
73
78
  ci_pipeline: ci_pipeline,
74
79
  ci_run_id: ci_run_id,
75
80
  ci_run_url: ci_run_url,
81
+ ci_build_duration: ci_build_duration,
76
82
  vc_host_type: vc_host_type,
77
83
  vc_host: vc_host,
78
84
  vc_repo_name: vc_repo_name,
@@ -267,6 +273,128 @@ module Fastlane
267
273
  else
268
274
  UI.success("✅ Upload to Buildstash successful!")
269
275
  end
276
+
277
+ # Upload metadata artifacts if provided
278
+ unless metadata_artifacts.empty?
279
+ upload_metadata_artifacts(
280
+ metadata_artifacts: metadata_artifacts,
281
+ pending_upload_id: pending_upload_id,
282
+ api_key: api_key
283
+ )
284
+ end
285
+ end
286
+
287
+ def self.upload_metadata_artifacts(metadata_artifacts:, pending_upload_id:, api_key:)
288
+ max_files = 10
289
+ max_size_bytes = 5 * 1024 * 1024
290
+
291
+ artifacts_to_upload = metadata_artifacts.first(max_files)
292
+ skipped_count = metadata_artifacts.length - artifacts_to_upload.length
293
+
294
+ if skipped_count > 0
295
+ UI.important("⚠️ Skipping #{skipped_count} metadata artifact(s) — maximum of #{max_files} files allowed per upload.")
296
+ end
297
+
298
+ UI.message("Uploading #{artifacts_to_upload.length} metadata artifact(s)...")
299
+
300
+ artifacts_to_upload.each_with_index do |artifact, index|
301
+ file_path = artifact[:path] || artifact["path"]
302
+ description = artifact[:description] || artifact["description"]
303
+
304
+ unless file_path
305
+ UI.important("⚠️ Metadata artifact at index #{index} has no path — skipping.")
306
+ next
307
+ end
308
+
309
+ unless File.exist?(file_path)
310
+ UI.important("⚠️ Metadata artifact not found at path: #{file_path} — skipping.")
311
+ next
312
+ end
313
+
314
+ file_size = File.size(file_path)
315
+ if file_size > max_size_bytes
316
+ size_mb = (file_size.to_f / (1024 * 1024)).round(2)
317
+ UI.important("⚠️ Metadata artifact '#{File.basename(file_path)}' is #{size_mb}MB — exceeds the 5MB limit, skipping.")
318
+ next
319
+ end
320
+
321
+ filename = File.basename(file_path)
322
+ desc_text = description ? " (#{description})" : ""
323
+ UI.message("Uploading metadata artifact #{index + 1}/#{artifacts_to_upload.length}: #{filename}#{desc_text}")
324
+
325
+ # Request presigned upload URL for this metadata artifact
326
+ meta_request_response = Helper::BuildstashHelper.post_json(
327
+ url: "https://app.buildstash.com/api/v1/upload/metadata/request",
328
+ body: {
329
+ primary_pending_upload_id: pending_upload_id,
330
+ filename: filename,
331
+ size_bytes: file_size
332
+ },
333
+ headers: {
334
+ "Authorization" => "Bearer #{api_key}",
335
+ "Content-Type" => "application/json",
336
+ "Accept" => "application/json"
337
+ }
338
+ )
339
+
340
+ unless meta_request_response.is_a?(Net::HTTPSuccess)
341
+ UI.error("Failed to request metadata upload for '#{filename}': #{meta_request_response.code} #{meta_request_response.body} — skipping.")
342
+ next
343
+ end
344
+
345
+ meta_request_data = JSON.parse(meta_request_response.body)
346
+ metadata_pending_upload_id = meta_request_data["metadata_pending_upload_id"]
347
+ presigned_data = meta_request_data["presigned_upload_data"]
348
+
349
+ unless presigned_data && presigned_data["url"]
350
+ UI.error("No presigned upload URL returned for metadata artifact '#{filename}' — skipping.")
351
+ next
352
+ end
353
+
354
+ upload_headers = presigned_data["headers"] || {}
355
+
356
+ # Upload the metadata file to the presigned URL
357
+ upload_response = Helper::BuildstashHelper.upload_file(
358
+ url: presigned_data["url"],
359
+ file_path: file_path,
360
+ headers: {
361
+ "Content-Type" => upload_headers["Content-Type"] || "application/octet-stream",
362
+ "Content-Length" => (upload_headers["Content-Length"] || file_size).to_s,
363
+ "Content-Disposition" => upload_headers["Content-Disposition"] || "attachment; filename=\"#{filename}\"",
364
+ "x-amz-acl" => "private"
365
+ }
366
+ )
367
+
368
+ unless upload_response.is_a?(Net::HTTPSuccess)
369
+ UI.error("Metadata artifact upload failed for '#{filename}': #{upload_response.code} #{upload_response.body} — skipping.")
370
+ next
371
+ end
372
+
373
+ # Verify the metadata artifact upload
374
+ verify_body = { pending_upload_id: metadata_pending_upload_id }
375
+ verify_body[:file_description] = description if description
376
+
377
+ meta_verify_response = Helper::BuildstashHelper.post_json(
378
+ url: "https://app.buildstash.com/api/v1/upload/metadata/verify",
379
+ body: verify_body,
380
+ headers: {
381
+ "Authorization" => "Bearer #{api_key}",
382
+ "Content-Type" => "application/json",
383
+ "Accept" => "application/json"
384
+ }
385
+ )
386
+
387
+ unless meta_verify_response.is_a?(Net::HTTPSuccess)
388
+ UI.error("Metadata artifact verification failed for '#{filename}': #{meta_verify_response.code} #{meta_verify_response.body} — skipping.")
389
+ next
390
+ end
391
+
392
+ meta_verify_data = JSON.parse(meta_verify_response.body)
393
+ artifact_id = meta_verify_data["metadata_artifact_id"]
394
+ UI.success("Metadata artifact '#{filename}' uploaded successfully (ID: #{artifact_id}).")
395
+ end
396
+
397
+ UI.success("✅ All metadata artifacts processed.")
270
398
  end
271
399
 
272
400
  def self.description
@@ -307,6 +435,13 @@ module Fastlane
307
435
  type: String
308
436
  ),
309
437
 
438
+ FastlaneCore::ConfigItem.new(
439
+ key: :custom_target,
440
+ description: "Custom target for this build (must exactly match a target defined in your Buildstash app)",
441
+ optional: true,
442
+ type: String
443
+ ),
444
+
310
445
  FastlaneCore::ConfigItem.new(
311
446
  key: :stream,
312
447
  description: "Buildstash stream",
@@ -412,6 +547,13 @@ module Fastlane
412
547
  type: String,
413
548
  ),
414
549
 
550
+ FastlaneCore::ConfigItem.new(
551
+ key: :ci_build_duration,
552
+ description: "CI build duration (e.g. '00:05:00')",
553
+ optional: true,
554
+ type: String,
555
+ ),
556
+
415
557
  FastlaneCore::ConfigItem.new(
416
558
  key: :vc_host_type,
417
559
  description: "Version control host type (git, svn, hg, perforce, etc)",
@@ -461,6 +603,14 @@ module Fastlane
461
603
  type: String,
462
604
  ),
463
605
 
606
+ FastlaneCore::ConfigItem.new(
607
+ key: :metadata_artifacts,
608
+ description: "List of supplementary files to upload alongside the build (e.g. logs). Each entry is a Hash with a required `:path` key and an optional `:description` key. Maximum 10 files, 5MB per file",
609
+ optional: true,
610
+ type: Array,
611
+ default_value: []
612
+ ),
613
+
464
614
  ]
465
615
  end
466
616
 
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Buildstash
3
- VERSION = "1.0.3"
3
+ VERSION = "1.0.4"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-buildstash
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Buildstash