fastlane-plugin-paper_tools_builds 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 +81 -0
- data/lib/fastlane/plugin/paper_tools_builds/actions/paper_tools_builds_upload_action.rb +163 -0
- data/lib/fastlane/plugin/paper_tools_builds/helper/paper_tools_builds_helper.rb +16 -0
- data/lib/fastlane/plugin/paper_tools_builds/version.rb +5 -0
- data/lib/fastlane/plugin/paper_tools_builds.rb +15 -0
- metadata +98 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 908c8abf1c1c43649aec2095b46ef05c1536dd1ce4702494eb2654510ef4142e
|
|
4
|
+
data.tar.gz: 556964951b566ef27f528f0be710ddd67b893b5e6d35ce61e356915c9f3c8b8d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: bd9e42c757e48cb02ab14fb76bb7f2bed0a6ebde6e0b2852ee8fc977b5d1c0611ae20c611091b3deff8ecf8716c33ac7c8410b69a34bf70e25c76f4da639a7ec
|
|
7
|
+
data.tar.gz: 50e08177846dcb5a096138fc86e38f473d779bcd0b26116628a0c39046010663cd608c1fd3a5d33428f421c07bebc78976ae8335711ed9df597f812fefa9faa0
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) paper.tools
|
|
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,81 @@
|
|
|
1
|
+
# fastlane-plugin-paper_tools_builds
|
|
2
|
+
|
|
3
|
+
Upload a build to Builds by paper.tools from a fastlane lane. The
|
|
4
|
+
`paper_tools_builds_upload` action wraps the `builds` CLI, so it inherits the
|
|
5
|
+
resumable multipart upload, the exit codes, and the staging-or-production default
|
|
6
|
+
without reimplementing any of them.
|
|
7
|
+
|
|
8
|
+
This directory is the source of truth. It is published to RubyGems as
|
|
9
|
+
`fastlane-plugin-paper_tools_builds`. The name portion is underscored because
|
|
10
|
+
fastlane rejects a dash after the `fastlane-plugin-` prefix.
|
|
11
|
+
|
|
12
|
+
## Setup
|
|
13
|
+
|
|
14
|
+
Install the CLI, then add the plugin:
|
|
15
|
+
|
|
16
|
+
```shell
|
|
17
|
+
brew install paper-tools/tap/builds
|
|
18
|
+
fastlane add_plugin paper_tools_builds
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`paper_tools_builds_upload` shells out to the `builds` binary, so it must be on
|
|
22
|
+
`PATH` (or pass `binary:` with a path).
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
lane :distribute do
|
|
28
|
+
build_app(scheme: "App")
|
|
29
|
+
|
|
30
|
+
build_id = paper_tools_builds_upload(
|
|
31
|
+
file: lane_context[SharedValues::IPA_OUTPUT_PATH],
|
|
32
|
+
channel: "qa",
|
|
33
|
+
to: "qa,cto@acme.com",
|
|
34
|
+
version: get_version_number,
|
|
35
|
+
build_number: get_build_number
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
UI.message("Uploaded build #{build_id}")
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Set `BUILDS_TOKEN`, `BUILDS_ORG`, and `BUILDS_APP` in the environment — the token
|
|
43
|
+
never belongs in a Fastfile. The action reads them, and the build id it returns
|
|
44
|
+
is also on `lane_context[SharedValues::PAPER_TOOLS_BUILDS_BUILD_ID]`.
|
|
45
|
+
|
|
46
|
+
## Options
|
|
47
|
+
|
|
48
|
+
| Option | Env | Description |
|
|
49
|
+
| --------------- | -------------- | ---------------------------------------------- |
|
|
50
|
+
| `file` | `BUILDS_FILE` | Path to the `.ipa`, `.apk`, or `.aab`. Required. |
|
|
51
|
+
| `channel` | `BUILDS_CHANNEL` | The channel to land on. Required. |
|
|
52
|
+
| `token` | `BUILDS_TOKEN` | A `builds:write` token. Kept out of argv. |
|
|
53
|
+
| `to` | | Comma-separated recipients. |
|
|
54
|
+
| `org` | `BUILDS_ORG` | The organisation id. |
|
|
55
|
+
| `app` | `BUILDS_APP` | The app id. |
|
|
56
|
+
| `api_url` | `BUILDS_API_URL` | Override the binary's built-in host. |
|
|
57
|
+
| `version` | | The marketing version. |
|
|
58
|
+
| `build_number` | | The build number. |
|
|
59
|
+
| `release_notes` | | Release notes. |
|
|
60
|
+
| `tags` | | Comma-separated tags. |
|
|
61
|
+
| `format` | | Force the format when the extension is unclear. |
|
|
62
|
+
| `notify` | | Notify recipients. |
|
|
63
|
+
| `concurrency` | | Parallel part uploads. |
|
|
64
|
+
| `binary` | | Path to the `builds` binary. Defaults to `builds`. |
|
|
65
|
+
|
|
66
|
+
## A non-zero exit fails the lane
|
|
67
|
+
|
|
68
|
+
The action fails the lane on any non-zero exit, and the exit code says which
|
|
69
|
+
class it was — auth, validation, quota, network. See the CLI's exit-code table in
|
|
70
|
+
the service `README.md`.
|
|
71
|
+
|
|
72
|
+
## Development
|
|
73
|
+
|
|
74
|
+
```shell
|
|
75
|
+
bundle install
|
|
76
|
+
bundle exec rspec
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The canonical repository is a private GitLab project, mirrored to GitHub for
|
|
80
|
+
public issues and the RubyGems source link. Push to GitLab; the mirror follows.
|
|
81
|
+
A `v*` tag publishes the gem to RubyGems from CI.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
require 'fastlane/action'
|
|
2
|
+
require 'open3'
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Fastlane
|
|
6
|
+
module Actions
|
|
7
|
+
module SharedValues
|
|
8
|
+
PAPER_TOOLS_BUILDS_BUILD_ID = :PAPER_TOOLS_BUILDS_BUILD_ID
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Uploads a build by shelling out to the `builds` binary.
|
|
12
|
+
#
|
|
13
|
+
# The binary is the single upload path, so the lane inherits its resumable
|
|
14
|
+
# multipart upload, its exit codes, and its staging-or-production default
|
|
15
|
+
# without reimplementing any of it. The token travels in the environment,
|
|
16
|
+
# never in the argument list, so it stays out of a process listing and a log.
|
|
17
|
+
class PaperToolsBuildsUploadAction < Action
|
|
18
|
+
def self.run(params)
|
|
19
|
+
command = [params[:binary], 'upload', params[:file], '--channel', params[:channel], '--json']
|
|
20
|
+
command += ['--to', params[:to]] unless params[:to].nil?
|
|
21
|
+
command += ['--version', params[:version]] unless params[:version].nil?
|
|
22
|
+
command += ['--build-number', params[:build_number].to_s] unless params[:build_number].nil?
|
|
23
|
+
command += ['--release-notes', params[:release_notes]] unless params[:release_notes].nil?
|
|
24
|
+
command += ['--tags', params[:tags]] unless params[:tags].nil?
|
|
25
|
+
command += ['--format', params[:format]] unless params[:format].nil?
|
|
26
|
+
command += ['--concurrency', params[:concurrency].to_s] unless params[:concurrency].nil?
|
|
27
|
+
command += ['--org', params[:org]] unless params[:org].nil?
|
|
28
|
+
command += ['--app', params[:app]] unless params[:app].nil?
|
|
29
|
+
command += ['--api-url', params[:api_url]] unless params[:api_url].nil?
|
|
30
|
+
command += (params[:notify] ? ['--notify'] : ['--no-notify']) unless params[:notify].nil?
|
|
31
|
+
|
|
32
|
+
# The token goes in the environment, not the command, so it never lands
|
|
33
|
+
# in argv. `builds` reads BUILDS_TOKEN there.
|
|
34
|
+
env = {}
|
|
35
|
+
env['BUILDS_TOKEN'] = params[:token] unless params[:token].nil?
|
|
36
|
+
|
|
37
|
+
UI.message("Uploading #{params[:file]} to channel #{params[:channel]}…")
|
|
38
|
+
stdout, stderr, status = Open3.capture3(env, *command)
|
|
39
|
+
|
|
40
|
+
unless status.success?
|
|
41
|
+
UI.error(stderr.strip) unless stderr.strip.empty?
|
|
42
|
+
# The binary's exit code names the failure class — auth, quota,
|
|
43
|
+
# network — and the lane fails with it rather than swallowing it.
|
|
44
|
+
UI.user_error!("builds upload failed (exit #{status.exitstatus}).")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
build = parse(stdout)
|
|
48
|
+
build_id = build['build_id']
|
|
49
|
+
Actions.lane_context[SharedValues::PAPER_TOOLS_BUILDS_BUILD_ID] = build_id
|
|
50
|
+
UI.success("Uploaded. Build #{build_id} is #{build['status']}.")
|
|
51
|
+
build_id
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The `--json` upload response, or an empty hash if it was not JSON. A
|
|
55
|
+
# non-JSON stdout is not fatal — the upload succeeded — so the id is simply
|
|
56
|
+
# unavailable rather than an error.
|
|
57
|
+
def self.parse(stdout)
|
|
58
|
+
JSON.parse(stdout)
|
|
59
|
+
rescue JSON::ParserError
|
|
60
|
+
{}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.description
|
|
64
|
+
'Upload a build to Builds by paper.tools'
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.details
|
|
68
|
+
'Wraps the `builds` CLI. Install it first (brew install ' \
|
|
69
|
+
'paper-tools/tap/builds), then set a builds:write token in ' \
|
|
70
|
+
'BUILDS_TOKEN or pass it as `token`.'
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.return_value
|
|
74
|
+
'The id of the accepted build, also stored in ' \
|
|
75
|
+
'lane_context[SharedValues::PAPER_TOOLS_BUILDS_BUILD_ID].'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def self.authors
|
|
79
|
+
['paper.tools']
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def self.available_options
|
|
83
|
+
[
|
|
84
|
+
FastlaneCore::ConfigItem.new(key: :file,
|
|
85
|
+
env_name: 'BUILDS_FILE',
|
|
86
|
+
description: 'Path to the .ipa, .apk, or .aab',
|
|
87
|
+
verify_block: proc do |value|
|
|
88
|
+
UI.user_error!("No file at #{value}") unless File.exist?(value)
|
|
89
|
+
end),
|
|
90
|
+
FastlaneCore::ConfigItem.new(key: :channel,
|
|
91
|
+
env_name: 'BUILDS_CHANNEL',
|
|
92
|
+
description: 'The channel to land on'),
|
|
93
|
+
FastlaneCore::ConfigItem.new(key: :token,
|
|
94
|
+
env_name: 'BUILDS_TOKEN',
|
|
95
|
+
description: 'A builds:write API token',
|
|
96
|
+
sensitive: true,
|
|
97
|
+
optional: true),
|
|
98
|
+
FastlaneCore::ConfigItem.new(key: :to,
|
|
99
|
+
description: 'Comma-separated recipients to distribute to',
|
|
100
|
+
optional: true),
|
|
101
|
+
FastlaneCore::ConfigItem.new(key: :org,
|
|
102
|
+
env_name: 'BUILDS_ORG',
|
|
103
|
+
description: 'The organisation id',
|
|
104
|
+
optional: true),
|
|
105
|
+
FastlaneCore::ConfigItem.new(key: :app,
|
|
106
|
+
env_name: 'BUILDS_APP',
|
|
107
|
+
description: 'The app id',
|
|
108
|
+
optional: true),
|
|
109
|
+
FastlaneCore::ConfigItem.new(key: :api_url,
|
|
110
|
+
env_name: 'BUILDS_API_URL',
|
|
111
|
+
description: 'Override the binary\'s built-in API host',
|
|
112
|
+
optional: true),
|
|
113
|
+
FastlaneCore::ConfigItem.new(key: :version,
|
|
114
|
+
description: 'The marketing version',
|
|
115
|
+
optional: true),
|
|
116
|
+
FastlaneCore::ConfigItem.new(key: :build_number,
|
|
117
|
+
description: 'The build number',
|
|
118
|
+
optional: true),
|
|
119
|
+
FastlaneCore::ConfigItem.new(key: :release_notes,
|
|
120
|
+
description: 'Release notes for this build',
|
|
121
|
+
optional: true),
|
|
122
|
+
FastlaneCore::ConfigItem.new(key: :tags,
|
|
123
|
+
description: 'Comma-separated tags',
|
|
124
|
+
optional: true),
|
|
125
|
+
FastlaneCore::ConfigItem.new(key: :format,
|
|
126
|
+
description: 'Force the format when the extension does not name it',
|
|
127
|
+
optional: true),
|
|
128
|
+
FastlaneCore::ConfigItem.new(key: :notify,
|
|
129
|
+
description: 'Notify recipients; defaults to the channel setting',
|
|
130
|
+
optional: true,
|
|
131
|
+
is_string: false),
|
|
132
|
+
FastlaneCore::ConfigItem.new(key: :concurrency,
|
|
133
|
+
description: 'How many parts to upload at once',
|
|
134
|
+
optional: true,
|
|
135
|
+
type: Integer),
|
|
136
|
+
FastlaneCore::ConfigItem.new(key: :binary,
|
|
137
|
+
description: 'Path to the builds binary',
|
|
138
|
+
optional: true,
|
|
139
|
+
default_value: 'builds'),
|
|
140
|
+
]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def self.is_supported?(platform)
|
|
144
|
+
[:ios, :mac, :android].include?(platform)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def self.category
|
|
148
|
+
:building
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def self.example_code
|
|
152
|
+
[
|
|
153
|
+
'paper_tools_builds_upload(
|
|
154
|
+
file: lane_context[SharedValues::IPA_OUTPUT_PATH],
|
|
155
|
+
channel: "qa",
|
|
156
|
+
version: get_version_number,
|
|
157
|
+
build_number: get_build_number
|
|
158
|
+
)',
|
|
159
|
+
]
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
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 PaperToolsBuildsHelper
|
|
8
|
+
# Whether the `builds` binary is on PATH, or at the given path. The action
|
|
9
|
+
# lets the binary report its own absence; this is for a lane that wants to
|
|
10
|
+
# check first.
|
|
11
|
+
def self.available?(binary = 'builds')
|
|
12
|
+
system(binary, '--version', out: File::NULL, err: File::NULL)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'fastlane/plugin/paper_tools_builds/version'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
# Loads every action and helper the plugin ships, the way `fastlane` expects a
|
|
5
|
+
# plugin's entry point to.
|
|
6
|
+
module PaperToolsBuilds
|
|
7
|
+
def self.all_classes
|
|
8
|
+
Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
Fastlane::PaperToolsBuilds.all_classes.each do |current|
|
|
14
|
+
require current
|
|
15
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: fastlane-plugin-paper_tools_builds
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- paper.tools
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-08-21 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: fastlane
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.0'
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 2.0.0
|
|
23
|
+
type: :development
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - "~>"
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '2.0'
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 2.0.0
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: rspec
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '3.0'
|
|
40
|
+
type: :development
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.0'
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: rake
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '13.0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '13.0'
|
|
61
|
+
description:
|
|
62
|
+
email: builds@paper.tools
|
|
63
|
+
executables: []
|
|
64
|
+
extensions: []
|
|
65
|
+
extra_rdoc_files: []
|
|
66
|
+
files:
|
|
67
|
+
- LICENSE
|
|
68
|
+
- README.md
|
|
69
|
+
- lib/fastlane/plugin/paper_tools_builds.rb
|
|
70
|
+
- lib/fastlane/plugin/paper_tools_builds/actions/paper_tools_builds_upload_action.rb
|
|
71
|
+
- lib/fastlane/plugin/paper_tools_builds/helper/paper_tools_builds_helper.rb
|
|
72
|
+
- lib/fastlane/plugin/paper_tools_builds/version.rb
|
|
73
|
+
homepage: https://builds.paper.tools
|
|
74
|
+
licenses:
|
|
75
|
+
- MIT
|
|
76
|
+
metadata:
|
|
77
|
+
homepage_uri: https://builds.paper.tools
|
|
78
|
+
source_code_uri: https://github.com/paper-tools/fastlane-plugin-paper_tools_builds
|
|
79
|
+
post_install_message:
|
|
80
|
+
rdoc_options: []
|
|
81
|
+
require_paths:
|
|
82
|
+
- lib
|
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - ">="
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '2.6'
|
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - ">="
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '0'
|
|
93
|
+
requirements: []
|
|
94
|
+
rubygems_version: 3.5.22
|
|
95
|
+
signing_key:
|
|
96
|
+
specification_version: 4
|
|
97
|
+
summary: Upload builds to Builds by paper.tools from fastlane
|
|
98
|
+
test_files: []
|