├── fastlane ├── Pluginfile ├── apk │ └── app-release.apk └── Fastfile ├── .travis.yml ├── lib └── fastlane │ └── plugin │ ├── fir │ ├── version.rb │ ├── helper │ │ └── fir_helper.rb │ └── actions │ │ └── fir_action.rb │ └── fir.rb ├── .rspec ├── Gemfile ├── .gitignore ├── Rakefile ├── spec ├── fir_action_spec.rb └── spec_helper.rb ├── LICENSE ├── .circleci └── config.yml ├── fastlane-plugin-fir.gemspec ├── README.md └── .rubocop.yml /fastlane/Pluginfile: -------------------------------------------------------------------------------- 1 | # Autogenerated by fastlane 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # os: osx # enable this if you need macOS support 2 | language: ruby 3 | rvm: 4 | - 2.2.4 5 | -------------------------------------------------------------------------------- /lib/fastlane/plugin/fir/version.rb: -------------------------------------------------------------------------------- 1 | module Fastlane 2 | module Fir 3 | VERSION = "0.3.0" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /fastlane/apk/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongorigin/fastlane-plugin-fir/HEAD/fastlane/apk/app-release.apk -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | --color 3 | --format d 4 | --format RspecJunitFormatter 5 | --out test-results/rspec/rspec.xml 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') 6 | eval_gemfile(plugins_path) if File.exist?(plugins_path) 7 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | lane :test do 2 | fir( 3 | api_token: "...", # your token 4 | apk_path: "./fastlane/apk/app-release.apk", 5 | changelog: "- new: feature a\n- new: feature b" 6 | ) 7 | end 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | Gemfile.lock 3 | 4 | ## Documentation cache and generated files: 5 | /.yardoc/ 6 | /_yardoc/ 7 | /doc/ 8 | /rdoc/ 9 | fastlane/README.md 10 | fastlane/report.xml 11 | coverage 12 | test-results 13 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | 3 | require 'rspec/core/rake_task' 4 | RSpec::Core::RakeTask.new 5 | 6 | require 'rubocop/rake_task' 7 | RuboCop::RakeTask.new(:rubocop) 8 | 9 | task default: [:spec, :rubocop] 10 | -------------------------------------------------------------------------------- /spec/fir_action_spec.rb: -------------------------------------------------------------------------------- 1 | describe Fastlane::Actions::FirAction do 2 | describe '#run' do 3 | it 'prints a message' do 4 | expect(Fastlane::UI).to receive(:message).with("The fir plugin is working!") 5 | 6 | Fastlane::Actions::FirAction.run(nil) 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/fastlane/plugin/fir/helper/fir_helper.rb: -------------------------------------------------------------------------------- 1 | module Fastlane 2 | module Helper 3 | class FirHelper 4 | # class methods that you define here become available in your action 5 | # as `Helper::FirHelper.your_method` 6 | # 7 | def self.show_message 8 | UI.message("Hello from the fir plugin helper!") 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 2 | 3 | require 'simplecov' 4 | 5 | # SimpleCov.minimum_coverage 95 6 | SimpleCov.start 7 | 8 | # This module is only used to check the environment is currently a testing env 9 | module SpecHelper 10 | end 11 | 12 | require 'fastlane' # to import the Action super class 13 | require 'fastlane/plugin/fir' # import the actual plugin 14 | 15 | Fastlane.load_actions # load other actions (in case your plugin calls other actions or shared values) 16 | -------------------------------------------------------------------------------- /lib/fastlane/plugin/fir.rb: -------------------------------------------------------------------------------- 1 | require 'fastlane/plugin/fir/version' 2 | 3 | module Fastlane 4 | module Fir 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::Fir.all_classes.each do |current| 15 | require current 16 | end 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 dong 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. 22 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Ruby CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-ruby/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/ruby:2.4.2 11 | 12 | working_directory: ~/repo 13 | 14 | steps: 15 | - checkout 16 | 17 | # Download and cache dependencies 18 | - restore_cache: 19 | keys: 20 | - v1-dependencies-{{ checksum "Gemfile" }} 21 | # fallback to using the latest cache if no exact match is found 22 | - v1-dependencies- 23 | 24 | - run: 25 | name: install dependencies 26 | command: bundle check || bundle install --jobs=4 --retry=3 --path vendor/bundle 27 | 28 | - save_cache: 29 | paths: 30 | - ./vendor 31 | key: v1-dependencies-{{ checksum "Gemfile" }} 32 | 33 | # run tests! 34 | - run: 35 | name: run tests 36 | command: bundle exec rake 37 | 38 | # collect reports 39 | - store_test_results: 40 | path: ~/repo/test-results 41 | - store_artifacts: 42 | path: ~/repo/test-results 43 | destination: test-results 44 | -------------------------------------------------------------------------------- /fastlane-plugin-fir.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | lib = File.expand_path("../lib", __FILE__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require 'fastlane/plugin/fir/version' 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = 'fastlane-plugin-fir' 9 | spec.version = Fastlane::Fir::VERSION 10 | spec.author = 'dongorigin' 11 | spec.email = 'dongorigin@gmail.com' 12 | 13 | spec.summary = 'Upload a new build to fir.im' 14 | spec.homepage = "https://github.com/dongorigin/fastlane-plugin-fir" 15 | spec.license = "MIT" 16 | 17 | spec.files = Dir["lib/**/*"] + %w(README.md LICENSE) 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ['lib'] 20 | 21 | # Currently dependency fir-cli, removed in the future 22 | spec.add_dependency 'fir-cli', '~> 1.6' 23 | 24 | spec.add_development_dependency 'pry' 25 | spec.add_development_dependency 'bundler' 26 | spec.add_development_dependency 'rspec' 27 | spec.add_development_dependency 'rspec_junit_formatter' 28 | spec.add_development_dependency 'rake' 29 | spec.add_development_dependency 'rubocop', '0.49.1' 30 | spec.add_development_dependency 'simplecov' 31 | spec.add_development_dependency 'fastlane', '>= 2.63.0' 32 | end 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fir plugin 2 | 3 | [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-fir) 4 | [![Build Status](https://travis-ci.org/dongorigin/fastlane-plugin-fir.svg?branch=master)](https://travis-ci.org/dongorigin/fastlane-plugin-fir) 5 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/dongorigin/fastlane-plugin-fir/blob/master/LICENSE) 6 | 7 | ## Getting Started 8 | 9 | This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-fir`, add it to your project by running: 10 | ```bash 11 | fastlane add_plugin fir 12 | ``` 13 | 14 | ## About fir 15 | 16 | Upload a new build to [fir](fir.im) for distribute the build to beta testers. Currently based on [fir-cli](https://github.com/FIRHQ/fir-cli) implementation. 17 | 18 | ## Features 19 | 20 | - [x] support android 21 | - [ ] support ios 22 | - [ ] remove dependency fir-cli 23 | 24 | ## Example 25 | 26 | 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`. 27 | ```ruby 28 | fir( 29 | api_token: '...', 30 | apk_path: './app-release.apk', 31 | changelog: 'Changelog' 32 | ) 33 | ``` 34 | 35 | ## Parameters 36 | 37 | | Key | Description | 38 | |-----------|--------------------------------------------------------------| 39 | | api_token | API Token for fir.im | 40 | | apk_path | Path to your APK file. Optional if you use the gradle action | 41 | | changelog | Release changelog, support string or file path | 42 | 43 | To show the full documentation in your terminal, run 44 | ```bash 45 | fastlane action fir 46 | ``` 47 | 48 | ## Run tests for this plugin 49 | 50 | To run both the tests, and code style validation, run 51 | ``` 52 | rake 53 | ``` 54 | 55 | To automatically fix many of the styling issues, use 56 | ``` 57 | rubocop -a 58 | ``` 59 | 60 | ## Issues and Feedback 61 | 62 | For any other issues and feedback about this plugin, please submit it to this repository. 63 | 64 | ## Troubleshooting 65 | 66 | If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide. 67 | 68 | ## Using _fastlane_ Plugins 69 | 70 | For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/). 71 | 72 | ## About _fastlane_ 73 | 74 | _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). 75 | -------------------------------------------------------------------------------- /lib/fastlane/plugin/fir/actions/fir_action.rb: -------------------------------------------------------------------------------- 1 | module Fastlane 2 | module Actions 3 | module SharedValues 4 | FIR_DOWNLOAD_LINK = :FIR_DOWNLOAD_LINK 5 | end 6 | 7 | class FirAction < Action 8 | def self.run(params) 9 | command = ["fir publish #{params[:apk_path]}"] 10 | command << "-T #{params[:api_token]}" 11 | command << "-c \'#{params[:changelog]}\'" unless params[:changelog].empty? 12 | sh command.join(' ') 13 | 14 | # Actions.lane_context[SharedValues::FIR_DOWNLOAD_LINK] = "" 15 | end 16 | 17 | ##################################################### 18 | # @!group Documentation 19 | ##################################################### 20 | def self.description 21 | "Upload a new build to fir.im" 22 | end 23 | 24 | def self.details 25 | "Based on fir-cli" 26 | end 27 | 28 | def self.available_options 29 | [ 30 | FastlaneCore::ConfigItem.new(key: :api_token, 31 | env_name: "FL_FIR_API_TOKEN", 32 | description: "API Token for fir.im", 33 | sensitive: true, 34 | verify_block: proc do |value| 35 | UI.user_error!("No API token for FirAction given, pass using `api_token: 'token'`") unless (value and not value.empty?) 36 | end), 37 | FastlaneCore::ConfigItem.new(key: :apk_path, 38 | env_name: "FL_FIR_APK_PATH", 39 | description: "Path to your APK file. Optional if you use the gradle action", 40 | default_value: lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH], 41 | verify_block: proc do |value| 42 | UI.user_error!("Couldn't find file at path '#{value}'") unless File.exist?(value) 43 | end), 44 | FastlaneCore::ConfigItem.new(key: :changelog, 45 | env_name: "FL_FIR_CHANGELOG", 46 | description: "Release changelog, support string or file path", 47 | default_value: "") 48 | ] 49 | end 50 | 51 | def self.output 52 | [ 53 | # ['FIR_DOWNLOAD_LINK', 'The newly generated download link for this build'] 54 | ] 55 | end 56 | 57 | def self.authors 58 | ["dongorigin"] 59 | end 60 | 61 | def self.is_supported?(platform) 62 | # ios coming soon 63 | # [:android, :ios].include?(platform) 64 | platform == :android 65 | end 66 | 67 | def self.category 68 | :beta 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/MultipleComparison: 2 | Enabled: false 3 | 4 | Style/PercentLiteralDelimiters: 5 | Enabled: false 6 | 7 | # kind_of? is a good way to check a type 8 | Style/ClassCheck: 9 | EnforcedStyle: kind_of? 10 | 11 | Style/FrozenStringLiteralComment: 12 | Enabled: false 13 | 14 | # This doesn't work with older versions of Ruby (pre 2.4.0) 15 | Style/SafeNavigation: 16 | Enabled: false 17 | 18 | # This doesn't work with older versions of Ruby (pre 2.4.0) 19 | Performance/RegexpMatch: 20 | Enabled: false 21 | 22 | # This suggests use of `tr` instead of `gsub`. While this might be more performant, 23 | # these methods are not at all interchangable, and behave very differently. This can 24 | # lead to people making the substitution without considering the differences. 25 | Performance/StringReplacement: 26 | Enabled: false 27 | 28 | # .length == 0 is also good, we don't always want .zero? 29 | Style/NumericPredicate: 30 | Enabled: false 31 | 32 | # this would cause errors with long lanes 33 | Metrics/BlockLength: 34 | Enabled: false 35 | 36 | # this is a bit buggy 37 | Metrics/ModuleLength: 38 | Enabled: false 39 | 40 | # certificate_1 is an okay variable name 41 | Style/VariableNumber: 42 | Enabled: false 43 | 44 | # This is used a lot across the fastlane code base for config files 45 | Style/MethodMissing: 46 | Enabled: false 47 | 48 | # This rule isn't useful, lots of discussion happening around it also 49 | # e.g. https://github.com/bbatsov/rubocop/issues/2338 50 | MultilineBlockChain: 51 | Enabled: false 52 | 53 | # 54 | # File.chmod(0777, f) 55 | # 56 | # is easier to read than 57 | # 58 | # File.chmod(0o777, f) 59 | # 60 | Style/NumericLiteralPrefix: 61 | Enabled: false 62 | 63 | # 64 | # command = (!clean_expired.nil? || !clean_pattern.nil?) ? CLEANUP : LIST 65 | # 66 | # is easier to read than 67 | # 68 | # command = !clean_expired.nil? || !clean_pattern.nil? ? CLEANUP : LIST 69 | # 70 | Style/TernaryParentheses: 71 | Enabled: false 72 | 73 | # sometimes it is useful to have those empty methods 74 | Style/EmptyMethod: 75 | Enabled: false 76 | 77 | # It's better to be more explicit about the type 78 | Style/BracesAroundHashParameters: 79 | Enabled: false 80 | 81 | # specs sometimes have useless assignments, which is fine 82 | Lint/UselessAssignment: 83 | Exclude: 84 | - '**/spec/**/*' 85 | 86 | # We could potentially enable the 2 below: 87 | Layout/IndentHash: 88 | Enabled: false 89 | 90 | Layout/AlignHash: 91 | Enabled: false 92 | 93 | # HoundCI doesn't like this rule 94 | Layout/DotPosition: 95 | Enabled: false 96 | 97 | # We allow !! as it's an easy way to convert ot boolean 98 | Style/DoubleNegation: 99 | Enabled: false 100 | 101 | # Prevent to replace [] into %i 102 | Style/SymbolArray: 103 | Enabled: false 104 | 105 | # We still support Ruby 2.0.0 106 | Layout/IndentHeredoc: 107 | Enabled: false 108 | 109 | # This cop would not work fine with rspec 110 | Style/MixinGrouping: 111 | Exclude: 112 | - '**/spec/**/*' 113 | 114 | # Sometimes we allow a rescue block that doesn't contain code 115 | Lint/HandleExceptions: 116 | Enabled: false 117 | 118 | # Cop supports --auto-correct. 119 | Lint/UnusedBlockArgument: 120 | Enabled: false 121 | 122 | Lint/AmbiguousBlockAssociation: 123 | Enabled: false 124 | 125 | # Needed for $verbose 126 | Style/GlobalVars: 127 | Enabled: false 128 | 129 | # We want to allow class Fastlane::Class 130 | Style/ClassAndModuleChildren: 131 | Enabled: false 132 | 133 | # $? Exit 134 | Style/SpecialGlobalVars: 135 | Enabled: false 136 | 137 | Metrics/AbcSize: 138 | Enabled: false 139 | 140 | Metrics/MethodLength: 141 | Enabled: false 142 | 143 | Metrics/CyclomaticComplexity: 144 | Enabled: false 145 | 146 | # The %w might be confusing for new users 147 | Style/WordArray: 148 | MinSize: 19 149 | 150 | # raise and fail are both okay 151 | Style/SignalException: 152 | Enabled: false 153 | 154 | # Better too much 'return' than one missing 155 | Style/RedundantReturn: 156 | Enabled: false 157 | 158 | # Having if in the same line might not always be good 159 | Style/IfUnlessModifier: 160 | Enabled: false 161 | 162 | # and and or is okay 163 | Style/AndOr: 164 | Enabled: false 165 | 166 | # Configuration parameters: CountComments. 167 | Metrics/ClassLength: 168 | Max: 320 169 | 170 | 171 | # Configuration parameters: AllowURI, URISchemes. 172 | Metrics/LineLength: 173 | Max: 370 174 | 175 | # Configuration parameters: CountKeywordArgs. 176 | Metrics/ParameterLists: 177 | Max: 17 178 | 179 | Metrics/PerceivedComplexity: 180 | Max: 18 181 | 182 | # Sometimes it's easier to read without guards 183 | Style/GuardClause: 184 | Enabled: false 185 | 186 | # We allow both " and ' 187 | Style/StringLiterals: 188 | Enabled: false 189 | 190 | # something = if something_else 191 | # that's confusing 192 | Style/ConditionalAssignment: 193 | Enabled: false 194 | 195 | # Better to have too much self than missing a self 196 | Style/RedundantSelf: 197 | Enabled: false 198 | 199 | # e.g. 200 | # def self.is_supported?(platform) 201 | # we may never use `platform` 202 | Lint/UnusedMethodArgument: 203 | Enabled: false 204 | 205 | # the let(:key) { ... } 206 | Lint/ParenthesesAsGroupedExpression: 207 | Exclude: 208 | - '**/spec/**/*' 209 | 210 | # This would reject is_ in front of methods 211 | # We use `is_supported?` everywhere already 212 | Style/PredicateName: 213 | Enabled: false 214 | 215 | # We allow the $ 216 | Style/PerlBackrefs: 217 | Enabled: false 218 | 219 | # Disable '+ should be surrounded with a single space' for xcodebuild_spec.rb 220 | Layout/SpaceAroundOperators: 221 | Exclude: 222 | - '**/spec/actions_specs/xcodebuild_spec.rb' 223 | 224 | AllCops: 225 | TargetRubyVersion: 2.0 226 | Include: 227 | - '**/fastlane/Fastfile' 228 | Exclude: 229 | - '**/lib/assets/custom_action_template.rb' 230 | - './vendor/**/*' 231 | 232 | # They have not to be snake_case 233 | Style/FileName: 234 | Exclude: 235 | - '**/Dangerfile' 236 | - '**/Brewfile' 237 | - '**/Gemfile' 238 | - '**/Podfile' 239 | - '**/Rakefile' 240 | - '**/Fastfile' 241 | - '**/Deliverfile' 242 | - '**/Snapfile' 243 | - '**/*.gemspec' 244 | 245 | # We're not there yet 246 | Style/Documentation: 247 | Enabled: false 248 | 249 | # Added after upgrade to 0.38.0 250 | Style/MutableConstant: 251 | Enabled: false 252 | 253 | # length > 0 is good 254 | Style/ZeroLengthPredicate: 255 | Enabled: false 256 | 257 | # Adds complexity 258 | Style/IfInsideElse: 259 | Enabled: false 260 | 261 | # Sometimes we just want to 'collect' 262 | Style/CollectionMethods: 263 | Enabled: false 264 | --------------------------------------------------------------------------------