mirror of
https://github.com/SideStore/SideStore.git
synced 2026-03-29 23:05:39 +02:00
Compare commits
3 Commits
work/suprs
...
85ff9b09ca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85ff9b09ca | ||
|
|
4100e8b1b9 | ||
|
|
42fae569ca |
63
.github/maintenance/cache.py
vendored
Normal file
63
.github/maintenance/cache.py
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
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
|
||||
'''
|
||||
99
.github/workflows/alpha.yml
vendored
99
.github/workflows/alpha.yml
vendored
@@ -2,7 +2,7 @@ name: Alpha SideStore Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [staging]
|
||||
branches: [alpha]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
@@ -13,8 +13,6 @@ jobs:
|
||||
build:
|
||||
runs-on: macos-26
|
||||
env:
|
||||
DEPLOY_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_NAME: Alpha
|
||||
CHANNEL: alpha
|
||||
UPSTREAM_CHANNEL: "nightly"
|
||||
@@ -25,33 +23,36 @@ jobs:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Find Last Successful commit
|
||||
run: |
|
||||
LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \
|
||||
"false" "${{ env.CHANNEL }}" || echo "")
|
||||
echo "LAST_SUCCESSFUL_COMMIT=$LAST_SUCCESSFUL_COMMIT" | tee -a $GITHUB_ENV
|
||||
|
||||
- run: brew install ldid xcbeautify
|
||||
|
||||
# --------------------------------------------------
|
||||
# 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="${{ github.run_number }}"
|
||||
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 commit-id)
|
||||
SHORT_COMMIT=$(python3 scripts/ci/workflow.py commid-id)
|
||||
|
||||
NORMALIZED_VERSION=$(python3 scripts/ci/workflow.py compute-normalized \
|
||||
QUALIFIED_VERSION=$(python3 scripts/ci/workflow.py compute-qualified \
|
||||
"$MARKETING_VERSION" \
|
||||
"$BUILD_NUM" \
|
||||
"${{ env.CHANNEL }}" \
|
||||
"$SHORT_COMMIT")
|
||||
|
||||
python3 scripts/ci/workflow.py set-marketing-version "$NORMALIZED_VERSION"
|
||||
python3 scripts/ci/workflow.py set-marketing-version "$QUALIFIED_VERSION"
|
||||
|
||||
echo "BUILD_NUM=$BUILD_NUM" | tee -a $GITHUB_ENV
|
||||
echo "SHORT_COMMIT=$SHORT_COMMIT" | tee -a $GITHUB_ENV
|
||||
echo "MARKETING_VERSION=$NORMALIZED_VERSION" | tee -a $GITHUB_ENV
|
||||
echo "MARKETING_VERSION=$QUALIFIED_VERSION" | tee -a $GITHUB_ENV
|
||||
|
||||
- name: Setup Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
@@ -88,9 +89,7 @@ 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"
|
||||
@@ -107,9 +106,7 @@ 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: |
|
||||
@@ -128,9 +125,7 @@ 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: |
|
||||
@@ -143,24 +138,20 @@ jobs:
|
||||
# --------------------------------------------------
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-logs-${{ env.MARKETING_VERSION }}.zip
|
||||
path: build-logs.zip
|
||||
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: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_BUILD == '1' }}
|
||||
with:
|
||||
name: tests-build-logs-${{ env.SHORT_COMMIT }}.zip
|
||||
path: tests-build-logs.zip
|
||||
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: tests-run-logs-${{ env.SHORT_COMMIT }}.zip
|
||||
path: tests-run-logs.zip
|
||||
name: encrypted-tests-run-logs-${{ env.SHORT_COMMIT }}.zip
|
||||
path: encrypted-tests-run-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -172,21 +163,30 @@ jobs:
|
||||
path: SideStore.dSYMs.zip
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
if: env.DEPLOY_KEY != ''
|
||||
with:
|
||||
repository: "SideStore/apps-v2.json"
|
||||
ref: "main"
|
||||
token: ${{ secrets.CROSS_REPO_PUSH_KEY }}
|
||||
path: "SideStore/apps-v2.json"
|
||||
|
||||
- name: Generate Metadata
|
||||
# --------------------------------------------------
|
||||
# deploy
|
||||
# --------------------------------------------------
|
||||
- name: Deploy
|
||||
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)
|
||||
BUNDLE_ID=$(python3 scripts/ci/workflow.py read-bundle-id)
|
||||
PRODUCT_NAME=$(python3 scripts/ci/workflow.py get-product-name)
|
||||
BUNDLE_ID=$(python3 scripts/ci/workflow.py get-bundle-id)
|
||||
SOURCE_JSON="_includes/source.json"
|
||||
IPA_NAME="$PRODUCT_NAME.ipa"
|
||||
|
||||
python3 scripts/ci/workflow.py generate-metadata \
|
||||
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" \
|
||||
"$CHANNEL" \
|
||||
"$SHORT_COMMIT" \
|
||||
"$MARKETING_VERSION" \
|
||||
@@ -195,23 +195,8 @@ jobs:
|
||||
"$IPA_NAME" \
|
||||
"$LAST_SUCCESSFUL_COMMIT"
|
||||
|
||||
- name: Deploy
|
||||
if: env.DEPLOY_KEY != ''
|
||||
run: |
|
||||
SOURCE_JSON="_includes/source.json"
|
||||
RELEASE_NOTES=$(python3 scripts/ci/workflow.py retrieve-release-notes "$CHANNEL")
|
||||
|
||||
python3 scripts/ci/workflow.py deploy \
|
||||
SideStore/apps-v2.json \
|
||||
"$SOURCE_JSON" \
|
||||
"$CHANNEL" \
|
||||
"$MARKETING_VERSION"
|
||||
|
||||
|
||||
# --------------------------------------------------
|
||||
# upload release to GH
|
||||
# --------------------------------------------------
|
||||
- name: Upload Release
|
||||
run: |
|
||||
python3 scripts/ci/workflow.py upload-release \
|
||||
"$RELEASE_NAME" \
|
||||
"$CHANNEL" \
|
||||
|
||||
147
.github/workflows/nightly.yml
vendored
147
.github/workflows/nightly.yml
vendored
@@ -15,8 +15,6 @@ jobs:
|
||||
build:
|
||||
runs-on: macos-26
|
||||
env:
|
||||
DEPLOY_KEY: ${{ secrets.CROSS_REPO_PUSH_KEY }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_NAME: Nightly
|
||||
CHANNEL: nightly
|
||||
UPSTREAM_CHANNEL: ""
|
||||
@@ -27,63 +25,43 @@ jobs:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Find Last Successful commit
|
||||
run: |
|
||||
LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \
|
||||
"false" "${{ env.CHANNEL }}" || echo "")
|
||||
echo "LAST_SUCCESSFUL_COMMIT=$LAST_SUCCESSFUL_COMMIT" | tee -a $GITHUB_ENV
|
||||
|
||||
- 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
|
||||
|
||||
- run: brew install ldid xcbeautify
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
|
||||
# --------------------------------------------------
|
||||
# runtime env setup
|
||||
# --------------------------------------------------
|
||||
- name: Setup Env
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
run: |
|
||||
BUILD_NUM="${{ github.run_number }}"
|
||||
MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version)
|
||||
SHORT_COMMIT=$(python3 scripts/ci/workflow.py commit-id)
|
||||
- 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
|
||||
|
||||
NORMALIZED_VERSION=$(python3 scripts/ci/workflow.py compute-normalized \
|
||||
- name: Setup Env
|
||||
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)
|
||||
|
||||
QUALIFIED_VERSION=$(python3 scripts/ci/workflow.py compute-qualified \
|
||||
"$MARKETING_VERSION" \
|
||||
"$BUILD_NUM" \
|
||||
"${{ env.CHANNEL }}" \
|
||||
"$SHORT_COMMIT")
|
||||
|
||||
python3 scripts/ci/workflow.py set-marketing-version "$NORMALIZED_VERSION"
|
||||
python3 scripts/ci/workflow.py set-marketing-version "$QUALIFIED_VERSION"
|
||||
|
||||
echo "BUILD_NUM=$BUILD_NUM" | tee -a $GITHUB_ENV
|
||||
echo "SHORT_COMMIT=$SHORT_COMMIT" | tee -a $GITHUB_ENV
|
||||
echo "MARKETING_VERSION=$NORMALIZED_VERSION" | tee -a $GITHUB_ENV
|
||||
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:
|
||||
@@ -93,9 +71,7 @@ jobs:
|
||||
key: xcode-build-cache-${{ github.ref_name }}-${{ github.sha }}
|
||||
|
||||
- name: Restore Cache (last)
|
||||
if: >
|
||||
steps.build_gate.outputs.should_skip != 'true' &&
|
||||
steps.xcode-cache-exact.outputs.cache-hit != 'true'
|
||||
if: steps.xcode-cache-exact.outputs.cache-hit != 'true'
|
||||
id: xcode-cache-fallback
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
@@ -108,23 +84,19 @@ jobs:
|
||||
# build and test
|
||||
# --------------------------------------------------
|
||||
- name: Clean
|
||||
if: steps.build_gate.outputs.should_skip != 'true' && contains(github.event.head_commit.message, '[--clean-build]')
|
||||
if: 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: >
|
||||
steps.build_gate.outputs.should_skip != 'true' &&
|
||||
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"
|
||||
|
||||
- name: Build
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
id: build
|
||||
env:
|
||||
BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }}
|
||||
@@ -135,11 +107,8 @@ 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: |
|
||||
@@ -148,9 +117,7 @@ jobs:
|
||||
exit $STATUS
|
||||
|
||||
- name: Save Cache
|
||||
if: >
|
||||
steps.build_gate.outputs.should_skip != 'true' &&
|
||||
steps.xcode-cache-fallback.outputs.cache-hit != 'true'
|
||||
if: ${{ steps.xcode-cache-fallback.outputs.cache-hit != 'true' }}
|
||||
uses: actions/cache/save@v3
|
||||
with:
|
||||
path: |
|
||||
@@ -159,11 +126,8 @@ 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: |
|
||||
@@ -175,57 +139,56 @@ jobs:
|
||||
# artifacts
|
||||
# --------------------------------------------------
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
with:
|
||||
name: build-logs-${{ env.MARKETING_VERSION }}.zip
|
||||
path: build-logs.zip
|
||||
name: encrypted-build-logs-${{ env.MARKETING_VERSION }}.zip
|
||||
path: encrypted-build-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: >
|
||||
steps.build_gate.outputs.should_skip != 'true' &&
|
||||
vars.ENABLE_TESTS == '1' &&
|
||||
vars.ENABLE_TESTS_BUILD == '1'
|
||||
if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_BUILD == '1' }}
|
||||
with:
|
||||
name: tests-build-logs-${{ env.SHORT_COMMIT }}.zip
|
||||
path: tests-build-logs.zip
|
||||
name: encrypted-tests-build-logs-${{ env.SHORT_COMMIT }}.zip
|
||||
path: encrypted-tests-build-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: >
|
||||
steps.build_gate.outputs.should_skip != 'true' &&
|
||||
vars.ENABLE_TESTS == '1' &&
|
||||
vars.ENABLE_TESTS_RUN == '1'
|
||||
if: ${{ vars.ENABLE_TESTS == '1' && vars.ENABLE_TESTS_RUN == '1' }}
|
||||
with:
|
||||
name: tests-run-logs-${{ env.SHORT_COMMIT }}.zip
|
||||
path: tests-run-logs.zip
|
||||
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' && env.DEPLOY_KEY != ''
|
||||
with:
|
||||
repository: "SideStore/apps-v2.json"
|
||||
ref: "main"
|
||||
token: ${{ secrets.CROSS_REPO_PUSH_KEY }}
|
||||
path: "SideStore/apps-v2.json"
|
||||
|
||||
- name: Generate Metadata
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
# --------------------------------------------------
|
||||
# deploy
|
||||
# --------------------------------------------------
|
||||
- name: Deploy
|
||||
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)
|
||||
BUNDLE_ID=$(python3 scripts/ci/workflow.py read-bundle-id)
|
||||
PRODUCT_NAME=$(python3 scripts/ci/workflow.py get-product-name)
|
||||
BUNDLE_ID=$(python3 scripts/ci/workflow.py get-bundle-id)
|
||||
SOURCE_JSON="_includes/source.json"
|
||||
IPA_NAME="$PRODUCT_NAME.ipa"
|
||||
|
||||
python3 scripts/ci/workflow.py generate-metadata \
|
||||
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" \
|
||||
"$CHANNEL" \
|
||||
"$SHORT_COMMIT" \
|
||||
"$MARKETING_VERSION" \
|
||||
@@ -234,24 +197,8 @@ jobs:
|
||||
"$IPA_NAME" \
|
||||
"$LAST_SUCCESSFUL_COMMIT"
|
||||
|
||||
- name: Deploy
|
||||
if: steps.build_gate.outputs.should_skip != 'true' && env.DEPLOY_KEY != ''
|
||||
run: |
|
||||
SOURCE_JSON="_includes/source.json"
|
||||
RELEASE_NOTES=$(python3 scripts/ci/workflow.py retrieve-release-notes "$CHANNEL")
|
||||
|
||||
python3 scripts/ci/workflow.py deploy \
|
||||
SideStore/apps-v2.json \
|
||||
"$SOURCE_JSON" \
|
||||
"$CHANNEL" \
|
||||
"$MARKETING_VERSION"
|
||||
|
||||
|
||||
# --------------------------------------------------
|
||||
# upload release to GH
|
||||
# --------------------------------------------------
|
||||
- name: Upload Release
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
run: |
|
||||
python3 scripts/ci/workflow.py upload-release \
|
||||
"$RELEASE_NAME" \
|
||||
"$CHANNEL" \
|
||||
|
||||
28
.github/workflows/obsolete/alpha.yml
vendored
Normal file
28
.github/workflows/obsolete/alpha.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
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 }}
|
||||
103
.github/workflows/obsolete/beta.yml
vendored
Normal file
103
.github/workflows/obsolete/beta.yml
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
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: |
|
||||
<!-- NOTE: to reset SideSource cache, go to `https://apps.sidestore.io/reset-cache/nightly/<sidesource key>`. This is not included in the GitHub Action since it makes draft releases so they can be edited and have a changelog. -->
|
||||
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/
|
||||
34
.github/workflows/obsolete/increase-beta-build-num.sh
vendored
Executable file
34
.github/workflows/obsolete/increase-beta-build-num.sh
vendored
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/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
|
||||
82
.github/workflows/obsolete/nightly.yml
vendored
Normal file
82
.github/workflows/obsolete/nightly.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
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 }}
|
||||
|
||||
105
.github/workflows/obsolete/reusable-sidestore-build.yml
vendored
Normal file
105
.github/workflows/obsolete/reusable-sidestore-build.yml
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
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
|
||||
358
.github/workflows/obsolete/sidestore-build.yml
vendored
Normal file
358
.github/workflows/obsolete/sidestore-build.yml
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
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
|
||||
281
.github/workflows/obsolete/sidestore-deploy.yml
vendored
Normal file
281
.github/workflows/obsolete/sidestore-deploy.yml
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
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<<EOF" >> $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<<EOF" >> $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 <<EOF
|
||||
This is release for:
|
||||
- version: "${{ inputs.version }}"
|
||||
- revision: "${{ inputs.short_commit }}"
|
||||
- timestamp: "${{ steps.date.outputs.date }}"
|
||||
|
||||
Release Notes:
|
||||
${{ steps.release_notes.outputs.content }}
|
||||
EOF
|
||||
}
|
||||
|
||||
LOCALIZED_DESCRIPTION=$(get_description)
|
||||
echo "$LOCALIZED_DESCRIPTION"
|
||||
|
||||
# multiline strings
|
||||
echo "LOCALIZED_DESCRIPTION<<EOF" >> $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
|
||||
24
.github/workflows/obsolete/sidestore-shared.yml
vendored
Normal file
24
.github/workflows/obsolete/sidestore-shared.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
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 }}
|
||||
165
.github/workflows/obsolete/sidestore-tests-build.yml
vendored
Normal file
165
.github/workflows/obsolete/sidestore-tests-build.yml
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
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
|
||||
196
.github/workflows/obsolete/sidestore-tests-run.yml
vendored
Normal file
196
.github/workflows/obsolete/sidestore-tests-run.yml
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
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 </dev/null >> 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 </dev/null > 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
|
||||
130
.github/workflows/pr.yml
vendored
130
.github/workflows/pr.yml
vendored
@@ -1,90 +1,98 @@
|
||||
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 }}
|
||||
runs-on: macos-26
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: 'macos-14'
|
||||
version: '16.1'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 1 # shallow clone just for PR
|
||||
|
||||
- run: brew install ldid xcbeautify
|
||||
- name: Install dependencies
|
||||
run: brew install ldid
|
||||
|
||||
- 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 }})
|
||||
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=$NORMALIZED_VERSION" | tee -a $GITHUB_ENV
|
||||
- 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 Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
with:
|
||||
xcode-version: "26.2"
|
||||
xcode-version: ${{ matrix.version }}
|
||||
|
||||
- name: Restore Cache (exact)
|
||||
id: xcode-cache-exact
|
||||
uses: actions/cache/restore@v3
|
||||
- name: Cache Build
|
||||
uses: irgaly/xcode-cache@v1
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
~/Library/Caches/org.swift.swiftpm
|
||||
key: xcode-build-cache-${{ github.ref_name }}-${{ github.sha }}
|
||||
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-
|
||||
|
||||
- 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 }}
|
||||
- name: List Files and derived data
|
||||
run: |
|
||||
python3 scripts/ci/workflow.py build; STATUS=$?
|
||||
python3 scripts/ci/workflow.py encrypt-build
|
||||
mv SideStore.ipa SideStore-${{ env.MARKETING_VERSION }}.ipa
|
||||
exit $STATUS
|
||||
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: 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-build-cache-${{ github.ref_name }}-${{ github.sha }}
|
||||
|
||||
- name: Build SideStore
|
||||
run: NSUnbufferedIO=YES make build 2>&1 | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-logs-${{ env.MARKETING_VERSION }}.zip
|
||||
path: build-logs.zip
|
||||
- name: Fakesign app
|
||||
run: make fakesign
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: SideStore-${{ env.MARKETING_VERSION }}.ipa
|
||||
path: SideStore-${{ env.MARKETING_VERSION }}.ipa
|
||||
- name: Convert to IPA
|
||||
run: make ipa
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- 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-${{ env.MARKETING_VERSION }}-dSYMs.zip
|
||||
path: SideStore.dSYMs.zip
|
||||
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: ./SideStore.xcarchive/dSYMs/*
|
||||
|
||||
263
.github/workflows/stable.yml
vendored
263
.github/workflows/stable.yml
vendored
@@ -1,135 +1,242 @@
|
||||
name: Stable SideStore build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+'
|
||||
- '[0-9]+.[0-9]+.[0-9]+' # example: 1.0.0
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build SideStore - stable
|
||||
runs-on: macos-26
|
||||
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CHANNEL: stable
|
||||
UPSTREAM_CHANNEL: ""
|
||||
name: Build SideStore - stable (on tag push)
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: 'macos-26'
|
||||
version: '26.0'
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Find Last Successful commit
|
||||
- name: Echo Build.xcconfig
|
||||
run: |
|
||||
LAST_SUCCESSFUL_COMMIT=$(python3 scripts/ci/workflow.py last-successful-commit \
|
||||
"true" || echo "")
|
||||
echo "LAST_SUCCESSFUL_COMMIT=$LAST_SUCCESSFUL_COMMIT" | tee -a $GITHUB_ENV
|
||||
echo "cat Build.xcconfig"
|
||||
cat Build.xcconfig
|
||||
shell: bash
|
||||
|
||||
- run: brew install ldid xcbeautify
|
||||
# - 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: Setup Env
|
||||
- name: Echo Updated Build.xcconfig
|
||||
run: |
|
||||
MARKETING_VERSION=$(python3 scripts/ci/workflow.py get-marketing-version)
|
||||
SHORT_COMMIT=$(python3 scripts/ci/workflow.py commit-id)
|
||||
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"
|
||||
echo "Build.xcconfig: $MARKETING_VERSION"
|
||||
echo "Tag: ${{ github.ref_name }}"
|
||||
echo 'Version mismatch: $tag != $marketing_version ... '
|
||||
echo " expected-tag : $MARKETING_VERSION"
|
||||
echo " pushed-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
|
||||
|
||||
echo "MARKETING_VERSION=$MARKETING_VERSION" | tee -a $GITHUB_ENV
|
||||
echo "SHORT_COMMIT=$SHORT_COMMIT" | tee -a $GITHUB_ENV
|
||||
- name: Install dependencies - ldid & xcbeautify
|
||||
run: |
|
||||
brew install ldid xcbeautify
|
||||
|
||||
- name: Setup Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
with:
|
||||
xcode-version: "26.0"
|
||||
xcode-version: ${{ matrix.version }}
|
||||
|
||||
- name: Restore Cache (exact)
|
||||
id: xcode-cache-exact
|
||||
- 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-build-cache-stable-${{ github.sha }}
|
||||
key: xcode-cache-build-stable-${{ github.sha }}
|
||||
|
||||
- name: Restore Cache (last)
|
||||
if: steps.xcode-cache-exact.outputs.cache-hit != 'true'
|
||||
id: xcode-cache-fallback
|
||||
- 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-build-cache-stable-
|
||||
key: xcode-cache-build-stable-
|
||||
|
||||
- name: Build
|
||||
id: build
|
||||
env:
|
||||
BUILD_LOG_ZIP_PASSWORD: ${{ secrets.BUILD_LOG_ZIP_PASSWORD }}
|
||||
- name: (Build) Clean previous build artifacts
|
||||
run: |
|
||||
python3 scripts/ci/workflow.py build; STATUS=$?
|
||||
python3 scripts/ci/workflow.py encrypt-build
|
||||
exit $STATUS
|
||||
make clean
|
||||
mkdir -p build/logs
|
||||
shell: bash
|
||||
|
||||
- name: Save Cache
|
||||
if: ${{ steps.xcode-cache-fallback.outputs.cache-hit != 'true' }}
|
||||
- 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' }}
|
||||
uses: actions/cache/save@v3
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
~/Library/Caches/org.swift.swiftpm
|
||||
key: xcode-build-cache-stable-${{ github.sha }}
|
||||
key: xcode-cache-build-stable-${{ github.sha }}
|
||||
|
||||
- name: (Build) List Files and Build artifacts
|
||||
run: |
|
||||
echo ">>>>>>>>> Workdir <<<<<<<<<<"
|
||||
ls -la .
|
||||
echo ""
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-logs-${{ env.MARKETING_VERSION }}.zip
|
||||
path: build-logs.zip
|
||||
echo ">>>>>>>>> Build <<<<<<<<<<"
|
||||
find build -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists
|
||||
echo ""
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
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: SideStore-${{ env.MARKETING_VERSION }}.ipa
|
||||
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
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- 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-${{ env.MARKETING_VERSION }}-dSYMs.zip
|
||||
name: SideStore-${{ steps.version.outputs.version }}-dSYMs.zip
|
||||
path: SideStore.dSYMs.zip
|
||||
|
||||
- name: Generate Metadata
|
||||
run: |
|
||||
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)
|
||||
IPA_NAME="$PRODUCT_NAME.ipa"
|
||||
- name: Get current date
|
||||
id: date
|
||||
run: echo "date=$(date -u +'%c')" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
python3 scripts/ci/workflow.py generate-metadata \
|
||||
"${{ github.ref_name }}" \
|
||||
"$SHORT_COMMIT" \
|
||||
"$MARKETING_VERSION" \
|
||||
"$CHANNEL" \
|
||||
"$BUNDLE_ID" \
|
||||
"$IPA_NAME" \
|
||||
"$LAST_SUCCESSFUL_COMMIT"
|
||||
- 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
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
python3 scripts/ci/workflow.py upload-release \
|
||||
"${{ github.ref_name }}" \
|
||||
"${{ github.ref_name }}" \
|
||||
"$GITHUB_SHA" \
|
||||
"$GITHUB_REPOSITORY" \
|
||||
"$UPSTREAM_CHANNEL" \
|
||||
"true"
|
||||
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: |
|
||||
<!-- NOTE: to reset SideSource cache, go to `https://apps.sidestore.io/reset-cache/nightly/<sidesource key>`. This is not included in the GitHub Action since it makes draft releases so they can be edited and have a changelog. -->
|
||||
## 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 }}`
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -69,7 +69,4 @@ SideStore/.skip-prebuilt-fetch-em_proxy
|
||||
test-recording.mp4
|
||||
test-recording.log
|
||||
altstore-sources.md
|
||||
local-build.sh
|
||||
|
||||
source-metadata.json
|
||||
release-notes.md
|
||||
local-build.sh
|
||||
@@ -48,90 +48,6 @@
|
||||
remoteGlobalIDString = BF58047A246A28F7008AE704;
|
||||
remoteInfo = AltBackup;
|
||||
};
|
||||
A802C9F82F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C5DA2F525B910049FE2B /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 87B8C3401E0E9C37002F817D;
|
||||
remoteInfo = "fragmentzip-cli-macOS";
|
||||
};
|
||||
A802C9FA2F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C5DA2F525B910049FE2B /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = B315FDB02866CCF8002E243C;
|
||||
remoteInfo = "fragmentzip-cli-iOS";
|
||||
};
|
||||
A802C9FC2F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C5DA2F525B910049FE2B /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = B315FDB52866CD91002E243C;
|
||||
remoteInfo = "fragmentzip-macOS";
|
||||
};
|
||||
A802C9FE2F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C5DA2F525B910049FE2B /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = B315FDCE2866CDD3002E243C;
|
||||
remoteInfo = "fragmentzip-iOS";
|
||||
};
|
||||
A802CA012F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C5B62F525B910049FE2B /* libgeneral.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 87977F6F227C4B71004F31DA;
|
||||
remoteInfo = libgeneral;
|
||||
};
|
||||
A802CA062F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C95A2F525B910049FE2B /* Roxas.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = BFADAFF819AE7BB70050CF31;
|
||||
remoteInfo = Roxas;
|
||||
};
|
||||
A802CA082F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C95A2F525B910049FE2B /* Roxas.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = BF8624801BB742E700C12EEE;
|
||||
remoteInfo = RoxasTV;
|
||||
};
|
||||
A802CA0A2F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C95A2F525B910049FE2B /* Roxas.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = BFADB00319AE7BB80050CF31;
|
||||
remoteInfo = RoxasTests;
|
||||
};
|
||||
A802CA0E2F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C8B62F525B910049FE2B /* SampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 44B1EE7C23DB90D5004E2E29;
|
||||
remoteInfo = SampleApp;
|
||||
};
|
||||
A802CA102F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C8B62F525B910049FE2B /* SampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 445A906A2400612800B487B4;
|
||||
remoteInfo = "NSAttributedString+MarkdownTests";
|
||||
};
|
||||
A802CA132F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C8CF2F525B910049FE2B /* SampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 44E8FA8923D90632009E1D13;
|
||||
remoteInfo = SampleApp;
|
||||
};
|
||||
A802CA162F525C030049FE2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A802C8DB2F525B910049FE2B /* SwiftSampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 44962FDA23E7A54A00E2A598;
|
||||
remoteInfo = SwiftSampleApp;
|
||||
};
|
||||
A81173222F4B8DBD0013ABD0 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A811720B2F4B8BA80013ABD0 /* em_proxy.xcodeproj */;
|
||||
@@ -1903,174 +1819,6 @@
|
||||
remoteGlobalIDString = 44962FDA23E7A54A00E2A598;
|
||||
remoteInfo = SwiftSampleApp;
|
||||
};
|
||||
A8F3C1312F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3BD152F4E3794006BC252 /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 87B8C3401E0E9C37002F817D;
|
||||
remoteInfo = "fragmentzip-cli-macOS";
|
||||
};
|
||||
A8F3C1332F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3BD152F4E3794006BC252 /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = B315FDB02866CCF8002E243C;
|
||||
remoteInfo = "fragmentzip-cli-iOS";
|
||||
};
|
||||
A8F3C1352F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3BD152F4E3794006BC252 /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = B315FDB52866CD91002E243C;
|
||||
remoteInfo = "fragmentzip-macOS";
|
||||
};
|
||||
A8F3C1372F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3BD152F4E3794006BC252 /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = B315FDCE2866CDD3002E243C;
|
||||
remoteInfo = "fragmentzip-iOS";
|
||||
};
|
||||
A8F3C13A2F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3BCF12F4E3794006BC252 /* libgeneral.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 87977F6F227C4B71004F31DA;
|
||||
remoteInfo = libgeneral;
|
||||
};
|
||||
A8F3C13F2F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3C0952F4E3794006BC252 /* Roxas.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = BFADAFF819AE7BB70050CF31;
|
||||
remoteInfo = Roxas;
|
||||
};
|
||||
A8F3C1412F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3C0952F4E3794006BC252 /* Roxas.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = BF8624801BB742E700C12EEE;
|
||||
remoteInfo = RoxasTV;
|
||||
};
|
||||
A8F3C1432F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3C0952F4E3794006BC252 /* Roxas.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = BFADB00319AE7BB80050CF31;
|
||||
remoteInfo = RoxasTests;
|
||||
};
|
||||
A8F3C1472F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3BFF12F4E3794006BC252 /* SampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 44B1EE7C23DB90D5004E2E29;
|
||||
remoteInfo = SampleApp;
|
||||
};
|
||||
A8F3C1492F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3BFF12F4E3794006BC252 /* SampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 445A906A2400612800B487B4;
|
||||
remoteInfo = "NSAttributedString+MarkdownTests";
|
||||
};
|
||||
A8F3C14C2F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3C00A2F4E3794006BC252 /* SampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 44E8FA8923D90632009E1D13;
|
||||
remoteInfo = SampleApp;
|
||||
};
|
||||
A8F3C14F2F4E37A5006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3C0162F4E3794006BC252 /* SwiftSampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 44962FDA23E7A54A00E2A598;
|
||||
remoteInfo = SwiftSampleApp;
|
||||
};
|
||||
A8F3FC062F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3F7E42F4E96D7006BC252 /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 87B8C3401E0E9C37002F817D;
|
||||
remoteInfo = "fragmentzip-cli-macOS";
|
||||
};
|
||||
A8F3FC082F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3F7E42F4E96D7006BC252 /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = B315FDB02866CCF8002E243C;
|
||||
remoteInfo = "fragmentzip-cli-iOS";
|
||||
};
|
||||
A8F3FC0A2F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3F7E42F4E96D7006BC252 /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = B315FDB52866CD91002E243C;
|
||||
remoteInfo = "fragmentzip-macOS";
|
||||
};
|
||||
A8F3FC0C2F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3F7E42F4E96D7006BC252 /* libfragmentzip.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = B315FDCE2866CDD3002E243C;
|
||||
remoteInfo = "fragmentzip-iOS";
|
||||
};
|
||||
A8F3FC0F2F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3F7C02F4E96D7006BC252 /* libgeneral.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 87977F6F227C4B71004F31DA;
|
||||
remoteInfo = libgeneral;
|
||||
};
|
||||
A8F3FC142F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3FB642F4E96D7006BC252 /* Roxas.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = BFADAFF819AE7BB70050CF31;
|
||||
remoteInfo = Roxas;
|
||||
};
|
||||
A8F3FC162F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3FB642F4E96D7006BC252 /* Roxas.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = BF8624801BB742E700C12EEE;
|
||||
remoteInfo = RoxasTV;
|
||||
};
|
||||
A8F3FC182F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3FB642F4E96D7006BC252 /* Roxas.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = BFADB00319AE7BB80050CF31;
|
||||
remoteInfo = RoxasTests;
|
||||
};
|
||||
A8F3FC1B2F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3FAD92F4E96D7006BC252 /* SampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 44E8FA8923D90632009E1D13;
|
||||
remoteInfo = SampleApp;
|
||||
};
|
||||
A8F3FC1F2F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3FAC02F4E96D7006BC252 /* SampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 44B1EE7C23DB90D5004E2E29;
|
||||
remoteInfo = SampleApp;
|
||||
};
|
||||
A8F3FC212F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3FAC02F4E96D7006BC252 /* SampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 445A906A2400612800B487B4;
|
||||
remoteInfo = "NSAttributedString+MarkdownTests";
|
||||
};
|
||||
A8F3FC242F4E998F006BC252 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8F3FAE52F4E96D7006BC252 /* SwiftSampleApp.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 44962FDA23E7A54A00E2A598;
|
||||
remoteInfo = SwiftSampleApp;
|
||||
};
|
||||
A8FAC1CE2F4B51980061A851 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A8FAC0562F4B50D10061A851 /* em_proxy.xcodeproj */;
|
||||
@@ -2439,12 +2187,6 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
191E5FAB290A5D92001A3B7C /* libminimuxer_swift.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libminimuxer_swift.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A802C5B62F525B910049FE2B /* libgeneral.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libgeneral.xcodeproj; sourceTree = "<group>"; };
|
||||
A802C5DA2F525B910049FE2B /* libfragmentzip.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libfragmentzip.xcodeproj; sourceTree = "<group>"; };
|
||||
A802C8B62F525B910049FE2B /* SampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
A802C8CF2F525B910049FE2B /* SampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
A802C8DB2F525B910049FE2B /* SwiftSampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SwiftSampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
A802C95A2F525B910049FE2B /* Roxas.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = Roxas.xcodeproj; sourceTree = "<group>"; };
|
||||
A8116EAD2F4B8BA80013ABD0 /* libgeneral.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libgeneral.xcodeproj; sourceTree = "<group>"; };
|
||||
A8116ED12F4B8BA80013ABD0 /* libfragmentzip.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libfragmentzip.xcodeproj; sourceTree = "<group>"; };
|
||||
A81171432F4B8BA80013ABD0 /* SampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
@@ -2633,18 +2375,6 @@
|
||||
A8EEDA1E2F4B19B000F2436D /* Roxas.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = Roxas.xcodeproj; sourceTree = "<group>"; };
|
||||
A8EEDA9B2F4B19B000F2436D /* em_proxy.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = em_proxy.xcodeproj; sourceTree = "<group>"; };
|
||||
A8EEDA9D2F4B19B000F2436D /* minimuxer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = minimuxer.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3BCF12F4E3794006BC252 /* libgeneral.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libgeneral.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3BD152F4E3794006BC252 /* libfragmentzip.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libfragmentzip.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3BFF12F4E3794006BC252 /* SampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3C00A2F4E3794006BC252 /* SampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3C0162F4E3794006BC252 /* SwiftSampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SwiftSampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3C0952F4E3794006BC252 /* Roxas.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = Roxas.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3F7C02F4E96D7006BC252 /* libgeneral.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libgeneral.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3F7E42F4E96D7006BC252 /* libfragmentzip.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libfragmentzip.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3FAC02F4E96D7006BC252 /* SampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3FAD92F4E96D7006BC252 /* SampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3FAE52F4E96D7006BC252 /* SwiftSampleApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SwiftSampleApp.xcodeproj; sourceTree = "<group>"; };
|
||||
A8F3FB642F4E96D7006BC252 /* Roxas.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = Roxas.xcodeproj; sourceTree = "<group>"; };
|
||||
A8FABA492F4B50D00061A851 /* libimobiledevice.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libimobiledevice.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A8FABA4A2F4B50D00061A851 /* libem_proxy_swift.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libem_proxy_swift.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A8FABCC32F4B50D10061A851 /* libgeneral.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libgeneral.xcodeproj; sourceTree = "<group>"; };
|
||||
@@ -2683,13 +2413,6 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
177EF33D2F4D8B8E008CAAE1 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
"NSAttributedString+Markdown.m",
|
||||
);
|
||||
target = BFD247692284B9A500981D42 /* SideStore */;
|
||||
};
|
||||
A8A5AFBE2F4C33A300572B4A /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
@@ -2899,7 +2622,6 @@
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
EMProxyWrapper.swift,
|
||||
IfManager.swift,
|
||||
MinimuxerWrapper.swift,
|
||||
Utils/common/AbstractClassError.swift,
|
||||
Utils/common/BuildInfo.swift,
|
||||
@@ -2948,7 +2670,7 @@
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
A8A5AC9D2F4C338F00572B4A /* Roxas */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Roxas; sourceTree = "<group>"; };
|
||||
A8A5ACE42F4C339400572B4A /* MarkdownAttributedString */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (177EF33D2F4D8B8E008CAAE1 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = MarkdownAttributedString; sourceTree = "<group>"; };
|
||||
A8A5ACE42F4C339400572B4A /* MarkdownAttributedString */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = MarkdownAttributedString; sourceTree = "<group>"; };
|
||||
A8A5AE1B2F4C33A300572B4A /* libplist */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8A5AFC02F4C33A300572B4A /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = libplist; sourceTree = "<group>"; };
|
||||
A8A5AE662F4C33A300572B4A /* libimobiledevice-glue */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8A5AFBF2F4C33A300572B4A /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = "libimobiledevice-glue"; sourceTree = "<group>"; };
|
||||
A8A5AF5E2F4C33A300572B4A /* libimobiledevice */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8A5AFBE2F4C33A300572B4A /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = libimobiledevice; sourceTree = "<group>"; };
|
||||
@@ -3035,60 +2757,6 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
A802C5E12F525B910049FE2B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A802C9F92F525C030049FE2B /* libfragmentzip */,
|
||||
A802C9FB2F525C030049FE2B /* libfragmentzip */,
|
||||
A802C9FD2F525C030049FE2B /* libfragmentzip.a */,
|
||||
A802C9FF2F525C030049FE2B /* libfragmentzip.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A802C5E32F525B910049FE2B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A802CA022F525C030049FE2B /* libgeneral */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A802C8E32F525B910049FE2B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A802CA142F525C030049FE2B /* SampleApp.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A802C8E52F525B910049FE2B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A802CA0F2F525C030049FE2B /* SampleApp.app */,
|
||||
A802CA112F525C030049FE2B /* NSAttributedString+MarkdownTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A802C8E72F525B910049FE2B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A802CA172F525C030049FE2B /* SwiftSampleApp.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A802C95B2F525B910049FE2B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A802CA072F525C030049FE2B /* Roxas.framework */,
|
||||
A802CA092F525C030049FE2B /* Roxas.framework */,
|
||||
A802CA0B2F525C030049FE2B /* RoxasTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A811720E2F4B8BA80013ABD0 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -4404,114 +4072,6 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3BD1C2F4E3794006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3C1322F4E37A5006BC252 /* libfragmentzip */,
|
||||
A8F3C1342F4E37A5006BC252 /* libfragmentzip */,
|
||||
A8F3C1362F4E37A5006BC252 /* libfragmentzip.a */,
|
||||
A8F3C1382F4E37A5006BC252 /* libfragmentzip.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3BD1E2F4E3794006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3C13B2F4E37A5006BC252 /* libgeneral */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3C01E2F4E3794006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3C1482F4E37A5006BC252 /* SampleApp.app */,
|
||||
A8F3C14A2F4E37A5006BC252 /* NSAttributedString+MarkdownTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3C0202F4E3794006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3C1502F4E37A5006BC252 /* SwiftSampleApp.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3C0222F4E3794006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3C14D2F4E37A5006BC252 /* SampleApp.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3C0962F4E3794006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3C1402F4E37A5006BC252 /* Roxas.framework */,
|
||||
A8F3C1422F4E37A5006BC252 /* Roxas.framework */,
|
||||
A8F3C1442F4E37A5006BC252 /* RoxasTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3F7EB2F4E96D7006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3FC072F4E998F006BC252 /* libfragmentzip */,
|
||||
A8F3FC092F4E998F006BC252 /* libfragmentzip */,
|
||||
A8F3FC0B2F4E998F006BC252 /* libfragmentzip.a */,
|
||||
A8F3FC0D2F4E998F006BC252 /* libfragmentzip.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3F7ED2F4E96D7006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3FC102F4E998F006BC252 /* libgeneral */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3FAED2F4E96D7006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3FC1C2F4E998F006BC252 /* SampleApp.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3FAEF2F4E96D7006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3FC252F4E998F006BC252 /* SwiftSampleApp.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3FAF12F4E96D7006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3FC202F4E998F006BC252 /* SampleApp.app */,
|
||||
A8F3FC222F4E998F006BC252 /* NSAttributedString+MarkdownTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8F3FB652F4E96D7006BC252 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A8F3FC152F4E998F006BC252 /* Roxas.framework */,
|
||||
A8F3FC172F4E998F006BC252 /* Roxas.framework */,
|
||||
A8F3FC192F4E998F006BC252 /* RoxasTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8FAC0592F4B50D10061A851 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -5081,10 +4641,6 @@
|
||||
ProductGroup = A8A5B06A2F4C347700572B4A /* Products */;
|
||||
ProjectRef = A8A5B0622F4C347700572B4A /* libfragmentzip.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3BD1C2F4E3794006BC252 /* Products */;
|
||||
ProjectRef = A8F3BD152F4E3794006BC252 /* libfragmentzip.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8636E9B2F4CF74D00E66784 /* Products */;
|
||||
ProjectRef = A8636E922F4CF74D00E66784 /* libfragmentzip.xcodeproj */;
|
||||
@@ -5101,10 +4657,6 @@
|
||||
ProductGroup = A85AEC6B2F4B22F6002E2E11 /* Products */;
|
||||
ProjectRef = A85AE43E2F4B22F6002E2E11 /* libfragmentzip.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3F7EB2F4E96D7006BC252 /* Products */;
|
||||
ProjectRef = A8F3F7E42F4E96D7006BC252 /* libfragmentzip.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8A5B3BA2F4C4C8600572B4A /* Products */;
|
||||
ProjectRef = A8A5B3B32F4C4C8600572B4A /* libfragmentzip.xcodeproj */;
|
||||
@@ -5133,10 +4685,6 @@
|
||||
ProductGroup = A8CCC2482F4B654400B0089A /* Products */;
|
||||
ProjectRef = A8CCBF072F4B654400B0089A /* libfragmentzip.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A802C5E12F525B910049FE2B /* Products */;
|
||||
ProjectRef = A802C5DA2F525B910049FE2B /* libfragmentzip.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A811973F2F4C1C710013ABD0 /* Products */;
|
||||
ProjectRef = A81194062F4C1C710013ABD0 /* libfragmentzip.xcodeproj */;
|
||||
@@ -5189,10 +4737,6 @@
|
||||
ProductGroup = A8A5B06C2F4C347700572B4A /* Products */;
|
||||
ProjectRef = A8A5B03E2F4C347700572B4A /* libgeneral.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A802C5E32F525B910049FE2B /* Products */;
|
||||
ProjectRef = A802C5B62F525B910049FE2B /* libgeneral.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8CCD22A2F4B6B0000B0089A /* Products */;
|
||||
ProjectRef = A8CCCEBF2F4B6B0000B0089A /* libgeneral.xcodeproj */;
|
||||
@@ -5209,18 +4753,10 @@
|
||||
ProductGroup = A8FAD7302F4B61310061A851 /* Products */;
|
||||
ProjectRef = A8FAD38F2F4B61310061A851 /* libgeneral.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3F7ED2F4E96D7006BC252 /* Products */;
|
||||
ProjectRef = A8F3F7C02F4E96D7006BC252 /* libgeneral.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8EEDA212F4B19B000F2436D /* Products */;
|
||||
ProjectRef = A8EED1D72F4B19B000F2436D /* libgeneral.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3BD1E2F4E3794006BC252 /* Products */;
|
||||
ProjectRef = A8F3BCF12F4E3794006BC252 /* libgeneral.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8636E992F4CF74D00E66784 /* Products */;
|
||||
ProjectRef = A8636E6E2F4CF74D00E66784 /* libgeneral.xcodeproj */;
|
||||
@@ -5345,10 +4881,6 @@
|
||||
ProductGroup = A8A5BE7E2F4C4D6800572B4A /* Products */;
|
||||
ProjectRef = A8A5BE7D2F4C4D6800572B4A /* Roxas.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3FB652F4E96D7006BC252 /* Products */;
|
||||
ProjectRef = A8F3FB642F4E96D7006BC252 /* Roxas.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A85AEC732F4B22F6002E2E11 /* Products */;
|
||||
ProjectRef = A85AEC612F4B22F6002E2E11 /* Roxas.xcodeproj */;
|
||||
@@ -5377,10 +4909,6 @@
|
||||
ProductGroup = A8FACF9D2F4B5CD40061A851 /* Products */;
|
||||
ProjectRef = A8FACF932F4B5CD40061A851 /* Roxas.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A802C95B2F525B910049FE2B /* Products */;
|
||||
ProjectRef = A802C95A2F525B910049FE2B /* Roxas.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A85A27CA2F4B370D002E2E11 /* Products */;
|
||||
ProjectRef = A85A27C02F4B370D002E2E11 /* Roxas.xcodeproj */;
|
||||
@@ -5401,10 +4929,6 @@
|
||||
ProductGroup = A86372122F4CF74D00E66784 /* Products */;
|
||||
ProjectRef = A86372112F4CF74D00E66784 /* Roxas.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3C0962F4E3794006BC252 /* Products */;
|
||||
ProjectRef = A8F3C0952F4E3794006BC252 /* Roxas.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8EEDA272F4B19B000F2436D /* Products */;
|
||||
ProjectRef = A8EEDA1E2F4B19B000F2436D /* Roxas.xcodeproj */;
|
||||
@@ -5425,10 +4949,6 @@
|
||||
ProductGroup = A8CCE16B2F4B76CF00B0089A /* Products */;
|
||||
ProjectRef = A8CCE15B2F4B76CF00B0089A /* Roxas.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3C01E2F4E3794006BC252 /* Products */;
|
||||
ProjectRef = A8F3BFF12F4E3794006BC252 /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A811973D2F4C1C710013ABD0 /* Products */;
|
||||
ProjectRef = A81196782F4C1C710013ABD0 /* SampleApp.xcodeproj */;
|
||||
@@ -5497,10 +5017,6 @@
|
||||
ProductGroup = A8A5C5EE2F4C4FEC00572B4A /* Products */;
|
||||
ProjectRef = A8A5C5C12F4C4FEC00572B4A /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3C0222F4E3794006BC252 /* Products */;
|
||||
ProjectRef = A8F3C00A2F4E3794006BC252 /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8118FCC2F4C1C250013ABD0 /* Products */;
|
||||
ProjectRef = A8118F012F4C1C250013ABD0 /* SampleApp.xcodeproj */;
|
||||
@@ -5545,14 +5061,6 @@
|
||||
ProductGroup = A8FAC0632F4B50D10061A851 /* Products */;
|
||||
ProjectRef = A8FABF722F4B50D10061A851 /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A802C8E52F525B910049FE2B /* Products */;
|
||||
ProjectRef = A802C8B62F525B910049FE2B /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3FAED2F4E96D7006BC252 /* Products */;
|
||||
ProjectRef = A8F3FAD92F4E96D7006BC252 /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8FACFA52F4B5CD40061A851 /* Products */;
|
||||
ProjectRef = A8FACE982F4B5CD40061A851 /* SampleApp.xcodeproj */;
|
||||
@@ -5573,10 +5081,6 @@
|
||||
ProductGroup = A85A11E02F4B34EF002E2E11 /* Products */;
|
||||
ProjectRef = A85A10DD2F4B34EF002E2E11 /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3FAF12F4E96D7006BC252 /* Products */;
|
||||
ProjectRef = A8F3FAC02F4E96D7006BC252 /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8CCC24E2F4B654400B0089A /* Products */;
|
||||
ProjectRef = A8CCC1792F4B654400B0089A /* SampleApp.xcodeproj */;
|
||||
@@ -5597,10 +5101,6 @@
|
||||
ProductGroup = A8CCD2222F4B6B0000B0089A /* Products */;
|
||||
ProjectRef = A8CCD1552F4B6B0000B0089A /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A802C8E32F525B910049FE2B /* Products */;
|
||||
ProjectRef = A802C8CF2F525B910049FE2B /* SampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8CCC2502F4B654400B0089A /* Products */;
|
||||
ProjectRef = A8CCC1922F4B654400B0089A /* SampleApp.xcodeproj */;
|
||||
@@ -5637,10 +5137,6 @@
|
||||
ProductGroup = A81197392F4C1C710013ABD0 /* Products */;
|
||||
ProjectRef = A811969D2F4C1C710013ABD0 /* SwiftSampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3C0202F4E3794006BC252 /* Products */;
|
||||
ProjectRef = A8F3C0162F4E3794006BC252 /* SwiftSampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A863719D2F4CF74D00E66784 /* Products */;
|
||||
ProjectRef = A86371932F4CF74D00E66784 /* SwiftSampleApp.xcodeproj */;
|
||||
@@ -5665,10 +5161,6 @@
|
||||
ProductGroup = A85AEC752F4B22F6002E2E11 /* Products */;
|
||||
ProjectRef = A85AE6D52F4B22F6002E2E11 /* SwiftSampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8F3FAEF2F4E96D7006BC252 /* Products */;
|
||||
ProjectRef = A8F3FAE52F4E96D7006BC252 /* SwiftSampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8FACF9B2F4B5CD40061A851 /* Products */;
|
||||
ProjectRef = A8FACEBD2F4B5CD40061A851 /* SwiftSampleApp.xcodeproj */;
|
||||
@@ -5701,10 +5193,6 @@
|
||||
ProductGroup = A8A5B6C02F4C4C8600572B4A /* Products */;
|
||||
ProjectRef = A8A5B6B42F4C4C8600572B4A /* SwiftSampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A802C8E72F525B910049FE2B /* Products */;
|
||||
ProjectRef = A802C8DB2F525B910049FE2B /* SwiftSampleApp.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = A8A5ACE52F4C339400572B4A /* Products */;
|
||||
ProjectRef = A8A5ACDC2F4C339400572B4A /* SwiftSampleApp.xcodeproj */;
|
||||
@@ -5728,90 +5216,6 @@
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
A802C9F92F525C030049FE2B /* libfragmentzip */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = libfragmentzip;
|
||||
remoteRef = A802C9F82F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802C9FB2F525C030049FE2B /* libfragmentzip */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = libfragmentzip;
|
||||
remoteRef = A802C9FA2F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802C9FD2F525C030049FE2B /* libfragmentzip.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libfragmentzip.a;
|
||||
remoteRef = A802C9FC2F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802C9FF2F525C030049FE2B /* libfragmentzip.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libfragmentzip.a;
|
||||
remoteRef = A802C9FE2F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802CA022F525C030049FE2B /* libgeneral */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = libgeneral;
|
||||
remoteRef = A802CA012F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802CA072F525C030049FE2B /* Roxas.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Roxas.framework;
|
||||
remoteRef = A802CA062F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802CA092F525C030049FE2B /* Roxas.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Roxas.framework;
|
||||
remoteRef = A802CA082F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802CA0B2F525C030049FE2B /* RoxasTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = RoxasTests.xctest;
|
||||
remoteRef = A802CA0A2F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802CA0F2F525C030049FE2B /* SampleApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = SampleApp.app;
|
||||
remoteRef = A802CA0E2F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802CA112F525C030049FE2B /* NSAttributedString+MarkdownTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "NSAttributedString+MarkdownTests.xctest";
|
||||
remoteRef = A802CA102F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802CA142F525C030049FE2B /* SampleApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = SampleApp.app;
|
||||
remoteRef = A802CA132F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A802CA172F525C030049FE2B /* SwiftSampleApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = SwiftSampleApp.app;
|
||||
remoteRef = A802CA162F525C030049FE2B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A81173232F4B8DBD0013ABD0 /* libem_proxy_static.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
@@ -7548,174 +6952,6 @@
|
||||
remoteRef = A8EEDAF12F4B1A0700F2436D /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C1322F4E37A5006BC252 /* libfragmentzip */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = libfragmentzip;
|
||||
remoteRef = A8F3C1312F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C1342F4E37A5006BC252 /* libfragmentzip */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = libfragmentzip;
|
||||
remoteRef = A8F3C1332F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C1362F4E37A5006BC252 /* libfragmentzip.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libfragmentzip.a;
|
||||
remoteRef = A8F3C1352F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C1382F4E37A5006BC252 /* libfragmentzip.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libfragmentzip.a;
|
||||
remoteRef = A8F3C1372F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C13B2F4E37A5006BC252 /* libgeneral */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = libgeneral;
|
||||
remoteRef = A8F3C13A2F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C1402F4E37A5006BC252 /* Roxas.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Roxas.framework;
|
||||
remoteRef = A8F3C13F2F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C1422F4E37A5006BC252 /* Roxas.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Roxas.framework;
|
||||
remoteRef = A8F3C1412F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C1442F4E37A5006BC252 /* RoxasTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = RoxasTests.xctest;
|
||||
remoteRef = A8F3C1432F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C1482F4E37A5006BC252 /* SampleApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = SampleApp.app;
|
||||
remoteRef = A8F3C1472F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C14A2F4E37A5006BC252 /* NSAttributedString+MarkdownTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "NSAttributedString+MarkdownTests.xctest";
|
||||
remoteRef = A8F3C1492F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C14D2F4E37A5006BC252 /* SampleApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = SampleApp.app;
|
||||
remoteRef = A8F3C14C2F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3C1502F4E37A5006BC252 /* SwiftSampleApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = SwiftSampleApp.app;
|
||||
remoteRef = A8F3C14F2F4E37A5006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC072F4E998F006BC252 /* libfragmentzip */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = libfragmentzip;
|
||||
remoteRef = A8F3FC062F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC092F4E998F006BC252 /* libfragmentzip */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = libfragmentzip;
|
||||
remoteRef = A8F3FC082F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC0B2F4E998F006BC252 /* libfragmentzip.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libfragmentzip.a;
|
||||
remoteRef = A8F3FC0A2F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC0D2F4E998F006BC252 /* libfragmentzip.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libfragmentzip.a;
|
||||
remoteRef = A8F3FC0C2F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC102F4E998F006BC252 /* libgeneral */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = libgeneral;
|
||||
remoteRef = A8F3FC0F2F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC152F4E998F006BC252 /* Roxas.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Roxas.framework;
|
||||
remoteRef = A8F3FC142F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC172F4E998F006BC252 /* Roxas.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Roxas.framework;
|
||||
remoteRef = A8F3FC162F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC192F4E998F006BC252 /* RoxasTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = RoxasTests.xctest;
|
||||
remoteRef = A8F3FC182F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC1C2F4E998F006BC252 /* SampleApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = SampleApp.app;
|
||||
remoteRef = A8F3FC1B2F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC202F4E998F006BC252 /* SampleApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = SampleApp.app;
|
||||
remoteRef = A8F3FC1F2F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC222F4E998F006BC252 /* NSAttributedString+MarkdownTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "NSAttributedString+MarkdownTests.xctest";
|
||||
remoteRef = A8F3FC212F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8F3FC252F4E998F006BC252 /* SwiftSampleApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = SwiftSampleApp.app;
|
||||
remoteRef = A8F3FC242F4E998F006BC252 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
A8FAC1CF2F4B51980061A851 /* libem_proxy_static.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
|
||||
@@ -92,6 +92,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
self.setTintColor()
|
||||
self.setTintColor()
|
||||
self.prepareImageCache()
|
||||
|
||||
|
||||
@@ -368,7 +368,7 @@ private extension FeaturedViewController
|
||||
#keyPath(StoreApp._source._apps),
|
||||
#keyPath(StoreApp.bundleIdentifier),
|
||||
StoreApp.altstoreAppID,
|
||||
#keyPath(StoreApp.installedApp)
|
||||
#keyPath(StoreApp.installedApp),
|
||||
)
|
||||
|
||||
let primaryFetchRequest = fetchRequest.copy() as! NSFetchRequest<StoreApp>
|
||||
|
||||
@@ -997,7 +997,6 @@ extension AppManager
|
||||
case .failure(let error): completionHandler(.failure(error))
|
||||
case .success(let installedApp): completionHandler(.success(installedApp))
|
||||
}
|
||||
//UIApplication.shared.open(shortcutURLon, options: [:], completionHandler: nil)
|
||||
}
|
||||
installOperation.addDependency(sendAppOperation)
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ import AltStoreCore
|
||||
import AltSign
|
||||
import Roxas
|
||||
|
||||
let shortcutURLonDelay = URL(string: "shortcuts://run-shortcut?name=TurnOnDataDelay")!
|
||||
|
||||
@objc(InstallAppOperation)
|
||||
final class InstallAppOperation: ResultOperation<InstalledApp>
|
||||
{
|
||||
@@ -178,13 +176,6 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
|
||||
|
||||
var installing = true
|
||||
if installedApp.storeApp?.bundleIdentifier.range(of: Bundle.Info.appbundleIdentifier) != nil {
|
||||
do {
|
||||
// we need to flush changes to the disk now in case the changes are lost when iOS kills current process
|
||||
try installedApp.managedObjectContext?.save()
|
||||
} catch {
|
||||
print("Failed to flush installedApp to disk: \(error)")
|
||||
}
|
||||
|
||||
// Reinstalling ourself will hang until we leave the app, so we need to exit it without force closing
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||||
if UIApplication.shared.applicationState != .active {
|
||||
@@ -213,10 +204,6 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
|
||||
let alert = UIAlertController(title: "Finish Refresh", message: "Please reopen SideStore after the process is finished.To finish refreshing, SideStore must be moved to the background. To do this, you can either go to the Home Screen manually or by hitting Continue. Please reopen SideStore after doing this.", preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default, handler: { _ in
|
||||
print("Going home")
|
||||
// Cell Shortcut
|
||||
UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in
|
||||
print("Cell OFF Shortcut finished execution.")}
|
||||
|
||||
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
|
||||
}))
|
||||
|
||||
@@ -233,8 +220,6 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cell Shortcut
|
||||
UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in print("Cell OFF Shortcut finished execution.")}
|
||||
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@ private extension PatchAppOperation
|
||||
#if targetEnvironment(simulator)
|
||||
throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion)
|
||||
#else
|
||||
|
||||
let spotlightPath = "Applications/Spotlight.app/Spotlight"
|
||||
let spotlightFileURL = self.patchDirectory.appendingPathComponent(spotlightPath)
|
||||
|
||||
|
||||
@@ -25,48 +25,39 @@ final class SendAppOperation: ResultOperation<()>
|
||||
self.progress.totalUnitCount = 1
|
||||
}
|
||||
|
||||
override func main() {
|
||||
override func main()
|
||||
{
|
||||
super.main()
|
||||
|
||||
if let error = self.context.error {
|
||||
|
||||
if let error = self.context.error
|
||||
{
|
||||
return self.finish(.failure(error))
|
||||
}
|
||||
|
||||
|
||||
guard let resignedApp = self.context.resignedApp else {
|
||||
return self.finish(.failure(OperationError.invalidParameters("SendAppOperation.main: self.resignedApp is nil")))
|
||||
}
|
||||
|
||||
let shortcutURLoff = URL(string: "shortcuts://run-shortcut?name=TurnOffData")!
|
||||
|
||||
|
||||
// self.context.resignedApp.fileURL points to the app bundle, but we want the .ipa.
|
||||
let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL, storeApp: nil)
|
||||
let fileURL = InstalledApp.refreshedIPAURL(for: app)
|
||||
|
||||
print("AFC App `fileURL`: \(fileURL.absoluteString)")
|
||||
|
||||
// Wait for Shortcut to Finish Before Proceeding
|
||||
UIApplication.shared.open(shortcutURLoff, options: [:]) { _ in
|
||||
print("Shortcut finished execution. Proceeding with file transfer.")
|
||||
|
||||
DispatchQueue.global().async {
|
||||
self.processFile(at: fileURL, for: app.bundleIdentifier)
|
||||
|
||||
if let data = NSData(contentsOf: fileURL) {
|
||||
do {
|
||||
let bytes = Data(data)
|
||||
try yeetAppAFC(app.bundleIdentifier, bytes)
|
||||
self.progress.completedUnitCount += 1
|
||||
self.finish(.success(()))
|
||||
} catch {
|
||||
self.finish(.failure(MinimuxerError.RwAfc))
|
||||
self.progress.completedUnitCount += 1
|
||||
self.finish(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func processFile(at fileURL: URL, for bundleIdentifier: String) {
|
||||
guard let data = NSData(contentsOf: fileURL) else {
|
||||
} else {
|
||||
print("IPA doesn't exist????")
|
||||
return self.finish(.failure(OperationError(.appNotFound(name: bundleIdentifier))))
|
||||
}
|
||||
|
||||
do {
|
||||
let bytes = Data(data)
|
||||
try yeetAppAFC(bundleIdentifier, bytes)
|
||||
self.progress.completedUnitCount += 1
|
||||
self.finish(.success(()))
|
||||
} catch {
|
||||
self.finish(.failure(MinimuxerError.RwAfc))
|
||||
self.progress.completedUnitCount += 1
|
||||
self.finish(.success(()))
|
||||
self.finish(.failure(OperationError(.appNotFound(name: resignedApp.name))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,40 +399,6 @@ private extension DatabaseManager
|
||||
// For backwards compatibility reasons, we cannot use localApp's buildVersion as storeBuildVersion,
|
||||
// or else the latest update will _always_ be considered new because we don't use buildVersions in our source (yet).
|
||||
installedApp = InstalledApp(resignedApp: localApp, originalBundleIdentifier: StoreApp.altstoreAppID, certificateSerialNumber: serialNumber, storeBuildVersion: nil, context: context)
|
||||
|
||||
// figure out if the current AltStoreApp is signed with "Use Main Profie" option
|
||||
// by checking if the first extension's entitlement's application-identifier matches current one
|
||||
repeat {
|
||||
guard let pluginURL = Bundle.main.builtInPlugInsURL else {
|
||||
installedApp.useMainProfile = true
|
||||
break
|
||||
}
|
||||
guard let pluginFolders = try? FileManager.default.contentsOfDirectory(at: pluginURL, includingPropertiesForKeys: nil) else {
|
||||
installedApp.useMainProfile = true
|
||||
break
|
||||
}
|
||||
|
||||
guard let pluginFolder = pluginFolders.first, let altPluginApp = ALTApplication(fileURL: pluginFolder) else {
|
||||
installedApp.useMainProfile = true
|
||||
break
|
||||
}
|
||||
|
||||
let entitlements = altPluginApp.entitlements
|
||||
guard let appId = entitlements[ALTEntitlement.applicationIdentifier] as? String else {
|
||||
installedApp.useMainProfile = false
|
||||
print("no ALTEntitlementApplicationIdentifier???")
|
||||
break
|
||||
}
|
||||
|
||||
if appId.hasSuffix(Bundle.main.bundleIdentifier!) {
|
||||
installedApp.useMainProfile = true
|
||||
} else {
|
||||
installedApp.useMainProfile = false
|
||||
}
|
||||
|
||||
|
||||
} while(false)
|
||||
|
||||
installedApp.storeApp = storeApp
|
||||
}
|
||||
|
||||
|
||||
2
Dependencies/AltSign
vendored
2
Dependencies/AltSign
vendored
Submodule Dependencies/AltSign updated: 7efe511440...4819a7984f
2
Dependencies/minimuxer
vendored
2
Dependencies/minimuxer
vendored
Submodule Dependencies/minimuxer updated: f9432a085b...9035aa25ae
@@ -1,132 +0,0 @@
|
||||
//
|
||||
// IfManager.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by ny on 2/27/26.
|
||||
// Copyright © 2026 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
fileprivate func uti(_ uint: UInt32) -> String? {
|
||||
var buf = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
||||
var addr = in_addr(s_addr: uint.bigEndian)
|
||||
guard inet_ntop(AF_INET, &addr, &buf, UInt32(INET_ADDRSTRLEN)) != nil,
|
||||
let str = String(utf8String: buf) else { return nil }
|
||||
return str
|
||||
}
|
||||
|
||||
fileprivate func socktouint(_ sock: inout sockaddr) -> UInt32 {
|
||||
var buf = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
||||
guard getnameinfo(&sock, socklen_t(sock.sa_len), &buf, socklen_t(buf.count), nil, socklen_t(0), NI_NUMERICHOST) == 0,
|
||||
let name = String(utf8String: buf) else {
|
||||
return 0
|
||||
}
|
||||
var addr = in_addr()
|
||||
guard name.withCString({ cString in
|
||||
inet_pton(AF_INET, cString, &addr)
|
||||
}) == 1 else { return 0 }
|
||||
return addr.s_addr.bigEndian
|
||||
}
|
||||
|
||||
public struct NetInfo: Hashable, CustomStringConvertible {
|
||||
public let name: String
|
||||
public let hostIP: String
|
||||
public let destIP: String
|
||||
public let maskIP: String
|
||||
|
||||
private let host: UInt32
|
||||
private let dest: UInt32
|
||||
private let mask: UInt32
|
||||
|
||||
init(name: String, host: UInt32, dest: UInt32, mask: UInt32) {
|
||||
self.name = name
|
||||
self.host = host
|
||||
self.dest = dest
|
||||
self.mask = mask
|
||||
self.hostIP = uti(host) ?? "10.7.0.0"
|
||||
self.destIP = uti(dest) ?? "10.7.0.1"
|
||||
self.maskIP = uti(mask) ?? "255.255.255.0"
|
||||
}
|
||||
|
||||
init?(_ ifaddr: ifaddrs) {
|
||||
guard
|
||||
let ianame = String(utf8String: ifaddr.ifa_name)
|
||||
else { return nil }
|
||||
|
||||
let host = socktouint(&ifaddr.ifa_addr.pointee)
|
||||
let dest = socktouint(&ifaddr.ifa_dstaddr.pointee)
|
||||
let mask = socktouint(&ifaddr.ifa_netmask.pointee)
|
||||
|
||||
self.init(name: ianame, host: host, dest: dest, mask: mask)
|
||||
}
|
||||
|
||||
// computed networking values (still numeric internally)
|
||||
public var minIP: UInt32 { host & mask }
|
||||
public var maxIP: UInt32 { host | ~mask }
|
||||
|
||||
public var minIPString: String { uti(minIP) ?? "nil" }
|
||||
public var maxIPString: String { uti(maxIP) ?? "nil" }
|
||||
|
||||
public var description: String {
|
||||
"\(name) | ip=\(hostIP) dest=\(destIP) mask=\(maskIP) range=\(minIPString)-\(maxIPString)"
|
||||
}
|
||||
}
|
||||
|
||||
final class IfManager: Sendable {
|
||||
public static let shared = IfManager()
|
||||
nonisolated(unsafe) private(set) var addrs: Set<NetInfo> = Set()
|
||||
|
||||
private init() {
|
||||
self.addrs = IfManager.query()
|
||||
}
|
||||
|
||||
|
||||
public func query() {
|
||||
addrs = IfManager.query()
|
||||
}
|
||||
|
||||
private static func query() -> Set<NetInfo> {
|
||||
var addrs = Set<NetInfo>()
|
||||
var head: UnsafeMutablePointer<ifaddrs>? = nil
|
||||
guard getifaddrs(&head) == 0, let first = head else { return addrs }
|
||||
defer { freeifaddrs(head) }
|
||||
|
||||
var cursor: UnsafeMutablePointer<ifaddrs>? = first
|
||||
while let current = cursor {
|
||||
// we only want v4 interfaces that aren't loopback and aren't masked 255.255.255.255
|
||||
let entry = current.pointee
|
||||
let flags = Int32(entry.ifa_flags)
|
||||
|
||||
let isIPv4 = entry.ifa_addr.pointee.sa_family == UInt8(AF_INET)
|
||||
let isActive = (flags & (IFF_UP | IFF_RUNNING | IFF_LOOPBACK)) == (IFF_UP | IFF_RUNNING)
|
||||
|
||||
if isIPv4, isActive, let info = NetInfo(entry), info.maskIP != "255.255.255.255" {
|
||||
addrs.insert(info)
|
||||
}
|
||||
|
||||
cursor = entry.ifa_next
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
private var nextLAN: NetInfo? {
|
||||
addrs.first { $0.name.starts(with: "en") }
|
||||
}
|
||||
|
||||
var nextProbableSideVPN: NetInfo? {
|
||||
// try old 10.7.0.1 first, then fallback to next v4
|
||||
// user should only be connected to StosVPN/LocalDevVPN
|
||||
addrs.first {
|
||||
$0.hostIP == "10.7.0.1" ||
|
||||
$0.name.starts(with: "utun")
|
||||
}
|
||||
}
|
||||
|
||||
var sideVPNPatched: Bool {
|
||||
nextLAN?.maskIP == nextProbableSideVPN?.maskIP &&
|
||||
nextLAN?.maxIP == nextProbableSideVPN?.maxIP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,21 +13,14 @@ var isMinimuxerReady: Bool {
|
||||
print("isMinimuxerReady property is always true on simulator")
|
||||
return true
|
||||
#else
|
||||
IfManager.shared.query()
|
||||
if #available(iOS 26.4, *) {
|
||||
print("Running patched check")
|
||||
return minimuxer.ready() && IfManager.shared.sideVPNPatched
|
||||
} else {
|
||||
return minimuxer.ready()
|
||||
}
|
||||
return minimuxer.ready()
|
||||
#endif
|
||||
}
|
||||
|
||||
func minimuxerStartWithLogger(_ pairingFile: String, _ logPath: String, _ loggingEnabled: Bool) throws {
|
||||
func minimuxerStartWithLogger(_ pairingFile: String,_ logPath: String,_ loggingEnabled: Bool) throws {
|
||||
#if targetEnvironment(simulator)
|
||||
print("minimuxerStartWithLogger(\(pairingFile), \(logPath), \(loggingEnabled)) is no-op on simulator")
|
||||
print("minimuxerStartWithLogger(\(pairingFile), \(logPath), \(loggingEnabled) is no-op on simulator")
|
||||
#else
|
||||
print("minimuxerStartWithLogger(\(pairingFile), \(logPath), \(loggingEnabled))")
|
||||
try minimuxer.startWithLogger(pairingFile, logPath, loggingEnabled)
|
||||
#endif
|
||||
}
|
||||
@@ -44,8 +37,7 @@ func installProvisioningProfiles(_ profileData: Data) throws {
|
||||
#if targetEnvironment(simulator)
|
||||
print("installProvisioningProfiles(\(profileData)) is no-op on simulator")
|
||||
#else
|
||||
let slice = profileData.toRustByteSlice()
|
||||
try minimuxer.install_provisioning_profile(slice.forRust())
|
||||
try minimuxer.install_provisioning_profile(profileData.toRustByteSlice().forRust())
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -63,8 +55,7 @@ func yeetAppAFC(_ bundleId: String, _ rawBytes: Data) throws {
|
||||
#if targetEnvironment(simulator)
|
||||
print("yeetAppAFC(\(bundleId), \(rawBytes)) is no-op on simulator")
|
||||
#else
|
||||
let slice = rawBytes.toRustByteSlice()
|
||||
try minimuxer.yeet_app_afc(bundleId, slice.forRust())
|
||||
try minimuxer.yeet_app_afc(bundleId, rawBytes.toRustByteSlice().forRust())
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
37
release-notes.md
Normal file
37
release-notes.md
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
|
||||
### 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)
|
||||
@@ -95,7 +95,6 @@ def resolve_start_commit(last_successful: str):
|
||||
except Exception:
|
||||
return first_commit()
|
||||
|
||||
|
||||
def generate_release_notes(last_successful, tag, branch):
|
||||
current = head_commit()
|
||||
|
||||
@@ -125,12 +124,7 @@ def generate_release_notes(last_successful, tag, branch):
|
||||
for m in messages:
|
||||
section += f"{fmt_msg(m)}\n"
|
||||
|
||||
if commit_exists(branch):
|
||||
previous_range = branch
|
||||
else:
|
||||
previous_range = last_successful
|
||||
|
||||
prev_authors = authors(previous_range)
|
||||
prev_authors = authors(branch)
|
||||
recent_authors = authors(f"{last_successful}..{current}")
|
||||
new_authors = recent_authors - prev_authors
|
||||
|
||||
@@ -143,26 +137,13 @@ def generate_release_notes(last_successful, tag, branch):
|
||||
url = repo_url()
|
||||
section += (
|
||||
f"\n{HEADER_MARKER} Full Changelog: "
|
||||
f"[{ref_display(last_successful)}...{ref_display(current)}]"
|
||||
f"[{last_successful[:8]}...{current[:8]}]"
|
||||
f"({url}/compare/{last_successful}...{current})\n"
|
||||
)
|
||||
|
||||
return section
|
||||
|
||||
|
||||
def ref_display(ref):
|
||||
try:
|
||||
tag = run(f'git describe --tags --exact-match "{ref}" 2>/dev/null || true').strip()
|
||||
|
||||
# allow only semantic version tags: X.Y.Z
|
||||
if re.fullmatch(r'\d+\.\d+\.\d+', tag):
|
||||
return tag
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return ref[:8]
|
||||
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# markdown update
|
||||
# ----------------------------------------------------------
|
||||
@@ -235,7 +216,7 @@ def retrieve_tag(tag, file_path: Path):
|
||||
fr"^{TAG_MARKER} {re.escape(tag)}$",
|
||||
content,
|
||||
re.MULTILINE | re.IGNORECASE,
|
||||
)
|
||||
)
|
||||
|
||||
if not match:
|
||||
return ""
|
||||
@@ -295,4 +276,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
@@ -5,6 +5,7 @@ import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import textwrap
|
||||
import sys
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
@@ -107,13 +108,13 @@ def main():
|
||||
gen_cmd = (
|
||||
f"python3 {script} "
|
||||
f"{args.last_successful_commit} {args.release_tag} "
|
||||
f'--output-dir "{notes_dir}"'
|
||||
f"--output-dir \"{notes_dir}\""
|
||||
)
|
||||
else:
|
||||
gen_cmd = (
|
||||
f"python3 {script} "
|
||||
f"{args.short_commit} {args.release_tag} "
|
||||
f'--output-dir "{notes_dir}"'
|
||||
f"--output-dir \"{notes_dir}\""
|
||||
)
|
||||
|
||||
sh(gen_cmd, cwd=repo_root)
|
||||
@@ -139,7 +140,15 @@ def main():
|
||||
formatted = now.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
human = now.strftime("%c")
|
||||
|
||||
localized_description = getFormattedLocalizedDescription(args.marketing_version, args.short_commit, human, notes)
|
||||
localized_description = textwrap.dedent(f"""
|
||||
This is release for:
|
||||
- version: "{args.marketing_version}"
|
||||
- revision: "{args.short_commit}"
|
||||
- timestamp: "{human}"
|
||||
|
||||
Release Notes:
|
||||
{notes}
|
||||
""").strip()
|
||||
|
||||
metadata = {
|
||||
"is_beta": bool(args.is_beta),
|
||||
@@ -161,16 +170,6 @@ 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()
|
||||
main()
|
||||
@@ -6,13 +6,12 @@ import datetime
|
||||
from pathlib import Path
|
||||
import time
|
||||
import json
|
||||
import inspect
|
||||
import re
|
||||
from posix import getcwd
|
||||
|
||||
# REPO ROOT relative to script dir
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
SCRIPTS = ROOT / 'scripts/ci'
|
||||
BUILD_SETTINGS_OUTFILE = "project-build-settings.txt"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# helpers
|
||||
@@ -58,69 +57,101 @@ 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
|
||||
# ----------------------------------------------------------
|
||||
# BUILD NUMBER RESERVATION
|
||||
# ----------------------------------------------------------
|
||||
|
||||
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
|
||||
def reserve_build_number(repo, max_attempts=5):
|
||||
repo = Path(repo).resolve()
|
||||
version_json = repo / "version.json"
|
||||
|
||||
out = runAndGet(f"git rev-list --count {last_commit}..HEAD")
|
||||
return int(out)
|
||||
except Exception:
|
||||
return 0
|
||||
def utc_now():
|
||||
return datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
def read():
|
||||
branch = runAndGet("git rev-parse --abbrev-ref HEAD", cwd=repo)
|
||||
|
||||
defaults = {
|
||||
"build": 0,
|
||||
"issued_at": utc_now(),
|
||||
"tag": branch,
|
||||
}
|
||||
|
||||
if version_json.exists():
|
||||
data = json.loads(version_json.read_text())
|
||||
else:
|
||||
data = {}
|
||||
|
||||
# fill missing fields
|
||||
for k, v in defaults.items():
|
||||
data.setdefault(k, v)
|
||||
|
||||
# ensure tag always tracks current branch
|
||||
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):
|
||||
run("git fetch --depth=1 origin HEAD", check=False, cwd=repo)
|
||||
run("git reset --hard FETCH_HEAD", check=False, cwd=repo)
|
||||
|
||||
data = read()
|
||||
data["build"] += 1
|
||||
data["issued_at"] = utc_now()
|
||||
|
||||
write(data)
|
||||
|
||||
run("git add version.json", check=False, cwd=repo)
|
||||
run(f"git commit -m '{data['tag']} - build no: {data['build']}' || true", check=False, cwd=repo)
|
||||
|
||||
rc = subprocess.call("git push", 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
|
||||
# ----------------------------------------------------------
|
||||
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 _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} = ' "
|
||||
def get_product_name():
|
||||
return runAndGet(
|
||||
"xcodebuild -showBuildSettings "
|
||||
"| grep PRODUCT_NAME "
|
||||
"| tail -1 "
|
||||
"| sed -e 's/.*= //g'"
|
||||
)
|
||||
|
||||
def query_build_setting(name):
|
||||
return _extract_setting(
|
||||
f"xcodebuild -showBuildSettings 2>&1 "
|
||||
f"| grep '{name} = ' "
|
||||
def get_bundle_id():
|
||||
return runAndGet(
|
||||
"xcodebuild -showBuildSettings 2>&1 "
|
||||
"| grep 'PRODUCT_BUNDLE_IDENTIFIER = ' "
|
||||
"| 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'")
|
||||
|
||||
def set_marketing_version(version):
|
||||
def set_marketing_version(qualified):
|
||||
run(
|
||||
f"sed -E -i '' "
|
||||
f"'s/^MARKETING_VERSION = .*/MARKETING_VERSION = {version}/' "
|
||||
f"'s/^MARKETING_VERSION = .*/MARKETING_VERSION = {qualified}/' "
|
||||
f"{ROOT}/Build.xcconfig"
|
||||
)
|
||||
|
||||
|
||||
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()
|
||||
return f"{base}-{date}.{build_num}+{short}"
|
||||
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}"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# CLEAN
|
||||
@@ -215,13 +246,13 @@ def tests_run(model):
|
||||
# ----------------------------------------------------------
|
||||
|
||||
def encrypt_logs(name):
|
||||
pwd = getenv("BUILD_LOG_ZIP_PASSWORD")
|
||||
cwd = getcwd()
|
||||
if not pwd or not pwd.strip():
|
||||
print("BUILD_LOG_ZIP_PASSWORD not set — logs will be uploaded UNENCRYPTED", file=sys.stderr)
|
||||
run(f'cd {cwd}/build/logs && zip -r {cwd}/{name}.zip *')
|
||||
return
|
||||
run(f'cd {cwd}/build/logs && zip -e -P "{pwd}" {cwd}/{name}.zip *')
|
||||
default_pwd = "12345"
|
||||
pwd = getenv("BUILD_LOG_ZIP_PASSWORD", default_pwd)
|
||||
|
||||
if pwd == default_pwd:
|
||||
print("Warning: BUILD_LOG_ZIP_PASSWORD not set, using fallback password", file=sys.stderr)
|
||||
|
||||
run(f'cd build/logs && zip -e -P "{pwd}" ../../{name}.zip *')
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# RELEASE NOTES
|
||||
@@ -245,13 +276,22 @@ def retrieve_release_notes(tag):
|
||||
# ----------------------------------------------------------
|
||||
# DEPLOY SOURCE.JSON
|
||||
# ----------------------------------------------------------
|
||||
def generate_metadata(release_tag, short_commit, marketing_version, channel, bundle_id, ipa_name, last_successful_commit=None):
|
||||
|
||||
def deploy(repo, source_json, release_tag, short_commit, marketing_version, channel, bundle_id, ipa_name, last_successful_commit=None):
|
||||
repo = (ROOT / repo).resolve()
|
||||
ipa_path = ROOT / ipa_name
|
||||
source_json_path = repo / source_json
|
||||
metadata = 'source-metadata.json'
|
||||
|
||||
if not repo.exists():
|
||||
raise SystemExit(f"{repo} repo missing")
|
||||
|
||||
if not ipa_path.exists():
|
||||
raise SystemExit(f"{ipa_path} missing")
|
||||
|
||||
if not source_json_path.exists():
|
||||
raise SystemExit(f"{source_json} missing inside repo")
|
||||
|
||||
cmd = (
|
||||
f"python3 {SCRIPTS}/generate_source_metadata.py "
|
||||
f"--repo-root {ROOT} "
|
||||
@@ -266,26 +306,12 @@ def generate_metadata(release_tag, short_commit, marketing_version, channel, bun
|
||||
f"--bundle-id {bundle_id}"
|
||||
)
|
||||
|
||||
# pass only if provided
|
||||
if last_successful_commit:
|
||||
cmd += f" --last-successful-commit {last_successful_commit}"
|
||||
|
||||
run(cmd)
|
||||
|
||||
def deploy(repo, source_json, release_tag, marketing_version):
|
||||
repo = (ROOT / repo).resolve()
|
||||
source_json_path = repo / source_json
|
||||
metadata = 'source-metadata.json'
|
||||
|
||||
if not repo.exists():
|
||||
raise SystemExit(f"{repo} repo missing")
|
||||
|
||||
if not (repo / ".git").exists():
|
||||
print("Repo is not a git repository, skipping deploy", file=sys.stderr)
|
||||
return
|
||||
|
||||
if not source_json_path.exists():
|
||||
raise SystemExit(f"{source_json} missing inside repo")
|
||||
|
||||
run("git config user.name 'GitHub Actions'", check=False)
|
||||
run("git config user.email 'github-actions@github.com'", check=False)
|
||||
|
||||
@@ -294,7 +320,7 @@ def deploy(repo, source_json, release_tag, marketing_version):
|
||||
run("git switch main || git switch -c main origin/main", cwd=repo)
|
||||
run("git reset --hard origin/main", cwd=repo)
|
||||
# ------------------------------------------------------
|
||||
|
||||
|
||||
max_attempts = 5
|
||||
for attempt in range(1, max_attempts + 1):
|
||||
if attempt > 1:
|
||||
@@ -317,49 +343,28 @@ def deploy(repo, source_json, release_tag, marketing_version):
|
||||
else:
|
||||
raise SystemExit("Deploy push failed after retries")
|
||||
|
||||
|
||||
def last_successful_commit(is_stable, tag=None):
|
||||
is_stable = str(is_stable).lower() in ("1", "true", "yes")
|
||||
def last_successful_commit(workflow, branch):
|
||||
import json
|
||||
|
||||
try:
|
||||
if is_stable:
|
||||
prev_tag = runAndGet(
|
||||
r'git tag --sort=-v:refname '
|
||||
r'| grep -E "^[0-9]+\.[0-9]+\.[0-9]+$" '
|
||||
r'| sed -n "2p" || true'
|
||||
).strip()
|
||||
out = runAndGet(
|
||||
f'gh run list '
|
||||
f'--workflow "{workflow}" '
|
||||
f'--json headSha,conclusion,headBranch'
|
||||
)
|
||||
|
||||
if prev_tag:
|
||||
return runAndGet(f'git rev-parse "{prev_tag}^{{commit}}"')
|
||||
runs = json.loads(out)
|
||||
|
||||
return None # ← changed
|
||||
|
||||
if tag:
|
||||
exists = subprocess.call(
|
||||
f'git rev-parse -q --verify "refs/tags/{tag}"',
|
||||
shell=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
) == 0
|
||||
|
||||
if exists:
|
||||
return runAndGet(f'git rev-parse "{tag}^{{commit}}"')
|
||||
for r in runs:
|
||||
if r.get("conclusion") == "success" and r.get("headBranch") == branch:
|
||||
return r["headSha"]
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
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")
|
||||
draft = False
|
||||
prerelease = True
|
||||
latest = False
|
||||
|
||||
if is_stable:
|
||||
prerelease = False
|
||||
latest = True
|
||||
|
||||
def upload_release(release_name, release_tag, commit_sha, repo, upstream_recommendation):
|
||||
token = getenv("GH_TOKEN")
|
||||
if token:
|
||||
os.environ["GH_TOKEN"] = token
|
||||
@@ -372,6 +377,7 @@ 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(
|
||||
@@ -385,92 +391,52 @@ def upload_release(release_name, release_tag, commit_sha, repo, upstream_tag_rec
|
||||
f"--retrieve {release_tag} "
|
||||
f"--output-dir {ROOT}"
|
||||
)
|
||||
|
||||
if is_stable:
|
||||
release_notes = re.sub(
|
||||
r'(?im)^[ \t]*#{1,6}[ \t]*what[’\']?s[ \t]+changed[ \t]*$',
|
||||
"## What's Changed",
|
||||
release_notes,
|
||||
flags=re.IGNORECASE | re.MULTILINE,
|
||||
)
|
||||
|
||||
upstream_block = ""
|
||||
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 [{repo} {tag}]"
|
||||
f"(https://github.com/{repo}/releases?q={tag}).\n\n"
|
||||
)
|
||||
|
||||
header = getFormattedUploadMsg(
|
||||
release_name, commit_sha, repo, upstream_block,
|
||||
built_time, built_date, marketing_version, is_stable,
|
||||
# normalize section header
|
||||
release_notes = re.sub(
|
||||
r'^\s*#{1,6}\s*what(?:\'?s|\s+is)?\s+(?:new|changed).*',
|
||||
"## What's Changed",
|
||||
release_notes,
|
||||
flags=re.IGNORECASE | re.MULTILINE,
|
||||
)
|
||||
|
||||
body = header + release_notes.lstrip() + "\n"
|
||||
upstream_block = ""
|
||||
if upstream_recommendation and upstream_recommendation.strip():
|
||||
upstream_block = 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)
|
||||
body = header + "\n\n" + release_notes.lstrip() + "\n"
|
||||
|
||||
body_file = ROOT / "release_body.md"
|
||||
body_file.write_text(body, encoding="utf-8")
|
||||
|
||||
draft_flag = "--draft" if draft else ""
|
||||
prerelease_flag = "--prerelease" if prerelease else ""
|
||||
latest_flag = "--latest=true" if latest else ""
|
||||
prerelease_flag = "--prerelease" if is_beta else ""
|
||||
|
||||
# create release if it doesn't exist
|
||||
exists = subprocess.call(
|
||||
f'gh release view "{release_tag}"',
|
||||
shell=True,
|
||||
cwd=ROOT,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
) == 0
|
||||
|
||||
if exists:
|
||||
run(
|
||||
f'gh release edit "{release_tag}" '
|
||||
f'--title "{release_name}" '
|
||||
f'--notes-file "{body_file}" '
|
||||
f'{draft_flag} {prerelease_flag} {latest_flag}'
|
||||
)
|
||||
else:
|
||||
run(
|
||||
f'gh release create "{release_tag}" '
|
||||
f'--title "{release_name}" '
|
||||
f'--notes-file "{body_file}" '
|
||||
f'{draft_flag} {prerelease_flag} {latest_flag}'
|
||||
)
|
||||
run(
|
||||
f'gh release edit "{release_tag}" '
|
||||
f'--title "{release_name}" '
|
||||
f'--notes-file "{body_file}" '
|
||||
f'{prerelease_flag}'
|
||||
)
|
||||
|
||||
run(
|
||||
f'gh release upload "{release_tag}" '
|
||||
f'SideStore.ipa SideStore.dSYMs.zip build-logs.zip '
|
||||
f'SideStore.ipa SideStore.dSYMs.zip encrypted-build-logs.zip'
|
||||
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 = ""
|
||||
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!**
|
||||
|
||||
""".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
|
||||
# ----------------------------------------------------------
|
||||
@@ -479,20 +445,17 @@ COMMANDS = {
|
||||
# ----------------------------------------------------------
|
||||
# SHARED
|
||||
# ----------------------------------------------------------
|
||||
"commit-id" : (short_commit, 0, ""),
|
||||
"count-new-commits" : (count_new_commits, 1, "<last_successful_commit>"),
|
||||
"commid-id" : (short_commit, 0, ""),
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# PROJECT INFO
|
||||
# ----------------------------------------------------------
|
||||
"get-marketing-version" : (get_marketing_version, 0, ""),
|
||||
"set-marketing-version" : (set_marketing_version, 1, "<normalized_version>"),
|
||||
"compute-normalized" : (compute_normalized_version,3, "<marketing> <build_num> <short_commit>"),
|
||||
"set-marketing-version" : (set_marketing_version, 1, "<qualified_version>"),
|
||||
"compute-qualified" : (compute_qualified_version, 4, "<marketing> <build_num> <channel> <short_commit>"),
|
||||
"reserve_build_number" : (reserve_build_number, 1, "<repo>"),
|
||||
"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
|
||||
@@ -517,22 +480,20 @@ COMMANDS = {
|
||||
# ----------------------------------------------------------
|
||||
# LOG ENCRYPTION
|
||||
# ----------------------------------------------------------
|
||||
"encrypt-build" : (lambda: encrypt_logs("build-logs"), 0, ""),
|
||||
"encrypt-tests-build" : (lambda: encrypt_logs("tests-build-logs"), 0, ""),
|
||||
"encrypt-tests-run" : (lambda: encrypt_logs("tests-run-logs"), 0, ""),
|
||||
"encrypt-build" : (lambda: encrypt_logs("encrypted-build-logs"), 0, ""),
|
||||
"encrypt-tests-build" : (lambda: encrypt_logs("encrypted-tests-build-logs"), 0, ""),
|
||||
"encrypt-tests-run" : (lambda: encrypt_logs("encrypted-tests-run-logs"), 0, ""),
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# RELEASE / DEPLOY
|
||||
# ----------------------------------------------------------
|
||||
"last-successful-commit" : (last_successful_commit, 1, "<is_stable> [tag]"),
|
||||
"release-notes" : (release_notes, 1, "<tag>"),
|
||||
"retrieve-release-notes" : (retrieve_release_notes, 1, "<tag>"),
|
||||
"generate-metadata" : (generate_metadata, 7,
|
||||
"<release_tag> <short_commit> <marketing_version> <channel> <bundle_id> <ipa_name> [last_successful_commit]"),
|
||||
"deploy" : (deploy, 4,
|
||||
"<repo> <source_json> <release_tag> <marketing_version>"),
|
||||
"upload-release" : (upload_release, 5,
|
||||
"<release_name> <release_tag> <commit_sha> <repo> <upstream_tag_recommended> [is_stable]"),}
|
||||
"last-successful-commit" : (last_successful_commit, 2, "<workflow_name> <branch>"),
|
||||
"release-notes" : (release_notes, 1, "<tag>"),
|
||||
"retrieve-release-notes" : (retrieve_release_notes, 1, "<tag>"),
|
||||
"deploy" : (deploy, 9,
|
||||
"<repo> <source_json> <release_tag> <short_commit> <marketing_version> <channel> <bundle_id> <ipa_name> [last_successful_commit]"),
|
||||
"upload-release" : (upload_release, 5, "<release_name> <release_tag> <commit_sha> <repo> <upstream_recommendation>"),
|
||||
}
|
||||
|
||||
def main():
|
||||
def usage():
|
||||
@@ -558,14 +519,15 @@ def main():
|
||||
suffix = f" {arg_usage}" if arg_usage else ""
|
||||
raise SystemExit(f"Usage: workflow.py {cmd}{suffix}")
|
||||
|
||||
args = sys.argv[2:]
|
||||
args = sys.argv[2:2 + argc]
|
||||
|
||||
result = func(*args) if args else func()
|
||||
result = func(*args) if argc else func()
|
||||
|
||||
# ONLY real outputs go to stdout
|
||||
if result is not None:
|
||||
sys.stdout.write(str(result))
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
11
source-metadata.json
Normal file
11
source-metadata.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"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)"
|
||||
}
|
||||
@@ -75,14 +75,6 @@
|
||||
{
|
||||
"identifier": "thatstel.la.altsource",
|
||||
"sourceURL": "https://alt.thatstel.la/"
|
||||
},
|
||||
{
|
||||
"identifier": "com.deliacheminot.mona",
|
||||
"sourceURL": "https://raw.githubusercontent.com/delia-cheminot/mona-hrt/refs/heads/main/ios_source.json"
|
||||
},
|
||||
{
|
||||
"identifier": "moe.ampersand.app.source",
|
||||
"sourceURL": "https://github.com/NyaomiDEV/Ampersand/releases/latest/download/altstore.json"
|
||||
}
|
||||
],
|
||||
"sources": [
|
||||
@@ -156,14 +148,6 @@
|
||||
{
|
||||
"identifier": "thatstel.la.altsource",
|
||||
"sourceURL": "https://alt.thatstel.la/"
|
||||
},
|
||||
{
|
||||
"identifier": "com.deliacheminot.mona",
|
||||
"sourceURL": "https://raw.githubusercontent.com/delia-cheminot/mona-hrt/refs/heads/main/ios_source.json"
|
||||
},
|
||||
{
|
||||
"identifier": "moe.ampersand.app.source",
|
||||
"sourceURL": "https://github.com/NyaomiDEV/Ampersand/releases/latest/download/altstore.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user