Skip to content

Commit

Permalink
Merge pull request #4 from qawolf/gen-272-update-fastlane-plugin-to-r…
Browse files Browse the repository at this point in the history
…equire-uploaded-filename

breaking changes to help with test automation
  • Loading branch information
smonn authored Nov 20, 2024
2 parents 4a05840 + 017fc8b commit eec8dec
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 70 deletions.
63 changes: 40 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To

```
# Add this to your Gemfile
gem "fastlane-plugin-qawolf", git: "https://github.com/qawolf/fastlane-plugin-qawolf", tag: "0.2.0"
gem "fastlane-plugin-qawolf", git: "https://github.com/qawolf/fastlane-plugin-qawolf", tag: "0.3.0"
```

## About qawolf
Expand All @@ -15,9 +15,6 @@ Fastlane plugin for QA Wolf integration.

Uploads build artifacts (IPA, APK, or AAB) to QA Wolf storage for automated testing. Optionally triggers a test run on QA Wolf.

> [!CAUTION]
> To ensure QA Wolf tests target the correct app build and help debugging issues, we require uploaded filenames to be unique in some way. The example below uses the git commit hash, but you can use another unique identifier such as the app version number if you wish.
> [!IMPORTANT]
> Testing iOS apps (IPA) on QA Wolf is not yet available.
Expand All @@ -27,12 +24,9 @@ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plu

