fastlane-plugin-match_import_multiple 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f4b052227308ac34eb0e6f3b05c963c1ab386c7506ff8c4be155982e44983763
4
+ data.tar.gz: 898a6d58c6bc0f12909ea7a30238168f615634f52262a976259478c1a73ae53d
5
+ SHA512:
6
+ metadata.gz: a0d5310bb184ba21c31df014c4cc6584eef5f67d27a62c54f546b1f211532827329b8956da9a2c1b7353bf18a96029aff9bf3bb573fcb0e91430112faa4cbe93
7
+ data.tar.gz: 7d01e6f41d0d22fe2a71242afe07374dd32daa7f360ca53b5a8a93fd720f3926ad6109af7a0dc28437867b823b6fe2030a37e1e384714d9bab2e2e61ab97147e
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Bogdan Matran <bogdancristian.matran@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # match_import_multiple plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-match_import_multiple)
4
+
5
+ ## About match_import_multiple
6
+
7
+ Wraps _match_'s `Importer` so a single invocation can register many provisioning profiles for the same certificate. _match_'s built-in `match import` only accepts one `.mobileprovision` (or `.provisionprofile`) per call, which means teams managing many bundle identifiers under the same signing certificate have to run the import once per profile — repeating the same App Store Connect login, the same git/S3 storage round trip, and the same Matchfile configuration each time.
8
+
9
+ This plugin keeps the same UX as upstream `fastlane match import` (cert → p12 → profile prompts, `Matchfile` auto-loaded, all _match_ options forwarded as-is) and only changes the profile argument, which now accepts an `Array` of paths or a comma-separated `String`. The action loops over the profiles and delegates each one to the unmodified upstream `Match::Importer#import_cert`, so behavior stays consistent with stock _fastlane_ and future _fastlane_ releases require no code changes here.
10
+
11
+ ## Installation
12
+
13
+ Add the plugin to your project's `fastlane/Pluginfile`:
14
+
15
+ ```ruby
16
+ gem 'fastlane-plugin-match_import_multiple',
17
+ git: 'https://github.com/BogdanMatran/fastlane-plugin-match_import_multiple.git',
18
+ branch: 'main'
19
+ ```
20
+
21
+ Then make sure your project's `Gemfile` evaluates the `Pluginfile`:
22
+
23
+ ```ruby
24
+ # Gemfile
25
+ source "https://rubygems.org"
26
+ gem 'fastlane'
27
+
28
+ plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
29
+ eval_gemfile(plugins_path) if File.exist?(plugins_path)
30
+ ```
31
+
32
+ Install:
33
+
34
+ ```bash
35
+ bundle install
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ### From a `Fastfile`
41
+
42
+ ```ruby
43
+ lane :import_profiles do
44
+ match_import_multiple(
45
+ type: "appstore",
46
+ cert_path: "./assets/dist.cer",
47
+ p12_path: "./assets/dist.p12",
48
+ profile_paths: [
49
+ "./assets/AppStore_app.mobileprovision",
50
+ "./assets/AppStore_app.ShareExtension.mobileprovision",
51
+ "./assets/AppStore_app.NotificationExtension.mobileprovision"
52
+ ]
53
+ )
54
+ end
55
+ ```
56
+
57
+ `git_url`, `username`, `team_id`, and other _match_ options are picked up from your project's `Matchfile` and `Appfile` automatically — exactly like with `fastlane match import`.
58
+
59
+ Run it:
60
+
61
+ ```bash
62
+ bundle exec fastlane import_profiles
63
+ ```
64
+
65
+ ### From the CLI (no lane needed)
66
+
67
+ ```bash
68
+ bundle exec fastlane run match_import_multiple \
69
+ type:appstore \
70
+ cert_path:./assets/dist.cer \
71
+ p12_path:./assets/dist.p12 \
72
+ profile_paths:./assets/profile1.mobileprovision,./assets/profile2.mobileprovision
73
+ ```
74
+
75
+ `profile_paths` accepts a comma-separated string on the CLI; arrays are normalized internally.
76
+
77
+ ### Interactive (mirrors upstream `fastlane match import`)
78
+
79
+ If you omit any of `cert_path`, `p12_path`, or `profile_paths`, the plugin prompts for them in the same order as `fastlane match import`:
80
+
81
+ ```bash
82
+ bundle exec fastlane run match_import_multiple type:appstore
83
+ # Certificate (.cer) path: ./assets/dist.cer
84
+ # Private key (.p12) path: ./assets/dist.p12
85
+ # Provisioning profile (.mobileprovision or .provisionprofile) path(s),
86
+ # comma-separated, or leave empty to skip: ./a.mobileprovision,./b.mobileprovision
87
+ ```
88
+
89
+ ## Parameters
90
+
91
+ | Parameter | Type | Description |
92
+ | ---------------- | --------------- | ---------------------------------------------------------------------------------------------------- |
93
+ | `profile_paths` | `Array[String]` or comma-separated `String` | Provisioning profile paths to import. Prompts interactively if omitted. |
94
+ | `cert_path` | `String` | Path to the `.cer` certificate (shared across all profiles). Prompts interactively if omitted. |
95
+ | `p12_path` | `String` | Path to the `.p12` private key (shared across all profiles). Prompts interactively if omitted. |
96
+ | _all match opts_ | varies | Every option that `fastlane match import` accepts (`type`, `git_url`, `storage_mode`, `api_key_path`, `username`, `team_id`, `skip_certificate_matching`, `force_legacy_encryption`, etc.) is forwarded as-is. |
97
+
98
+ ## Behavior notes
99
+
100
+ - **One commit per profile.** Each profile triggers its own `Match::Importer#import_cert` call, which clones the certs repo, copies the profile, and pushes a commit. Importing _N_ profiles produces _N_ commits in the certs repo. This keeps the plugin a thin wrapper around upstream and resilient to future _match_ changes.
101
+ - **`app_identifier` is not required for import.** _match_'s option list declares `app_identifier` as required, but the import flow reads bundle ids from each `.mobileprovision` file directly. The plugin avoids forcing the prompt by passing the configuration straight through to `Match::Importer`, the same way upstream `match import` does.
102
+ - **`Matchfile` is auto-loaded** by the plugin, mirroring upstream's behavior. You don't need to repeat `git_url`, `type`, `storage_mode`, etc. in the action call if your `Matchfile` already sets them.
103
+
104
+ ## Run tests for this plugin
105
+
106
+ ```
107
+ bundle install
108
+ bundle exec rake
109
+ ```
110
+
111
+ This runs RSpec specs and RuboCop. To auto-fix style issues:
112
+
113
+ ```
114
+ bundle exec rubocop -a
115
+ ```
116
+
117
+ ## Troubleshooting
118
+
119
+ If you have trouble using _fastlane_ plugins, check the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
120
+
121
+ ## About _fastlane_
122
+
123
+ _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).
@@ -0,0 +1,144 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane_core/configuration/configuration'
3
+ require_relative '../helper/match_import_multiple_helper'
4
+
5
+ module Fastlane
6
+ module Actions
7
+ class MatchImportMultipleAction < Action
8
+ def self.run(params)
9
+ require 'match/importer'
10
+
11
+ # Mirror what `fastlane match import` does after building its Configuration:
12
+ # load Matchfile defaults so storage/type/etc are picked up automatically.
13
+ begin
14
+ params.load_configuration_file("Matchfile")
15
+ rescue StandardError
16
+ # Matchfile is optional
17
+ end
18
+
19
+ importer = ::Match::Importer.new
20
+
21
+ # Same prompt order as upstream `fastlane match import`: cert -> p12 -> profile(s).
22
+ cert_path = importer.ensure_valid_file_path(params[:cert_path], "Certificate", ".cer")
23
+ p12_path = importer.ensure_valid_file_path(params[:p12_path], "Private key", ".p12")
24
+
25
+ profile_paths = resolve_profile_paths(params[:profile_paths])
26
+ UI.user_error!("No provisioning profiles provided") if profile_paths.empty?
27
+
28
+ profile_paths.each_with_index do |profile_path, idx|
29
+ UI.message("Importing profile #{idx + 1}/#{profile_paths.length}: #{profile_path}")
30
+ importer.import_cert(
31
+ params,
32
+ cert_path: cert_path,
33
+ p12_path: p12_path,
34
+ profile_path: profile_path
35
+ )
36
+ end
37
+
38
+ UI.success("Imported #{profile_paths.length} provisioning profile(s) into the match repo")
39
+ end
40
+
41
+ # Mirrors upstream match's interactive UX:
42
+ # - Array given -> use as-is
43
+ # - String (single/CSV) -> split on commas
44
+ # - nil -> prompt the user (comma-separated input)
45
+ # Each path is normalized to an absolute path and verified to exist.
46
+ def self.resolve_profile_paths(value)
47
+ raw = case value
48
+ when Array
49
+ value
50
+ when String
51
+ value.split(",")
52
+ when nil
53
+ UI.input("Provisioning profile (.mobileprovision or .provisionprofile) path(s), comma-separated, or leave empty to skip:").split(",")
54
+ else
55
+ UI.user_error!("Invalid profile_paths value: #{value.inspect}")
56
+ end
57
+
58
+ raw.map { |entry| entry.to_s.strip }.reject(&:empty?).map do |path|
59
+ absolute = File.absolute_path(path)
60
+ UI.user_error!("Provisioning profile does not exist at path: #{absolute}") unless File.exist?(absolute)
61
+ absolute
62
+ end
63
+ end
64
+
65
+ def self.description
66
+ "Import multiple provisioning profiles into a match repo in a single invocation"
67
+ end
68
+
69
+ def self.details
70
+ <<~DETAILS
71
+ Wraps fastlane match's Importer so you can pass an array of provisioning
72
+ profile paths together with a single shared certificate and private key.
73
+ Iterates over the profiles and delegates to the unmodified upstream
74
+ Match::Importer#import_cert. All match options (storage backend, type,
75
+ team, App Store Connect API key, encryption settings, Matchfile, etc.)
76
+ are forwarded as-is.
77
+ DETAILS
78
+ end
79
+
80
+ def self.authors
81
+ ["Bogdan Matran"]
82
+ end
83
+
84
+ def self.return_value
85
+ end
86
+
87
+ def self.is_supported?(platform)
88
+ [:ios, :mac].include?(platform)
89
+ end
90
+
91
+ def self.available_options
92
+ require 'match/options'
93
+
94
+ plugin_options = [
95
+ FastlaneCore::ConfigItem.new(
96
+ key: :profile_paths,
97
+ description: "Array (or comma-separated string) of provisioning profile paths to import. Prompts interactively if omitted, mirroring `fastlane match import`",
98
+ skip_type_validation: true,
99
+ optional: true
100
+ ),
101
+ FastlaneCore::ConfigItem.new(
102
+ key: :cert_path,
103
+ description: "Path to the .cer certificate (shared across all profiles). Prompts interactively if omitted",
104
+ type: String,
105
+ optional: true,
106
+ verify_block: proc { |value| UI.user_error!("Certificate not found at path: #{value}") if value && !File.exist?(value) }
107
+ ),
108
+ FastlaneCore::ConfigItem.new(
109
+ key: :p12_path,
110
+ description: "Path to the .p12 private key (shared across all profiles). Prompts interactively if omitted",
111
+ type: String,
112
+ optional: true,
113
+ verify_block: proc { |value| UI.user_error!("Private key not found at path: #{value}") if value && !File.exist?(value) }
114
+ )
115
+ ]
116
+
117
+ reserved_keys = plugin_options.map(&:key)
118
+ match_options = ::Match::Options.available_options.reject { |opt| reserved_keys.include?(opt.key) }
119
+
120
+ plugin_options + match_options
121
+ end
122
+
123
+ def self.example_code
124
+ [
125
+ 'match_import_multiple(
126
+ type: "appstore",
127
+ git_url: "git@github.com:your-org/certs.git",
128
+ cert_path: "./assets/dist.cer",
129
+ p12_path: "./assets/dist.p12",
130
+ profile_paths: [
131
+ "./assets/AppStore_app1.mobileprovision",
132
+ "./assets/AppStore_app2.mobileprovision",
133
+ "./assets/AppStore_app3.mobileprovision"
134
+ ]
135
+ )'
136
+ ]
137
+ end
138
+
139
+ def self.category
140
+ :code_signing
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane_core/ui/ui'
2
+
3
+ module Fastlane
4
+ UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
5
+
6
+ module Helper
7
+ class MatchImportMultipleHelper
8
+ # class methods that you define here become available in your action
9
+ # as `Helper::MatchImportMultipleHelper.your_method`
10
+ #
11
+ def self.show_message
12
+ UI.message("Hello from the match_import_multiple plugin helper!")
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module MatchImportMultiple
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/match_import_multiple/version'
2
+
3
+ module Fastlane
4
+ module MatchImportMultiple
5
+ # Return all .rb files inside the "actions" and "helper" directory
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
8
+ end
9
+ end
10
+ end
11
+
12
+ # By default we want to import all available actions and helpers
13
+ # A plugin can contain any number of actions and plugins
14
+ Fastlane::MatchImportMultiple.all_classes.each do |current|
15
+ require current
16
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-match_import_multiple
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Bogdan Matran
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-05-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Wraps fastlane match's Importer to accept an array of provisioning profile
14
+ paths so you can register many profiles for the same certificate in one command,
15
+ instead of running fastlane match import once per profile.
16
+ email: bogdancristian.matran@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE
22
+ - README.md
23
+ - lib/fastlane/plugin/match_import_multiple.rb
24
+ - lib/fastlane/plugin/match_import_multiple/actions/match_import_multiple_action.rb
25
+ - lib/fastlane/plugin/match_import_multiple/helper/match_import_multiple_helper.rb
26
+ - lib/fastlane/plugin/match_import_multiple/version.rb
27
+ homepage:
28
+ licenses:
29
+ - MIT
30
+ metadata:
31
+ rubygems_mfa_required: 'true'
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '2.7'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubygems_version: 3.3.26
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: Import multiple provisioning profiles into a match repo in a single invocation
51
+ test_files: []