├── .gitignore ├── images └── pull_request.png ├── .github ├── renovate.json └── workflows │ ├── after_merge.yml │ └── main.yml ├── LICENSE ├── action.yml ├── README.md └── entrypoint.py /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.vscode 3 | dupa.py 4 | diffuse-output.txt 5 | -------------------------------------------------------------------------------- /images/pull_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usefulness/diffuse-action/HEAD/images/pull_request.png -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "assignees": [ 3 | "mateuszkwiecinski" 4 | ], 5 | "extends": [ 6 | "config:recommended" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.github/workflows/after_merge.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | 6 | jobs: 7 | test-apk: 8 | runs-on: ubuntu-latest 9 | name: Run diffuse action 10 | steps: 11 | - uses: actions/checkout@v6 12 | 13 | - uses: actions/setup-java@v5 14 | with: 15 | distribution: temurin 16 | java-version: 24 17 | 18 | - name: Get sample .apk for test purposes 19 | run: wget https://github.com/appium/appium/blob/906350fd335f9485376214fdd17c7cdb6c9ff26b/sample-code/apps/ApiDemos-debug.apk?raw=true -q -O sample-apk.apk 20 | 21 | - id: diffuse 22 | uses: ./ 23 | with: 24 | old-file-path: sample-apk.apk 25 | new-file-path: sample-apk.apk 26 | 27 | - uses: actions/upload-artifact@v5 28 | with: 29 | name: diffuse-output 30 | path: ${{ steps.diffuse.outputs.diff-file }} 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2020 Mateusz Kwieciński 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 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Diffuse Action for Gradle' 2 | description: "Generates Jake Wharton's Diffuse tool output between head and target branch of a Pull Request" 3 | inputs: 4 | old-file-path: 5 | description: 'old file path' 6 | required: true 7 | old-mapping-path: 8 | description: 'old mapping file produced by R8 or ProGuard' 9 | required: false 10 | new-file-path: 11 | description: 'new file path' 12 | required: true 13 | new-mapping-path: 14 | description: 'new mapping file produced by R8 or ProGuard' 15 | required: false 16 | lib-version: 17 | description: 'release version, e.g "0.1.0" or "latest"' 18 | default: latest 19 | required: true 20 | diffuse-repo: 21 | description: 'Diffuse repo id, with published release artifacts, e.g "usefulness/diffuse" or "JakeWharton/diffuse"' 22 | required: true 23 | default: usefulness/diffuse 24 | debug: 25 | description: 'if true, shows additional debug information' 26 | required: false 27 | default: 'false' 28 | 29 | outputs: 30 | diff-raw: 31 | description: "Diffuse full output" 32 | value: ${{ steps.run-diffuse.outputs.diff-raw }} 33 | diff-file: 34 | description: "Diffuse full output as file" 35 | value: ${{ steps.run-diffuse.outputs.diff-file }} 36 | diff-gh-comment: 37 | description: "Diffuse full output as Github comment. Summary in expanded state, other sections collapsed" 38 | value: ${{ steps.run-diffuse.outputs.diff-gh-comment }} 39 | diff-gh-comment-all-collapsed: 40 | description: "Diffuse full output as Github comment. All sections are collapsed" 41 | value: ${{ steps.run-diffuse.outputs.diff-gh-comment-all-collapsed }} 42 | diff-gh-comment-no-dex: 43 | description: "Diffuse full output as Github comment, without dex section, workaround for https://github.com/JakeWharton/diffuse/issues/96" 44 | value: ${{ steps.run-diffuse.outputs.diff-gh-comment-no-dex }} 45 | diff-gh-comment-no-dex-all-collapsed: 46 | description: "Diffuse full output as Github comment all collapsed, without dex section, workaround for https://github.com/JakeWharton/diffuse/issues/96" 47 | value: ${{ steps.run-diffuse.outputs.diff-gh-comment-no-dex-all-collapsed }} 48 | 49 | summary: 50 | description: "Diffuse summary" 51 | value: ${{ steps.run-diffuse.outputs.summary }} 52 | apk: 53 | description: "Diffuse apk info" 54 | value: ${{ steps.run-diffuse.outputs.apk }} 55 | dex: 56 | description: "Diffuse dex info" 57 | value: ${{ steps.run-diffuse.outputs.dex }} 58 | manifest: 59 | description: "Diffuse manifest info" 60 | value: ${{ steps.run-diffuse.outputs.manifest }} 61 | arcs: 62 | description: "Diffuse arcs info" 63 | value: ${{ steps.run-diffuse.outputs.arcs }} 64 | jar: 65 | description: "Diffuse jar info" 66 | value: ${{ steps.run-diffuse.outputs.jar }} 67 | classes: 68 | description: "Diffuse classes info" 69 | value: ${{ steps.run-diffuse.outputs.classes }} 70 | 71 | size-old-bytes: 72 | description: "Old artifact size, number, in Bytes" 73 | value: ${{ steps.run-diffuse.outputs.size-old-bytes }} 74 | size-old-text: 75 | description: "Old artifact size, text, formatted with unit i.e. 320 KiB" 76 | value: ${{ steps.run-diffuse.outputs.size-old-text }} 77 | size-new-bytes: 78 | description: "New artifact size, number, in Bytes" 79 | value: ${{ steps.run-diffuse.outputs.size-new-bytes }} 80 | size-new-text: 81 | description: "New artifact size, text, formatted with unit i.e. 320 KiB" 82 | value: ${{ steps.run-diffuse.outputs.size-new-text }} 83 | size-diff-comment_style_1: 84 | description: "Size diff in a human readable form. i.e. '+16.6MiB (16.1MiB -> 32.7MiB)'" 85 | value: ${{ steps.run-diffuse.outputs.size-diff-comment_style_1 }} 86 | branding: 87 | color: 'red' 88 | icon: 'check-square' 89 | runs: 90 | using: 'composite' 91 | steps: 92 | - id: run-diffuse 93 | env: 94 | INPUT_OLD_FILE: ${{ inputs.old-file-path }} 95 | INPUT_NEW_FILE: ${{ inputs.new-file-path }} 96 | INPUT_OLD_MAPPING_FILE: ${{ inputs.old-mapping-path }} 97 | INPUT_NEW_MAPPING_FILE: ${{ inputs.new-mapping-path }} 98 | INPUT_LIB_VERSION: ${{ inputs.lib-version }} 99 | INPUT_DIFFUSE_REPO: ${{ inputs.diffuse-repo }} 100 | INPUT_DEBUG: ${{ inputs.debug }} 101 | INPUT_GITHUB_TOKEN: ${{ github.token }} 102 | run: | 103 | python3 -m venv "$GITHUB_ACTION_PATH"/diffuse-venv 104 | if [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then 105 | source "$GITHUB_ACTION_PATH"/diffuse-venv/Scripts/activate 106 | else 107 | source "$GITHUB_ACTION_PATH"/diffuse-venv/bin/activate 108 | fi 109 | python3 -m pip install requests 110 | python3 "$GITHUB_ACTION_PATH"/entrypoint.py 111 | shell: bash 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Diffuse - Github Action 2 | ![.github/workflows/after_merge.yml](https://github.com/usefulness/diffuse_action/workflows/.github/workflows/after_merge.yml/badge.svg) 3 | 4 | Simple Github Action wrapper for Jake Wharton's [Diffuse](https://github.com/JakeWharton/diffuse) tool. 5 | 6 | ## Usage 7 | The action only exposes _output_ containing the diff, so to effectively consume its output it is highly recommended to use other Github Actions to customize your experience. 8 | 9 | ### Configuration: 10 | By default, this action uses Diffuse fork - https://github.com/usefulness/diffuse (due to: https://github.com/JakeWharton/diffuse/issues/111) 11 | ``` 12 | - id: diffuse 13 | uses: usefulness/diffuse-action@v1 14 | with: 15 | old-file-path: old/file/path/old_file.apk 16 | new-file-path: new/file/path/new_file.apk 17 | ``` 18 | 19 | You can override the config to use the original [Diffuse](https://github.com/JakeWharton/diffuse) binary 20 | ``` 21 | - id: diffuse 22 | uses: usefulness/diffuse-action@v1 23 | with: 24 | old-file-path: old/file/path/old_file.apk 25 | new-file-path: new/file/path/new_file.apk 26 | diffuse-repo: JakeWharton/diffuse 27 | lib-version: 0.1.0 28 | ``` 29 | 30 | ##### Parameters 31 | `old-file-path` - Path to reference file the diff should be generated for 32 | `new-file-path` - Path to current file the diff should be generated for 33 | `lib-version` _(Optional)_ - Overrides dependency version, by default uses the latest published version 34 | `diffuse-repo` _(Optional)_ - Overrides [usefulness/diffuse](https://github.com/usefulness/diffuse) as the default repository containing published release artifacts. 35 | 36 | ##### Outputs 37 | See full list of [outputs](https://github.com/usefulness/diffuse-action/blob/master/action.yml#L27). 38 | For example: referencing `steps.diffuse.outputs.diff-gh-comment` at a later stage will print Diffuse tool output as a nicely formatted github comment 39 | 40 | ### Sample: Create Pull Request comment 41 | 42 | TODO: explain why to use free `actions/cache` for now and list its limitation. 43 | Good introduction to the problem: https://github.com/JakeWharton/dependency-tree-diff/discussions/8#discussioncomment-1535744 44 | 45 | 1. Integrate with a regular Pull Request workflow: 46 | 47 | ```yaml 48 | name: Pull Request workflow 49 | 50 | on: 51 | pull_request: 52 | 53 | jobs: 54 | generate-diff: 55 | runs-on: ubuntu-latest 56 | 57 | steps: 58 | - uses: actions/checkout@v2 59 | 60 | - uses: actions/setup-java@v3 61 | with: 62 | distribution: 'temurin' 63 | java-version: 23 64 | 65 | - uses: gradle/actions/setup-gradle@v3 66 | with: 67 | arguments: assemble 68 | 69 | # Generating the diff starts here 👇 70 | 71 | - uses: actions/cache@v2 72 | name: Download base 73 | with: 74 | path: diffuse-source-file 75 | key: diffuse-${{ github.event.pull_request.base.sha }} 76 | 77 | - id: diffuse 78 | uses: usefulness/diffuse-action@v1 79 | with: 80 | old-file-path: diffuse-source-file 81 | new-file-path: app/build/outputs/release/app.apk 82 | 83 | 84 | # Consuming action output starts here 👇 85 | 86 | - uses: peter-evans/find-comment@v1 87 | id: find_comment 88 | with: 89 | issue-number: ${{ github.event.pull_request.number }} 90 | body-includes: Diffuse output 91 | 92 | - uses: peter-evans/create-or-update-comment@v1 93 | if: ${{ steps.diffuse.outputs.diff-raw != null || steps.find_comment.outputs.comment-id != null }} 94 | with: 95 | body: | 96 | Diffuse output (customize your message here): 97 | 98 | ${{ steps.diffuse.outputs.diff-gh-comment }} 99 | edit-mode: replace 100 | comment-id: ${{ steps.find_comment.outputs.comment-id }} 101 | issue-number: ${{ github.event.pull_request.number }} 102 | token: ${{ secrets.GITHUB_TOKEN }} 103 | 104 | - uses: actions/upload-artifact@v2 105 | with: 106 | name: diffuse-output 107 | path: ${{ steps.diffuse.outputs.diff-file }} 108 | ``` 109 | 110 | 2. Integrate with you post-merge flow: 111 | ```yaml 112 | on: 113 | push: 114 | branches: 115 | - master 116 | - main 117 | - trunk 118 | - develop 119 | - maine 120 | - mane 121 | schedule: 122 | - cron: '0 3 * * 1,4' 123 | 124 | jobs: 125 | diffuse_cache: 126 | runs-on: ubuntu-latest 127 | name: Cache artifact for diffuse 128 | steps: 129 | - uses: actions/checkout@v2 130 | 131 | - uses: actions/setup-java@v3 132 | with: 133 | distribution: 'temurin' 134 | java-version: 23 135 | 136 | - uses: gradle/actions/setup-gradle@v3 137 | with: 138 | arguments: assemble 139 | 140 | # Integration starts here 👇 141 | 142 | - uses: actions/cache@v2 143 | name: Upload base 144 | with: 145 | path: diffuse-source-file 146 | key: diffuse-${{ github.sha }} 147 | 148 | # Copy your build artifact under `diffuse-source-file` name which will be saved in cache 149 | - run: cp /app/build/outputs/debug/sample-apk.apk diffuse-source-file 150 | shell: bash 151 | ``` 152 | 153 | 154 | ### More examples 155 | 156 | Sample application as a [pull request comment](https://github.com/mateuszkwiecinski/github_browser/pull/52) 157 | Corresponding [workflow](https://github.com/mateuszkwiecinski/github_browser/blob/master/.github/workflows/run_diffuse.yml) file 158 | 159 | ![pull_request](/images/pull_request.png) 160 | 161 | 162 | 163 |
164 |

165 | 166 | 🙏 Praise 🙏 be 🙏 to 🙏 Wharton 🙏 167 | 168 |

169 |
170 | -------------------------------------------------------------------------------- /entrypoint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import os 3 | import re 4 | import subprocess 5 | import requests 6 | import json 7 | import uuid 8 | import zipfile 9 | import stat 10 | from itertools import zip_longest 11 | 12 | 13 | def find_tool_coordinates(): 14 | input_lib_version = os.getenv("INPUT_LIB_VERSION", "").strip() 15 | diffuse_repo = os.getenv("INPUT_DIFFUSE_REPO", "").strip() 16 | if not diffuse_repo: 17 | raise RuntimeError("You must provide valid `diffuse-repo` input") 18 | if not input_lib_version: 19 | raise RuntimeError("You must provide valid `lib-version` input") 20 | 21 | if input_lib_version == "latest": 22 | request_url = "https://api.github.com/repos/{0}/releases/latest".format(diffuse_repo) 23 | else: 24 | request_url = "https://api.github.com/repos/{0}/releases/tags/{1}".format(diffuse_repo, input_lib_version) 25 | 26 | response = requests.get( 27 | request_url, 28 | headers={ 29 | "Content-Type": "application/vnd.github.v3+json", 30 | "Authorization": "token {0}".format(os.getenv("INPUT_GITHUB_TOKEN", "")) 31 | } 32 | ) 33 | 34 | if is_debug(): 35 | print("X-RateLimit-Limit: {0}".format(response.headers["X-RateLimit-Limit"])) 36 | print("X-RateLimit-Used: {0}".format(response.headers["X-RateLimit-Used"])) 37 | print("X-RateLimit-Remaining: {0}".format(response.headers["X-RateLimit-Remaining"])) 38 | 39 | parsed = json.loads(response.content) 40 | 41 | return parsed["assets"][0]["browser_download_url"], parsed["tag_name"] 42 | 43 | 44 | def is_debug(): 45 | return os.getenv("INPUT_DEBUG", "false").casefold() == "true".casefold() 46 | 47 | 48 | def is_windows(): 49 | return os.name == "nt" 50 | 51 | 52 | def github_output(key, message): 53 | delimiter = str(uuid.uuid4()) 54 | with open(os.environ['GITHUB_OUTPUT'], mode='a', encoding='UTF-8') as fh: 55 | print(f'{key}<<${delimiter}', file=fh) 56 | print(message, file=fh) 57 | print(f'${delimiter}', file=fh) 58 | 59 | 60 | def section(_title, _content): 61 | return f""" 62 |
63 | {_title} 64 | 65 | ``` 66 | {_content} 67 | ``` 68 |
69 | 70 | """ 71 | 72 | 73 | def header(_content): 74 | return f""" 75 | ``` 76 | {_content} 77 | ``` 78 | """ 79 | 80 | 81 | def grouper(iterable, n, fillvalue=None): 82 | args = [iter(iterable)] * n 83 | return zip_longest(*args, fillvalue=fillvalue) 84 | 85 | 86 | def sizeof_fmt(num, suffix='B', sign=False): 87 | for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']: 88 | if abs(num) < 1024.0: 89 | if sign: 90 | return "%+3.1f%s%s" % (num, unit, suffix) 91 | else: 92 | return "%3.1f%s%s" % (num, unit, suffix) 93 | num /= 1024.0 94 | if sign: 95 | return "%+.1f%s%s" % (num, 'Yi', suffix) 96 | else: 97 | return "%.1f%s%s" % (num, 'Yi', suffix) 98 | 99 | 100 | url, lib_version = find_tool_coordinates() 101 | if is_debug(): 102 | print("url of the tool: {}".format(url)) 103 | 104 | downloadArgs = "" 105 | if not is_debug(): 106 | downloadArgs += "-q" 107 | 108 | if url.endswith(".jar"): 109 | r = requests.get(url, allow_redirects=True) 110 | open("diffuse.jar", "wb").write(r.content) 111 | exec_call = ["java", "-jar", "diffuse.jar"] 112 | else: 113 | r = requests.get(url, allow_redirects=True) 114 | open("diffuse.zip", "wb").write(r.content) 115 | with zipfile.ZipFile("diffuse.zip", "r") as zip_ref: 116 | zip_ref.extractall("diffuse_extracted") 117 | 118 | if is_windows(): 119 | executable_name = "diffuse.bat" 120 | else: 121 | executable_name = "diffuse" 122 | runnable = os.path.join("diffuse_extracted", f"diffuse-{lib_version}", "bin", executable_name) 123 | st = os.stat("diffuse_extracted") 124 | os.chmod(runnable, st.st_mode | stat.S_IEXEC) 125 | exec_call = [runnable] 126 | exec_call.append("diff") 127 | 128 | oldFile = os.getenv("INPUT_OLD_FILE") 129 | newFile = os.getenv("INPUT_NEW_FILE") 130 | 131 | typeSelector = { 132 | ".apk": "--apk", 133 | ".aab": "--aab", 134 | ".aar": "--aar", 135 | ".jar": "--jar", 136 | } 137 | path, file_extension = os.path.splitext(newFile) 138 | exec_call.append(typeSelector.get(file_extension)) 139 | exec_call.append(oldFile) 140 | exec_call.append(newFile) 141 | 142 | if os.getenv("INPUT_OLD_MAPPING_FILE").strip(): 143 | exec_call.extend(["--old-mapping", os.getenv("INPUT_OLD_MAPPING_FILE")]) 144 | if os.getenv("INPUT_NEW_MAPPING_FILE").strip(): 145 | exec_call.extend(["--new-mapping", os.getenv("INPUT_NEW_MAPPING_FILE")]) 146 | exec_call.append("--text") 147 | output_file_name = "diffuse-output.txt" 148 | exec_call.append(output_file_name) 149 | 150 | oldSize = os.stat(oldFile).st_size 151 | oldSizeText = sizeof_fmt(oldSize) 152 | newSize = os.stat(newFile).st_size 153 | newSizeText = sizeof_fmt(newSize) 154 | diff = newSize - oldSize 155 | diffComment1 = f"**{sizeof_fmt(diff, sign=True)}** ({oldSizeText} -> {newSizeText})" 156 | if is_debug(): 157 | print("Old: {} bytes".format(oldSizeText)) 158 | print("New: {} bytes".format(newSizeText)) 159 | print("Diff: {} bytes".format(diffComment1)) 160 | print(diffComment1) 161 | print(" ".join(exec_call)) 162 | 163 | github_output("size-old-bytes", oldSize) 164 | github_output("size-old-text", oldSizeText) 165 | github_output("size-new-bytes", newSize) 166 | github_output("size-new-text", newSizeText) 167 | github_output("size-diff-comment_style_1", diffComment1) 168 | 169 | 170 | process = subprocess.run(exec_call) 171 | if process.returncode != 0: 172 | raise Exception("Error while executing diffuse") 173 | 174 | with open(output_file_name, mode="r", encoding="utf-8") as output: 175 | outputPath = os.path.realpath(output.name) 176 | diff = output.read() 177 | 178 | if process.returncode != 0: 179 | raise Exception("Error while executing diffuse") 180 | 181 | if is_debug(): 182 | print(f"Diff size: {len(diff)}") 183 | 184 | headerPattern = re.compile('=+\\s=+\\s+(\\w+)\\s+=+\\s=*\\s') 185 | sections = ["SUMMARY"] + headerPattern.split(diff) 186 | 187 | if is_debug(): 188 | print(f"Found {len(sections)} sections") 189 | print(f"Full output stored in: {outputPath}") 190 | 191 | github_comment = "" 192 | github_comment_all_collapsed = "" 193 | github_comment_no_dex = "" 194 | github_comment_no_dex_all_collapsed = "" 195 | github_output_limit = 4500 196 | 197 | for (title, content) in grouper(sections, 2): 198 | key = title.lower().strip().replace(" ", "-") 199 | value = content.rstrip().lstrip("\n").replace("$", "_").replace("`", "") 200 | if len(value) > github_output_limit: 201 | value = value[0:github_output_limit] + "\n...✂" 202 | 203 | github_output(key, value) 204 | if key == "summary": 205 | github_comment += header(value) 206 | github_comment_no_dex += header(value) 207 | github_comment_all_collapsed += section(title, value) 208 | github_comment_no_dex_all_collapsed += section(title, value) 209 | else: 210 | github_comment += section(title.strip(), value) 211 | github_comment_all_collapsed += section(title.strip(), value) 212 | if key != "dex": 213 | github_comment_no_dex += section(title.strip(), value) 214 | github_comment_no_dex_all_collapsed += section(title.strip(), value) 215 | 216 | github_output("diff-file", outputPath) 217 | github_output("diff-raw", diff[0:github_output_limit]) 218 | github_output("diff-gh-comment", github_comment) 219 | github_output("diff-gh-comment-all-collapsed", github_comment_all_collapsed) 220 | github_output("diff-gh-comment-no-dex", github_comment_no_dex) 221 | github_output("diff-gh-comment-no-dex-all-collapsed", github_comment_no_dex_all_collapsed) 222 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | 4 | concurrency: 5 | group: ${{ github.workflow }}-${{ github.ref }} 6 | cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} 7 | 8 | jobs: 9 | test-apk: 10 | runs-on: ubuntu-latest 11 | needs: 12 | - fetch-test-apk-old 13 | - fetch-test-apk-new 14 | name: Run diffuse action (part 1) 15 | steps: 16 | - uses: actions/checkout@v6 17 | 18 | - uses: actions/setup-java@v5 19 | with: 20 | distribution: temurin 21 | java-version: 24 22 | 23 | - uses: actions/download-artifact@v6 24 | with: 25 | name: old-apk 26 | 27 | - uses: actions/download-artifact@v6 28 | with: 29 | name: new-apk 30 | 31 | - id: diffuse 32 | uses: ./ 33 | with: 34 | old-file-path: old-apk.apk 35 | new-file-path: new-apk.apk 36 | debug: true 37 | 38 | - uses: peter-evans/find-comment@v4 39 | id: find_comment 40 | with: 41 | issue-number: ${{ github.event.pull_request.number }} 42 | body-includes: diffuse-smoke-test-1 43 | 44 | - uses: peter-evans/create-or-update-comment@v5 45 | with: 46 | body: | 47 | ### diffuse-smoke-test-1 48 | `size-old-bytes`: ${{ steps.diffuse.outputs.size-old-bytes }} 49 | `size-old-text`: ${{ steps.diffuse.outputs.size-old-text }} 50 | `size-new-bytes`: ${{ steps.diffuse.outputs.size-new-bytes }} 51 | `size-new-text`: ${{ steps.diffuse.outputs.size-new-text }} 52 | `size-diff-comment_style_1`: ${{ steps.diffuse.outputs.size-diff-comment_style_1 }} 53 | 54 | `steps.diffuse.outputs.diff-gh-comment:` 55 | ${{ steps.diffuse.outputs.diff-gh-comment }} 56 | 57 | `steps.diffuse.outputs.summary` 58 | ``` 59 | ${{ steps.diffuse.outputs.summary }} 60 | ``` 61 | 62 | `steps.diffuse.outputs.manifest` 63 | ``` 64 | ${{ steps.diffuse.outputs.manifest }} 65 | ``` 66 | 67 | `steps.diffuse.outputs.dex` 68 | ``` 69 | ${{ steps.diffuse.outputs.dex }} 70 | ``` 71 | 72 | `steps.diffuse.outputs.diff-gh-comment-all-collapsed` 73 | ${{ steps.diffuse.outputs.diff-gh-comment-all-collapsed }} 74 | edit-mode: replace 75 | comment-id: ${{ steps.find_comment.outputs.comment-id }} 76 | issue-number: ${{ github.event.pull_request.number }} 77 | token: ${{ secrets.GITHUB_TOKEN }} 78 | 79 | - uses: actions/upload-artifact@v5 80 | with: 81 | name: diffuse-output-1 82 | path: ${{ steps.diffuse.outputs.diff-file }} 83 | 84 | test-apk-2: 85 | runs-on: ubuntu-latest 86 | needs: 87 | - fetch-test-apk-very-old 88 | - fetch-test-apk-new 89 | name: Run diffuse action (part 2) 90 | steps: 91 | - uses: actions/checkout@v6 92 | 93 | - uses: actions/setup-java@v5 94 | with: 95 | distribution: temurin 96 | java-version: 24 97 | 98 | - uses: actions/download-artifact@v6 99 | with: 100 | name: very-old-apk 101 | 102 | - uses: actions/download-artifact@v6 103 | with: 104 | name: new-apk 105 | 106 | - id: diffuse 107 | uses: ./ 108 | with: 109 | old-file-path: very-old-apk.apk 110 | new-file-path: new-apk.apk 111 | debug: true 112 | 113 | - uses: peter-evans/find-comment@v4 114 | id: find_comment 115 | with: 116 | issue-number: ${{ github.event.pull_request.number }} 117 | body-includes: diffuse-smoke-test-2 118 | 119 | - uses: peter-evans/create-or-update-comment@v5 120 | with: 121 | body: | 122 | ### diffuse-smoke-test-2 123 | `size-old-bytes`: ${{ steps.diffuse.outputs.size-old-bytes }} 124 | `size-old-text`: ${{ steps.diffuse.outputs.size-old-text }} 125 | `size-new-bytes`: ${{ steps.diffuse.outputs.size-new-bytes }} 126 | `size-new-text`: ${{ steps.diffuse.outputs.size-new-text }} 127 | `size-diff-comment_style_1`: ${{ steps.diffuse.outputs.size-diff-comment_style_1 }} 128 | 129 | `steps.diffuse.outputs.diff-gh-comment-no-dex:` 130 | ${{ steps.diffuse.outputs.diff-gh-comment-no-dex }} 131 | 132 | `steps.diffuse.outputs.summary` 133 | ``` 134 | ${{ steps.diffuse.outputs.summary }} 135 | ``` 136 | 137 | `steps.diffuse.outputs.manifest` 138 | ``` 139 | ${{ steps.diffuse.outputs.manifest }} 140 | ``` 141 | 142 | `steps.diffuse.outputs.dex` 143 | ``` 144 | ${{ steps.diffuse.outputs.dex }} 145 | ``` 146 | 147 | `steps.diffuse.outputs.diff-gh-comment-no-dex-all-collapsed` 148 | ${{ steps.diffuse.outputs.diff-gh-comment-no-dex-all-collapsed }} 149 | edit-mode: replace 150 | comment-id: ${{ steps.find_comment.outputs.comment-id }} 151 | issue-number: ${{ github.event.pull_request.number }} 152 | token: ${{ secrets.GITHUB_TOKEN }} 153 | 154 | - uses: actions/upload-artifact@v5 155 | with: 156 | name: diffuse-output-2 157 | path: ${{ steps.diffuse.outputs.diff-file }} 158 | 159 | fetch-test-apk-very-old: 160 | runs-on: ubuntu-latest 161 | steps: 162 | - name: Get very old version of Android Auto app for test purposes 163 | run: wget "https://github.com/usefulness/storage/raw/master/android-auto-very-old.apk" -O very-old-apk.apk 164 | 165 | - uses: actions/upload-artifact@v5 166 | with: 167 | name: very-old-apk 168 | path: very-old-apk.apk 169 | retention-days: 1 170 | 171 | fetch-test-apk-old: 172 | runs-on: ubuntu-latest 173 | steps: 174 | - name: Get old version of Android Auto app for test purposes 175 | run: wget "https://github.com/usefulness/storage/raw/master/android-auto-old.apk" -O old-apk.apk 176 | 177 | - uses: actions/upload-artifact@v5 178 | with: 179 | name: old-apk 180 | path: old-apk.apk 181 | retention-days: 1 182 | 183 | fetch-test-apk-new: 184 | runs-on: ubuntu-latest 185 | steps: 186 | - name: Get new version of Android Auto app for test purposes 187 | run: wget "https://github.com/usefulness/storage/raw/master/android-auto-new.apk" -O new-apk.apk 188 | 189 | - uses: actions/upload-artifact@v5 190 | with: 191 | name: new-apk 192 | path: new-apk.apk 193 | retention-days: 1 194 | 195 | smoke-test: 196 | runs-on: ${{ matrix.os }} 197 | needs: 198 | - fetch-test-apk-very-old 199 | - fetch-test-apk-new 200 | strategy: 201 | fail-fast: false 202 | matrix: 203 | os: [ ubuntu-latest, macos-latest, windows-latest, ubuntu-24.04 ] 204 | steps: 205 | - uses: actions/checkout@v6 206 | 207 | - uses: actions/setup-java@v5 208 | with: 209 | distribution: temurin 210 | java-version: 24 211 | 212 | - uses: actions/download-artifact@v6 213 | with: 214 | name: very-old-apk 215 | 216 | - uses: actions/download-artifact@v6 217 | with: 218 | name: new-apk 219 | 220 | - id: diffuse-custom-repo-hardcoded 221 | uses: ./ 222 | with: 223 | old-file-path: very-old-apk.apk 224 | new-file-path: new-apk.apk 225 | lib-version: 0.3.0 226 | diffuse-repo: JakeWharton/diffuse 227 | debug: true 228 | 229 | - uses: actions/upload-artifact@v5 230 | with: 231 | name: diffuse-custom-repo-hardcoded-${{ matrix.os }} 232 | path: ${{ steps.diffuse-custom-repo-hardcoded.outputs.diff-file }} 233 | 234 | - id: diffuse-custom-repo-latest 235 | uses: ./ 236 | with: 237 | old-file-path: very-old-apk.apk 238 | new-file-path: new-apk.apk 239 | lib-version: latest 240 | diffuse-repo: JakeWharton/diffuse 241 | 242 | - uses: actions/upload-artifact@v5 243 | with: 244 | name: diffuse-custom-repo-latest-${{ matrix.os }} 245 | path: ${{ steps.diffuse-custom-repo-latest.outputs.diff-file }} 246 | 247 | --------------------------------------------------------------------------------