feat: implement deployement pipeline (#2)

This commit is contained in:
Malo Léon 2023-04-26 16:54:43 +02:00
parent ee58f96126
commit 155d048c18
7 changed files with 184 additions and 100 deletions

View File

@ -7,7 +7,7 @@ module Fastlane
def self.run(params)
# Check parameters
unless Helper::AndroidCdHelper.is_set(params[:beta_type])
UI.error("Parameters beta_type cannot be null")
UI.error("Parameters beta_type cannot be null")
puts("Error on beta type parameter")
end

View File

@ -1,43 +0,0 @@
# Ruby CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
#
version: 2
jobs:
build:
docker:
# specify the version you desire here
- image: circleci/ruby:2.5
working_directory: ~/repo
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "Gemfile" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run:
name: install dependencies
command: bundle check || bundle install --jobs=4 --retry=3 --path vendor/bundle
- save_cache:
paths:
- ./vendor
key: v1-dependencies-{{ checksum "Gemfile" }}
# run tests!
- run:
name: run tests
command: bundle exec rake
# collect reports
- store_test_results:
path: ~/repo/test-results
- store_artifacts:
path: ~/repo/test-results
destination: test-results

View File

@ -2,5 +2,7 @@ source('https://rubygems.org')
gemspec
gem 'json'
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

View File

@ -0,0 +1,116 @@
require 'fastlane/action'
require_relative '../helper/ios_cd_helper'
module Fastlane
module Actions
class BuildAndDeploy < Action
def self.run(params)
# Check parameters
unless Helper::IosCdHelper.is_set(params[:beta_type])
UI.error("❌ Parameters beta_type cannot be null")
puts("Error on beta type parameter")
end
UI.message("⌛️ Building and deploying to Store in #{params[:beta_type]}..")
# Decrypt the keys archive and Extract the keys archive
Helper::IosCdHelper.decrypt_ios_keys('.')
# Retrieve credentials
creds = Helper::IosCdHelper.parseIosCredentials
UI.message(creds.to_s)
# Ensure temporary keychain exists
Fastlane::Actions.ensure_temp_keychain(creds['temp_keychain_user'], creds['temp_keychain_password'])
# Obtain App Store Connect API key
api_key = Fastlane::Actions.app_store_connect_api_key(
key_id: creds['apple_key_id'],
issuer_id: creds['apple_issuer_id'],
key_content: creds['apple_key_content'],
duration: 1200,
in_house: false
)
# Increment build number for latest TestFlight build
Fastlane::Actions.increment_build_number({
build_number: Fastlane::Actions.latest_testflight_build_number + 1,
xcodeproj: "Runner.xcodeproj"
})
# Install Cocoapods
Fastlane::Actions.cocoapods(
clean_install: true
)
# Set up code signing using match
# Configures and runs `match` which manages code signing certificates and provisioning profiles for the project.
# The function takes the app's bundle identifier, an authorization token for the project's Git repository, and the name and password for a temporary keychain used to store the signing certificate.
# It uses the App Store Connect API key to access the App Store and increment the build number.
# It then runs `gym` to build and sign the app using the selected provisioning profile, and finally, uses `pilot` to upload the app to TestFlight for beta testing.
Fastlane::Actions.match(
type: 'appstore',
app_identifier: creds['app_identifier_extensions'],
git_basic_authorization: Base64.strict_encode64(ENV["GIT_AUTHORIZATION"]),
keychain_name: creds['temp_keychain_user'],
keychain_password: creds['temp_keychain_password'],
api_key: api_key
)
# Build and export app using Gym
# Builds and packages an iOS app or framework for distribution to the App Store, TestFlight, or Enterprise distribution.
Fastlane::Actions.gym(
configuration: "Release",
workspace: "Runner.xcworkspace",
scheme: "your_schema",
export_method: "app-store",
export_options: {
provisioningProfiles: creds['provisioning_profiles']
}
)
# Upload build to App Store Connect using Pilot
Fastlane::Actions.pilot(
apple_id: creds['developer_app_id'].to_s,
app_identifier: creds['developer_app_identifier'].to_s,
skip_waiting_for_build_processing: true,
skip_submission: true,
distribute_external: false,
notify_external_testers: false,
ipa: "./Runner.ipa"
)
Fastlane::Actions.delete_temp_keychain
end
def self.description
"Testflight and AppStore deployment plugin for Fastlane, simplifying the build and deployment porcess to internal, external, and production channels, and promoting builds for testing."
end
def self.authors
["SAS Wyatt Studio"]
end
def self.return_value
end
def self.details
"The Fastlane Testflight / Appstore deloyment action streamlines the build and deployment to internal, external and production channels. Allow you to promote builds on testflight beta tests."
end
def self.available_options
[
FastlaneCore::ConfigItem.new(key: :beta_type,
env_name: "IOS_CD_TEST_TYPE",
optional: false,
description: "Type of test (internal, external, production)")
]
end
def self.is_supported?(platform)
true
end
end
end
end

View File

@ -1,47 +0,0 @@
require 'fastlane/action'
require_relative '../helper/ios_cd_helper'
module Fastlane
module Actions
class IosCdAction < Action
def self.run(params)
UI.message("The ios_cd plugin is working!")
end
def self.description
"Testflight and AppStore deployment plugin for Fastlane, simplifying the build and deployment porcess to internal, external, and production channels, and promoting builds for testing."
end
def self.authors
["Malo Léon"]
end
def self.return_value
# If your method provides a return value, you can describe here what it does
end
def self.details
# Optional:
"The Fastlane Testflight / Appstore deloyment action streamlines the build and deployment to internal, external and production channels. Allow you to promote builds on testflight beta tests."
end
def self.available_options
[
# FastlaneCore::ConfigItem.new(key: :your_option,
# env_name: "IOS_CD_YOUR_OPTION",
# description: "A description of your option",
# optional: false,
# type: String)
]
end
def self.is_supported?(platform)
# Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
# See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
#
# [:ios, :mac, :android].include?(platform)
true
end
end
end
end

View File

@ -1,15 +1,71 @@
require 'fastlane/action'
require 'json'
require 'fastlane_core/ui/ui'
module Fastlane
UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
module Helper
class IosCdHelper
# class methods that you define here become available in your action
# as `Helper::IosCdHelper.your_method`
#
def self.show_message
UI.message("Hello from the ios_cd plugin helper!")
# Define method to delete temporary keychain
def delete_temp_keychain(name)
if File.exist?(File.expand_path("~/Library/Keychains/#{name}-db"))
Fastlane::Actions.delete_keychain(
name: name
)
end
end
# Define method to create temporary keychain
def create_temp_keychain(name, password)
Fastlane::Actions.create_keychain(
name: name,
password: password,
unlock: false,
timeout: 0
)
end
# Define method to ensure that temporary keychain exists
def ensure_temp_keychain(name, password)
delete_temp_keychain(name)
create_temp_keychain(name, password)
end
# Check if a parameter is set or not
def self.is_set(variable)
str_variable = variable
str_variable = variable.strip if variable.class.to_s == "String"
variable && !(str_variable.nil? || str_variable.empty?)
end
# Decrypts ios credentials
def self.decrypt_ios_keys(ios_directory)
# Define the GPG command with options
gpg_command = "gpg --quiet --batch --yes --decrypt --passphrase=#{ENV['IOS_KEYS_SECRET_PASSPHRASE']} \
--output #{ios_directory}/ios_keys.zip #{ios_directory}/ios_keys.zip.gpg"
# Execute the GPG command using system
system(gpg_command)
# Check if the command executed successfully
if $?.success?
# Move the extracted files to the current directory
`jar xvf #{ios_directory} && mv #{ios_directory}/ios_keys/* #{ios_directory}`
else
puts("Erreur lors de la décompression du fichier GPG")
end
end
# Parse credential file
def parseIosCredentials(ios_directory)
if File.exists?("#{ios_directory}/ios_crendentials.json")
# Read file and decrypt it
file = File.read("#{ios_directory}/ios_crendentials.json")
JSON.parse(file)
else
UI.error("❌ Ios credentials doesn't exist")
puts("json file doesn't exist")
end
end
end

View File

@ -1,9 +1,9 @@
describe Fastlane::Actions::IosCdAction do
describe Fastlane::Actions::BuildAndDeploy do
describe '#run' do
it 'prints a message' do
expect(Fastlane::UI).to receive(:message).with("The ios_cd plugin is working!")
Fastlane::Actions::IosCdAction.run(nil)
Fastlane::Actions::BuildAndDeploy.run(nil)
end
end
end