diff --git a/.github/workflows/build_firmware.yml b/.github/workflows/build_firmware.yml index d384540a4..19381e211 100644 --- a/.github/workflows/build_firmware.yml +++ b/.github/workflows/build_firmware.yml @@ -21,7 +21,7 @@ jobs: # Use 'arctastic' self-hosted runner pool when building in the main repo runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }} outputs: - artifact-id: ${{ steps.upload.outputs.artifact-id }} + artifact-id: ${{ steps.upload-firmware.outputs.artifact-id }} steps: - uses: actions/checkout@v6 with: @@ -71,7 +71,7 @@ jobs: - name: Store binaries as an artifact uses: actions/upload-artifact@v6 - id: upload + id: upload-firmware with: name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }} overwrite: true @@ -84,3 +84,12 @@ jobs: release/*.zip release/device-*.sh release/device-*.bat + + - name: Store manifests as an artifact + uses: actions/upload-artifact@v6 + id: upload-manifest + with: + name: manifest-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }} + overwrite: true + path: | + release/*.mt.json diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index d7bde7bc5..8a25829e4 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -233,6 +233,40 @@ jobs: description: "Download firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation" github-token: ${{ secrets.GITHUB_TOKEN }} + shame: + if: github.repository == 'meshtastic/firmware' + continue-on-error: true + runs-on: ubuntu-latest + needs: [build] + steps: + - uses: actions/checkout@v6 + with: + filter: blob:none # means we download all the git history but none of the commit (except ones with checkout like the head) + fetch-depth: 0 + - name: Download the current manifests + uses: actions/download-artifact@v7 + with: + path: ./manifests-new/ + pattern: manifest-* + merge-multiple: true + - name: Upload combined manifests for later commit and global stats crunching. + uses: actions/upload-artifact@v6 + id: upload-manifest + with: + name: manifests-all + overwrite: true + path: | + manifests-new/*.mt.json + - name: Find the merge base + run: echo "MERGE_BASE=$(git merge-base "origin/$base" "$head")" >> $GITHUB_ENV + env: + base: ${{ github.base_ref }} + head: ${{ github.head_ref }} + - name: Download the old manifests + run: gh run download -R ${{ github.repository }} --commit ${{ env.MERGE_BASE }} --name manifests-all --dir manifest-old/ + - name: Do scan and post comment + run: python3 bin/shame.py ${{ github.event.pull_request.number }} manifests-old/ manifests-new/ + release-artifacts: runs-on: ubuntu-latest if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }} diff --git a/bin/shame.py b/bin/shame.py new file mode 100644 index 000000000..9e9a7ea40 --- /dev/null +++ b/bin/shame.py @@ -0,0 +1,101 @@ +import sys +import os +import json +from github import Github + +def parseFile(path): + with open(path, "r") as f: + data = json.loads(f) + for file in data["files"]: + if file["name"].endswith(".bin"): + return file["name"], file["bytes"] + +if len(sys.argv) != 4: + print(f"expected usage: {sys.argv[0]} ") + sys.exit(1) + +pr_number = int(sys.argv[1]) + +token = os.getenv("GITHUB_TOKEN") +if not token: + raise EnvironmentError("GITHUB_TOKEN not found in environment.") + +repo_name = os.getenv("GITHUB_REPOSITORY") # "owner/repo" +if not repo_name: + raise EnvironmentError("GITHUB_REPOSITORY not found in environment.") + +oldFiles = sys.argv[2] +old = set(os.path.join(oldFiles, f) for f in os.listdir(oldFiles) if os.path.isfile(f)) +newFiles = sys.argv[3] +new = set(os.path.join(newFiles, f) for f in os.listdir(newFiles) if os.path.isfile(f)) + +startMarkdown = "# Target Size Changes\n\n" +markdown = "" + +newlyIntroduced = new - old +if len(newlyIntroduced) > 0: + markdown += "## Newly Introduced Targets\n\n" + # create a table + markdown += "| File | Size |\n" + markdown += "| ---- | ---- |\n" + for f in newlyIntroduced: + name, size = parseFile(f) + markdown += f"| `{name}` | {size}b |\n" + +removed = old - new +if len(removed) > 0: + markdown += "\n## Removed Targets\n\n" + # create a table + markdown += "| File | Size |\n" + markdown += "| ---- | ---- |\n" + for f in removed: + name, size = parseFile(f) + markdown += f"| `{name}` | {size}b |\n" + +both = old & new +degradations = [] +improvements = [] +for f in both: + oldName, oldSize = parseFile(f) + _, newSize = parseFile(f) + if oldSize != newSize: + if newSize < oldSize: + improvements.append((oldName, oldSize, newSize)) + else: + degradations.append((oldName, oldSize, newSize)) + +if len(degradations) > 0: + markdown += "\n## Degradation\n\n" + # create a table + markdown += "| File | Difference | Old Size | New Size |\n" + markdown += "| ---- | ---------- | -------- | -------- |\n" + for oldName, oldSize, newSize in degradations: + markdown += f"| `{oldName}` | **{oldSize - newSize}b** | {oldSize}b | {newSize}b |\n" + +if len(improvements) > 0: + markdown += "\n## Improvement\n\n" + # create a table + markdown += "| File | Difference | Old Size | New Size |\n" + markdown += "| ---- | ---------- | -------- | -------- |\n" + for oldName, oldSize, newSize in improvements: + markdown += f"| `{oldName}` | **{oldSize - newSize}b** | {oldSize}b | {newSize}b |\n" + +if len(markdown) == 0: + markdown = "No changes in target sizes detected." + +g = Github(token) +repo = g.get_repo(repo_name) +pr = repo.get_pull(pr_number) + +existing_comment = None +for comment in pr.get_issue_comments(): + if comment.body.startswith(startMarkdown): + existing_comment = comment + break + +final_markdown = startMarkdown + markdown + +if existing_comment: + existing_comment.edit(body=final_markdown) +else: + pr.create_issue_comment(body=final_markdown)