Skip to content

Commit

Permalink
Install app from GitHub action
Browse files Browse the repository at this point in the history
  • Loading branch information
bmarty committed Nov 16, 2022
1 parent e3306a9 commit f752146
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 0 deletions.
94 changes: 94 additions & 0 deletions tools/install/installFromGitHub.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/env bash

# Exit on any error
set -e

if [[ "$#" -ne 1 ]]; then
echo "Usage: $0 GitHub_token" >&2
exit 1
fi

gitHubToken=$1

# Path where the app is cloned (it's where this project has been cloned)
appPath=$(dirname $(dirname $(dirname $0)))
# Path where the APK will be downloaded from CI (it's a dir)
baseImportPath="${appPath}/tmp/DebugApks"

# Select device
serialNumber=$(${appPath}/tools/install/androidSelectDevice.sh)

# Detect device architecture
arch=$(adb -s ${serialNumber} shell getprop ro.product.cpu.abi)

echo
echo "Will install the application on device ${serialNumber} with arch ${arch}"

# Artifact URL
echo
read -p "Artifact url (ex: https://github.com/vector-im/element-android/suites/9293388174/artifacts/435942121)? " artifactUrl

## Example of default value for Gplay
#artifactUrl=${artifactUrl:-https://github.com/vector-im/element-android/suites/9293388174/artifacts/435942121}
## Example of default value for FDroid
# artifactUrl=${artifactUrl:-https://github.com/vector-im/element-android/suites/9293388174/artifacts/435942119}

artifactId=$(echo ${artifactUrl} | rev | cut -d'/' -f1 | rev)

# Download files
targetPath=${baseImportPath}/${artifactId}

filename="artifact.zip"

fullFilePath="${targetPath}/${filename}"

# Check if file already exists
if test -f "$fullFilePath"; then
read -p "$fullFilePath already exists. Override (yes/no) default to no ? " download
download=${download:-no}
else
download="yes"
fi

# Ignore error from now
set +e

if [ ${download} == "yes" ]; then
echo "Downloading ${filename} to ${targetPath}..."
python3 ${appPath}/tools/release/download_github_artifacts.py \
--token ${gitHubToken} \
--artifactUrl ${artifactUrl} \
--directory ${targetPath} \
--filename ${filename} \
--ignoreErrors
fi

echo "Unzipping ${filename}..."
unzip $fullFilePath -d ${targetPath}

## gplay or fdroid
if test -d "${targetPath}/gplay"; then
variant="gplay"
elif test -d "${targetPath}/fdroid"; then
variant="fdroid"
else
echo "No variant found"
exit 1
fi

fullApkPath="${targetPath}/${variant}/debug/vector-${variant}-${arch}-debug.apk"

echo "Installing ${fullApkPath} to device ${serialNumber}..."
adb -s ${serialNumber} install -r ${fullApkPath}

# Check error and propose to uninstall and retry installing
if [[ "$?" -ne 0 ]]; then
read -p "Error, do you want to uninstall the application then retry (yes/no) default to no ? " retry
retry=${retry:-no}
if [ ${retry} == "yes" ]; then
echo "Uninstalling..."
adb -s ${serialNumber} uninstall im.vector.app.debug
echo "Installing again..."
adb -s ${serialNumber} install -r ${fullApkPath}
fi
fi
154 changes: 154 additions & 0 deletions tools/release/download_github_artifacts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#!/usr/bin/env python3
#
# Copyright 2022 New Vector Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import argparse
import hashlib
import json
import os
# Run `pip3 install requests` if not installed yet
import requests

# This script downloads artifacts from GitHub.
# Ref: https://docs.github.com/en/rest/actions/artifacts#get-an-artifact

error = False

### Arguments

