fastlane-plugin-google_play_track_updater 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 +7 -0
- data/LICENSE +21 -0
- data/README.md +177 -0
- data/lib/fastlane/plugin/google_play_track_updater/actions/halt_google_play_release_action.rb +81 -0
- data/lib/fastlane/plugin/google_play_track_updater/actions/resume_google_play_release_action.rb +81 -0
- data/lib/fastlane/plugin/google_play_track_updater/actions/update_google_play_release_rollout_action.rb +88 -0
- data/lib/fastlane/plugin/google_play_track_updater/client.rb +240 -0
- data/lib/fastlane/plugin/google_play_track_updater/helper/google_play_track_updater_helper.rb +13 -0
- data/lib/fastlane/plugin/google_play_track_updater/version.rb +5 -0
- data/lib/fastlane/plugin/google_play_track_updater.rb +16 -0
- metadata +65 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 11eadb84667aef723c783a8dcffa26780b405708ff266657ddacc2a8d7f91d2f
|
|
4
|
+
data.tar.gz: f680a23a1d846440ca71559f04d20636e0faeb95729471b700deaa879c16f3cd
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: '08cc54c3f46d2a9748e21a7de9eb83bfd024f5ad176b00f7144a38bdec1b9787982bc30b71d818dbe7a850ea14367c83abe7f2be46e6258854d12e6a54d200d8'
|
|
7
|
+
data.tar.gz: defce589cb05520229a89060ca58073c2e7e59ec9ef1abaec5a332b9854b324f96969bdd22042d633ebd7a9c5b18451f051fbc2fea8adaec6473163d3c9505cf
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Takuma Homma <nagomimatcha@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,177 @@
|
|
|
1
|
+
# google_play_track_updater plugin
|
|
2
|
+
|
|
3
|
+
[](https://rubygems.org/gems/fastlane-plugin-google_play_track_updater)
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-google_play_track_updater`, add it to your project by running:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# to Gemfile
|
|
11
|
+
bundle add 'fastlane-plugin-google_play_track_updater'
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# to Pluginfile
|
|
16
|
+
fastlane add_plugin google_play_track_updater
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## About google_play_track_updater
|
|
20
|
+
|
|
21
|
+
A fastlane plugin for managing Google Play release tracks. This plugin provides three actions to control release statuses and rollout fractions:
|
|
22
|
+
|
|
23
|
+
- **`halt_google_play_release`** - Halts an active staged rollout or completed release
|
|
24
|
+
- **`resume_google_play_release`** - Resumes a halted release
|
|
25
|
+
- **`update_google_play_release_rollout`** - Updates the rollout percentage for a staged rollout
|
|
26
|
+
|
|
27
|
+
## Motivation
|
|
28
|
+
|
|
29
|
+
While [supply](https://docs.fastlane.tools/actions/supply/) can also change release statuses, it requires many configuration parameters which can lead to unintended side effects. This plugin provides dedicated actions for each specific operation, making release management more explicit and manageable.
|
|
30
|
+
|
|
31
|
+
By using focused actions like `halt_google_play_release`, `resume_google_play_release`, and `update_google_play_release_rollout`, you can:
|
|
32
|
+
|
|
33
|
+
- Clearly express your intent in your Fastfile
|
|
34
|
+
- Reduce the risk of accidentally modifying other release properties
|
|
35
|
+
- Simplify your CI/CD pipelines with purpose-built commands
|
|
36
|
+
|
|
37
|
+
## Actions
|
|
38
|
+
|
|
39
|
+
### halt_google_play_release
|
|
40
|
+
|
|
41
|
+
Halts an active staged rollout or completed release for a specific version on a Google Play track.
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
halt_google_play_release(
|
|
45
|
+
package_name: "com.example.app",
|
|
46
|
+
track: "production",
|
|
47
|
+
version_name: "1.0.0",
|
|
48
|
+
json_file_path: "path/to/service-account.json"
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Parameters:**
|
|
53
|
+
|
|
54
|
+
| Key | Description | Required | Type |
|
|
55
|
+
|-----|-------------|----------|------|
|
|
56
|
+
| `package_name` | The package name of the application (e.g., 'com.example.app') | Yes | String |
|
|
57
|
+
| `track` | The track of the application (production, beta, alpha, internal) | Yes | String |
|
|
58
|
+
| `version_name` | The version name to halt (e.g., '1.0.0') | Yes | String |
|
|
59
|
+
| `json_file_path` | Path to a file containing service account or external account JSON | No* | String |
|
|
60
|
+
| `json_key_data` | Service account or external account JSON data as a string | No* | String |
|
|
61
|
+
|
|
62
|
+
\* Either `json_file_path` or `json_key_data` must be provided
|
|
63
|
+
|
|
64
|
+
### resume_google_play_release
|
|
65
|
+
|
|
66
|
+
Resumes a halted staged rollout for a specific version on a Google Play track. The status will change from 'halted' to either 'completed' (if no user_fraction is set) or 'inProgress' (if user_fraction is set for staged rollout).
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
resume_google_play_release(
|
|
70
|
+
package_name: "com.example.app",
|
|
71
|
+
track: "production",
|
|
72
|
+
version_name: "1.0.0",
|
|
73
|
+
json_file_path: "path/to/service-account.json"
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Parameters:**
|
|
78
|
+
|
|
79
|
+
| Key | Description | Required | Type |
|
|
80
|
+
|-----|-------------|----------|------|
|
|
81
|
+
| `package_name` | The package name of the application (e.g., 'com.example.app') | Yes | String |
|
|
82
|
+
| `track` | The track of the application (production, beta, alpha, internal) | Yes | String |
|
|
83
|
+
| `version_name` | The version name to resume (e.g., '1.0.0') | Yes | String |
|
|
84
|
+
| `json_file_path` | Path to a file containing service account or external account JSON | No* | String |
|
|
85
|
+
| `json_key_data` | Service account or external account JSON data as a string | No* | String |
|
|
86
|
+
|
|
87
|
+
\* Either `json_file_path` or `json_key_data` must be provided
|
|
88
|
+
|
|
89
|
+
### update_google_play_release_rollout
|
|
90
|
+
|
|
91
|
+
Updates the rollout percentage for a staged rollout on a Google Play track. Only updates releases with 'inProgress' status.
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
update_google_play_release_rollout(
|
|
95
|
+
package_name: "com.example.app",
|
|
96
|
+
track: "production",
|
|
97
|
+
version_name: "1.0.0",
|
|
98
|
+
user_fraction: 0.5, # 50% rollout
|
|
99
|
+
json_file_path: "path/to/service-account.json"
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Parameters:**
|
|
104
|
+
|
|
105
|
+
| Key | Description | Required | Type |
|
|
106
|
+
|-----|-------------|----------|------|
|
|
107
|
+
| `package_name` | The package name of the application (e.g., 'com.example.app') | Yes | String |
|
|
108
|
+
| `track` | The track of the application (production, beta, alpha, internal) | Yes | String |
|
|
109
|
+
| `version_name` | The version name to update (e.g., '1.0.0') | Yes | String |
|
|
110
|
+
| `user_fraction` | The rollout percentage as a fraction (0.0 to 1.0, exclusive). e.g., 0.1 for 10% rollout | Yes | Float |
|
|
111
|
+
| `json_file_path` | Path to a file containing service account or external account JSON | No* | String |
|
|
112
|
+
| `json_key_data` | Service account or external account JSON data as a string | No* | String |
|
|
113
|
+
|
|
114
|
+
\* Either `json_file_path` or `json_key_data` must be provided
|
|
115
|
+
|
|
116
|
+
## Example
|
|
117
|
+
|
|
118
|
+
Here are examples of how to use each action in your `Fastfile`:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
lane :halt_release do
|
|
122
|
+
halt_google_play_release(
|
|
123
|
+
package_name: "com.example.app",
|
|
124
|
+
track: "production",
|
|
125
|
+
version_name: "1.0.0",
|
|
126
|
+
json_file_path: "path/to/service-account.json"
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
lane :resume_release do
|
|
131
|
+
resume_google_play_release(
|
|
132
|
+
package_name: "com.example.app",
|
|
133
|
+
track: "production",
|
|
134
|
+
version_name: "1.0.0",
|
|
135
|
+
json_file_path: "path/to/external-account.json"
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
lane :update_rollout do
|
|
140
|
+
update_google_play_release_rollout(
|
|
141
|
+
package_name: "com.example.app",
|
|
142
|
+
track: "production",
|
|
143
|
+
version_name: "1.0.0",
|
|
144
|
+
user_fraction: 0.5,
|
|
145
|
+
json_file_path: "path/to/service-account.json"
|
|
146
|
+
)
|
|
147
|
+
end
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Run tests for this plugin
|
|
151
|
+
|
|
152
|
+
To run both the tests, and code style validation, run
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
rake
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
To automatically fix many of the styling issues, use
|
|
159
|
+
```
|
|
160
|
+
rubocop -a
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Issues and Feedback
|
|
164
|
+
|
|
165
|
+
For any other issues and feedback about this plugin, please submit it to this repository.
|
|
166
|
+
|
|
167
|
+
## Troubleshooting
|
|
168
|
+
|
|
169
|
+
If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
|
|
170
|
+
|
|
171
|
+
## Using _fastlane_ Plugins
|
|
172
|
+
|
|
173
|
+
For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
|
|
174
|
+
|
|
175
|
+
## About _fastlane_
|
|
176
|
+
|
|
177
|
+
_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,81 @@
|
|
|
1
|
+
require 'fastlane/action'
|
|
2
|
+
require_relative '../client'
|
|
3
|
+
|
|
4
|
+
module Fastlane
|
|
5
|
+
module Actions
|
|
6
|
+
class HaltGooglePlayReleaseAction < Action
|
|
7
|
+
def self.run(params)
|
|
8
|
+
package_name = params[:package_name]
|
|
9
|
+
track = params[:track]
|
|
10
|
+
version_name = params[:version_name]
|
|
11
|
+
json_file_path = params[:json_file_path]
|
|
12
|
+
json_key_data = params[:json_key_data]
|
|
13
|
+
client = Fastlane::GooglePlayTrackUpdater::GooglePlayClient.new(
|
|
14
|
+
json_file_path: json_file_path,
|
|
15
|
+
json_key_data: json_key_data
|
|
16
|
+
)
|
|
17
|
+
client.halt_release(
|
|
18
|
+
package_name: package_name,
|
|
19
|
+
track: track,
|
|
20
|
+
version_name: version_name
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.description
|
|
25
|
+
'Halts an active staged rollout or completed for a specific version on a Google Play track.'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.authors
|
|
29
|
+
['Takuma Homma']
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.return_value
|
|
33
|
+
# If your method provides a return value, you can describe here what it does
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.details
|
|
37
|
+
'Halts an active staged rollout or completed for a specific version on a Google Play track.'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.available_options
|
|
41
|
+
[
|
|
42
|
+
FastlaneCore::ConfigItem.new(key: :package_name,
|
|
43
|
+
env_name: 'HALT_GOOGLE_PLAY_RELEASE_PACKAGE_NAME',
|
|
44
|
+
description: 'The package name of the application. e.g. \'com.example.app\'',
|
|
45
|
+
optional: false,
|
|
46
|
+
type: String),
|
|
47
|
+
FastlaneCore::ConfigItem.new(key: :track,
|
|
48
|
+
env_name: "HALT_GOOGLE_PLAY_RELEASE_TRACK",
|
|
49
|
+
description: 'The track of the application. The available tracks are: production, beta, alpha, internal',
|
|
50
|
+
optional: false,
|
|
51
|
+
type: String),
|
|
52
|
+
FastlaneCore::ConfigItem.new(key: :version_name,
|
|
53
|
+
env_name: 'HALT_GOOGLE_PLAY_RELEASE_VERSION_NAME',
|
|
54
|
+
description: 'The version name to update. e.g. \'1.0.0\'',
|
|
55
|
+
optional: false,
|
|
56
|
+
type: String),
|
|
57
|
+
FastlaneCore::ConfigItem.new(key: :json_file_path,
|
|
58
|
+
env_name: 'HALT_GOOGLE_PLAY_RELEASE_JSON_FILE_PATH',
|
|
59
|
+
description: 'The path to a file containing service account or external account JSON, used to authenticate with Google',
|
|
60
|
+
optional: true,
|
|
61
|
+
type: String),
|
|
62
|
+
FastlaneCore::ConfigItem.new(key: :json_key_data,
|
|
63
|
+
env_name: 'HALT_GOOGLE_PLAY_RELEASE_JSON_KEY_DATA',
|
|
64
|
+
description: 'The file data containing service account or external account JSON, used to authenticate with Google',
|
|
65
|
+
optional: true,
|
|
66
|
+
type: String)
|
|
67
|
+
|
|
68
|
+
]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.is_supported?(platform)
|
|
72
|
+
# Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
|
|
73
|
+
# See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
|
|
74
|
+
#
|
|
75
|
+
# [:ios, :mac, :android].include?(platform)
|
|
76
|
+
|
|
77
|
+
platform == :android
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
data/lib/fastlane/plugin/google_play_track_updater/actions/resume_google_play_release_action.rb
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'fastlane/action'
|
|
2
|
+
require_relative '../client'
|
|
3
|
+
|
|
4
|
+
module Fastlane
|
|
5
|
+
module Actions
|
|
6
|
+
class ResumeGooglePlayReleaseAction < Action
|
|
7
|
+
def self.run(params)
|
|
8
|
+
package_name = params[:package_name]
|
|
9
|
+
track = params[:track]
|
|
10
|
+
version_name = params[:version_name]
|
|
11
|
+
json_file_path = params[:json_file_path]
|
|
12
|
+
json_key_data = params[:json_key_data]
|
|
13
|
+
client = Fastlane::GooglePlayTrackUpdater::GooglePlayClient.new(
|
|
14
|
+
json_file_path: json_file_path,
|
|
15
|
+
json_key_data: json_key_data
|
|
16
|
+
)
|
|
17
|
+
client.resume_release(
|
|
18
|
+
package_name: package_name,
|
|
19
|
+
track: track,
|
|
20
|
+
version_name: version_name
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.description
|
|
25
|
+
'Resumes a halted staged rollout for a specific version on a Google Play track.'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.authors
|
|
29
|
+
["Takuma Homma"]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.return_value
|
|
33
|
+
# If your method provides a return value, you can describe here what it does
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.details
|
|
37
|
+
'Resumes a halted staged rollout for a specific version on a Google Play track.'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.available_options
|
|
41
|
+
[
|
|
42
|
+
FastlaneCore::ConfigItem.new(key: :package_name,
|
|
43
|
+
env_name: 'RESUME_GOOGLE_PLAY_RELEASE_PACKAGE_NAME',
|
|
44
|
+
description: 'The package name of the application. e.g. \'com.example.app\'',
|
|
45
|
+
optional: false,
|
|
46
|
+
type: String),
|
|
47
|
+
FastlaneCore::ConfigItem.new(key: :track,
|
|
48
|
+
env_name: "RESUME_GOOGLE_PLAY_RELEASE_TRACK",
|
|
49
|
+
description: 'The track of the application. The available tracks are: production, beta, alpha, internal',
|
|
50
|
+
optional: false,
|
|
51
|
+
type: String),
|
|
52
|
+
FastlaneCore::ConfigItem.new(key: :version_name,
|
|
53
|
+
env_name: 'RESUME_GOOGLE_PLAY_RELEASE_VERSION_NAME',
|
|
54
|
+
description: 'The version name to update. e.g. \'1.0.0\'',
|
|
55
|
+
optional: false,
|
|
56
|
+
type: String),
|
|
57
|
+
FastlaneCore::ConfigItem.new(key: :json_file_path,
|
|
58
|
+
env_name: 'RESUME_GOOGLE_PLAY_RELEASE_JSON_FILE_PATH',
|
|
59
|
+
description: 'The path to a file containing service account or external account JSON, used to authenticate with Google',
|
|
60
|
+
optional: true,
|
|
61
|
+
type: String),
|
|
62
|
+
FastlaneCore::ConfigItem.new(key: :json_key_data,
|
|
63
|
+
env_name: 'RESUME_GOOGLE_PLAY_RELEASE_JSON_KEY_DATA',
|
|
64
|
+
description: 'The file data containing service account or external account JSON, used to authenticate with Google',
|
|
65
|
+
optional: true,
|
|
66
|
+
type: String)
|
|
67
|
+
|
|
68
|
+
]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.is_supported?(platform)
|
|
72
|
+
# Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
|
|
73
|
+
# See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
|
|
74
|
+
#
|
|
75
|
+
# [:ios, :mac, :android].include?(platform)
|
|
76
|
+
|
|
77
|
+
platform == :android
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require 'fastlane/action'
|
|
2
|
+
require_relative '../client'
|
|
3
|
+
|
|
4
|
+
module Fastlane
|
|
5
|
+
module Actions
|
|
6
|
+
class UpdateGooglePlayReleaseRolloutAction < Action
|
|
7
|
+
def self.run(params)
|
|
8
|
+
package_name = params[:package_name]
|
|
9
|
+
track = params[:track]
|
|
10
|
+
version_name = params[:version_name]
|
|
11
|
+
user_fraction = params[:user_fraction]
|
|
12
|
+
json_file_path = params[:json_file_path]
|
|
13
|
+
json_key_data = params[:json_key_data]
|
|
14
|
+
client = Fastlane::GooglePlayTrackUpdater::GooglePlayClient.new(
|
|
15
|
+
json_file_path: json_file_path,
|
|
16
|
+
json_key_data: json_key_data
|
|
17
|
+
)
|
|
18
|
+
client.update_rollout(
|
|
19
|
+
package_name: package_name,
|
|
20
|
+
track: track,
|
|
21
|
+
version_name: version_name,
|
|
22
|
+
user_fraction: user_fraction
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.description
|
|
27
|
+
'Updates the rollout percentage for a staged rollout on a Google Play track.'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.authors
|
|
31
|
+
["Takuma Homma"]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.return_value
|
|
35
|
+
# If your method provides a return value, you can describe here what it does
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.details
|
|
39
|
+
'Updates the rollout percentage for a staged rollout on a Google Play track.'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.available_options
|
|
43
|
+
[
|
|
44
|
+
FastlaneCore::ConfigItem.new(key: :package_name,
|
|
45
|
+
env_name: 'UPDATE_GOOGLE_PLAY_RELEASE_ROLLOUT_PACKAGE_NAME',
|
|
46
|
+
description: 'The package name of the application. e.g. \'com.example.app\'',
|
|
47
|
+
optional: false,
|
|
48
|
+
type: String),
|
|
49
|
+
FastlaneCore::ConfigItem.new(key: :track,
|
|
50
|
+
env_name: "UPDATE_GOOGLE_PLAY_RELEASE_ROLLOUT_TRACK",
|
|
51
|
+
description: 'The track of the application. The available tracks are: production, beta, alpha, internal',
|
|
52
|
+
optional: false,
|
|
53
|
+
type: String),
|
|
54
|
+
FastlaneCore::ConfigItem.new(key: :version_name,
|
|
55
|
+
env_name: 'UPDATE_GOOGLE_PLAY_RELEASE_ROLLOUT_VERSION_NAME',
|
|
56
|
+
description: 'The version name to update. e.g. \'1.0.0\'',
|
|
57
|
+
optional: false,
|
|
58
|
+
type: String),
|
|
59
|
+
FastlaneCore::ConfigItem.new(key: :user_fraction,
|
|
60
|
+
env_name: 'UPDATE_GOOGLE_PLAY_RELEASE_ROLLOUT_USER_FRACTION',
|
|
61
|
+
description: 'The rollout percentage as a fraction (0.0 to 1.0, exclusive). e.g. 0.1 for 10% rollout',
|
|
62
|
+
optional: false,
|
|
63
|
+
type: Float),
|
|
64
|
+
FastlaneCore::ConfigItem.new(key: :json_file_path,
|
|
65
|
+
env_name: 'UPDATE_GOOGLE_PLAY_RELEASE_ROLLOUT_JSON_FILE_PATH',
|
|
66
|
+
description: 'The path to a file containing service account or external account JSON, used to authenticate with Google',
|
|
67
|
+
optional: true,
|
|
68
|
+
type: String),
|
|
69
|
+
FastlaneCore::ConfigItem.new(key: :json_key_data,
|
|
70
|
+
env_name: 'UPDATE_GOOGLE_PLAY_RELEASE_ROLLOUT_JSON_KEY_DATA',
|
|
71
|
+
description: 'The file data containing service account or external account JSON, used to authenticate with Google',
|
|
72
|
+
optional: true,
|
|
73
|
+
type: String)
|
|
74
|
+
|
|
75
|
+
]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def self.is_supported?(platform)
|
|
79
|
+
# Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
|
|
80
|
+
# See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
|
|
81
|
+
#
|
|
82
|
+
# [:ios, :mac, :android].include?(platform)
|
|
83
|
+
|
|
84
|
+
platform == :android
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
require 'googleauth'
|
|
2
|
+
require 'google/apis/androidpublisher_v3'
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Fastlane
|
|
6
|
+
module GooglePlayTrackUpdater
|
|
7
|
+
class GooglePlayClient
|
|
8
|
+
attr_accessor :android_publisher_service
|
|
9
|
+
|
|
10
|
+
AndroidPublisher = Google::Apis::AndroidpublisherV3
|
|
11
|
+
|
|
12
|
+
# Initializes a new GooglePlayClient instance with authentication credentials
|
|
13
|
+
#
|
|
14
|
+
# @param json_file_path [String, nil] Path to a file containing service account or external account JSON
|
|
15
|
+
# @param json_key_data [String, nil] Service account or external account JSON data as a string
|
|
16
|
+
# @raise [FastlaneCore::Interface::FastlaneError] If neither or both authentication parameters are provided
|
|
17
|
+
# @raise [FastlaneCore::Interface::FastlaneError] If the JSON type is not 'service_account' or 'external_account'
|
|
18
|
+
def initialize(json_file_path: nil, json_key_data: nil)
|
|
19
|
+
if json_file_path.nil? && json_key_data.nil?
|
|
20
|
+
UI.user_error!('Specify exactly one of \'json_file_path: \' or \'json_key_data: \' for service/external account authentication.')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
account_raw_json = if json_file_path
|
|
24
|
+
File.open(File.expand_path(json_file_path))
|
|
25
|
+
elsif json_key_data
|
|
26
|
+
StringIO.new(json_key_data)
|
|
27
|
+
end
|
|
28
|
+
account_json = JSON.parse(account_raw_json.read)
|
|
29
|
+
account_raw_json.rewind
|
|
30
|
+
|
|
31
|
+
case account_json['type']
|
|
32
|
+
when 'external_account'
|
|
33
|
+
auth_client = Google::Auth::ExternalAccount::Credentials.make_creds(json_key_io: account_raw_json, scope: AndroidPublisher::AUTH_ANDROIDPUBLISHER)
|
|
34
|
+
when 'service_account'
|
|
35
|
+
auth_client = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: account_raw_json, scope: AndroidPublisher::AUTH_ANDROIDPUBLISHER)
|
|
36
|
+
else
|
|
37
|
+
UI.user_error!("Invalid Google Credentials JSON: type: #{account_json['type']} is not available.")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
auth_client.fetch_access_token!
|
|
41
|
+
|
|
42
|
+
service = AndroidPublisher::AndroidPublisherService.new
|
|
43
|
+
service.authorization = auth_client
|
|
44
|
+
self.android_publisher_service = service
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Halts an active staged rollout or completed release for a specific version on a Google Play track
|
|
48
|
+
#
|
|
49
|
+
# @param package_name [String] The package name of the application (e.g., 'com.example.app')
|
|
50
|
+
# @param track [String] The track of the application (production, beta, alpha, internal)
|
|
51
|
+
# @param version_name [String] The version name to halt (e.g., '1.0.0')
|
|
52
|
+
# @raise [FastlaneCore::Interface::FastlaneError] If the release with the specified version is not found
|
|
53
|
+
# @raise [Google::Apis::Error] If the API request fails
|
|
54
|
+
def halt_release(package_name:, track:, version_name:)
|
|
55
|
+
validate_inputs_release_status(package_name: package_name, track: track, version_name: version_name)
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
edit = android_publisher_service.insert_edit(package_name)
|
|
59
|
+
edit_id = edit.id
|
|
60
|
+
|
|
61
|
+
current_track = android_publisher_service.get_edit_track(package_name, edit_id, track)
|
|
62
|
+
|
|
63
|
+
target_releases = current_track.releases.select do |release|
|
|
64
|
+
release.name == version_name
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if target_releases.empty?
|
|
68
|
+
UI.user_error!("Could not find a release with version '#{version_name}' on track: '#{track}'.")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
is_halted = false
|
|
72
|
+
|
|
73
|
+
target_releases.each do |release|
|
|
74
|
+
next unless release.status == 'completed' || release.status == 'inProgress'
|
|
75
|
+
|
|
76
|
+
release.status = 'halted'
|
|
77
|
+
UI.message("Preparing to halt release for version '#{version_name}' on track: #{track}...")
|
|
78
|
+
is_halted = true
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if is_halted
|
|
82
|
+
android_publisher_service.update_edit_track(package_name, edit_id, track, current_track)
|
|
83
|
+
android_publisher_service.commit_edit(package_name, edit_id)
|
|
84
|
+
UI.success("Successfully changed status to 'halted' for version '#{version_name}' on track: #{track}.")
|
|
85
|
+
else
|
|
86
|
+
UI.message("No releases found to halt for version '#{version_name}' on track: #{track}.")
|
|
87
|
+
end
|
|
88
|
+
rescue Google::Apis::Error => e
|
|
89
|
+
UI.error!("Failed to halt release for version '#{version_name}' on track: #{track}. Google Api Error: #{e.message}")
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Resumes a halted staged rollout for a specific version on a Google Play track
|
|
94
|
+
#
|
|
95
|
+
# Changes the status from 'halted' to either 'completed' (if no user_fraction is set)
|
|
96
|
+
# or 'inProgress' (if user_fraction is set for staged rollout)
|
|
97
|
+
#
|
|
98
|
+
# @param package_name [String] The package name of the application (e.g., 'com.example.app')
|
|
99
|
+
# @param track [String] The track of the application (production, beta, alpha, internal)
|
|
100
|
+
# @param version_name [String] The version name to resume (e.g., '1.0.0')
|
|
101
|
+
# @raise [FastlaneCore::Interface::FastlaneError] If the release with the specified version is not found
|
|
102
|
+
# @raise [Google::Apis::Error] If the API request fails
|
|
103
|
+
def resume_release(package_name:, track:, version_name:)
|
|
104
|
+
validate_inputs_release_status(package_name: package_name, track: track, version_name: version_name)
|
|
105
|
+
|
|
106
|
+
begin
|
|
107
|
+
edit = android_publisher_service.insert_edit(package_name)
|
|
108
|
+
edit_id = edit.id
|
|
109
|
+
|
|
110
|
+
completed_changed = false
|
|
111
|
+
in_progress_changed = false
|
|
112
|
+
|
|
113
|
+
current_track = android_publisher_service.get_edit_track(package_name, edit_id, track)
|
|
114
|
+
|
|
115
|
+
target_releases = current_track.releases.select do |release|
|
|
116
|
+
release.name == version_name
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
if target_releases.empty?
|
|
120
|
+
UI.user_error!("Could not find a release with version '#{version_name}' on track: '#{track}'.")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
target_releases.each do |release|
|
|
124
|
+
next unless release.status == 'halted'
|
|
125
|
+
|
|
126
|
+
if release.user_fraction.nil?
|
|
127
|
+
release.status = 'completed'
|
|
128
|
+
completed_changed = true
|
|
129
|
+
else
|
|
130
|
+
release.status = 'inProgress'
|
|
131
|
+
in_progress_changed = true
|
|
132
|
+
end
|
|
133
|
+
UI.message("Preparing to resume release for version '#{version_name}' on track: #{track}...")
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
if completed_changed || in_progress_changed
|
|
137
|
+
android_publisher_service.update_edit_track(package_name, edit_id, track, current_track)
|
|
138
|
+
android_publisher_service.commit_edit(package_name, edit_id)
|
|
139
|
+
changed_release = if in_progress_changed
|
|
140
|
+
'inProgress'
|
|
141
|
+
elsif completed_changed
|
|
142
|
+
'completed'
|
|
143
|
+
end
|
|
144
|
+
UI.success("Successfully changed status to #{changed_release || 'completed'} for version '#{version_name}' on track: #{track}.")
|
|
145
|
+
else
|
|
146
|
+
UI.message("No halted releases found for version '#{version_name}' on track: #{track}.")
|
|
147
|
+
end
|
|
148
|
+
rescue Google::Apis::Error => e
|
|
149
|
+
UI.error!("Failed to resume release for '#{version_name}' on track: #{track}. Google Api Error: #{e.message}")
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Updates the rollout percentage for a staged rollout on a Google Play track
|
|
154
|
+
#
|
|
155
|
+
# Only updates releases with 'inProgress' status
|
|
156
|
+
#
|
|
157
|
+
# @param package_name [String] The package name of the application (e.g., 'com.example.app')
|
|
158
|
+
# @param track [String] The track of the application (production, beta, alpha, internal)
|
|
159
|
+
# @param version_name [String] The version name to update (e.g., '1.0.0')
|
|
160
|
+
# @param user_fraction [Float] The rollout percentage as a fraction (0.0 to 1.0, exclusive). e.g., 0.1 for 10% rollout
|
|
161
|
+
# @raise [FastlaneCore::Interface::FastlaneError] If the release with the specified version is not found
|
|
162
|
+
# @raise [FastlaneCore::Interface::FastlaneError] If user_fraction is not within the valid range (0.0, 1.0)
|
|
163
|
+
# @raise [Google::Apis::Error] If the API request fails
|
|
164
|
+
def update_rollout(package_name:, track:, version_name:, user_fraction:)
|
|
165
|
+
validate_inputs_rollout(package_name: package_name, track: track, version_name: version_name, user_fraction: user_fraction)
|
|
166
|
+
|
|
167
|
+
begin
|
|
168
|
+
edit = android_publisher_service.insert_edit(package_name)
|
|
169
|
+
edit_id = edit.id
|
|
170
|
+
|
|
171
|
+
current_track = android_publisher_service.get_edit_track(package_name, edit_id, track)
|
|
172
|
+
|
|
173
|
+
target_releases = current_track.releases.select do |release|
|
|
174
|
+
release.name == version_name
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
if target_releases.empty?
|
|
178
|
+
UI.user_error!("Could not find a release with version '#{version_name}' on track: '#{track}'.")
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
is_rollout_updated = false
|
|
182
|
+
|
|
183
|
+
target_releases.each do |release|
|
|
184
|
+
next unless release.status == 'inProgress'
|
|
185
|
+
|
|
186
|
+
release.user_fraction = user_fraction.to_f
|
|
187
|
+
UI.verbose("Preparing to update rollout to #{user_fraction} for version '#{version_name}' on track: #{track}...")
|
|
188
|
+
is_rollout_updated = true
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
if is_rollout_updated
|
|
192
|
+
android_publisher_service.update_edit_track(package_name, edit_id, track, current_track)
|
|
193
|
+
android_publisher_service.commit_edit(package_name, edit_id)
|
|
194
|
+
UI.success("Successfully updated rollout to #{user_fraction} for version '#{version_name}' on track: #{track}.")
|
|
195
|
+
else
|
|
196
|
+
UI.message("No inProgress releases found to update rollout for version '#{version_name}' on track: #{track}.")
|
|
197
|
+
end
|
|
198
|
+
rescue Google::Apis::Error => e
|
|
199
|
+
UI.error!("Failed to update rollout for version '#{version_name}' on track: #{track}. Google Api Error: #{e.message}")
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
private
|
|
204
|
+
|
|
205
|
+
def validate_inputs_release_status(package_name:, track:, version_name:)
|
|
206
|
+
if package_name.nil? || package_name.empty?
|
|
207
|
+
UI.user_error!('Specify the package name using the \'package_name:\' .')
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
if track.nil? || track.empty?
|
|
211
|
+
UI.user_error!('Specify the track using the \'track:\' .')
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
if version_name.nil? || version_name.empty?
|
|
215
|
+
UI.user_error!('Specify the version_name using the \'version_name:\' .')
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def validate_inputs_rollout(package_name:, track:, version_name:, user_fraction:)
|
|
220
|
+
if package_name.nil? || package_name.empty?
|
|
221
|
+
UI.user_error!('Specify the package name using the \'package_name:\' .')
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
if track.nil? || track.empty?
|
|
225
|
+
UI.user_error!('Specify the track using the \'track:\' .')
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
if version_name.nil? || version_name.empty?
|
|
229
|
+
UI.user_error!('Specify the version_name using the \'version_name:\' .')
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
fraction = user_fraction&.to_f
|
|
233
|
+
|
|
234
|
+
if fraction.nil? || fraction <= 0.0 || fraction >= 1.0
|
|
235
|
+
UI.user_error!('Invalid \'user_fraction:\' provided. Please specify a value from 0 and 1 (exclusive). e.g., 0.1 for 10% rollout.')
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
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 GooglePlayTrackUpdaterHelper
|
|
8
|
+
# class methods that you define here become available in your action
|
|
9
|
+
# as `Helper::GooglePlayTrackUpdaterHelper.your_method`
|
|
10
|
+
|
|
11
|
+
# end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'fastlane/plugin/google_play_track_updater/version'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
module GooglePlayTrackUpdater
|
|
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::GooglePlayTrackUpdater.all_classes.each do |current|
|
|
15
|
+
require current
|
|
16
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: fastlane-plugin-google_play_track_updater
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Takuma Homma
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: google-apis-androidpublisher_v3
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.3'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.3'
|
|
26
|
+
description: fastlane plugin for Google Play track management. Includes halt_google_play_release,
|
|
27
|
+
resume_google_play_release, and update_google_play_release_rollout actions to control
|
|
28
|
+
release statuses and rollout fractions.
|
|
29
|
+
email: nagomimatcha@gmail.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- LICENSE
|
|
35
|
+
- README.md
|
|
36
|
+
- lib/fastlane/plugin/google_play_track_updater.rb
|
|
37
|
+
- lib/fastlane/plugin/google_play_track_updater/actions/halt_google_play_release_action.rb
|
|
38
|
+
- lib/fastlane/plugin/google_play_track_updater/actions/resume_google_play_release_action.rb
|
|
39
|
+
- lib/fastlane/plugin/google_play_track_updater/actions/update_google_play_release_rollout_action.rb
|
|
40
|
+
- lib/fastlane/plugin/google_play_track_updater/client.rb
|
|
41
|
+
- lib/fastlane/plugin/google_play_track_updater/helper/google_play_track_updater_helper.rb
|
|
42
|
+
- lib/fastlane/plugin/google_play_track_updater/version.rb
|
|
43
|
+
homepage: https://github.com/mataku/fastlane-plugin-google_play_track_updater
|
|
44
|
+
licenses:
|
|
45
|
+
- MIT
|
|
46
|
+
metadata:
|
|
47
|
+
rubygems_mfa_required: 'true'
|
|
48
|
+
rdoc_options: []
|
|
49
|
+
require_paths:
|
|
50
|
+
- lib
|
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '2.6'
|
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
requirements: []
|
|
62
|
+
rubygems_version: 3.6.9
|
|
63
|
+
specification_version: 4
|
|
64
|
+
summary: Control Google Play tracks by halting, resuming, or updating rollout fractions.
|
|
65
|
+
test_files: []
|