From 1449f8c74f7d542757382d783ed0d6a836e5797c Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:04:44 +0530 Subject: [PATCH 01/22] staging: prepare new branch for alpha release channels and high velocity development --- .github/workflows/alpha.yml | 4 ++-- .github/workflows/nightly.yml | 2 +- scripts/ci/workflow.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 3cbe2a76..61a96900 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -2,7 +2,7 @@ name: Alpha SideStore Build on: push: - branches: [alpha] + branches: [staging] workflow_dispatch: concurrency: @@ -40,7 +40,7 @@ jobs: run: | BUILD_NUM=$(python3 scripts/ci/workflow.py reserve_build_number 'Dependencies/beta-build-num') MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) - SHORT_COMMIT=$(python3 scripts/ci/workflow.py commid-id) + SHORT_COMMIT=$(python3 scripts/ci/workflow.py commit-id) QUALIFIED_VERSION=$(python3 scripts/ci/workflow.py compute-qualified \ "$MARKETING_VERSION" \ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 9f5db6f5..19e8aeee 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -42,7 +42,7 @@ jobs: run: | BUILD_NUM=$(python3 scripts/ci/workflow.py reserve_build_number 'Dependencies/beta-build-num') MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) - SHORT_COMMIT=$(python3 scripts/ci/workflow.py commid-id) + SHORT_COMMIT=$(python3 scripts/ci/workflow.py commit-id) QUALIFIED_VERSION=$(python3 scripts/ci/workflow.py compute-qualified \ "$MARKETING_VERSION" \ diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index 44e767db..e15fdb96 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -450,7 +450,7 @@ COMMANDS = { # ---------------------------------------------------------- # SHARED # ---------------------------------------------------------- - "commid-id" : (short_commit, 0, ""), + "commit-id" : (short_commit, 0, ""), # ---------------------------------------------------------- # PROJECT INFO @@ -534,4 +534,4 @@ def main(): sys.stdout.flush() if __name__ == "__main__": - main() \ No newline at end of file + main() From c1a033a627250b5a46a43b6e21c6b25c7b56a5d1 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:14:40 +0530 Subject: [PATCH 02/22] staging: added some redundant files to gitignore --- .gitignore | 5 ++++- release-notes.md | 37 ------------------------------------- source-metadata.json | 11 ----------- 3 files changed, 4 insertions(+), 49 deletions(-) delete mode 100644 release-notes.md delete mode 100644 source-metadata.json diff --git a/.gitignore b/.gitignore index 9c74f983..646b998f 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,7 @@ SideStore/.skip-prebuilt-fetch-em_proxy test-recording.mp4 test-recording.log altstore-sources.md -local-build.sh \ No newline at end of file +local-build.sh + +source-metadata.json +release-notes.md diff --git a/release-notes.md b/release-notes.md deleted file mode 100644 index a268ad38..00000000 --- a/release-notes.md +++ /dev/null @@ -1,37 +0,0 @@ - - -### nightly -#### What's Changed -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- altsign updated to latest -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- re added openSSL from new path -- updated altsign to use xcframework for openSSL which was causing huge download of 1.2 GB each time -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: improve more ci worflow -- CI: full rewrite - moved logic into ci.py and kept workflow scripts mostly dummy - -#### Full Changelog: [38715283...99712f00](https://github.com/SideStore/SideStore/compare/38715283073ea37949a462b889ce3cad403ea499...99712f0020a4f2ae57d8d781514fa735f893c23a) diff --git a/source-metadata.json b/source-metadata.json deleted file mode 100644 index e3b80492..00000000 --- a/source-metadata.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "is_beta": false, - "bundle_identifier": "com.SideStore.SideStore", - "version_ipa": "0.6.3", - "version_date": "2026-02-23T23:38:22Z", - "release_channel": "nightly", - "size": 29313346, - "sha256": "51ec327bca0b0056ccd4c2eb1a130cb7c5bb21de2f303251eea3e0a7336699c4", - "download_url": "https://github.com/SideStore/SideStore/releases/download/nightly/SideStore.ipa", - "localized_description": "This is release for:\n - version: \"0.6.3-nightly.2026.02.24.42+abc123de\"\n - revision: \"99712f00\"\n - timestamp: \"Mon Feb 23 23:38:22 2026\"\n\nRelease Notes:\n#### What's Changed\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- altsign updated to latest\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- re added openSSL from new path\n- updated altsign to use xcframework for openSSL which was causing huge download of 1.2 GB each time\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: improve more ci worflow\n- CI: full rewrite - moved logic into ci.py and kept workflow scripts mostly dummy\n\n#### Full Changelog: [38715283...99712f00](https://github.com/SideStore/SideStore/compare/38715283073ea37949a462b889ce3cad403ea499...99712f0020a4f2ae57d8d781514fa735f893c23a)" -} \ No newline at end of file From efbb40982e8c1cd1ebdeeb78f1245eafe0a38375 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:20:14 +0530 Subject: [PATCH 03/22] ci: fix indentation in release notes --- scripts/ci/workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index e15fdb96..ee47755b 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -406,7 +406,7 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_recomme upstream_block = "" if upstream_recommendation and upstream_recommendation.strip(): - upstream_block = upstream_recommendation.strip() + "\n\n" + upstream_block = f"{upstream_recommendation.strip()}\n\n" raw_body = f""" This is an ⚠️ **EXPERIMENTAL** ⚠️ {release_name} build for commit [{commit_sha}](https://github.com/{repo}/commit/{commit_sha}). From f44ed0a94790000c4c5f7c6383fd970eedb6b742 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 18:19:54 +0530 Subject: [PATCH 04/22] ci: fix indentation in release notes --- scripts/ci/generate_source_metadata.py | 22 ++++++++++--------- scripts/ci/workflow.py | 29 +++++++++++++------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/scripts/ci/generate_source_metadata.py b/scripts/ci/generate_source_metadata.py index 61cbfa12..e881655e 100644 --- a/scripts/ci/generate_source_metadata.py +++ b/scripts/ci/generate_source_metadata.py @@ -140,15 +140,7 @@ def main(): formatted = now.strftime("%Y-%m-%dT%H:%M:%SZ") human = now.strftime("%c") - localized_description = textwrap.dedent(f""" - This is release for: - - version: "{args.marketing_version}" - - revision: "{args.short_commit}" - - timestamp: "{human}" - - Release Notes: - {notes} - """).strip() + localized_description = getFormattedLocalizedDescription(args.marketing_version, args.short_commit, human, notes) metadata = { "is_beta": bool(args.is_beta), @@ -170,6 +162,16 @@ def main(): print(f"Wrote {out_file}") +def getFormattedLocalizedDescription(marketing_version, short_commit, human, notes): + return f""" +This is release for: + - version: "{marketing_version}" + - revision: "{short_commit}" + - timestamp: "{human}" + +Release Notes: +{notes} +""".lstrip("\n") if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index ee47755b..eeb3f3e6 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -408,20 +408,7 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_recomme if upstream_recommendation and upstream_recommendation.strip(): upstream_block = f"{upstream_recommendation.strip()}\n\n" - raw_body = f""" - This is an ⚠️ **EXPERIMENTAL** ⚠️ {release_name} build for commit [{commit_sha}](https://github.com/{repo}/commit/{commit_sha}). - - {release_name} builds are **extremely experimental builds only meant to be used by developers and beta testers. They often contain bugs and experimental features. Use at your own risk!** - - {upstream_block}## Build Info - - Built at (UTC): `{built_time}` - Built at (UTC date): `{built_date}` - Commit SHA: `{commit_sha}` - Version: `{marketing_version}` - """ - - header = inspect.cleandoc(raw_body) + header = getFormattedUploadMsg(release_name, release_tag, commit_sha, repo, upstream_block, built_time, built_date, marketing_version) body = header + "\n\n" + release_notes.lstrip() + "\n" body_file = ROOT / "release_body.md" @@ -442,6 +429,20 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_recomme f'--clobber' ) +def getFormattedUploadMsg(release_name, release_tag, commit_sha, repo, upstream_block, built_time, built_date, marketing_version): + return f""" +This is an ⚠️ **EXPERIMENTAL** ⚠️ {release_name} build for commit [{commit_sha}](https://github.com/{repo}/commit/{commit_sha}). + +{release_name} builds are **extremely experimental builds only meant to be used by developers and beta testers. They often contain bugs and experimental features. Use at your own risk!** + +{upstream_block}## Build Info + +Built at (UTC): `{built_time}` +Built at (UTC date): `{built_date}` +Commit SHA: `{commit_sha}` +Version: `{marketing_version}` +""".lstrip("\n") + # ---------------------------------------------------------- # ENTRYPOINT # ---------------------------------------------------------- From 046d2788b99e7e352b3d5bf5b20cef60d96ddeed Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 18:20:27 +0530 Subject: [PATCH 05/22] ci: fix indentation in release notes --- scripts/ci/generate_source_metadata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/ci/generate_source_metadata.py b/scripts/ci/generate_source_metadata.py index e881655e..c1e897e5 100644 --- a/scripts/ci/generate_source_metadata.py +++ b/scripts/ci/generate_source_metadata.py @@ -165,9 +165,9 @@ def main(): def getFormattedLocalizedDescription(marketing_version, short_commit, human, notes): return f""" This is release for: - - version: "{marketing_version}" - - revision: "{short_commit}" - - timestamp: "{human}" + - version: "{marketing_version}" + - revision: "{short_commit}" + - timestamp: "{human}" Release Notes: {notes} From b7085aaecaf623c4beb6c49ea61d5bbb60324215 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 18:54:41 +0530 Subject: [PATCH 06/22] ci: improve speed by caching brew install step and reading project settings from dumped xcodebuild -showProjectSettings instead of invoking each time. --- .github/workflows/alpha.yml | 17 ++++++++++--- .github/workflows/nightly.yml | 18 +++++++++++--- scripts/ci/generate_source_metadata.py | 1 - scripts/ci/workflow.py | 33 +++++++++++++++++++------- 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 61a96900..ef7734b6 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -23,7 +23,17 @@ jobs: submodules: recursive fetch-depth: 0 - - run: brew install ldid xcbeautify + - uses: actions/cache@v4 + with: + path: | + /opt/homebrew/Cellar + /opt/homebrew/Homebrew + /opt/homebrew/Library + ~/Library/Caches/Homebrew + key: brew-${{ runner.os }}-ldid-xcbeautify-v1 + - run: | + brew list ldid >/dev/null 2>&1 || brew install ldid + brew list xcbeautify >/dev/null 2>&1 || brew install xcbeautify # -------------------------------------------------- # runtime env setup @@ -176,8 +186,9 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - PRODUCT_NAME=$(python3 scripts/ci/workflow.py get-product-name) - BUNDLE_ID=$(python3 scripts/ci/workflow.py get-bundle-id) + python3 scripts/ci/workflow.py dump-project-settings + PRODUCT_NAME=$(python3 scripts/ci/workflow.py read-product-name) + BUNDLE_ID=$(python3 scripts/ci/workflow.py read-bundle-id) SOURCE_JSON="_includes/source.json" IPA_NAME="$PRODUCT_NAME.ipa" diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 19e8aeee..704c688e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -25,7 +25,18 @@ jobs: submodules: recursive fetch-depth: 0 - - run: brew install ldid xcbeautify + - uses: actions/cache@v4 + with: + path: | + /opt/homebrew/Cellar + /opt/homebrew/Homebrew + /opt/homebrew/Library + ~/Library/Caches/Homebrew + key: brew-${{ runner.os }}-ldid-xcbeautify-v1 + + - run: | + brew list ldid >/dev/null 2>&1 || brew install ldid + brew list xcbeautify >/dev/null 2>&1 || brew install xcbeautify # -------------------------------------------------- # runtime env setup @@ -178,8 +189,9 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - PRODUCT_NAME=$(python3 scripts/ci/workflow.py get-product-name) - BUNDLE_ID=$(python3 scripts/ci/workflow.py get-bundle-id) + python3 scripts/ci/workflow.py dump-project-settings + PRODUCT_NAME=$(python3 scripts/ci/workflow.py read-product-name) + BUNDLE_ID=$(python3 scripts/ci/workflow.py read-bundle-id) SOURCE_JSON="_includes/source.json" IPA_NAME="$PRODUCT_NAME.ipa" diff --git a/scripts/ci/generate_source_metadata.py b/scripts/ci/generate_source_metadata.py index c1e897e5..bea03b76 100644 --- a/scripts/ci/generate_source_metadata.py +++ b/scripts/ci/generate_source_metadata.py @@ -5,7 +5,6 @@ import json import subprocess from pathlib import Path import argparse -import textwrap import sys SCRIPT_DIR = Path(__file__).resolve().parent diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index eeb3f3e6..235f3103 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -6,12 +6,12 @@ import datetime from pathlib import Path import time import json -import inspect import re # REPO ROOT relative to script dir ROOT = Path(__file__).resolve().parents[2] SCRIPTS = ROOT / 'scripts/ci' +BUILD_SETTINGS_OUTFILE = "project-build-settings.txt" # ---------------------------------------------------------- # helpers @@ -127,23 +127,35 @@ def reserve_build_number(repo, max_attempts=5): # ---------------------------------------------------------- # PROJECT INFO # ---------------------------------------------------------- +def dump_project_settings(outdir=None): + outfile = Path(outdir).resolve() / BUILD_SETTINGS_OUTFILE if outdir else BUILD_SETTINGS_OUTFILE + run(f"xcodebuild -showBuildSettings 2>&1 > '{outfile}'") -def get_product_name(): - return runAndGet( - "xcodebuild -showBuildSettings " - "| grep PRODUCT_NAME " +def _extract_setting(cmd): + out = runAndGet(cmd + " || true").strip() # prevent grep failure from aborting + return out if out else None + +def _read_dumped_build_setting(name): + return _extract_setting( + f"cat '{BUILD_SETTINGS_OUTFILE}' " + f"| grep '{name} = ' " "| tail -1 " "| sed -e 's/.*= //g'" ) -def get_bundle_id(): - return runAndGet( - "xcodebuild -showBuildSettings 2>&1 " - "| grep 'PRODUCT_BUNDLE_IDENTIFIER = ' " +def query_build_setting(name): + return _extract_setting( + f"xcodebuild -showBuildSettings 2>&1 " + f"| grep '{name} = ' " "| tail -1 " "| sed -e 's/.*= //g'" ) +def get_product_name(): return query_build_setting("PRODUCT_NAME") +def get_bundle_id(): return query_build_setting("PRODUCT_BUNDLE_IDENTIFIER") +def read_product_name(): return _read_dumped_build_setting("PRODUCT_NAME") +def read_bundle_id(): return _read_dumped_build_setting("PRODUCT_BUNDLE_IDENTIFIER") + def get_marketing_version(): return runAndGet(f"grep MARKETING_VERSION {ROOT}/Build.xcconfig | sed -e 's/MARKETING_VERSION = //g'") @@ -462,6 +474,9 @@ COMMANDS = { "reserve_build_number" : (reserve_build_number, 1, ""), "get-product-name" : (get_product_name, 0, ""), "get-bundle-id" : (get_bundle_id, 0, ""), + "dump-project-settings" : (dump_project_settings, 0, ""), + "read-product-name" : (read_product_name, 0, ""), + "read-bundle-id" : (read_bundle_id, 0, ""), # ---------------------------------------------------------- # CLEAN From 25f34c6f69a782e793c3f1e2b699d39a26dcf3a6 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:23:12 +0530 Subject: [PATCH 07/22] ci: added back the nightly schedule checking for new commits and only then build --- .github/workflows/alpha.yml | 30 ++++++++++---- .github/workflows/nightly.yml | 76 ++++++++++++++++++++++++++++++----- scripts/ci/workflow.py | 16 ++++++++ 3 files changed, 103 insertions(+), 19 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index ef7734b6..7093eaa0 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -23,6 +23,13 @@ jobs: submodules: recursive fetch-depth: 0 + - run: | + LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \ + "${{ github.workflow }}" "${{ env.CHANNEL }}" || echo "") + echo "LAST_SUCCESSFUL_COMMIT=$LAST_SUCCESSFUL_COMMIT" | tee -a $GITHUB_ENV + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/cache@v4 with: path: | @@ -99,7 +106,9 @@ jobs: python3 scripts/ci/workflow.py clean-spm-cache - name: Boot simulator (async) - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} + if: > + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_RUN == '1' run: | mkdir -p build/logs python3 scripts/ci/workflow.py boot-sim-async "iPhone 17 Pro" @@ -116,7 +125,9 @@ jobs: - name: Tests Build id: test-build - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_BUILD == '1' }} + if: > + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_BUILD == '1' env: BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }} run: | @@ -135,7 +146,9 @@ jobs: - name: Tests Run id: test-run - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} + if: > + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_RUN == '1' env: BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }} run: | @@ -152,13 +165,17 @@ jobs: path: encrypted-build-logs.zip - uses: actions/upload-artifact@v4 - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_BUILD == '1' }} + if: > + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_BUILD == '1' with: name: encrypted-tests-build-logs-${{ env.SHORT_COMMIT }}.zip path: encrypted-tests-build-logs.zip - uses: actions/upload-artifact@v4 - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} + if: > + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_RUN == '1' with: name: encrypted-tests-run-logs-${{ env.SHORT_COMMIT }}.zip path: encrypted-tests-run-logs.zip @@ -192,9 +209,6 @@ jobs: SOURCE_JSON="_includes/source.json" IPA_NAME="$PRODUCT_NAME.ipa" - LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \ - "${{ github.workflow }}" "$CHANNEL") - python3 scripts/ci/workflow.py deploy \ SideStore/apps-v2.json \ "$SOURCE_JSON" \ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 704c688e..a60317b5 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -25,7 +25,34 @@ jobs: submodules: recursive fetch-depth: 0 + - run: | + LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \ + "${{ github.workflow }}" "${{ env.CHANNEL }}" || echo "") + echo "LAST_SUCCESSFUL_COMMIT=$LAST_SUCCESSFUL_COMMIT" | tee -a $GITHUB_ENV + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check for new changes (on schedule) + id: check_changes + if: github.event_name == 'schedule' + run: | + NEW_COMMITS=$(python3 scripts/ci/workflow.py count-new-commits "$LAST_SUCCESSFUL_COMMIT") + SHOULD_BUILD=$([ "${NEW_COMMITS:-0}" -ge 1 ] && echo true || echo false) + echo "should_build=$SHOULD_BUILD" >> $GITHUB_OUTPUT + echo "NEW_COMMITS=$NEW_COMMITS" | tee -a $GITHUB_ENV + + - name: Should Skip Building (on schedule) + id: build_gate + run: | + SHOULD_SKIP=$( + { [ "${{ github.event_name }}" = "schedule" ] && \ + [ "${{ steps.check_changes.outputs.should_build }}" != "true" ]; \ + } && echo true || echo false + ) + echo "should_skip=$SHOULD_SKIP" >> $GITHUB_OUTPUT + - uses: actions/cache@v4 + if: steps.build_gate.outputs.should_skip != 'true' with: path: | /opt/homebrew/Cellar @@ -37,11 +64,13 @@ jobs: - run: | brew list ldid >/dev/null 2>&1 || brew install ldid brew list xcbeautify >/dev/null 2>&1 || brew install xcbeautify + if: steps.build_gate.outputs.should_skip != 'true' # -------------------------------------------------- # runtime env setup # -------------------------------------------------- - uses: actions/checkout@v4 + if: steps.build_gate.outputs.should_skip != 'true' with: repository: "SideStore/beta-build-num" ref: ${{ env.CHANNEL }} @@ -50,6 +79,7 @@ jobs: fetch-depth: 1 - name: Setup Env + if: steps.build_gate.outputs.should_skip != 'true' run: | BUILD_NUM=$(python3 scripts/ci/workflow.py reserve_build_number 'Dependencies/beta-build-num') MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) @@ -68,11 +98,13 @@ jobs: echo "MARKETING_VERSION=$QUALIFIED_VERSION" | tee -a $GITHUB_ENV - name: Setup Xcode + if: steps.build_gate.outputs.should_skip != 'true' uses: maxim-lobanov/setup-xcode@v1.6.0 with: xcode-version: "26.2" - name: Restore Cache (exact) + if: steps.build_gate.outputs.should_skip != 'true' id: xcode-cache-exact uses: actions/cache/restore@v3 with: @@ -82,7 +114,9 @@ jobs: key: xcode-build-cache-${{ github.ref_name }}-${{ github.sha }} - name: Restore Cache (last) - if: steps.xcode-cache-exact.outputs.cache-hit != 'true' + if: > + steps.build_gate.outputs.should_skip != 'true' && + steps.xcode-cache-exact.outputs.cache-hit != 'true' id: xcode-cache-fallback uses: actions/cache/restore@v3 with: @@ -95,19 +129,23 @@ jobs: # build and test # -------------------------------------------------- - name: Clean - if: contains(github.event.head_commit.message, '[--clean-build]') + if: steps.build_gate.outputs.should_skip != 'true' && contains(github.event.head_commit.message, '[--clean-build]') run: | python3 scripts/ci/workflow.py clean python3 scripts/ci/workflow.py clean-derived-data python3 scripts/ci/workflow.py clean-spm-cache - name: Boot simulator (async) - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} + if: > + steps.build_gate.outputs.should_skip != 'true' && + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_RUN == '1' run: | mkdir -p build/logs python3 scripts/ci/workflow.py boot-sim-async "iPhone 17 Pro" - name: Build + if: steps.build_gate.outputs.should_skip != 'true' id: build env: BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }} @@ -118,8 +156,11 @@ jobs: exit $STATUS - name: Tests Build + if: > + steps.build_gate.outputs.should_skip != 'true' && + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_BUILD == '1' id: test-build - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_BUILD == '1' }} env: BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }} run: | @@ -128,7 +169,9 @@ jobs: exit $STATUS - name: Save Cache - if: ${{ steps.xcode-cache-fallback.outputs.cache-hit != 'true' }} + if: > + steps.build_gate.outputs.should_skip != 'true' && + steps.xcode-cache-fallback.outputs.cache-hit != 'true' uses: actions/cache/save@v3 with: path: | @@ -137,8 +180,11 @@ jobs: key: xcode-build-cache-${{ github.ref_name }}-${{ github.sha }} - name: Tests Run + if: > + steps.build_gate.outputs.should_skip != 'true' && + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_RUN == '1' id: test-run - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} env: BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }} run: | @@ -150,32 +196,42 @@ jobs: # artifacts # -------------------------------------------------- - uses: actions/upload-artifact@v4 + if: steps.build_gate.outputs.should_skip != 'true' with: name: encrypted-build-logs-${{ env.MARKETING_VERSION }}.zip path: encrypted-build-logs.zip - uses: actions/upload-artifact@v4 - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_BUILD == '1' }} + if: > + steps.build_gate.outputs.should_skip != 'true' && + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_BUILD == '1' with: name: encrypted-tests-build-logs-${{ env.SHORT_COMMIT }}.zip path: encrypted-tests-build-logs.zip - uses: actions/upload-artifact@v4 - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} + if: > + steps.build_gate.outputs.should_skip != 'true' && + vars.ENABLE_TESTS == '1' && + vars.ENABLE_TESTS_RUN == '1' with: name: encrypted-tests-run-logs-${{ env.SHORT_COMMIT }}.zip path: encrypted-tests-run-logs.zip - uses: actions/upload-artifact@v4 + if: steps.build_gate.outputs.should_skip != 'true' with: name: SideStore-${{ env.MARKETING_VERSION }}.ipa path: SideStore.ipa - uses: actions/upload-artifact@v4 + if: steps.build_gate.outputs.should_skip != 'true' with: name: SideStore-${{ env.MARKETING_VERSION }}-dSYMs.zip path: SideStore.dSYMs.zip - uses: actions/checkout@v4 + if: steps.build_gate.outputs.should_skip != 'true' with: repository: "SideStore/apps-v2.json" ref: "main" @@ -186,6 +242,7 @@ jobs: # deploy # -------------------------------------------------- - name: Deploy + if: steps.build_gate.outputs.should_skip != 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -195,9 +252,6 @@ jobs: SOURCE_JSON="_includes/source.json" IPA_NAME="$PRODUCT_NAME.ipa" - LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \ - "${{ github.workflow }}" "$CHANNEL") - python3 scripts/ci/workflow.py deploy \ SideStore/apps-v2.json \ "$SOURCE_JSON" \ diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index 235f3103..c431c6b9 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -57,6 +57,21 @@ def getenv(name, default=""): def short_commit(): return runAndGet("git rev-parse --short HEAD") +def count_new_commits(last_commit): + if not last_commit or not last_commit.strip(): + return 0 + + try: + total = int(runAndGet("git rev-list --count HEAD")) + if total == 1: + head = runAndGet("git rev-parse HEAD") + return 1 if head != last_commit else 0 + + out = runAndGet(f"git rev-list --count {last_commit}..HEAD") + return int(out) + except Exception: + return 0 + # ---------------------------------------------------------- # BUILD NUMBER RESERVATION # ---------------------------------------------------------- @@ -464,6 +479,7 @@ COMMANDS = { # SHARED # ---------------------------------------------------------- "commit-id" : (short_commit, 0, ""), + "count-new-commits" : (count_new_commits, 1, ""), # ---------------------------------------------------------- # PROJECT INFO From b91bcee70f08edbe4be326e877d2c58e8ca4da2d Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:27:46 +0530 Subject: [PATCH 08/22] ci: added some names to few steps --- .github/workflows/alpha.yml | 7 +++++-- .github/workflows/nightly.yml | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 7093eaa0..d8b7b698 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -23,7 +23,8 @@ jobs: submodules: recursive fetch-depth: 0 - - run: | + - name: Find Last Successful commit + run: | LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \ "${{ github.workflow }}" "${{ env.CHANNEL }}" || echo "") echo "LAST_SUCCESSFUL_COMMIT=$LAST_SUCCESSFUL_COMMIT" | tee -a $GITHUB_ENV @@ -38,7 +39,9 @@ jobs: /opt/homebrew/Library ~/Library/Caches/Homebrew key: brew-${{ runner.os }}-ldid-xcbeautify-v1 - - run: | + + - name: brew install ldid and xcbeautify + run: | brew list ldid >/dev/null 2>&1 || brew install ldid brew list xcbeautify >/dev/null 2>&1 || brew install xcbeautify diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a60317b5..0312d7ef 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -25,7 +25,8 @@ jobs: submodules: recursive fetch-depth: 0 - - run: | + - name: Find Last Successful commit + run: | LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \ "${{ github.workflow }}" "${{ env.CHANNEL }}" || echo "") echo "LAST_SUCCESSFUL_COMMIT=$LAST_SUCCESSFUL_COMMIT" | tee -a $GITHUB_ENV @@ -61,7 +62,8 @@ jobs: ~/Library/Caches/Homebrew key: brew-${{ runner.os }}-ldid-xcbeautify-v1 - - run: | + - name: brew install ldid and xcbeautify + run: | brew list ldid >/dev/null 2>&1 || brew install ldid brew list xcbeautify >/dev/null 2>&1 || brew install xcbeautify if: steps.build_gate.outputs.should_skip != 'true' From 967b9f75729f206e53525281b31f2192461c0e30 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:32:02 +0530 Subject: [PATCH 09/22] ci: removed caching for ldid and xcbeautify coz they take much more time to restore than install --- .github/workflows/alpha.yml | 14 +------------- .github/workflows/nightly.yml | 15 +-------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index d8b7b698..f7b46211 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -31,19 +31,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/cache@v4 - with: - path: | - /opt/homebrew/Cellar - /opt/homebrew/Homebrew - /opt/homebrew/Library - ~/Library/Caches/Homebrew - key: brew-${{ runner.os }}-ldid-xcbeautify-v1 - - - name: brew install ldid and xcbeautify - run: | - brew list ldid >/dev/null 2>&1 || brew install ldid - brew list xcbeautify >/dev/null 2>&1 || brew install xcbeautify + - run: brew install ldid && xcbeautify # -------------------------------------------------- # runtime env setup diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 0312d7ef..5ec9e84f 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -52,20 +52,7 @@ jobs: ) echo "should_skip=$SHOULD_SKIP" >> $GITHUB_OUTPUT - - uses: actions/cache@v4 - if: steps.build_gate.outputs.should_skip != 'true' - with: - path: | - /opt/homebrew/Cellar - /opt/homebrew/Homebrew - /opt/homebrew/Library - ~/Library/Caches/Homebrew - key: brew-${{ runner.os }}-ldid-xcbeautify-v1 - - - name: brew install ldid and xcbeautify - run: | - brew list ldid >/dev/null 2>&1 || brew install ldid - brew list xcbeautify >/dev/null 2>&1 || brew install xcbeautify + - run: brew install ldid && xcbeautify if: steps.build_gate.outputs.should_skip != 'true' # -------------------------------------------------- From 47db2c3d5d4e4b5c91ef736baf5231952c991e5b Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:35:50 +0530 Subject: [PATCH 10/22] ci: fix typo in brew command --- .github/workflows/alpha.yml | 2 +- .github/workflows/nightly.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index f7b46211..5ba3efb9 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -31,7 +31,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: brew install ldid && xcbeautify + - run: brew install ldid xcbeautify # -------------------------------------------------- # runtime env setup diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 5ec9e84f..8c4be197 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -52,7 +52,7 @@ jobs: ) echo "should_skip=$SHOULD_SKIP" >> $GITHUB_OUTPUT - - run: brew install ldid && xcbeautify + - run: brew install ldid xcbeautify if: steps.build_gate.outputs.should_skip != 'true' # -------------------------------------------------- From 1b1c7c58e252a2b9e0aecbf0d05b210d26d1e627 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:43:03 +0530 Subject: [PATCH 11/22] ci: moved cache maintenance script into obsolete --- .github/{ => workflows/obsolete}/maintenance/cache.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{ => workflows/obsolete}/maintenance/cache.py (100%) diff --git a/.github/maintenance/cache.py b/.github/workflows/obsolete/maintenance/cache.py similarity index 100% rename from .github/maintenance/cache.py rename to .github/workflows/obsolete/maintenance/cache.py From bf5b1c935cb08955a3989d0776520eb43907b7ba Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:43:35 +0530 Subject: [PATCH 12/22] ci: cleanup - removed obsolete stuffs --- .github/workflows/obsolete/alpha.yml | 28 -- .github/workflows/obsolete/beta.yml | 103 ----- .../obsolete/increase-beta-build-num.sh | 34 -- .../workflows/obsolete/maintenance/cache.py | 63 --- .github/workflows/obsolete/nightly.yml | 82 ---- .../obsolete/reusable-sidestore-build.yml | 105 ----- .../workflows/obsolete/sidestore-build.yml | 358 ------------------ .../workflows/obsolete/sidestore-deploy.yml | 281 -------------- .../workflows/obsolete/sidestore-shared.yml | 24 -- .../obsolete/sidestore-tests-build.yml | 165 -------- .../obsolete/sidestore-tests-run.yml | 196 ---------- 11 files changed, 1439 deletions(-) delete mode 100644 .github/workflows/obsolete/alpha.yml delete mode 100644 .github/workflows/obsolete/beta.yml delete mode 100755 .github/workflows/obsolete/increase-beta-build-num.sh delete mode 100644 .github/workflows/obsolete/maintenance/cache.py delete mode 100644 .github/workflows/obsolete/nightly.yml delete mode 100644 .github/workflows/obsolete/reusable-sidestore-build.yml delete mode 100644 .github/workflows/obsolete/sidestore-build.yml delete mode 100644 .github/workflows/obsolete/sidestore-deploy.yml delete mode 100644 .github/workflows/obsolete/sidestore-shared.yml delete mode 100644 .github/workflows/obsolete/sidestore-tests-build.yml delete mode 100644 .github/workflows/obsolete/sidestore-tests-run.yml diff --git a/.github/workflows/obsolete/alpha.yml b/.github/workflows/obsolete/alpha.yml deleted file mode 100644 index 9066ff6a..00000000 --- a/.github/workflows/obsolete/alpha.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Alpha SideStore build -on: - push: - branches: - - develop-alpha - -# cancel duplicate run if from same branch -concurrency: - group: ${{ github.ref }} - cancel-in-progress: true - -jobs: - Reusable-build: - uses: ./.github/workflows/reusable-sidestore-build.yml - with: - # bundle_id: "com.SideStore.SideStore.Alpha" - bundle_id: "com.SideStore.SideStore" - # bundle_id_suffix: ".Alpha" - is_beta: true - publish: ${{ vars.PUBLISH_ALPHA_UPDATES == 'true' }} - is_shared_build_num: false - release_tag: "alpha" - release_name: "Alpha" - upstream_tag: "nightly" - upstream_name: "Nightly" - secrets: - CROSS_REPO_PUSH_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }} - BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/obsolete/beta.yml b/.github/workflows/obsolete/beta.yml deleted file mode 100644 index 432ff1cb..00000000 --- a/.github/workflows/obsolete/beta.yml +++ /dev/null @@ -1,103 +0,0 @@ -name: Beta SideStore build -on: - push: - tags: - - '[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+' # example: 1.0.0-beta.1 - -jobs: - build: - name: Build and upload SideStore Beta - strategy: - fail-fast: false - matrix: - include: - - os: 'macos-14' - version: '15.4' - - runs-on: ${{ matrix.os }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install dependencies - run: brew install ldid - - - name: Change version to tag - run: sed -e '/MARKETING_VERSION = .*/s/= .*/= ${{ github.ref_name }}/' -i '' Build.xcconfig - - - name: Get version - id: version - run: echo "version=$(grep MARKETING_VERSION Build.xcconfig | sed -e "s/MARKETING_VERSION = //g")" >> $GITHUB_OUTPUT - - - name: Echo version - run: echo "${{ steps.version.outputs.version }}" - - - name: Setup Xcode - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: ${{ matrix.version }} - - - - name: Cache Build - uses: irgaly/xcode-cache@v1 - with: - key: xcode-cache-deriveddata-${{ github.sha }} - restore-keys: xcode-cache-deriveddata - - - name: Build SideStore - run: make build | xcpretty && exit ${PIPESTATUS[0]} - - - name: Fakesign app - run: make fakesign - - - name: Convert to IPA - run: make ipa - - - name: Get current date - id: date - run: echo "date=$(date -u +'%c')" >> $GITHUB_OUTPUT - - - name: Get current date in AltStore date form - id: date_altstore - run: echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT - - - name: Upload to new beta release - uses: softprops/action-gh-release@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - name: ${{ steps.version.outputs.version }} - tag_name: ${{ github.ref_name }} - draft: true - prerelease: true - files: SideStore.ipa - body: | - - Beta builds are hand-picked builds from development commits that will allow you to try out new features earlier than normal. However, **they might contain bugs and other issues. Use at your own risk!** - - ## Changelog - - - TODO - - ## Build Info - - Built at (UTC): `${{ steps.date.outputs.date }}` - Built at (UTC date): `${{ steps.date_altstore.outputs.date }}` - Commit SHA: `${{ github.sha }}` - Version: `${{ steps.version.outputs.version }}` - - - name: Add version to IPA file name - run: mv SideStore.ipa SideStore-${{ steps.version.outputs.version }}.ipa - - - name: Upload SideStore.ipa Artifact - uses: actions/upload-artifact@v4 - with: - name: SideStore-${{ steps.version.outputs.version }}.ipa - path: SideStore-${{ steps.version.outputs.version }}.ipa - - - name: Upload *.dSYM Artifact - uses: actions/upload-artifact@v4 - with: - name: SideStore-${{ steps.version.outputs.version }}-dSYM - path: ./*.dSYM/ diff --git a/.github/workflows/obsolete/increase-beta-build-num.sh b/.github/workflows/obsolete/increase-beta-build-num.sh deleted file mode 100755 index 2e24ef20..00000000 --- a/.github/workflows/obsolete/increase-beta-build-num.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -# Ensure we are in root directory -cd "$(dirname "$0")/../.." - -DATE=`date -u +'%Y.%m.%d'` -BUILD_NUM=1 - -# Use RELEASE_CHANNEL from the environment variable or default to "beta" -RELEASE_CHANNEL=${RELEASE_CHANNEL:-"beta"} - -write() { - sed -e "/MARKETING_VERSION = .*/s/$/-$RELEASE_CHANNEL.$DATE.$BUILD_NUM+$(git rev-parse --short HEAD)/" -i '' Build.xcconfig - echo "$DATE,$BUILD_NUM" > build_number.txt -} - -if [ ! -f "build_number.txt" ]; then - write - exit 0 -fi - -LAST_DATE=`cat build_number.txt | perl -n -e '/([^,]*),([^ ]*)$/ && print $1'` -LAST_BUILD_NUM=`cat build_number.txt | perl -n -e '/([^,]*),([^ ]*)$/ && print $2'` - -# if [[ "$DATE" != "$LAST_DATE" ]]; then -# write -# else -# BUILD_NUM=`expr $LAST_BUILD_NUM + 1` -# write -# fi - -# Build number is always incremental -BUILD_NUM=`expr $LAST_BUILD_NUM + 1` -write diff --git a/.github/workflows/obsolete/maintenance/cache.py b/.github/workflows/obsolete/maintenance/cache.py deleted file mode 100644 index 231bc77e..00000000 --- a/.github/workflows/obsolete/maintenance/cache.py +++ /dev/null @@ -1,63 +0,0 @@ -import requests -import sys -import os - -# Your GitHub Personal Access Token -GITHUB_TOKEN = os.getenv("GITHUB_TOKEN") - -# Repository details -REPO_OWNER = "SideStore" -REPO_NAME = "SideStore" - - -API_URL = f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/actions/caches" - -# Common headers for GitHub API calls -HEADERS = { - "Accept": "application/vnd.github+json", - "Authorization": f"Bearer {GITHUB_TOKEN}" -} - -def list_caches(): - response = requests.get(API_URL, headers=HEADERS) - if response.status_code != 200: - print(f"Failed to list caches. HTTP {response.status_code}") - print("Response:", response.text) - sys.exit(1) - data = response.json() - return data.get("actions_caches", []) - -def delete_cache(cache_id): - delete_url = f"{API_URL}/{cache_id}" - response = requests.delete(delete_url, headers=HEADERS) - return response.status_code - -def main(): - caches = list_caches() - if not caches: - print("No caches found.") - return - - print("Found caches:") - for cache in caches: - print(f"ID: {cache.get('id')}, Key: {cache.get('key')}") - - print("\nDeleting caches...") - for cache in caches: - cache_id = cache.get("id") - status = delete_cache(cache_id) - if status == 204: - print(f"Successfully deleted cache with ID: {cache_id}") - else: - print(f"Failed to delete cache with ID: {cache_id}. HTTP status code: {status}") - - print("All caches processed.") - -if __name__ == "__main__": - main() - - -### How to use -''' -just export the GITHUB_TOKEN and then run this script via `python3 cache.py' to delete the caches -''' \ No newline at end of file diff --git a/.github/workflows/obsolete/nightly.yml b/.github/workflows/obsolete/nightly.yml deleted file mode 100644 index 65662b62..00000000 --- a/.github/workflows/obsolete/nightly.yml +++ /dev/null @@ -1,82 +0,0 @@ -name: Nightly SideStore Build -on: - push: - branches: - - develop - schedule: - - cron: '0 0 * * *' # Runs every night at midnight UTC - workflow_dispatch: # Allows manual trigger - -# cancel duplicate run if from same branch -concurrency: - group: ${{ github.ref }} - cancel-in-progress: true - -jobs: - check-changes: - if: github.event_name == 'schedule' - runs-on: ubuntu-latest - outputs: - has_changes: ${{ steps.check.outputs.has_changes }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Ensure full history - - - name: Get last successful workflow run - id: get_last_success - run: | - LAST_SUCCESS=$(gh run list --workflow "Nightly SideStore Build" --json createdAt,conclusion \ - --jq '[.[] | select(.conclusion=="success")][0].createdAt' || echo "") - echo "Last successful run: $LAST_SUCCESS" - echo "last_success=$LAST_SUCCESS" >> $GITHUB_ENV - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Check for new commits since last successful build - id: check - run: | - if [ -n "$LAST_SUCCESS" ]; then - NEW_COMMITS=$(git rev-list --count --since="$LAST_SUCCESS" origin/develop) - COMMIT_LOG=$(git log --since="$LAST_SUCCESS" --pretty=format:"%h %s" origin/develop) - else - NEW_COMMITS=1 - COMMIT_LOG=$(git log -n 10 --pretty=format:"%h %s" origin/develop) # Show last 10 commits if no history - fi - - echo "Has changes: $NEW_COMMITS" - echo "New commits since last successful build:" - echo "$COMMIT_LOG" - - if [ "$NEW_COMMITS" -gt 0 ]; then - echo "has_changes=true" >> $GITHUB_OUTPUT - else - echo "has_changes=false" >> $GITHUB_OUTPUT - fi - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - LAST_SUCCESS: ${{ env.last_success }} - - Reusable-build: - if: | - always() && - (github.event_name == 'push' || - (github.event_name == 'schedule' && needs.check-changes.result == 'success' && needs.check-changes.outputs.has_changes == 'true')) - needs: check-changes - uses: ./.github/workflows/reusable-sidestore-build.yml - with: - # bundle_id: "com.SideStore.SideStore.Nightly" - bundle_id: "com.SideStore.SideStore" - # bundle_id_suffix: ".Nightly" - is_beta: true - publish: ${{ vars.PUBLISH_NIGHTLY_UPDATES == 'true' }} - is_shared_build_num: false - release_tag: "nightly" - release_name: "Nightly" - upstream_tag: "0.5.10" - upstream_name: "Stable" - secrets: - CROSS_REPO_PUSH_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }} - BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }} - diff --git a/.github/workflows/obsolete/reusable-sidestore-build.yml b/.github/workflows/obsolete/reusable-sidestore-build.yml deleted file mode 100644 index 6cd3f0f7..00000000 --- a/.github/workflows/obsolete/reusable-sidestore-build.yml +++ /dev/null @@ -1,105 +0,0 @@ -name: Reusable SideStore Build - -on: - workflow_call: - inputs: - is_beta: - required: false - default: false - type: boolean - publish: - required: false - default: false - type: boolean - is_shared_build_num: - required: false - default: true - type: boolean - release_name: - required: true - type: string - release_tag: - required: true - type: string - upstream_tag: - required: true - type: string - upstream_name: - required: true - type: string - bundle_id: - default: com.SideStore.SideStore - required: true - type: string - bundle_id_suffix: - default: '' - required: false - type: string - - secrets: - # GITHUB_TOKEN: - # required: true - CROSS_REPO_PUSH_KEY: - required: true - BUILD_LOG_ZIP_PASSWORD: - required: false - - -# since build cache, test-build cache, test-run cache are involved, out of order exec if serialization is on individual jobs will wreak all sorts of havoc -# so we serialize on the entire workflow -concurrency: - group: serialize-workflow - -jobs: - shared: - uses: ./.github/workflows/sidestore-shared.yml - secrets: inherit - - build: - needs: shared - uses: ./.github/workflows/sidestore-build.yml - with: - is_beta: ${{ inputs.is_beta }} - is_shared_build_num: ${{ inputs.is_shared_build_num }} - release_tag: ${{ inputs.release_tag }} - short_commit: ${{ needs.shared.outputs.short-commit }} - bundle_id: ${{ inputs.bundle_id }} - bundle_id_suffix: ${{ inputs.bundle_id_suffix }} - secrets: inherit - - # tests-build: - # if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_BUILD == '1' }} - # needs: shared - # uses: ./.github/workflows/sidestore-tests-build.yml - # with: - # release_tag: ${{ inputs.release_tag }} - # short_commit: ${{ needs.shared.outputs.short-commit }} - # secrets: inherit - - # tests-run: - # if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} - # needs: [shared, tests-build] - # uses: ./.github/workflows/sidestore-tests-run.yml - # with: - # release_tag: ${{ inputs.release_tag }} - # short_commit: ${{ needs.shared.outputs.short-commit }} - # secrets: inherit - - deploy: - # needs: [shared, build, tests-build, tests-run] # Keep tests-run in needs - needs: [shared, build] # Keep tests-run in needs - if: ${{ always() && (needs.tests-run.result == 'skipped' || needs.tests-run.result == 'success') }} - uses: ./.github/workflows/sidestore-deploy.yml - with: - is_beta: ${{ inputs.is_beta }} - publish: ${{ inputs.publish }} - release_name: ${{ inputs.release_name }} - release_tag: ${{ inputs.release_tag }} - upstream_tag: ${{ inputs.upstream_tag }} - upstream_name: ${{ inputs.upstream_name }} - version: ${{ needs.build.outputs.version }} - short_commit: ${{ needs.shared.outputs.short-commit }} - release_channel: ${{ needs.build.outputs.release-channel }} - marketing_version: ${{ needs.build.outputs.marketing-version }} - bundle_id: ${{ inputs.bundle_id }} - secrets: inherit \ No newline at end of file diff --git a/.github/workflows/obsolete/sidestore-build.yml b/.github/workflows/obsolete/sidestore-build.yml deleted file mode 100644 index ae5391a1..00000000 --- a/.github/workflows/obsolete/sidestore-build.yml +++ /dev/null @@ -1,358 +0,0 @@ -name: SideStore Build - -on: - workflow_call: - inputs: - is_beta: - type: boolean - is_shared_build_num: - type: boolean - release_tag: - type: string - bundle_id: - type: string - bundle_id_suffix: - type: string - short_commit: - type: string - secrets: - CROSS_REPO_PUSH_KEY: - required: true - BUILD_LOG_ZIP_PASSWORD: - required: false - outputs: - version: - value: ${{ jobs.build.outputs.version }} - marketing-version: - value: ${{ jobs.build.outputs.marketing-version }} - release-channel: - value: ${{ jobs.build.outputs.release-channel }} - -jobs: - build: - name: Build SideStore - ${{ inputs.release_tag }} - strategy: - fail-fast: false - matrix: - include: - - os: 'macos-26' - version: '26.0' - runs-on: ${{ matrix.os }} - outputs: - version: ${{ steps.version.outputs.version }} - marketing-version: ${{ steps.marketing-version.outputs.MARKETING_VERSION }} - release-channel: ${{ steps.release-channel.outputs.RELEASE_CHANNEL }} - - steps: - - name: Set beta status - run: echo "IS_BETA=${{ inputs.is_beta }}" >> $GITHUB_ENV - shell: bash - - - name: Checkout code - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - - name: Install dependencies - ldid & xcbeautify - run: | - brew install ldid xcbeautify - - - name: Set ref based on is_shared_build_num - if: ${{ inputs.is_beta }} - id: set_ref - run: | - if [ "${{ inputs.is_shared_build_num }}" == "true" ]; then - echo "ref=main" >> $GITHUB_ENV - else - echo "ref=${{ inputs.release_tag }}" >> $GITHUB_ENV - fi - shell: bash - - - name: Checkout SideStore/beta-build-num repo - if: ${{ inputs.is_beta }} - uses: actions/checkout@v4 - with: - repository: 'SideStore/beta-build-num' - ref: ${{ env.ref }} - token: ${{ secrets.CROSS_REPO_PUSH_KEY }} - path: 'SideStore/beta-build-num' - - - name: Copy build_number.txt to repo root - if: ${{ inputs.is_beta }} - run: | - cp SideStore/beta-build-num/build_number.txt . - echo "cat build_number.txt" - cat build_number.txt - shell: bash - - - name: Echo Build.xcconfig - run: | - echo "cat Build.xcconfig" - cat Build.xcconfig - shell: bash - - - name: Set Release Channel info for build number bumper - id: release-channel - run: | - RELEASE_CHANNEL="${{ inputs.release_tag }}" - echo "RELEASE_CHANNEL=${RELEASE_CHANNEL}" >> $GITHUB_ENV - echo "RELEASE_CHANNEL=${RELEASE_CHANNEL}" >> $GITHUB_OUTPUT - echo "RELEASE_CHANNEL=${RELEASE_CHANNEL}" - shell: bash - - - name: Increase build number for beta builds - if: ${{ inputs.is_beta }} - run: | - bash .github/workflows/increase-beta-build-num.sh - shell: bash - - - name: Extract MARKETING_VERSION from Build.xcconfig - id: version - run: | - version=$(grep MARKETING_VERSION Build.xcconfig | sed -e 's/MARKETING_VERSION = //g') - echo "version=$version" >> $GITHUB_OUTPUT - echo "version=$version" - shell: bash - - - name: Set MARKETING_VERSION - if: ${{ inputs.is_beta }} - id: marketing-version - run: | - # Extract version number (e.g., "0.6.0") - version=$(echo "${{ steps.version.outputs.version }}" | sed -E 's/^[^0-9]*([0-9]+\.[0-9]+\.[0-9]+).*/\1/') - # Extract date (YYYYMMDD) (e.g., "20250205") - date=$(echo "${{ steps.version.outputs.version }}" | sed -E 's/.*\.([0-9]{4})\.([0-9]{2})\.([0-9]{2})\..*/\1\2\3/') - # Extract build number (e.g., "2") - build_num=$(echo "${{ steps.version.outputs.version }}" | sed -E 's/.*\.([0-9]+)\+.*/\1/') - - # Combine them into the final output - MARKETING_VERSION="${version}-${date}.${build_num}+${{ inputs.short_commit }}" - - echo "MARKETING_VERSION=$MARKETING_VERSION" >> $GITHUB_ENV - echo "MARKETING_VERSION=$MARKETING_VERSION" >> $GITHUB_OUTPUT - echo "MARKETING_VERSION=$MARKETING_VERSION" - shell: bash - - - name: Echo Updated Build.xcconfig, build_number.txt - if: ${{ inputs.is_beta }} - run: | - cat Build.xcconfig - cat build_number.txt - shell: bash - - - name: Setup Xcode - uses: maxim-lobanov/setup-xcode@v1.6.0 - with: - xcode-version: ${{ matrix.version }} - - - name: (Build) Restore Xcode & SwiftPM Cache (Exact match) - id: xcode-cache-restore - uses: actions/cache/restore@v3 - with: - path: | - ~/Library/Developer/Xcode/DerivedData - ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-build-${{ github.ref_name }}-${{ github.sha }} - - - name: (Build) Restore Xcode & SwiftPM Cache (Last Available) - id: xcode-cache-restore-recent - uses: actions/cache/restore@v3 - with: - path: | - ~/Library/Developer/Xcode/DerivedData - ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-build-${{ github.ref_name }}- - - # - name: (Build) Cache Build - # uses: irgaly/xcode-cache@v1.8.1 - # with: - # key: xcode-cache-deriveddata-build-${{ github.ref_name }}-${{ github.sha }} - # restore-keys: xcode-cache-deriveddata-build-${{ github.ref_name }}- - # swiftpm-cache-key: xcode-cache-sourcedata-build-${{ github.ref_name }}-${{ github.sha }} - # swiftpm-cache-restore-keys: | - # xcode-cache-sourcedata-build-${{ github.ref_name }}- - - - name: (Build) Clean previous build artifacts - # using 'tee' to intercept stdout and log for detailed build-log - run: | - make clean - mkdir -p build/logs - shell: bash - - - name: (Build) List Files and derived data - if: always() - shell: bash - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - ls -la . - echo "" - - echo ">>>>>>>>> SideStore <<<<<<<<<<" - find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Dependencies <<<<<<<<<<" - find Dependencies -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<" - ls -la ~/Library/Developer/Xcode/DerivedData || true # List contents if directory exists - echo "" - - - name: Set BundleID Suffix for Sidestore build - run: | - echo "BUNDLE_ID_SUFFIX=${{ inputs.bundle_id_suffix }}" >> $GITHUB_ENV - shell: bash - - - - name: Build SideStore.xcarchive - # using 'tee' to intercept stdout and log for detailed build-log - run: | - NSUnbufferedIO=YES make -B build 2>&1 | tee -a build/logs/build.log | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]} - shell: bash - - - name: Fakesign app - run: make fakesign | tee -a build/logs/build.log - shell: bash - - - name: Convert to IPA - run: make ipa | tee -a build/logs/build.log - shell: bash - - - name: (Build) Save Xcode & SwiftPM Cache - id: cache-save - if: ${{ steps.xcode-cache-restore.outputs.cache-hit != 'true' }} - uses: actions/cache/save@v3 - with: - path: | - ~/Library/Developer/Xcode/DerivedData - ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-build-${{ github.ref_name }}-${{ github.sha }} - - - name: (Build) List Files and Build artifacts - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - ls -la . - echo "" - - echo ">>>>>>>>> Build <<<<<<<<<<" - find build -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> SideStore <<<<<<<<<<" - find SideStore -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> SideStore.xcarchive <<<<<<<<<<" - find SideStore.xcarchive -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<" - ls -la ~/Library/Developer/Xcode/DerivedData || true # List contents if directory exists - echo "" - shell: bash - - - name: Encrypt build-logs for upload - id: encrypt-build-log - run: | - DEFAULT_BUILD_LOG_PASSWORD=12345 - - BUILD_LOG_ZIP_PASSWORD=${{ secrets.BUILD_LOG_ZIP_PASSWORD }} - BUILD_LOG_ZIP_PASSWORD=${BUILD_LOG_ZIP_PASSWORD:-$DEFAULT_BUILD_LOG_PASSWORD} - - if [ "$BUILD_LOG_ZIP_PASSWORD" == "$DEFAULT_BUILD_LOG_PASSWORD" ]; then - echo "Warning: BUILD_LOG_ZIP_PASSWORD is not set. Defaulting to '${DEFAULT_BUILD_LOG_PASSWORD}'." - fi - - pushd build/logs && zip -e -P "$BUILD_LOG_ZIP_PASSWORD" ../../encrypted-build-logs.zip * || popd - echo "::set-output name=encrypted::true" - shell: bash - - - name: Upload encrypted-build-logs.zip - id: attach-encrypted-build-log - if: ${{ always() && steps.encrypt-build-log.outputs.encrypted == 'true' }} - uses: actions/upload-artifact@v4 - with: - name: encrypted-build-logs-${{ steps.version.outputs.version }}.zip - path: encrypted-build-logs.zip - - - name: Upload SideStore.ipa Artifact - uses: actions/upload-artifact@v4 - with: - name: SideStore-${{ steps.version.outputs.version }}.ipa - path: SideStore.ipa - - - name: Zip dSYMs - run: zip -r -9 ./SideStore.dSYMs.zip ./SideStore.xcarchive/dSYMs - shell: bash - - - name: Upload *.dSYM Artifact - uses: actions/upload-artifact@v4 - with: - name: SideStore-${{ steps.version.outputs.version }}-dSYMs.zip - path: SideStore.dSYMs.zip - - - name: Keep rolling the build numbers for each successful build - if: ${{ inputs.is_beta }} - run: | - pushd SideStore/beta-build-num/ - - echo "Configure Git user (committer details)" - git config user.name "GitHub Actions" - git config user.email "github-actions@github.com" - - echo "Adding files to commit" - git add --verbose build_number.txt - git commit -m " - updated for ${{ inputs.release_tag }} - ${{ inputs.short_commit }} deployment" || echo "No changes to commit" - - echo "Pushing to remote repo" - git push --verbose - popd - shell: bash - - - name: Get last successful commit - id: get_last_commit - run: | - # Try to get the last successful workflow run commit - LAST_SUCCESS_SHA=$(gh run list --branch "${{ github.ref_name }}" --status success --json headSha --jq '.[0].headSha') - echo "LAST_SUCCESS_SHA=$LAST_SUCCESS_SHA" >> $GITHUB_OUTPUT - echo "LAST_SUCCESS_SHA=$LAST_SUCCESS_SHA" >> $GITHUB_ENV - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash - - - name: Create release notes - run: | - LAST_SUCCESS_SHA=${{ steps.get_last_commit.outputs.LAST_SUCCESS_SHA}} - echo "Last successful commit SHA: $LAST_SUCCESS_SHA" - - FROM_COMMIT=$LAST_SUCCESS_SHA - # Check if we got a valid SHA - if [ -z "$LAST_SUCCESS_SHA" ] || [ "$LAST_SUCCESS_SHA" = "null" ]; then - echo "No successful run found, using initial commit of branch" - # Get the first commit of the branch (initial commit) - FROM_COMMIT=$(git rev-list --max-parents=0 HEAD) - fi - - python3 update_release_notes.py $FROM_COMMIT ${{ inputs.release_tag }} ${{ github.ref_name }} - # cat release-notes.md - shell: bash - - - name: Upload release-notes.md - uses: actions/upload-artifact@v4 - with: - name: release-notes-${{ inputs.short_commit }}.md - path: release-notes.md - - - name: Upload update_release_notes.py - uses: actions/upload-artifact@v4 - with: - name: update_release_notes-${{ inputs.short_commit }}.py - path: update_release_notes.py - - - name: Upload update_apps.py - uses: actions/upload-artifact@v4 - with: - name: update_apps-${{ inputs.short_commit }}.py - path: update_apps.py \ No newline at end of file diff --git a/.github/workflows/obsolete/sidestore-deploy.yml b/.github/workflows/obsolete/sidestore-deploy.yml deleted file mode 100644 index 0fa50969..00000000 --- a/.github/workflows/obsolete/sidestore-deploy.yml +++ /dev/null @@ -1,281 +0,0 @@ -name: SideStore Deploy - -on: - workflow_call: - inputs: - is_beta: - type: boolean - publish: - type: boolean - release_name: - type: string - release_tag: - type: string - upstream_tag: - type: string - upstream_name: - type: string - version: - type: string - short_commit: - type: string - marketing_version: - type: string - release_channel: - type: string - bundle_id: - type: string - secrets: - CROSS_REPO_PUSH_KEY: - required: true - # GITHUB_TOKEN: - # required: true - -jobs: - deploy: - name: Deploy SideStore - ${{ inputs.release_tag }} - runs-on: macos-15 - steps: - - name: Download IPA artifact - uses: actions/download-artifact@v4 - with: - name: SideStore-${{ inputs.version }}.ipa - - - name: Download dSYM artifact - uses: actions/download-artifact@v4 - with: - name: SideStore-${{ inputs.version }}-dSYMs.zip - - - name: Download encrypted-build-logs artifact - uses: actions/download-artifact@v4 - with: - name: encrypted-build-logs-${{ inputs.version }}.zip - - - name: Download encrypted-tests-build-logs artifact - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_BUILD == '1' }} - uses: actions/download-artifact@v4 - with: - name: encrypted-tests-build-logs-${{ inputs.short_commit }}.zip - - - name: Download encrypted-tests-run-logs artifact - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} - uses: actions/download-artifact@v4 - with: - name: encrypted-tests-run-logs-${{ inputs.short_commit }}.zip - - - name: Download tests-recording artifact - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} - uses: actions/download-artifact@v4 - with: - name: tests-recording-${{ inputs.short_commit }}.mp4 - - - name: Download test-results artifact - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} - uses: actions/download-artifact@v4 - with: - name: test-results-${{ inputs.short_commit }}.zip - - - name: Download release-notes.md - uses: actions/download-artifact@v4 - with: - name: release-notes-${{ inputs.short_commit }}.md - - - name: Download update_release_notes.py - uses: actions/download-artifact@v4 - with: - name: update_release_notes-${{ inputs.short_commit }}.py - - - name: Download update_apps.py - uses: actions/download-artifact@v4 - with: - name: update_apps-${{ inputs.short_commit }}.py - - - name: Read release notes - id: release_notes - run: | - CONTENT=$(python3 update_release_notes.py --retrieve ${{ inputs.release_tag }}) - echo "content<> $GITHUB_OUTPUT - echo "$CONTENT" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - shell: bash - - - name: List files before upload - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - find . -maxdepth 4 -exec ls -ld {} + || true # List contents if directory exists - echo "" - shell: bash - - - name: Get current date - id: date - run: echo "date=$(date -u +'%c')" >> $GITHUB_OUTPUT - shell: bash - - - name: Get current date in AltStore date form - id: date_altstore - run: echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT - shell: bash - - - - name: List files to upload - id: list_uploads - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - find . -maxdepth 4 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - FILES="SideStore.ipa SideStore.dSYMs.zip encrypted-build-logs.zip" - - if [[ "${{ vars.ENABLE_TESTS }}" == "1" && "${{ vars.ENABLE_TESTS_BUILD }}" == "1" ]]; then - FILES="$FILES encrypted-tests-build-logs.zip" - fi - - if [[ "${{ vars.ENABLE_TESTS }}" == "1" && "${{ vars.ENABLE_TESTS_RUN }}" == "1" ]]; then - FILES="$FILES encrypted-tests-run-logs.zip test-results.zip tests-recording.mp4" - fi - - echo "Final upload list:" - for f in $FILES; do - if [[ -f "$f" ]]; then - echo " ✓ $f" - else - echo " - $f (missing)" - fi - done - - echo "files=$FILES" >> $GITHUB_OUTPUT - - - name: Set Upstream Recommendation - id: upstream_recommendation - run: | - UPSTREAM_NAME=$(echo "${{ inputs.upstream_name }}" | tr '[:upper:]' '[:lower:]') - if [[ "$UPSTREAM_NAME" != "nightly" ]]; then - echo "content<> $GITHUB_OUTPUT - echo "If you want to try out new features early but want a lower chance of bugs, you can look at [SideStore ${{ inputs.upstream_name }}](https://github.com/${{ github.repository }}/releases?q=${{ inputs.upstream_tag }})." >> $GITHUB_OUTPUT - echo "" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - else - echo "content=" >> $GITHUB_OUTPUT - fi - shell: bash - - - name: Upload to releases - uses: IsaacShelton/update-existing-release@v1.3.1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - release: ${{ inputs.release_name }} - tag: ${{ inputs.release_tag }} - prerelease: ${{ inputs.is_beta }} - files: ${{ steps.list_uploads.outputs.files }} - body: | - This is an ⚠️ **EXPERIMENTAL** ⚠️ ${{ inputs.release_name }} build for commit [${{ github.sha }}](https://github.com/${{ github.repository }}/commit/${{ github.sha }}). - - ${{ inputs.release_name }} builds are **extremely experimental builds only meant to be used by developers and beta testers. They often contain bugs and experimental features. Use at your own risk!** - - ${{ steps.upstream_recommendation.outputs.content }} - ## Build Info - - Built at (UTC): `${{ steps.date.outputs.date }}` - Built at (UTC date): `${{ steps.date_altstore.outputs.date }}` - Commit SHA: `${{ github.sha }}` - Version: `${{ inputs.version }}` - - ${{ steps.release_notes.outputs.content }} - - - name: Get formatted date - run: | - FORMATTED_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") - echo "Formatted date: $FORMATTED_DATE" - echo "FORMATTED_DATE=$FORMATTED_DATE" >> $GITHUB_ENV - shell: bash - - - name: Get size of IPA in bytes (macOS/Linux) - run: | - if [[ "$(uname)" == "Darwin" ]]; then - # macOS - IPA_SIZE=$(stat -f %z SideStore.ipa) - else - # Linux - IPA_SIZE=$(stat -c %s SideStore.ipa) - fi - echo "IPA size in bytes: $IPA_SIZE" - echo "IPA_SIZE=$IPA_SIZE" >> $GITHUB_ENV - shell: bash - - - name: Compute SHA-256 of IPA - run: | - SHA256_HASH=$(shasum -a 256 SideStore.ipa | awk '{ print $1 }') - echo "SHA-256 Hash: $SHA256_HASH" - echo "SHA256_HASH=$SHA256_HASH" >> $GITHUB_ENV - shell: bash - - - name: Set Release Info variables - run: | - echo "IS_BETA=${{ inputs.is_beta }}" >> $GITHUB_ENV - echo "BUNDLE_IDENTIFIER=${{ inputs.bundle_id }}" >> $GITHUB_ENV - echo "VERSION_IPA=${{ inputs.marketing_version }}" >> $GITHUB_ENV - echo "VERSION_DATE=$FORMATTED_DATE" >> $GITHUB_ENV - echo "RELEASE_CHANNEL=${{ inputs.release_channel }}" >> $GITHUB_ENV - echo "SIZE=$IPA_SIZE" >> $GITHUB_ENV - echo "SHA256=$SHA256_HASH" >> $GITHUB_ENV - echo "DOWNLOAD_URL=https://github.com/SideStore/SideStore/releases/download/${{ inputs.release_tag }}/SideStore.ipa" >> $GITHUB_ENV - - # Format localized description - get_description() { - cat <> $GITHUB_ENV - echo "$LOCALIZED_DESCRIPTION" >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV - shell: bash - - - name: Check if Publish updates is set - id: check_publish - run: | - echo "Publish updates to source.json = ${{ inputs.publish }}" - shell: bash - - - name: Checkout SideStore/apps-v2.json - if: ${{ inputs.is_beta && inputs.publish }} - uses: actions/checkout@v4 - with: - repository: 'SideStore/apps-v2.json' - ref: 'main' # this branch is shared by all beta builds, so beta build workflows are serialized - token: ${{ secrets.CROSS_REPO_PUSH_KEY }} - path: 'SideStore/apps-v2.json' - - # for stable builds, let the user manually edit the source.json - - name: Publish to SideStore/apps-v2.json - if: ${{ inputs.is_beta && inputs.publish }} - id: publish-release - shell: bash - run: | - # Copy and execute the update script - pushd SideStore/apps-v2.json/ - - # Configure Git user (committer details) - git config user.name "GitHub Actions" - git config user.email "github-actions@github.com" - - # update the source.json - python3 ../../update_apps.py "./_includes/source.json" - - # Commit changes and push using SSH - git add --verbose ./_includes/source.json - git commit -m " - updated for ${{ inputs.short_commit }} deployment" || echo "No changes to commit" - - git push --verbose - popd diff --git a/.github/workflows/obsolete/sidestore-shared.yml b/.github/workflows/obsolete/sidestore-shared.yml deleted file mode 100644 index 1f9cc79e..00000000 --- a/.github/workflows/obsolete/sidestore-shared.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: SideStore Shared - -on: - workflow_call: - outputs: - short-commit: - value: ${{ jobs.shared.outputs.short-commit }} - -jobs: - shared: - name: Shared Steps - strategy: - fail-fast: false - runs-on: 'macos-15' - steps: - - name: Set short commit hash - id: commit-id - run: | - # SHORT_COMMIT="${{ github.sha }}" - SHORT_COMMIT=${GITHUB_SHA:0:7} - echo "Short commit hash: $SHORT_COMMIT" - echo "SHORT_COMMIT=$SHORT_COMMIT" >> $GITHUB_OUTPUT - outputs: - short-commit: ${{ steps.commit-id.outputs.SHORT_COMMIT }} \ No newline at end of file diff --git a/.github/workflows/obsolete/sidestore-tests-build.yml b/.github/workflows/obsolete/sidestore-tests-build.yml deleted file mode 100644 index 6338e114..00000000 --- a/.github/workflows/obsolete/sidestore-tests-build.yml +++ /dev/null @@ -1,165 +0,0 @@ -name: SideStore Tests Build - -on: - workflow_call: - inputs: - release_tag: - type: string - short_commit: - type: string - secrets: - BUILD_LOG_ZIP_PASSWORD: - required: false - -jobs: - tests-build: - name: Tests-Build SideStore - ${{ inputs.release_tag }} - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_BUILD == '1' }} - strategy: - fail-fast: false - matrix: - include: - - os: 'macos-26' - version: '26.0' - runs-on: ${{ matrix.os }} - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install dependencies - xcbeautify - run: | - brew install xcbeautify - shell: bash - - - name: Setup Xcode - uses: maxim-lobanov/setup-xcode@v1.6.0 - with: - xcode-version: '26.0' - - # - name: (Tests-Build) Cache Build - # uses: irgaly/xcode-cache@v1.8.1 - # with: - # key: xcode-cache-deriveddata-test-${{ github.ref_name }}-${{ github.sha }} - # # tests shouldn't restore cache unless it is same build - # # restore-keys: xcode-cache-deriveddata-test-${{ github.ref_name }}- - # swiftpm-cache-key: xcode-cache-sourcedata-test-${{ github.ref_name }}-${{ github.sha }} - # swiftpm-cache-restore-keys: | - # xcode-cache-sourcedata-test-${{ github.ref_name }}- - # delete-used-deriveddata-cache: true - - - name: (Tests-Build) Restore Xcode & SwiftPM Cache (Exact match) - id: xcode-cache-restore - uses: actions/cache/restore@v3 - with: - path: | - ~/Library/Developer/Xcode/DerivedData - ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-tests-${{ github.ref_name }}-${{ github.sha }} - - - name: (Tests-Build) Restore Xcode & SwiftPM Cache (Last Available) - id: xcode-cache-restore-recent - uses: actions/cache/restore@v3 - with: - path: | - ~/Library/Developer/Xcode/DerivedData - ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-tests-${{ github.ref_name }}- - - - name: Clean Derived Data (if required) - if: ${{ vars.PERFORM_CLEAN_TESTS_BUILD == '1' }} - run: | - rm -rf ~/Library/Developer/Xcode/DerivedData/ - make clean - xcodebuild clean - shell: bash - - - name: (Tests-Build) Clean previous build artifacts - run: | - make clean - mkdir -p build/logs - shell: bash - - - name: (Tests-Build) List Files and derived data - shell: bash - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - ls -la . - echo "" - - echo ">>>>>>>>> SideStore <<<<<<<<<<" - find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Dependencies <<<<<<<<<<" - find Dependencies -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<" - ls -la ~/Library/Developer/Xcode/DerivedData || true # List contents if directory exists - echo "" - - - name: Build SideStore Tests - # using 'tee' to intercept stdout and log for detailed build-log - shell: bash - run: | - NSUnbufferedIO=YES make -B build-tests 2>&1 | tee -a build/logs/tests-build.log | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]} - - - name: (Tests-Build) Save Xcode & SwiftPM Cache - id: cache-save - if: ${{ steps.xcode-cache-restore.outputs.cache-hit != 'true' }} - uses: actions/cache/save@v3 - with: - path: | - ~/Library/Developer/Xcode/DerivedData - ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-tests-${{ github.ref_name }}-${{ github.sha }} - - - name: (Tests-Build) List Files and Build artifacts - if: always() - shell: bash - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - ls -la . - echo "" - - echo ">>>>>>>>> Build <<<<<<<<<<" - find build -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<" - find ~/Library/Developer/Xcode/DerivedData -maxdepth 8 -exec ls -ld {} + | grep "Build/Products" >> tests-build-deriveddata.txt || true - echo "" - - - uses: actions/upload-artifact@v4 - if: always() - with: - name: tests-build-deriveddata-${{ inputs.short_commit }}.txt - path: tests-build-deriveddata.txt - - - name: Encrypt tests-build-logs for upload - id: encrypt-test-log - if: always() - shell: bash - run: | - DEFAULT_BUILD_LOG_PASSWORD=12345 - - BUILD_LOG_ZIP_PASSWORD=${{ secrets.BUILD_LOG_ZIP_PASSWORD }} - BUILD_LOG_ZIP_PASSWORD=${BUILD_LOG_ZIP_PASSWORD:-$DEFAULT_BUILD_LOG_PASSWORD} - - if [ "$BUILD_LOG_ZIP_PASSWORD" == "$DEFAULT_BUILD_LOG_PASSWORD" ]; then - echo "Warning: BUILD_LOG_ZIP_PASSWORD is not set. Defaulting to '${DEFAULT_BUILD_LOG_PASSWORD}'." - fi - - pushd build/logs && zip -e -P "$BUILD_LOG_ZIP_PASSWORD" ../../encrypted-tests-build-logs.zip * || popd - echo "::set-output name=encrypted::true" - - - name: Upload encrypted-tests-build-logs.zip - id: attach-encrypted-test-log - if: always() && steps.encrypt-test-log.outputs.encrypted == 'true' - uses: actions/upload-artifact@v4 - with: - name: encrypted-tests-build-logs-${{ inputs.short_commit }}.zip - path: encrypted-tests-build-logs.zip \ No newline at end of file diff --git a/.github/workflows/obsolete/sidestore-tests-run.yml b/.github/workflows/obsolete/sidestore-tests-run.yml deleted file mode 100644 index b2b4dadf..00000000 --- a/.github/workflows/obsolete/sidestore-tests-run.yml +++ /dev/null @@ -1,196 +0,0 @@ -name: SideStore Tests Run - -on: - workflow_call: - inputs: - release_tag: - type: string - short_commit: - type: string - secrets: - BUILD_LOG_ZIP_PASSWORD: - required: false - -jobs: - tests-run: - name: Tests-Run SideStore - ${{ inputs.release_tag }} - if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }} - strategy: - fail-fast: false - matrix: - include: - - os: 'macos-26' - version: '26.0' - runs-on: ${{ matrix.os }} - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Boot Simulator async(nohup) for testing - run: | - mkdir -p build/logs - nohup make -B boot-sim-async > build/logs/tests-run.log 2>&1 & - shell: bash - - - name: Setup Xcode - uses: maxim-lobanov/setup-xcode@v1.6.0 - with: - xcode-version: '26.0' - - # - name: (Tests-Run) Cache Build - # uses: irgaly/xcode-cache@v1.8.1 - # with: - # # This comes from - # key: xcode-cache-deriveddata-test-${{ github.ref_name }}-${{ github.sha }} - # swiftpm-cache-key: xcode-cache-sourcedata-test-${{ github.ref_name }}-${{ github.sha }} - - - name: (Tests-Build) Restore Xcode & SwiftPM Cache (Exact match) [from tests-build job] - id: xcode-cache-restore - uses: actions/cache/restore@v3 - with: - path: | - ~/Library/Developer/Xcode/DerivedData - ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-tests-${{ github.ref_name }}-${{ github.sha }} - - - name: (Tests-Run) Clean previous build artifacts - run: | - make clean - mkdir -p build/logs - shell: bash - - - name: (Tests-Run) List Files and derived data - shell: bash - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - ls -la . - echo "" - - echo ">>>>>>>>> SideStore <<<<<<<<<<" - find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Dependencies <<<<<<<<<<" - find Dependencies -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<" - find ~/Library/Developer/Xcode/DerivedData -maxdepth 8 -exec ls -ld {} + | grep "Build/Products" >> tests-run-deriveddata.txt || true - echo "" - - - uses: actions/upload-artifact@v4 - if: always() - with: - name: tests-run-deriveddata-${{ inputs.short_commit }}.txt - path: tests-run-deriveddata.txt - - # we expect simulator to have been booted by now, so exit otherwise - - name: Simulator Boot Check - run: | - mkdir -p build/logs - make -B sim-boot-check | tee -a build/logs/tests-run.log - exit ${PIPESTATUS[0]} - shell: bash - - - name: Start Recording UI tests (if DEBUG_RECORD_TESTS is set to 1) - if: ${{ vars.DEBUG_RECORD_TESTS == '1' }} - run: | - nohup xcrun simctl io booted recordVideo -f tests-recording.mp4 --codec h264 tests-recording.log 2>&1 & - RECORD_PID=$! - echo "RECORD_PID=$RECORD_PID" >> $GITHUB_ENV - shell: bash - - - name: Run SideStore Tests - # using 'tee' to intercept stdout and log for detailed build-log - run: | - make run-tests 2>&1 | tee -a build/logs/tests-run.log && exit ${PIPESTATUS[0]} - # NSUnbufferedIO=YES make -B run-tests 2>&1 | tee build/logs/tests-run.log | xcpretty -r junit --output ./build/tests/test-results.xml && exit ${PIPESTATUS[0]} - shell: bash - - - name: Stop Recording tests - if: ${{ always() && env.RECORD_PID != '' }} - run: | - kill -INT ${{ env.RECORD_PID }} - shell: bash - - - name: (Tests-Run) List Files and Build artifacts - if: always() - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - ls -la . - echo "" - - echo ">>>>>>>>> Build <<<<<<<<<<" - find build -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists - echo "" - shell: bash - - - name: Encrypt tests-run-logs for upload - id: encrypt-test-log - if: always() - run: | - DEFAULT_BUILD_LOG_PASSWORD=12345 - - BUILD_LOG_ZIP_PASSWORD=${{ secrets.BUILD_LOG_ZIP_PASSWORD }} - BUILD_LOG_ZIP_PASSWORD=${BUILD_LOG_ZIP_PASSWORD:-$DEFAULT_BUILD_LOG_PASSWORD} - - if [ "$BUILD_LOG_ZIP_PASSWORD" == "$DEFAULT_BUILD_LOG_PASSWORD" ]; then - echo "Warning: BUILD_LOG_ZIP_PASSWORD is not set. Defaulting to '${DEFAULT_BUILD_LOG_PASSWORD}'." - fi - - pushd build/logs && zip -e -P "$BUILD_LOG_ZIP_PASSWORD" ../../encrypted-tests-run-logs.zip * || popd - echo "::set-output name=encrypted::true" - shell: bash - - - name: Upload encrypted-tests-run-logs.zip - id: attach-encrypted-test-log - if: always() && steps.encrypt-test-log.outputs.encrypted == 'true' - uses: actions/upload-artifact@v4 - with: - name: encrypted-tests-run-logs-${{ inputs.short_commit }}.zip - path: encrypted-tests-run-logs.zip - - - name: Print tests-recording.log contents (if exists) - if: ${{ always() && env.RECORD_PID != '' }} - run: | - if [ -f tests-recording.log ]; then - echo "tests-recording.log found. Its contents:" - cat tests-recording.log - else - echo "tests-recording.log not found." - fi - shell: bash - - - name: Check for tests-recording.mp4 presence - id: check-recording - if: ${{ always() && env.RECORD_PID != '' }} - run: | - if [ -f tests-recording.mp4 ]; then - echo "::set-output name=found::true" - echo "tests-recording.mp4 found." - else - echo "tests-recording.mp4 not found, skipping upload." - echo "::set-output name=found::false" - fi - shell: bash - - - name: Upload tests-recording.mp4 - id: upload-recording - if: ${{ always() && steps.check-recording.outputs.found == 'true' }} - uses: actions/upload-artifact@v4 - with: - name: tests-recording-${{ inputs.short_commit }}.mp4 - path: tests-recording.mp4 - - - name: Zip test-results - run: zip -r -9 ./test-results.zip ./build/tests - shell: bash - - - name: Upload Test Artifacts - uses: actions/upload-artifact@v4 - with: - name: test-results-${{ inputs.short_commit }}.zip - path: test-results.zip From 16bb57c82510fb959e02481c325868f2cc950489 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:51:25 +0530 Subject: [PATCH 13/22] ci: use proper messaging for upstream tag --- scripts/ci/workflow.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index c431c6b9..439d1856 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -396,7 +396,7 @@ def last_successful_commit(workflow, branch): return None -def upload_release(release_name, release_tag, commit_sha, repo, upstream_recommendation): +def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_recommended): token = getenv("GH_TOKEN") if token: os.environ["GH_TOKEN"] = token @@ -432,8 +432,13 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_recomme ) upstream_block = "" - if upstream_recommendation and upstream_recommendation.strip(): - upstream_block = f"{upstream_recommendation.strip()}\n\n" + if upstream_tag_recommended and upstream_tag_recommended.strip(): + tag = upstream_tag_recommended.strip() + upstream_block = ( + f"If you want to try out new features early but want a lower chance of bugs, " + f"you can look at [SideStore {tag}]" + f"(https://github.com/{repo}/releases?q={tag}).\n\n" + ) header = getFormattedUploadMsg(release_name, release_tag, commit_sha, repo, upstream_block, built_time, built_date, marketing_version) body = header + "\n\n" + release_notes.lstrip() + "\n" @@ -529,7 +534,7 @@ COMMANDS = { "retrieve-release-notes" : (retrieve_release_notes, 1, ""), "deploy" : (deploy, 9, " [last_successful_commit]"), - "upload-release" : (upload_release, 5, " "), + "upload-release" : (upload_release, 5, " "), } def main(): From fd920be3bf1cffcceda8cd5957369d33c24a2d82 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 21:15:28 +0530 Subject: [PATCH 14/22] ci: updated PR workflow to reflect latest --- .github/workflows/pr.yml | 132 ++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 70 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 29b9fe32..22d96e63 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -1,98 +1,90 @@ name: Pull Request SideStore build + on: pull_request: # types: [opened, synchronize, reopened, ready_for_review, converted_to_draft] types: [opened, synchronize, reopened, ready_for_review] +concurrency: + group: pr-${{ github.event.pull_request.number }} + cancel-in-progress: true + jobs: build: name: Build and upload SideStore if: ${{ github.event.pull_request.draft == false }} - strategy: - fail-fast: false - matrix: - include: - - os: 'macos-14' - version: '16.1' + runs-on: macos-26 - runs-on: ${{ matrix.os }} steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: submodules: recursive + fetch-depth: 1 # shallow clone just for PR - - name: Install dependencies - run: brew install ldid + - run: brew install ldid xcbeautify - - name: Install xcbeautify - run: brew install xcbeautify - - - name: Add PR suffix to version - run: sed -e "/MARKETING_VERSION = .*/s/\$/-pr.${{ github.event.pull_request.number }}+$(git rev-parse --short ${COMMIT:-HEAD})/" -i '' Build.xcconfig - env: - COMMIT: ${{ github.event.pull_request.head.sha }} - - - name: Get version - id: version - run: echo "version=$(grep MARKETING_VERSION Build.xcconfig | sed -e "s/MARKETING_VERSION = //g")" >> $GITHUB_OUTPUT - - - name: Echo version - run: echo "${{ steps.version.outputs.version }}" + - name: Setup Env + run: | + MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) + SHORT_COMMIT=$(git rev-parse --short ${{ github.event.pull_request.head.sha }}) + QUALIFIED_VERSION="${MARKETING_VERSION}-pr.${{ github.event.pull_request.number }}+${SHORT_COMMIT}" + python3 scripts/ci/workflow.py set-marketing-version "$QUALIFIED_VERSION" + echo "SHORT_COMMIT=$SHORT_COMMIT" | tee -a $GITHUB_ENV + echo "MARKETING_VERSION=$QUALIFIED_VERSION" | tee -a $GITHUB_ENV - name: Setup Xcode uses: maxim-lobanov/setup-xcode@v1.6.0 with: - xcode-version: ${{ matrix.version }} + xcode-version: "26.2" - - name: Cache Build - uses: irgaly/xcode-cache@v1 + - name: Restore Cache (exact) + id: xcode-cache-exact + uses: actions/cache/restore@v3 with: - key: xcode-cache-deriveddata-${{ github.sha }} - restore-keys: xcode-cache-deriveddata- - swiftpm-cache-key: xcode-cache-sourcedata-${{ github.sha }} - swiftpm-cache-restore-keys: | - xcode-cache-sourcedata- + path: | + ~/Library/Developer/Xcode/DerivedData + ~/Library/Caches/org.swift.swiftpm + key: xcode-build-cache-${{ github.ref_name }}-${{ github.sha }} - - name: List Files and derived data + - name: Restore Cache (last) + if: steps.xcode-cache-exact.outputs.cache-hit != 'true' + id: xcode-cache-fallback + uses: actions/cache/restore@v3 + with: + path: | + ~/Library/Developer/Xcode/DerivedData + ~/Library/Caches/org.swift.swiftpm + key: xcode-build-cache-${{ github.ref_name }}- + + - name: Build + env: + BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }} run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - ls -la . - echo "" - - echo ">>>>>>>>> SideStore <<<<<<<<<<" - find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Dependencies <<<<<<<<<<" - find Dependencies -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<" - ls -la ~/Library/Developer/Xcode/DerivedData || true # List contents if directory exists - echo "" + python3 scripts/ci/workflow.py build; STATUS=$? + python3 scripts/ci/workflow.py encrypt-build + mv SideStore.ipa SideStore-${{ env.MARKETING_VERSION }}.ipa + exit $STATUS - - - name: Build SideStore - run: NSUnbufferedIO=YES make build 2>&1 | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]} - - - name: Fakesign app - run: make fakesign - - - name: Convert to IPA - run: make ipa - - - name: Add version to IPA file name - run: mv SideStore.ipa SideStore-${{ steps.version.outputs.version }}.ipa - - - name: Upload SideStore.ipa Artifact - uses: actions/upload-artifact@v4 + - name: Save Cache + if: ${{ steps.xcode-cache-fallback.outputs.cache-hit != 'true' }} + uses: actions/cache/save@v3 with: - name: SideStore-${{ steps.version.outputs.version }}.ipa - path: SideStore-${{ steps.version.outputs.version }}.ipa + path: | + ~/Library/Developer/Xcode/DerivedData + ~/Library/Caches/org.swift.swiftpm + key: xcode-build-cache-${{ github.ref_name }}-${{ github.sha }} - - name: Upload *.dSYM Artifact - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v4 with: - name: SideStore-${{ steps.version.outputs.version }}-dSYM - path: ./SideStore.xcarchive/dSYMs/* + name: encrypted-build-logs-${{ env.MARKETING_VERSION }}.zip + path: encrypted-build-logs.zip + + - uses: actions/upload-artifact@v4 + with: + name: SideStore-${{ env.MARKETING_VERSION }}.ipa + path: SideStore-${{ env.MARKETING_VERSION }}.ipa + + - uses: actions/upload-artifact@v4 + with: + name: SideStore-${{ env.MARKETING_VERSION }}-dSYMs.zip + path: SideStore.dSYMs.zip From 21bbcd69f851acfd4aba341b1371cbdf30c21248 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Tue, 24 Feb 2026 22:07:36 +0530 Subject: [PATCH 15/22] ci: updated stable workflow as per workflow.py and other workflows --- .github/workflows/stable.yml | 250 +++++++++-------------------------- scripts/ci/workflow.py | 44 ++++-- 2 files changed, 97 insertions(+), 197 deletions(-) diff --git a/.github/workflows/stable.yml b/.github/workflows/stable.yml index b8edd762..978d03a2 100644 --- a/.github/workflows/stable.yml +++ b/.github/workflows/stable.yml @@ -1,242 +1,116 @@ name: Stable SideStore build + on: push: tags: - - '[0-9]+.[0-9]+.[0-9]+' # example: 1.0.0 + - '[0-9]+.[0-9]+.[0-9]+' workflow_dispatch: +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + jobs: build: - name: Build SideStore - stable (on tag push) - strategy: - fail-fast: false - matrix: - include: - - os: 'macos-26' - version: '26.0' - runs-on: ${{ matrix.os }} + name: Build SideStore - stable + runs-on: macos-26 + + env: + RELEASE_NAME: Stable + CHANNEL: stable + UPSTREAM_CHANNEL: "" steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: submodules: recursive + fetch-depth: 0 - - name: Echo Build.xcconfig + - run: brew install ldid xcbeautify + + - name: Setup Env run: | - echo "cat Build.xcconfig" - cat Build.xcconfig - shell: bash + MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) + SHORT_COMMIT=$(python3 scripts/ci/workflow.py commit-id) - # - name: Change MARKETING_VERSION to the pushed tag that triggered this build - # run: sed -e '/MARKETING_VERSION = .*/s/= .*/= ${{ github.ref_name }}/' -i '' Build.xcconfig - - - name: Echo Updated Build.xcconfig - run: | - cat Build.xcconfig - shell: bash - - - name: Extract MARKETING_VERSION from Build.xcconfig - id: version - run: | - version=$(grep MARKETING_VERSION Build.xcconfig | sed -e 's/MARKETING_VERSION = //g') - echo "version=$version" >> $GITHUB_OUTPUT - echo "version=$version" - - echo "MARKETING_VERSION=$version" >> $GITHUB_ENV - echo "MARKETING_VERSION=$version" >> $GITHUB_OUTPUT - echo "MARKETING_VERSION=$version" - - shell: bash - - - name: Fail the build if pushed tag and embedded MARKETING_VERSION in Build.xcconfig are mismatching - run: | if [ "$MARKETING_VERSION" != "${{ github.ref_name }}" ]; then - echo 'Version mismatch: $tag != $marketing_version ... ' - echo " expected-tag : $MARKETING_VERSION" - echo " pushed-tag : ${{ github.ref_name }}" + echo "Version mismatch" + echo "Build.xcconfig: $MARKETING_VERSION" + echo "Tag: ${{ github.ref_name }}" exit 1 fi - echo 'Version matches: $tag == $marketing_version ... ' - echo " expected-tag : $MARKETING_VERSION" - echo " pushed-tag : ${{ github.ref_name }}" - shell: bash - - name: Install dependencies - ldid & xcbeautify - run: | - brew install ldid xcbeautify + echo "MARKETING_VERSION=$MARKETING_VERSION" | tee -a $GITHUB_ENV + echo "SHORT_COMMIT=$SHORT_COMMIT" | tee -a $GITHUB_ENV - name: Setup Xcode uses: maxim-lobanov/setup-xcode@v1.6.0 with: - xcode-version: ${{ matrix.version }} + xcode-version: "26.0" - - name: (Build) Restore Xcode & SwiftPM Cache (Exact match) - id: xcode-cache-restore + - name: Restore Cache (exact) + id: xcode-cache-exact uses: actions/cache/restore@v3 with: path: | ~/Library/Developer/Xcode/DerivedData ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-build-stable-${{ github.sha }} + key: xcode-build-cache-stable-${{ github.sha }} - - name: (Build) Restore Xcode & SwiftPM Cache (Last Available) - id: xcode-cache-restore-recent + - name: Restore Cache (last) + if: steps.xcode-cache-exact.outputs.cache-hit != 'true' + id: xcode-cache-fallback uses: actions/cache/restore@v3 with: path: | ~/Library/Developer/Xcode/DerivedData ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-build-stable- + key: xcode-build-cache-stable- - - name: (Build) Clean previous build artifacts + - name: Clean + run: python3 scripts/ci/workflow.py clean + + - name: Build + id: build + env: + BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }} run: | - make clean - mkdir -p build/logs - shell: bash + python3 scripts/ci/workflow.py build; STATUS=$? + python3 scripts/ci/workflow.py encrypt-build + exit $STATUS - - name: (Build) List Files and derived data - if: always() - shell: bash - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - ls -la . - echo "" - - echo ">>>>>>>>> SideStore <<<<<<<<<<" - find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Dependencies <<<<<<<<<<" - find Dependencies -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<" - ls -la ~/Library/Developer/Xcode/DerivedData || true # List contents if directory exists - echo "" - - - name: Build SideStore.xcarchive - # using 'tee' to intercept stdout and log for detailed build-log - run: | - NSUnbufferedIO=YES make -B build 2>&1 | tee -a build/logs/build.log | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]} - shell: bash - - - name: Fakesign app - run: make fakesign | tee -a build/logs/build.log - shell: bash - - - name: Convert to IPA - run: make ipa | tee -a build/logs/build.log - shell: bash - - - name: (Build) Save Xcode & SwiftPM Cache - id: cache-save - if: ${{ steps.xcode-cache-restore.outputs.cache-hit != 'true' }} + - name: Save Cache + if: ${{ steps.xcode-cache-fallback.outputs.cache-hit != 'true' }} uses: actions/cache/save@v3 with: path: | ~/Library/Developer/Xcode/DerivedData ~/Library/Caches/org.swift.swiftpm - key: xcode-cache-build-stable-${{ github.sha }} - - - name: (Build) List Files and Build artifacts - run: | - echo ">>>>>>>>> Workdir <<<<<<<<<<" - ls -la . - echo "" + key: xcode-build-cache-stable-${{ github.sha }} - echo ">>>>>>>>> Build <<<<<<<<<<" - find build -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> SideStore <<<<<<<<<<" - find SideStore -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> SideStore.xcarchive <<<<<<<<<<" - find SideStore.xcarchive -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists - echo "" - - echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<" - ls -la ~/Library/Developer/Xcode/DerivedData || true # List contents if directory exists - echo "" - shell: bash - - - name: Encrypt build-logs for upload - id: encrypt-build-log - run: | - DEFAULT_BUILD_LOG_PASSWORD=12345 - - BUILD_LOG_ZIP_PASSWORD=${{ secrets.BUILD_LOG_ZIP_PASSWORD }} - BUILD_LOG_ZIP_PASSWORD=${BUILD_LOG_ZIP_PASSWORD:-$DEFAULT_BUILD_LOG_PASSWORD} - - if [ "$BUILD_LOG_ZIP_PASSWORD" == "$DEFAULT_BUILD_LOG_PASSWORD" ]; then - echo "Warning: BUILD_LOG_ZIP_PASSWORD is not set. Defaulting to '${DEFAULT_BUILD_LOG_PASSWORD}'." - fi - - pushd build/logs && zip -e -P "$BUILD_LOG_ZIP_PASSWORD" ../../encrypted-build-logs.zip * || popd - echo "::set-output name=encrypted::true" - shell: bash - - - name: Upload encrypted-build-logs.zip - id: attach-encrypted-build-log - if: ${{ always() && steps.encrypt-build-log.outputs.encrypted == 'true' }} - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v4 with: - name: encrypted-build-logs-${{ steps.version.outputs.version }}.zip + name: encrypted-build-logs-${{ env.MARKETING_VERSION }}.zip path: encrypted-build-logs.zip - - name: Upload SideStore.ipa Artifact - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v4 with: - name: SideStore-${{ steps.version.outputs.version }}.ipa + name: SideStore-${{ env.MARKETING_VERSION }}.ipa path: SideStore.ipa - - name: Zip dSYMs - run: zip -r -9 ./SideStore.dSYMs.zip ./SideStore.xcarchive/dSYMs - shell: bash - - - name: Upload *.dSYM Artifact - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v4 with: - name: SideStore-${{ steps.version.outputs.version }}-dSYMs.zip + name: SideStore-${{ env.MARKETING_VERSION }}-dSYMs.zip path: SideStore.dSYMs.zip - - name: Get current date - id: date - run: echo "date=$(date -u +'%c')" >> $GITHUB_OUTPUT - shell: bash - - - name: Get current date in AltStore date form - id: date_altstore - run: echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT - shell: bash - - name: Upload to releases - uses: IsaacShelton/update-existing-release@v1.3.1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - draft: true - release: ${{ github.ref_name }} # name - tag: ${{ github.ref_name }} - # stick with what the user pushed, do not use latest commit or anything, - # ex: if we want to go back to previous release due to hot issue, dev can create a new tag pointing to that older working tag/commit so as to keep it as an update (to revert major issue) - # in this case we do not want the tag to be auto-updated to latest - updateTag: false - prerelease: false - files: > - SideStore.ipa - SideStore.dSYMs.zip - encrypted-build-logs.zip - body: | - - ## Changelog - - - TODO - - ## Build Info - - Built at (UTC): `${{ steps.date.outputs.date }}` - Built at (UTC date): `${{ steps.date_altstore.outputs.date }}` - Commit SHA: `${{ github.sha }}` - Version: `${{ steps.version.outputs.version }}` + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + python3 scripts/ci/workflow.py upload-release \ + "$RELEASE_NAME" \ + "${{ github.ref_name }}" \ + "$GITHUB_SHA" \ + "$GITHUB_REPOSITORY" \ + "$UPSTREAM_CHANNEL" \ + "true" diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index 439d1856..78874d50 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -396,7 +396,18 @@ def last_successful_commit(workflow, branch): return None -def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_recommended): +def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_recommended, is_stable=False): + is_stable = str(is_stable).lower() in ("1", "true", "yes") + + if is_stable: + draft = True # always create a draft for stable and let user publish release + update_tag = False + prerelease = False + else: + draft = False + update_tag = True # update existing + prerelease = True + token = getenv("GH_TOKEN") if token: os.environ["GH_TOKEN"] = token @@ -423,7 +434,7 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_rec f"--retrieve {release_tag} " f"--output-dir {ROOT}" ) - # normalize section header + release_notes = re.sub( r'^\s*#{1,6}\s*what(?:\'?s|\s+is)?\s+(?:new|changed).*', "## What's Changed", @@ -440,19 +451,27 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_rec f"(https://github.com/{repo}/releases?q={tag}).\n\n" ) - header = getFormattedUploadMsg(release_name, release_tag, commit_sha, repo, upstream_block, built_time, built_date, marketing_version) - body = header + "\n\n" + release_notes.lstrip() + "\n" + header = getFormattedUploadMsg( + release_name, commit_sha, repo, upstream_block, + built_time, built_date, marketing_version, is_stable, + ) + + body = header + release_notes.lstrip() + "\n" body_file = ROOT / "release_body.md" body_file.write_text(body, encoding="utf-8") prerelease_flag = "--prerelease" if is_beta else "" + draft_flag = "--draft" if draft else "" + prerelease_flag = "--prerelease" if prerelease else "" + latest_flag = "" if update_tag else "--latest=false" + run( f'gh release edit "{release_tag}" ' f'--title "{release_name}" ' f'--notes-file "{body_file}" ' - f'{prerelease_flag}' + f'{draft_flag} {prerelease_flag} {latest_flag}' ) run( @@ -461,19 +480,26 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_rec f'--clobber' ) -def getFormattedUploadMsg(release_name, release_tag, commit_sha, repo, upstream_block, built_time, built_date, marketing_version): - return f""" + +def getFormattedUploadMsg(release_name, commit_sha, repo, upstream_block, built_time, built_date, marketing_version, is_stable): + experimental_header = "" + if not is_stable: + experimental_header = f""" This is an ⚠️ **EXPERIMENTAL** ⚠️ {release_name} build for commit [{commit_sha}](https://github.com/{repo}/commit/{commit_sha}). {release_name} builds are **extremely experimental builds only meant to be used by developers and beta testers. They often contain bugs and experimental features. Use at your own risk!** -{upstream_block}## Build Info +""".lstrip("\n") + + header = f""" +{experimental_header}{upstream_block}## Build Info Built at (UTC): `{built_time}` Built at (UTC date): `{built_date}` Commit SHA: `{commit_sha}` Version: `{marketing_version}` """.lstrip("\n") + return header # ---------------------------------------------------------- # ENTRYPOINT @@ -534,7 +560,7 @@ COMMANDS = { "retrieve-release-notes" : (retrieve_release_notes, 1, ""), "deploy" : (deploy, 9, " [last_successful_commit]"), - "upload-release" : (upload_release, 5, " "), + "upload-release" : (upload_release, 5, " [is_stable]"), } def main(): From 1ad0fe23fcbfc9f122fe7fc2e56f90a228bf02cd Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Wed, 25 Feb 2026 00:04:42 +0530 Subject: [PATCH 16/22] ci: fix - version number was inconsistent across deployment of beta channels --- .github/workflows/alpha.yml | 7 +++---- .github/workflows/nightly.yml | 7 +++---- .github/workflows/pr.yml | 6 +++--- scripts/ci/workflow.py | 14 +++++++------- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 5ba3efb9..76cc8fe5 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -50,17 +50,16 @@ jobs: MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) SHORT_COMMIT=$(python3 scripts/ci/workflow.py commit-id) - QUALIFIED_VERSION=$(python3 scripts/ci/workflow.py compute-qualified \ + NORMALIZED_VERSION=$(python3 scripts/ci/workflow.py compute-normalized \ "$MARKETING_VERSION" \ "$BUILD_NUM" \ - "${{ env.CHANNEL }}" \ "$SHORT_COMMIT") - python3 scripts/ci/workflow.py set-marketing-version "$QUALIFIED_VERSION" + python3 scripts/ci/workflow.py set-marketing-version "$NORMALIZED_VERSION" echo "BUILD_NUM=$BUILD_NUM" | tee -a $GITHUB_ENV echo "SHORT_COMMIT=$SHORT_COMMIT" | tee -a $GITHUB_ENV - echo "MARKETING_VERSION=$QUALIFIED_VERSION" | tee -a $GITHUB_ENV + echo "MARKETING_VERSION=$NORMALIZED_VERSION" | tee -a $GITHUB_ENV - name: Setup Xcode uses: maxim-lobanov/setup-xcode@v1.6.0 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 8c4be197..89dc7263 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -74,17 +74,16 @@ jobs: MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) SHORT_COMMIT=$(python3 scripts/ci/workflow.py commit-id) - QUALIFIED_VERSION=$(python3 scripts/ci/workflow.py compute-qualified \ + NORMALIZED_VERSION=$(python3 scripts/ci/workflow.py compute-normalized \ "$MARKETING_VERSION" \ "$BUILD_NUM" \ - "${{ env.CHANNEL }}" \ "$SHORT_COMMIT") - python3 scripts/ci/workflow.py set-marketing-version "$QUALIFIED_VERSION" + python3 scripts/ci/workflow.py set-marketing-version "$NORMALIZED_VERSION" echo "BUILD_NUM=$BUILD_NUM" | tee -a $GITHUB_ENV echo "SHORT_COMMIT=$SHORT_COMMIT" | tee -a $GITHUB_ENV - echo "MARKETING_VERSION=$QUALIFIED_VERSION" | tee -a $GITHUB_ENV + echo "MARKETING_VERSION=$NORMALIZED_VERSION" | tee -a $GITHUB_ENV - name: Setup Xcode if: steps.build_gate.outputs.should_skip != 'true' diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 22d96e63..931084a1 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -27,10 +27,10 @@ jobs: run: | MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) SHORT_COMMIT=$(git rev-parse --short ${{ github.event.pull_request.head.sha }}) - QUALIFIED_VERSION="${MARKETING_VERSION}-pr.${{ github.event.pull_request.number }}+${SHORT_COMMIT}" - python3 scripts/ci/workflow.py set-marketing-version "$QUALIFIED_VERSION" + NORMALIZED_VERSION="${MARKETING_VERSION}-pr.${{ github.event.pull_request.number }}+${SHORT_COMMIT}" + python3 scripts/ci/workflow.py set-marketing-version "$NORMALIZED_VERSION" echo "SHORT_COMMIT=$SHORT_COMMIT" | tee -a $GITHUB_ENV - echo "MARKETING_VERSION=$QUALIFIED_VERSION" | tee -a $GITHUB_ENV + echo "MARKETING_VERSION=$NORMALIZED_VERSION" | tee -a $GITHUB_ENV - name: Setup Xcode uses: maxim-lobanov/setup-xcode@v1.6.0 diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index 78874d50..1881af9e 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -181,9 +181,12 @@ def set_marketing_version(qualified): f"{ROOT}/Build.xcconfig" ) -def compute_qualified_version(marketing, build_num, channel, short): - date = datetime.datetime.now(datetime.UTC).strftime("%Y.%m.%d") - return f"{marketing}-{channel}.{date}.{build_num}+{short}" + +def compute_qualified_version(marketing, build_num, short): + now = datetime.datetime.now(datetime.UTC) + date = now.strftime("%Y%m%d") # normalized date + base = marketing.strip() + return f"{base}-{date}.{build_num}+{short}" # ---------------------------------------------------------- # CLEAN @@ -420,7 +423,6 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_rec meta = json.loads(metadata_path.read_text()) marketing_version = meta.get("version_ipa") - is_beta = bool(meta.get("is_beta")) build_datetime = meta.get("version_date") dt = datetime.datetime.fromisoformat( @@ -461,8 +463,6 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_rec body_file = ROOT / "release_body.md" body_file.write_text(body, encoding="utf-8") - prerelease_flag = "--prerelease" if is_beta else "" - draft_flag = "--draft" if draft else "" prerelease_flag = "--prerelease" if prerelease else "" latest_flag = "" if update_tag else "--latest=false" @@ -517,7 +517,7 @@ COMMANDS = { # ---------------------------------------------------------- "get-marketing-version" : (get_marketing_version, 0, ""), "set-marketing-version" : (set_marketing_version, 1, ""), - "compute-qualified" : (compute_qualified_version, 4, " "), + "compute-qualified" : (compute_qualified_version, 3, " "), "reserve_build_number" : (reserve_build_number, 1, ""), "get-product-name" : (get_product_name, 0, ""), "get-bundle-id" : (get_bundle_id, 0, ""), From d06520d46ff4924a0510a49fad5704dd9eab6916 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Wed, 25 Feb 2026 00:08:41 +0530 Subject: [PATCH 17/22] ci: fix - tag was not pushed --- scripts/ci/workflow.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index 1881af9e..55229760 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -480,6 +480,9 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_rec f'--clobber' ) + run(f'git tag -f "{release_tag}" "{commit_sha}"') + run(f'git push origin "refs/tags/{release_tag}" --force') + def getFormattedUploadMsg(release_name, commit_sha, repo, upstream_block, built_time, built_date, marketing_version, is_stable): experimental_header = "" From 7df29ca23b94bb11f880c9d5cc4b459ea0433d5d Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Wed, 25 Feb 2026 00:10:40 +0530 Subject: [PATCH 18/22] ci: fixes in workflow.py --- scripts/ci/workflow.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index 55229760..f7bfaf2a 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -174,15 +174,15 @@ def read_bundle_id(): return _read_dumped_build_setting("PRODUCT_BUNDLE_IDENT def get_marketing_version(): return runAndGet(f"grep MARKETING_VERSION {ROOT}/Build.xcconfig | sed -e 's/MARKETING_VERSION = //g'") -def set_marketing_version(qualified): +def set_marketing_version(version): run( f"sed -E -i '' " - f"'s/^MARKETING_VERSION = .*/MARKETING_VERSION = {qualified}/' " + f"'s/^MARKETING_VERSION = .*/MARKETING_VERSION = {version}/' " f"{ROOT}/Build.xcconfig" ) -def compute_qualified_version(marketing, build_num, short): +def compute_normalized_version(marketing, build_num, short): now = datetime.datetime.now(datetime.UTC) date = now.strftime("%Y%m%d") # normalized date base = marketing.strip() @@ -519,8 +519,8 @@ COMMANDS = { # PROJECT INFO # ---------------------------------------------------------- "get-marketing-version" : (get_marketing_version, 0, ""), - "set-marketing-version" : (set_marketing_version, 1, ""), - "compute-qualified" : (compute_qualified_version, 3, " "), + "set-marketing-version" : (set_marketing_version, 1, ""), + "compute-normalized" : (compute_normalized_version, 3, " "), "reserve_build_number" : (reserve_build_number, 1, ""), "get-product-name" : (get_product_name, 0, ""), "get-bundle-id" : (get_bundle_id, 0, ""), From 9efea00d09e230bddbf9ddafb91f03736703553d Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Wed, 25 Feb 2026 00:25:11 +0530 Subject: [PATCH 19/22] ci: use runner number as build number --- .github/workflows/alpha.yml | 27 ++++++++------ .github/workflows/nightly.yml | 29 +++++++-------- scripts/ci/workflow.py | 70 +---------------------------------- 3 files changed, 30 insertions(+), 96 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 76cc8fe5..f034fe14 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -36,17 +36,9 @@ jobs: # -------------------------------------------------- # runtime env setup # -------------------------------------------------- - - uses: actions/checkout@v4 - with: - repository: "SideStore/beta-build-num" - ref: ${{ env.CHANNEL }} - token: ${{ secrets.CROSS_REPO_PUSH_KEY }} - path: "Dependencies/beta-build-num" - fetch-depth: 1 - - name: Setup Env run: | - BUILD_NUM=$(python3 scripts/ci/workflow.py reserve_build_number 'Dependencies/beta-build-num') + BUILD_NUM="${{ github.run_number }}" MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) SHORT_COMMIT=$(python3 scripts/ci/workflow.py commit-id) @@ -180,6 +172,9 @@ jobs: path: SideStore.dSYMs.zip - uses: actions/checkout@v4 + if: > + steps.build_gate.outputs.should_skip != 'true' && + secrets.CROSS_REPO_PUSH_KEY != '' with: repository: "SideStore/apps-v2.json" ref: "main" @@ -190,6 +185,9 @@ jobs: # deploy # -------------------------------------------------- - name: Deploy + if: > + steps.build_gate.outputs.should_skip != 'true' && + secrets.CROSS_REPO_PUSH_KEY != '' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -198,7 +196,7 @@ jobs: BUNDLE_ID=$(python3 scripts/ci/workflow.py read-bundle-id) SOURCE_JSON="_includes/source.json" IPA_NAME="$PRODUCT_NAME.ipa" - + python3 scripts/ci/workflow.py deploy \ SideStore/apps-v2.json \ "$SOURCE_JSON" \ @@ -210,8 +208,13 @@ jobs: "$IPA_NAME" \ "$LAST_SUCCESSFUL_COMMIT" - RELEASE_NOTES=$(python3 scripts/ci/workflow.py retrieve-release-notes "$CHANNEL") - + # -------------------------------------------------- + # upload release + # -------------------------------------------------- + - name: Upload Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | python3 scripts/ci/workflow.py upload-release \ "$RELEASE_NAME" \ "$CHANNEL" \ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 89dc7263..ad39d225 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -58,19 +58,10 @@ jobs: # -------------------------------------------------- # runtime env setup # -------------------------------------------------- - - uses: actions/checkout@v4 - if: steps.build_gate.outputs.should_skip != 'true' - with: - repository: "SideStore/beta-build-num" - ref: ${{ env.CHANNEL }} - token: ${{ secrets.CROSS_REPO_PUSH_KEY }} - path: "Dependencies/beta-build-num" - fetch-depth: 1 - - name: Setup Env if: steps.build_gate.outputs.should_skip != 'true' run: | - BUILD_NUM=$(python3 scripts/ci/workflow.py reserve_build_number 'Dependencies/beta-build-num') + BUILD_NUM="${{ github.run_number }}" MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version) SHORT_COMMIT=$(python3 scripts/ci/workflow.py commit-id) @@ -219,7 +210,9 @@ jobs: path: SideStore.dSYMs.zip - uses: actions/checkout@v4 - if: steps.build_gate.outputs.should_skip != 'true' + if: > + steps.build_gate.outputs.should_skip != 'true' && + secrets.CROSS_REPO_PUSH_KEY != '' with: repository: "SideStore/apps-v2.json" ref: "main" @@ -230,7 +223,7 @@ jobs: # deploy # -------------------------------------------------- - name: Deploy - if: steps.build_gate.outputs.should_skip != 'true' + if: steps.build_gate.outputs.should_skip != 'true' && secrets.CROSS_REPO_PUSH_KEY != '' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -239,7 +232,7 @@ jobs: BUNDLE_ID=$(python3 scripts/ci/workflow.py read-bundle-id) SOURCE_JSON="_includes/source.json" IPA_NAME="$PRODUCT_NAME.ipa" - + python3 scripts/ci/workflow.py deploy \ SideStore/apps-v2.json \ "$SOURCE_JSON" \ @@ -251,8 +244,14 @@ jobs: "$IPA_NAME" \ "$LAST_SUCCESSFUL_COMMIT" - RELEASE_NOTES=$(python3 scripts/ci/workflow.py retrieve-release-notes "$CHANNEL") - + # -------------------------------------------------- + # upload release + # -------------------------------------------------- + - name: Upload Release + if: steps.build_gate.outputs.should_skip != 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | python3 scripts/ci/workflow.py upload-release \ "$RELEASE_NAME" \ "$CHANNEL" \ diff --git a/scripts/ci/workflow.py b/scripts/ci/workflow.py index f7bfaf2a..43191f14 100644 --- a/scripts/ci/workflow.py +++ b/scripts/ci/workflow.py @@ -72,73 +72,6 @@ def count_new_commits(last_commit): except Exception: return 0 -# ---------------------------------------------------------- -# BUILD NUMBER RESERVATION -# ---------------------------------------------------------- -def reserve_build_number(repo, max_attempts=5): - repo = Path(repo).resolve() - version_json = repo / "version.json" - - def utc_now(): - return datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%SZ") - - def current_branch(): - return runAndGet("git rev-parse --abbrev-ref HEAD", cwd=repo) - - def sync_with_remote(branch): - run(f"git fetch --depth=1 origin {branch}", check=False, cwd=repo) - run(f"git reset --hard origin/{branch}", check=False, cwd=repo) - - def read(branch): - defaults = { - "build": 0, - "issued_at": utc_now(), - "tag": branch, - } - - if version_json.exists(): - data = json.loads(version_json.read_text()) - else: - data = {} - - for k, v in defaults.items(): - data.setdefault(k, v) - - data["tag"] = branch - version_json.write_text(json.dumps(data, indent=2) + "\n") - return data - - def write(data): - version_json.write_text(json.dumps(data, indent=2) + "\n") - - for attempt in range(max_attempts): - branch = current_branch() - sync_with_remote(branch) - - data = read(branch) - data["build"] += 1 - data["issued_at"] = utc_now() - - write(data) - - run("git add version.json", check=False, cwd=repo) - run( - f"git commit -m '{branch} - build no: {data['build']}' || true", - check=False, - cwd=repo, - ) - - rc = subprocess.call(f"git push origin {branch}", shell=True, cwd=repo) - - if rc == 0: - print(f"Reserved build #{data['build']}", file=sys.stderr) - return data["build"] - - print("Push rejected, retrying...", file=sys.stderr) - time.sleep(2) - - raise SystemExit("Failed reserving build number") - # ---------------------------------------------------------- # PROJECT INFO # ---------------------------------------------------------- @@ -520,8 +453,7 @@ COMMANDS = { # ---------------------------------------------------------- "get-marketing-version" : (get_marketing_version, 0, ""), "set-marketing-version" : (set_marketing_version, 1, ""), - "compute-normalized" : (compute_normalized_version, 3, " "), - "reserve_build_number" : (reserve_build_number, 1, ""), + "compute-normalized" : (compute_normalized_version,3, " "), "get-product-name" : (get_product_name, 0, ""), "get-bundle-id" : (get_bundle_id, 0, ""), "dump-project-settings" : (dump_project_settings, 0, ""), From eb251b89c9a4798ad52ec81053bd3faea8e0bf33 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Wed, 25 Feb 2026 00:30:07 +0530 Subject: [PATCH 20/22] ci: fixes for yml --- .github/workflows/alpha.yml | 9 +++------ .github/workflows/nightly.yml | 7 +++---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index f034fe14..8ada271f 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -13,6 +13,7 @@ jobs: build: runs-on: macos-26 env: + HAS_DEPLOY_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }} RELEASE_NAME: Alpha CHANNEL: alpha UPSTREAM_CHANNEL: "nightly" @@ -172,9 +173,7 @@ jobs: path: SideStore.dSYMs.zip - uses: actions/checkout@v4 - if: > - steps.build_gate.outputs.should_skip != 'true' && - secrets.CROSS_REPO_PUSH_KEY != '' + if: steps.build_gate.outputs.should_skip != 'true' && env.HAS_PUSH_KEY != '' with: repository: "SideStore/apps-v2.json" ref: "main" @@ -185,9 +184,7 @@ jobs: # deploy # -------------------------------------------------- - name: Deploy - if: > - steps.build_gate.outputs.should_skip != 'true' && - secrets.CROSS_REPO_PUSH_KEY != '' + if: steps.build_gate.outputs.should_skip != 'true' && env.HAS_PUSH_KEY != '' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index ad39d225..f5f7c6ce 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -15,6 +15,7 @@ jobs: build: runs-on: macos-26 env: + HAS_DEPLOY_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }} RELEASE_NAME: Nightly CHANNEL: nightly UPSTREAM_CHANNEL: "" @@ -210,9 +211,7 @@ jobs: path: SideStore.dSYMs.zip - uses: actions/checkout@v4 - if: > - steps.build_gate.outputs.should_skip != 'true' && - secrets.CROSS_REPO_PUSH_KEY != '' + if: steps.build_gate.outputs.should_skip != 'true' && env.HAS_PUSH_KEY != '' with: repository: "SideStore/apps-v2.json" ref: "main" @@ -223,7 +222,7 @@ jobs: # deploy # -------------------------------------------------- - name: Deploy - if: steps.build_gate.outputs.should_skip != 'true' && secrets.CROSS_REPO_PUSH_KEY != '' + if: steps.build_gate.outputs.should_skip != 'true' && env.HAS_PUSH_KEY != '' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | From ad54cbadc15455f53e7300cefbdda25bb6bc9bea Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Wed, 25 Feb 2026 00:40:09 +0530 Subject: [PATCH 21/22] ci: fixes for yml --- .github/workflows/alpha.yml | 12 ++++-------- .github/workflows/nightly.yml | 13 ++++--------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 8ada271f..dee7366e 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -13,7 +13,8 @@ jobs: build: runs-on: macos-26 env: - HAS_DEPLOY_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }} + DEPLOY_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_NAME: Alpha CHANNEL: alpha UPSTREAM_CHANNEL: "nightly" @@ -29,8 +30,6 @@ jobs: LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \ "${{ github.workflow }}" "${{ env.CHANNEL }}" || echo "") echo "LAST_SUCCESSFUL_COMMIT=$LAST_SUCCESSFUL_COMMIT" | tee -a $GITHUB_ENV - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: brew install ldid xcbeautify @@ -173,7 +172,7 @@ jobs: path: SideStore.dSYMs.zip - uses: actions/checkout@v4 - if: steps.build_gate.outputs.should_skip != 'true' && env.HAS_PUSH_KEY != '' + if: env.DEPLOY_KEY != '' with: repository: "SideStore/apps-v2.json" ref: "main" @@ -184,9 +183,8 @@ jobs: # deploy # -------------------------------------------------- - name: Deploy - if: steps.build_gate.outputs.should_skip != 'true' && env.HAS_PUSH_KEY != '' + if: env.DEPLOY_KEY != '' env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | python3 scripts/ci/workflow.py dump-project-settings PRODUCT_NAME=$(python3 scripts/ci/workflow.py read-product-name) @@ -209,8 +207,6 @@ jobs: # upload release # -------------------------------------------------- - name: Upload Release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | python3 scripts/ci/workflow.py upload-release \ "$RELEASE_NAME" \ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index f5f7c6ce..a0feabc4 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -15,7 +15,8 @@ jobs: build: runs-on: macos-26 env: - HAS_DEPLOY_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }} + DEPLOY_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_NAME: Nightly CHANNEL: nightly UPSTREAM_CHANNEL: "" @@ -31,8 +32,6 @@ jobs: LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \ "${{ github.workflow }}" "${{ env.CHANNEL }}" || echo "") echo "LAST_SUCCESSFUL_COMMIT=$LAST_SUCCESSFUL_COMMIT" | tee -a $GITHUB_ENV - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Check for new changes (on schedule) id: check_changes @@ -211,7 +210,7 @@ jobs: path: SideStore.dSYMs.zip - uses: actions/checkout@v4 - if: steps.build_gate.outputs.should_skip != 'true' && env.HAS_PUSH_KEY != '' + if: steps.build_gate.outputs.should_skip != 'true' && env.DEPLOY_KEY != '' with: repository: "SideStore/apps-v2.json" ref: "main" @@ -222,9 +221,7 @@ jobs: # deploy # -------------------------------------------------- - name: Deploy - if: steps.build_gate.outputs.should_skip != 'true' && env.HAS_PUSH_KEY != '' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: steps.build_gate.outputs.should_skip != 'true' && env.DEPLOY_KEY != '' run: | python3 scripts/ci/workflow.py dump-project-settings PRODUCT_NAME=$(python3 scripts/ci/workflow.py read-product-name) @@ -248,8 +245,6 @@ jobs: # -------------------------------------------------- - name: Upload Release if: steps.build_gate.outputs.should_skip != 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | python3 scripts/ci/workflow.py upload-release \ "$RELEASE_NAME" \ From 7f8f4fa9a7fac73bd94c3baf0d79bb26c2647bb6 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Wed, 25 Feb 2026 00:42:02 +0530 Subject: [PATCH 22/22] ci: fixes for yml --- .github/workflows/alpha.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index dee7366e..e37f6480 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -184,7 +184,6 @@ jobs: # -------------------------------------------------- - name: Deploy if: env.DEPLOY_KEY != '' - env: run: | python3 scripts/ci/workflow.py dump-project-settings PRODUCT_NAME=$(python3 scripts/ci/workflow.py read-product-name)