parser = argparse.ArgumentParser(description='Download artifacts from GitHub.')
parser.add_argument('-t',
'--token',
required=True,
help='The GitHub token with read access.')
parser.add_argument('-a',
'--artifactUrl',
required=True,
help='the artifact_url from GitHub.')
parser.add_argument('-f',
'--filename',
help='the filename, if not provided, will use the artifact name.')
parser.add_argument('-i',
'--ignoreErrors',
help='Ignore errors that can be ignored. Build state and number of artifacts.',
action="store_true")
parser.add_argument('-d',
'--directory',
default="",
help='the target directory, where files will be downloaded. If not provided the build number will be used to create a directory.')
parser.add_argument('-v',
'--verbose',
help="increase output verbosity.",
action="store_true")
parser.add_argument('-s',
'--simulate',
help="simulate action, do not create folder or download any file.",
action="store_true")

args = parser.parse_args()

if args.verbose:
print("Argument:")
print(args)

# Split the artifact URL to get information
# Ex: https://github.com/vector-im/element-android/suites/9293388174/artifacts/435942121
artifactUrl = args.artifactUrl
if not artifactUrl.startswith('https://github.com/'):
print("❌ Invalid parameter --artifactUrl %s. Must start with 'https://github.com/'" % artifactUrl)
exit(1)
if "/artifacts/" not in artifactUrl:
print("❌ Invalid parameter --artifactUrl %s. Must contain '/artifacts/'" % artifactUrl)
exit(1)
artifactItems = artifactUrl.split("/")
if len(artifactItems) != 9:
print("❌ Invalid parameter --artifactUrl %s. Please check the format." % (artifactUrl))
exit(1)

gitHubRepoOwner = artifactItems[3]
gitHubRepo = artifactItems[4]
artifactId = artifactItems[8]

if args.verbose:
print("gitHubRepoOwner: %s, gitHubRepo: %s, artifactId: %s" % (gitHubRepoOwner, gitHubRepo, artifactId))

headers = {
'Authorization': "Bearer %s" % args.token,
'Accept': 'application/vnd.github+json'
}
base_url = "https://api.github.com/repos/%s/%s/actions/artifacts/%s" % (gitHubRepoOwner, gitHubRepo, artifactId)

### Fetch build state

print("Getting artifacts data of project '%s/%s' artifactId '%s'..." % (gitHubRepoOwner, gitHubRepo, artifactId))

if args.verbose:
print("Url: %s" % base_url)

r = requests.get(base_url, headers=headers)
data = json.loads(r.content.decode())

if args.verbose:
print("Json data:")
print(data)

if args.verbose:
print("Create subfolder %s to download artifacts..." % artifactId)

if args.directory == "":
targetDir = artifactId
else:
targetDir = args.directory

if not args.simulate:
os.makedirs(targetDir, exist_ok=True)

url = data.get("archive_download_url")
if args.filename is not None:
filename = args.filename
else:
filename = data.get("name") + ".zip"

## Print some info about the artifact origin
commitLink = "https://github.com/%s/%s/commit/%s" % (gitHubRepoOwner, gitHubRepo, data.get("workflow_run").get("head_sha"))
print("Preparing to download artifact `%s`, built from branch: `%s` (commit %s)" % (data.get("name"), data.get("workflow_run").get("head_branch"), commitLink))

if args.verbose:
print()
print("Artifact url: %s" % url)

target = targetDir + "/" + filename
sizeInBytes = data.get("size_in_bytes")
print("Downloading %s to '%s' (file size is %s bytes, this may take a while)..." % (filename, targetDir, sizeInBytes))
if not args.simulate:
# open file to write in binary mode
with open(target, "wb") as file:
# get request
response = requests.get(url, headers=headers)
# write to file
file.write(response.content)
print("Verifying file size...")
# get the file size
size = os.path.getsize(target)
if sizeInBytes != size:
# error = True
print("Warning, file size mismatch: expecting %s and get %s. This is just a warning for now..." % (sizeInBytes, size))

if error:
print("❌ Error(s) occurred, please check the log")
exit(1)
else:
print("Done!")

0 comments on commit f752146

Please sign in to comment.