From a5636dba22be90262f6e246161a87644701ebef5 Mon Sep 17 00:00:00 2001 From: Balrambhai Sharma Date: Mon, 10 Jul 2023 16:12:27 +0530 Subject: [PATCH] TP-31200 | Apk Size Diff Summary Generator (#6881) link: "https://github.cmd.navi-tech.in/medici/android-customer-app/pull/6881" --- .../actions/s3_file_transfer/dependencies.txt | 1 + .github/actions/s3_file_transfer/script.py | 70 +++++++++++ .github/workflows/android_build.yml | 17 +++ .github/workflows/generate_apk_diff.yml | 117 ++++++++++++++++++ .github/workflows/upload_file.yml | 44 +++++++ 5 files changed, 249 insertions(+) create mode 100644 .github/actions/s3_file_transfer/dependencies.txt create mode 100644 .github/actions/s3_file_transfer/script.py create mode 100644 .github/workflows/generate_apk_diff.yml create mode 100644 .github/workflows/upload_file.yml diff --git a/.github/actions/s3_file_transfer/dependencies.txt b/.github/actions/s3_file_transfer/dependencies.txt new file mode 100644 index 0000000000..1db657b6b3 --- /dev/null +++ b/.github/actions/s3_file_transfer/dependencies.txt @@ -0,0 +1 @@ +boto3 \ No newline at end of file diff --git a/.github/actions/s3_file_transfer/script.py b/.github/actions/s3_file_transfer/script.py new file mode 100644 index 0000000000..6fa47d052d --- /dev/null +++ b/.github/actions/s3_file_transfer/script.py @@ -0,0 +1,70 @@ +import os +import shutil +import boto3 +from botocore.exceptions import ClientError +import sys + +bucket = 'navi-github-actions-cache' +s3_file_name = 'latest_build.apk' + + +class ProgressTracker: + def __init__(self, total_size): + self.total_size = total_size + self.bytes_uploaded = 0 + self.bytes_downloaded = 0 + + def upload_progress_callback(self, bytes_uploaded): + self.bytes_uploaded += bytes_uploaded + bytes_left = self.total_size - self.bytes_uploaded + print(f"Uploaded: {to_mb(self.bytes_uploaded)} MB, Remaining: {to_mb(bytes_left)} MB, Total : {to_mb(self.total_size)} MB") + + def download_progress_callback(self, bytes_amount): + self.bytes_downloaded += bytes_amount + bytes_left = self.total_size - self.bytes_downloaded + print(f"Downloaded: {to_mb(self.bytes_downloaded)} MB, Remaining : {to_mb(bytes_left)} MB, Total : {to_mb(self.total_size)} MB") + +def upload_file(access_key, secret_key, local_path): + try: + file_path = local_path + file_size = os.path.getsize(file_path) + tracker = ProgressTracker(file_size) + s3 = boto3.client('s3', aws_access_key_id=access_key, + aws_secret_access_key=secret_key) + print('Uploading apk') + print(os.listdir()) + response = s3.upload_file(file_path, bucket, s3_file_name, Callback=tracker.upload_progress_callback) + print('File Uploaded Successfully') + except Exception as e: + print(f"Error uploading file: {str(e)}") + +def download_file(access_key, secret_key, local_path): + try: + # Create the directory for the local file path if it doesn't exist + os.makedirs(os.path.dirname(local_path), exist_ok=True) + + s3 = boto3.client('s3', aws_access_key_id=access_key, aws_secret_access_key=secret_key) + file_info = s3.head_object(Bucket=bucket, Key=s3_file_name) + file_size = file_info['ContentLength'] + tracker = ProgressTracker(file_size) + with open(local_path, 'wb') as f: + s3.download_fileobj(bucket, s3_file_name, f, Callback=tracker.download_progress_callback) + print("File downloaded successfully.") + print(local_path) # Print the file path + except Exception as e: + print(f"Error downloading file: {str(e)}") + +def to_mb(bytes): + return round(bytes/(1024*1024), 2) + + +if __name__ == "__main__": + command = sys.argv[1] + access_key = sys.argv[2] + secret_key = sys.argv[3] + if command == 'download': + local_path = sys.argv[4] + download_file(access_key, secret_key, local_path) + elif command == 'upload': + local_path = sys.argv[4] + upload_file(access_key, secret_key, local_path) \ No newline at end of file diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index 3e7ce66920..c5673e5b28 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -17,6 +17,23 @@ jobs: environment: qa type: debug output: APK + + generate-apk-diff: + if: github.event_name == 'pull_request' && github.base_ref == 'development' + uses: ./.github/workflows/generate_apk_diff.yml + needs: build-qa-debug + secrets: + AWS_ACCESS_KEY_GITHUB_CACHE: ${{ secrets.AWS_ACCESS_KEY_GITHUB_CACHE }} + AWS_SECRET_KEY_GITHUB_CACHE: ${{ secrets.AWS_SECRET_KEY_GITHUB_CACHE }} + + upload-apk-to-s3: + if: github.event_name == 'push' && github.ref_name == 'development' + uses: ./.github/workflows/upload_file.yml + needs: build-qa-debug + secrets: + AWS_ACCESS_KEY_GITHUB_CACHE: ${{ secrets.AWS_ACCESS_KEY_GITHUB_CACHE }} + AWS_SECRET_KEY_GITHUB_CACHE: ${{ secrets.AWS_SECRET_KEY_GITHUB_CACHE }} + build-qa-release: if: github.event_name == 'push' && (github.ref_name == 'master' || startsWith(github.ref_name, 'release-')) uses: ./.github/workflows/generate_apk.yml diff --git a/.github/workflows/generate_apk_diff.yml b/.github/workflows/generate_apk_diff.yml new file mode 100644 index 0000000000..bb6191cc27 --- /dev/null +++ b/.github/workflows/generate_apk_diff.yml @@ -0,0 +1,117 @@ +name: APK Diff CI + +on: + workflow_call: + secrets: + AWS_ACCESS_KEY_GITHUB_CACHE: + description: Access Key + required: true + AWS_SECRET_KEY_GITHUB_CACHE: + description: Secret Key + required: true + +jobs: + generate-apk-diff: + runs-on: self-hosted + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Download Artifact + id: download + uses: actions/download-artifact@v3 + with: + name: app-qa-debug + + - name: Echo Download Path + run: echo ${{steps.download.outputs.download-path}} + + - name: List Files + run: | + ls -R ${{steps.download.outputs.download-path}} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.9' + + - name: Install dependencies + run: pip install -r .github/actions/s3_file_transfer/dependencies.txt + + - name: Download File + run: python .github/actions/s3_file_transfer/script.py download ${{ secrets.AWS_ACCESS_KEY_GITHUB_CACHE }} ${{ secrets.AWS_SECRET_KEY_GITHUB_CACHE }} app/build/outputs/apk/dev/debug/latest_build.apk + + - name: Compare APK Size Diff + id: apk-diff + run: | + previous_apk_path="app/build/outputs/apk/dev/debug/latest_build.apk" + current_apk_path="${{steps.download.outputs.download-path}}/universal_apk/qaDebug/app-qa-debug-universal.apk" + + previous_apk_size=$(stat -c %s $previous_apk_path) + current_apk_size=$(stat -c %s $current_apk_path) + + size_diff=$((current_apk_size - previous_apk_size)) + echo "::set-output name=size_diff::$size_diff" + echo "The previous value is $previous_apk_size" + echo "The latest value is $current_apk_size" + + - name: Check Size Difference + id: size-diff-check + run: | + size_diff=${{ steps.apk-diff.outputs.size_diff }} + if [[ $size_diff -gt 71680 ]]; then + echo "::set-output name=job_status::failure" + elif [[ $size_diff -gt 25600 ]]; then + echo "::set-output name=job_status::warning" + else + echo "::set-output name=job_status::success" + fi + + - name: Write PR Comment + uses: actions/github-script@v6 + with: + script: | + const sizeDiff = ${{ steps.apk-diff.outputs.size_diff }}; + const sizeDiffKB = Math.round(sizeDiff / 1024); + const codeOwners = ['@satish-prasad', '@raaj-gopal', '@rahul-bhat', '@shankar-yadav', '@maila-rajanikanth', '@adarsh-s', '@siddiboina-susai', '@amit-kumar', '@jegatheeswaran-m']; // Replace with the desired code owners' usernames + const codeOwnerTags = codeOwners.join(' '); // Join the code owner usernames with a space + const additionalInfo = ` + APK size can increase due to various factors. Some common reasons include: + + - Adding external libraries: Before including any external libraries, it's advisable to seek signoff from ${codeOwnerTags}. + - Using high-resolution vectors: For vector XMLs larger than 48dp, consider using WebP format to optimize file size. + - Including Lottie JSON files: When adding Lottie animations, it's recommended to prioritize remote Lottie files over local ones. + - Adding assets/resources: The addition of assets and resources can contribute to APK size growth. + `; + let comment; + + if (sizeDiffKB > 70) { + comment = `### :exclamation: APK Size Exceeded Limit + + The APK size has increased by ${sizeDiffKB} KB bytes compared to the previous version. Please provide the reasons for this increase cc : ${codeOwnerTags} + ${additionalInfo}`; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }); + + } else if (sizeDiffKB > 25) { + comment = `### :warning: APK Size Warning + The APK size has increased by ${sizeDiffKB} KB bytes compared to the previous version. Please provide the reasons for this increase cc : ${codeOwnerTags} + ${additionalInfo}`; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }); + + } + + - name: Fail Job if Size Diff Exceeds 70 KB + if: ${{ steps.size-diff-check.outputs.job_status == 'failure' }} + run: exit 1 \ No newline at end of file diff --git a/.github/workflows/upload_file.yml b/.github/workflows/upload_file.yml new file mode 100644 index 0000000000..1e0b9d308f --- /dev/null +++ b/.github/workflows/upload_file.yml @@ -0,0 +1,44 @@ +name: Upload Latest Apk to S3 CI + +on: + workflow_call: + secrets: + AWS_ACCESS_KEY_GITHUB_CACHE: + description: Access Key + required: true + AWS_SECRET_KEY_GITHUB_CACHE: + description: Secret Key + required: true + +jobs: + build: + + runs-on: [ self-hosted ] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Download Artifact + id: download + uses: actions/download-artifact@v3 + with: + name: app-qa-debug + + - name: Print Download Path + run: echo ${{steps.download.outputs.download-path}} + + - name: List Files + run: | + ls -R ${{steps.download.outputs.download-path}} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.9' + + - name: Install dependencies + run: pip install -r .github/actions/s3_file_transfer/dependencies.txt + + - name: Upload File + run: python ./.github/actions/s3_file_transfer/script.py upload ${{secrets.AWS_ACCESS_KEY_GITHUB_CACHE}} ${{secrets.AWS_SECRET_KEY_GITHUB_CACHE}} ${{steps.download.outputs.download-path}}/universal_apk/qaDebug/app-qa-debug-universal.apk \ No newline at end of file