```ruby
lane :build do
# The uploaded filename must be unique for your team on the QA Wolf platform.
# One way to achieve that is to rely on the git commit hash.
# Feel free to use a different mechanism if desired (e.g. app version).
# It's recommended to only trigger builds with a clean git status.
# See https://docs.fastlane.tools/actions/#source-control for other source control actions
ensure_git_status_clean
commit = last_git_commit

# Build your app
# Ensure the APK/AAB file has been created. Your use case may vary.
Expand All @@ -47,10 +41,11 @@ lane :build do
# Must be set or available as env var QAWOLF_API_KEY
qawolf_api_key: "qawolf_...",

# You can omit this if your gradle build outputs the file with a unique filename.
# If not, you'll want to do something like the following.
# Make sure you use the right file extension!
filename: "app_#{commit[:abbreviated_commit_hash]}.apk"
# Must be set to guarantee the uploaded file is replaced.
# Typically, this should include a git branch name or a QA Wolf environment name.
# Reach out to QA Wolf if you're unsure.
# Do NOT include a file extension, it'll be appended based on the build output file.
executable_file_basename: "calculator_app_staging",

# Only set this if you have not built the artifact in the same lane,
# e.g. via gradle or similar, check official Fastlane docs for details.
Expand All @@ -63,19 +58,39 @@ lane :build do
# Must be set or available as env var QAWOLF_API_KEY
qawolf_api_key: "qawolf_...",

# These fields are dependent on how triggers are setup within QA Wolf.
# Reach out to support for help. All fields are optional.
branch: nil,
commit_url: nil,
deduplication_key: nil,
deployment_type: nil,
# Optional, but set if requested by the QA Wolf team.
# This is mostly to help distinguish between multiple apps within the same team/environment.
executable_environment_key: "RUN_INPUT_PATH",

# Optional, defaults to the current git branch, if available. Set to false to skip.
branch: git_branch,

# URL to your VCS commit URL
commit_url: "https://github.com/team/repo/commit/ec78d7d81a6a66e9e89fd29f6e0616d5ba09840a",

# Set to cancel ongoing test runs with the same value
deduplication_key: "some_idempotent_value",

# Must be set if configured in the QA Wolf deployment trigger
deployment_type: "deployment_name",

# Can be left empty as it's mostly for web tests
# If set, will be available as `process.env.URL`
deployment_url: nil,
hosting_service: nil,
sha: nil,
variables: nil,

# If configured in QA Wolf, set to GitHub or GitLab as needed
hosting_service: "GitHub",

# Optional, defaults to current git commit hash if available. Set to false to skip
sha: last_git_commit[:commit_hash],

# Additional hash of key-value pairs to set as environment variables for test runs
variables: {
FOO: "bar"
},

# Only set this if your lane does not include `upload_to_qawolf`
run_input_path: nil,
executable_filename: "calculator_app_staging.apk",
)
end
```
Expand Down Expand Up @@ -208,7 +223,9 @@ The instructions below are for maintainers of this plugin.
gradle(task: "clean assembleRelease")
# relies on output of the gradle task and env var QAWOLF_API_KEY
qawolf
# see example above for options
upload_to_qawolf
notify_deploy_qawolf
end
end
```
Expand Down
5 changes: 4 additions & 1 deletion fastlane/Fastfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
lane :test do
upload_to_qawolf(
file_path: "./fastlane/fastlane-test-app-debug.apk"
file_path: "./fastlane/fastlane-test-app-debug.apk",
executable_file_basename: "fastlane_test"
)
notify_deploy_qawolf(
deployment_type: "android",
sha: false,
executable_environment_key: "ANDROID_APP",
variables: {
HELLO: "WORLD"
}
Expand Down
45 changes: 29 additions & 16 deletions lib/fastlane/plugin/qawolf/actions/notify_deploy_qawolf_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,28 @@ module SharedValues

# Casing is important for the action name!
class NotifyDeployQawolfAction < Action
BASE_PATH = "/home/wolf/run-inputs-executables/"

def self.run(params)
qawolf_api_key = params[:qawolf_api_key] # Required
qawolf_base_url = params[:qawolf_base_url]

UI.message("🐺 Calling QA Wolf deploy success webhook...")

variables = params[:variables] || {}
executable_environment_key = params[:executable_environment_key]
branch = params[:branch] if params[:branch].kind_of?(String) && !params[:branch].empty?
sha = params[:sha] if params[:sha].kind_of?(String) && !params[:sha].empty?

options = {
branch: params[:branch],
branch: branch,
commit_url: params[:commit_url],
deployment_type: params[:deployment_type],
deployment_url: params[:deployment_url],
deduplication_key: params[:deduplication_key],
hosting_service: params[:hosting_service],
sha: params[:sha],
variables: variables.merge({
RUN_INPUT_PATH: run_input_path(params)
})
sha: sha,
variables: variables.merge({ executable_environment_key => run_input_path(params) })
}

run_id = Helper::QawolfHelper.notify_deploy(qawolf_api_key, qawolf_base_url, options)
Expand All @@ -42,11 +45,11 @@ def self.run(params)
end

def self.run_input_path(params)
if params[:run_input_path].nil?
UI.user_error!("🐺 No run input path found. Please run the `upload_to_qawolf` action first or set the `run_input_path` option.")
if params[:executable_filename].nil?
UI.user_error!("🐺 No executable filename found. Please run the `upload_to_qawolf` action first or set the `executable_filename` option.")
end

return params[:run_input_path]
return "#{BASE_PATH}#{params[:executable_filename]}"
end

def self.description
Expand Down Expand Up @@ -79,10 +82,16 @@ def self.available_options
description: "Your QA Wolf base URL",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :branch,
description: "If using Git, set this to the branch name so it can be displayed in the QA Wolf UI and find any pull requests in the linked repo",
FastlaneCore::ConfigItem.new(key: :executable_environment_key,
description: "Sets the environment key to use for the executable. Will alias the executable file's absolute path in tests to, for example, `process.env.RUN_INPUT_PATH` Defaults to `RUN_INPUT_PATH`",
optional: true,
default_value: "RUN_INPUT_PATH",
type: String),
FastlaneCore::ConfigItem.new(key: :branch,
description: "Defaults to the current git branch if available. Override by providing a custom value, or set it to false to send an empty value. Displayed in the QA Wolf UI to help find any pull requests in the linked repo",
optional: true,
default_value: Actions.git_branch,
type: Object),
FastlaneCore::ConfigItem.new(key: :commit_url,
description: "If you do not specify a hosting service, include this and the `sha` option to ensure the commit hash is a clickable link in QA Wolf",
optional: true,
Expand All @@ -104,16 +113,18 @@ def self.available_options
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :sha,
description: "If a Git commit triggered this, include the commit hash so that we can create commit checks if you also have a GitHub repo linked. Also displayed in the QA Wolf UI",
description: "Defaults to the current git commit hash. Override by providing a custom value, or set to false to send an empty value. We use it to create commit checks if you also have a GitHub repo linked. Also displayed in the QA Wolf UI",
optional: true,
type: String),
default_value: Actions.last_git_commit_hash(false),
type: Object),
FastlaneCore::ConfigItem.new(key: :variables,
description: "Optional key-value pairs to pass to the test run. These will be available as `process.env` in tests",
optional: true,
type: Object),
FastlaneCore::ConfigItem.new(key: :run_input_path,
env_name: "QAWOLF_RUN_INPUT_PATH",
description: "The path of the run input file to run in QA Wolf. Set by the `upload_to_qawolf` action",
default_value: {},
type: Hash),
FastlaneCore::ConfigItem.new(key: :executable_filename,
env_name: "QAWOLF_EXECUTABLE_FILENAME",
description: "The filename of the executable to use in QA Wolf. Set by the `upload_to_qawolf` action",
optional: true,
type: String)
]
Expand All @@ -130,6 +141,8 @@ def self.example_code
'notify_deploy_qawolf',
'notify_deploy_qawolf(
qawolf_api_key: ENV["QAWOLF_API_KEY"],
executable_environment_key: "MY_APP",
executable_filename: "<FILENAME>",
branch: "<BRANCH_NAME>",
commit_url: "<URL>",
deployment_type: "<DEPLOYMENT_TYPE>",
Expand Down
37 changes: 21 additions & 16 deletions lib/fastlane/plugin/qawolf/actions/upload_to_qawolf_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
module Fastlane
module Actions
module SharedValues
QAWOLF_RUN_INPUT_PATH = :QAWOLF_RUN_INPUT_PATH
QAWOLF_EXECUTABLE_FILENAME = :QAWOLF_EXECUTABLE_FILENAME
end

# Casing is important for the action name!
Expand All @@ -16,20 +16,20 @@ def self.run(params)
qawolf_api_key = params[:qawolf_api_key] # Required
qawolf_base_url = params[:qawolf_base_url]
file_path = params[:file_path] || default_file_path
filename = params[:filename]
executable_file_basename = params[:executable_file_basename]

validate_file_path(file_path)

UI.message("🐺 Uploading to QA Wolf...")

run_input_path = Helper::QawolfHelper.upload_file(qawolf_api_key, qawolf_base_url, file_path, filename)
uploaded_filename = Helper::QawolfHelper.upload_file(qawolf_api_key, qawolf_base_url, file_path, executable_file_basename)

ENV["QAWOLF_RUN_INPUT_PATH"] = run_input_path
ENV["QAWOLF_EXECUTABLE_FILENAME"] = uploaded_filename

UI.success("🐺 Uploaded #{file_path} to QA Wolf successfully. Run input path: #{run_input_path}")
UI.success("🐺 Setting environment variable QAWOLF_RUN_INPUT_PATH = #{run_input_path}")
UI.success("🐺 Uploaded #{file_path} to QA Wolf successfully. Executable filename: #{uploaded_filename}")
UI.success("🐺 Setting environment variable QAWOLF_EXECUTABLE_FILENAME = #{uploaded_filename}")

Actions.lane_context[SharedValues::QAWOLF_RUN_INPUT_PATH] = run_input_path
Actions.lane_context[SharedValues::QAWOLF_EXECUTABLE_FILENAME] = uploaded_filename
end

# Validate file_path.
Expand Down Expand Up @@ -58,7 +58,7 @@ def self.details

def self.output
[
['QAWOLF_RUN_INPUT_PATH', 'Uploaded file location for the executable artifact.']
['QAWOLF_EXECUTABLE_FILENAME', 'Uploaded filename for the executable artifact.']
]
end

Expand Down Expand Up @@ -94,12 +94,16 @@ def self.available_options
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :file_path,
description: "Path to the app file",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :filename,
description: "Optional uploaded filename to use instead of the original filename",
description: "Path to the built app file",
optional: true,
type: String,
verify_block: proc do |value|
file_path = File.expand_path(value)
UI.user_error!("Couldn't find file at path '#{file_path}'") unless File.exist?(file_path)
end),
FastlaneCore::ConfigItem.new(key: :executable_file_basename,
description: "Required file basename for the uploaded executable",
optional: false,
type: String)
]
end
Expand All @@ -112,12 +116,13 @@ def self.is_supported?(platform)

def self.example_code
[
'qawolf',
'upload_to_qawolf',
'upload_to_qawolf(
executable_file_basename: "my_app"
)',
'upload_to_qawolf(
qawolf_api_key: ENV["QAWOLF_API_KEY"],
file_path: "/path_to/app.apk",
filename: "custom_filename.apk"
executable_file_basename: "my_app"
)'
]
end
Expand Down
11 changes: 8 additions & 3 deletions lib/fastlane/plugin/qawolf/helper/qawolf_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,21 @@ def self.get_signed_url(qawolf_api_key, qawolf_base_url, filename)
# +qawolf_api_key+:: QA Wolf API key
# +qawolf_base_url+:: QA Wolf API base URL
# +file_path+:: Path to the file to be uploaded.
# +filename+:: Optional filename to use instead of the file's basename.
def self.upload_file(qawolf_api_key, qawolf_base_url, file_path, filename = nil)
# +executable_file_basename+:: Name to use for the uploaded file without extension
def self.upload_file(qawolf_api_key, qawolf_base_url, file_path, executable_file_basename)
unless executable_file_basename
UI.user_error!("`executable_file_basename` is required")
end

file_content = File.open(file_path, "rb")

headers = {
user_agent: "qawolf_fastlane_plugin",
content_type: "application/octet-stream"
}

signed_url, run_input_path = get_signed_url(qawolf_api_key, qawolf_base_url, filename || File.basename(file_path))
uploaded_filename = "#{executable_file_basename}#{File.extname(file_path)}"
signed_url, run_input_path = get_signed_url(qawolf_api_key, qawolf_base_url, uploaded_filename)

RestClient.put(signed_url, file_content, headers)

Expand Down
2 changes: 1 addition & 1 deletion lib/fastlane/plugin/qawolf/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Fastlane
module Qawolf
VERSION = "0.2.0"
VERSION = "0.3.0"
end
end
6 changes: 3 additions & 3 deletions spec/fastlane/actions/notify_deploy_qawolf_action_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

describe Fastlane::Actions::NotifyDeployQawolfAction do
describe "#run" do
let(:run_input_path) { "file.apk" }
let(:executable_filename) { "file.apk" }
let(:params) do
{
qawolf_api_key: "api_key",
run_input_path: run_input_path
executable_filename: executable_filename
}
end
let(:deploy_response) do
Expand All @@ -32,7 +32,7 @@
end

context "with no run input path set" do
let(:run_input_path) { nil }
let(:executable_filename) { nil }

it "fails when no test run is triggered" do
expect do
Expand Down
Loading

0 comments on commit eec8dec

Please sign in to comment.