Add new contributor to credits in SettingsView #283
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: ProStore iOS Build and Release | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: [ main ] | |
| paths-ignore: | |
| - 'README.md' | |
| - 'gallery/**' | |
| - 'website/**' | |
| - '.github/**' | |
| permissions: | |
| contents: write | |
| jobs: | |
| build-unsigned-ipa: | |
| name: Build IPA | |
| runs-on: macos-15 | |
| timeout-minutes: 60 | |
| outputs: | |
| version: ${{ steps.get_version.outputs.version }} | |
| release_exists: ${{ steps.check_release.outputs.exists }} | |
| changelog: ${{ steps.generate_changelog.outputs.CHANGELOG }} | |
| cached_object_version: ${{ steps.cache_object_version.outputs.object_version }} | |
| steps: | |
| - name: Checkout Repo | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: true | |
| - name: Show Xcode Version | |
| run: | | |
| echo "=== xcodebuild -version ===" | |
| xcodebuild -version || true | |
| echo "=== sw_vers ===" | |
| sw_vers || true | |
| - name: Install Build Tools | |
| run: | | |
| # jq | |
| if ! command -v jq >/dev/null 2>&1; then | |
| echo "jq not found — attempting to install via brew" | |
| if command -v brew >/dev/null 2>&1; then | |
| brew install jq || true | |
| fi | |
| fi | |
| # yq | |
| if ! command -v yq >/dev/null 2>&1; then | |
| echo "yq not found — attempting to install via brew" | |
| if command -v brew >/dev/null 2>&1; then | |
| brew install yq || true | |
| fi | |
| fi | |
| # gh (GitHub CLI) | |
| if ! command -v gh >/dev/null 2>&1; then | |
| echo "gh not found — attempting to install via brew" | |
| if command -v brew >/dev/null 2>&1; then | |
| brew install gh || true | |
| fi | |
| fi | |
| # xcodegen | |
| if ! command -v xcodegen >/dev/null 2>&1; then | |
| echo "xcodegen not found — attempting to install via brew" | |
| if command -v brew >/dev/null 2>&1; then | |
| brew install xcodegen || true | |
| fi | |
| fi | |
| # Fallback: official gh installer script (works across platforms) | |
| if ! command -v gh >/dev/null 2>&1; then | |
| echo "gh still not found — attempting official installer script" | |
| curl -fsSL https://cli.github.com/install.sh | sh || true | |
| fi | |
| echo "Tool versions (if installed):" | |
| echo "jq: $(jq --version 2>/dev/null || echo 'not installed')" | |
| echo "yq: $(yq --version 2>/dev/null || echo 'not installed')" | |
| echo "gh: $(gh --version 2>/dev/null || echo 'not installed')" | |
| echo "xcodegen: $(xcodegen --version 2>/dev/null || echo 'not installed')" | |
| shell: bash | |
| - name: Check Project Files | |
| run: | | |
| echo "Workspace files:" | |
| ls -la || true | |
| echo "project.yml (first 200 lines):" | |
| sed -n '1,200p' project.yml || true | |
| - name: Generate Xcode Project | |
| run: | | |
| set -e | |
| xcodegen generate --spec project.yml | |
| echo "Generated project at: $(pwd)/prostore.xcodeproj" | |
| echo "project.pbxproj header (first 60 lines):" | |
| sed -n '1,60p' prostore.xcodeproj/project.pbxproj || true | |
| - name: Resolve Swift Packages | |
| run: | | |
| set -e | |
| echo "Resolving Swift package dependencies for prostore..." | |
| xcodebuild -resolvePackageDependencies -project prostore.xcodeproj -scheme prostore -configuration Release | |
| - name: Build IPA | |
| id: cache_object_version | |
| run: | | |
| set -e | |
| ARCHIVE_PATH="$PWD/build/prostore.xcarchive" | |
| mkdir -p build | |
| # Cache file | |
| CACHE_FILE=".object_version_cache" | |
| CACHED_VERSION="" | |
| candidates=(77) # Add other candidate versions if needed | |
| # Try cached version first | |
| if [ -f "$CACHE_FILE" ]; then | |
| CACHED_VERSION=$(cat "$CACHE_FILE" | tr -d '\n') | |
| echo "Found cached objectVersion: $CACHED_VERSION" | |
| echo "----- Testing cached objectVersion = $CACHED_VERSION -----" | |
| /usr/bin/perl -0777 -pe "s/objectVersion = \\d+;/objectVersion = $CACHED_VERSION;/" -i.bak prostore.xcodeproj/project.pbxproj || true | |
| set +e | |
| xcodebuild clean archive \ | |
| -project prostore.xcodeproj \ | |
| -scheme prostore \ | |
| -archivePath "$ARCHIVE_PATH" \ | |
| -sdk iphoneos \ | |
| -configuration Release \ | |
| CODE_SIGN_IDENTITY="" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO | |
| rc=$? | |
| set -e | |
| if [ $rc -eq 0 ]; then | |
| echo "✅ Cached objectVersion $CACHED_VERSION works!" | |
| echo "object_version=$CACHED_VERSION" >> $GITHUB_OUTPUT | |
| exit 0 | |
| else | |
| echo "❌ Cached objectVersion $CACHED_VERSION failed, trying candidates..." | |
| fi | |
| fi | |
| # Try all candidates | |
| build_ok=0 | |
| for v in "${candidates[@]}"; do | |
| echo "----- Attempting build with objectVersion = $v -----" | |
| /usr/bin/perl -0777 -pe "s/objectVersion = \\d+;/objectVersion = $v;/" -i.bak prostore.xcodeproj/project.pbxproj || true | |
| echo "Header preview:" | |
| sed -n '1,20p' prostore.xcodeproj/project.pbxproj || true | |
| set +e | |
| xcodebuild clean archive \ | |
| -project prostore.xcodeproj \ | |
| -scheme prostore \ | |
| -archivePath "$ARCHIVE_PATH" \ | |
| -sdk iphoneos \ | |
| -configuration Release \ | |
| CODE_SIGN_IDENTITY="" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO | |
| rc=$? | |
| set -e | |
| if [ $rc -eq 0 ]; then | |
| echo "✅ xcodebuild succeeded with objectVersion = $v" | |
| echo "object_version=$v" >> $GITHUB_OUTPUT | |
| echo "$v" > "$CACHE_FILE" | |
| build_ok=1 | |
| break | |
| else | |
| echo "❌ xcodebuild failed (exit $rc). Trying next objectVersion..." | |
| fi | |
| done | |
| if [ "$build_ok" -ne 1 ]; then | |
| echo "ERROR: All objectVersion attempts failed." | |
| echo "===== project.pbxproj header =====" | |
| sed -n '1,200p' prostore.xcodeproj/project.pbxproj || true | |
| echo "===== build directory listing =====" | |
| ls -la build || true | |
| exit 74 | |
| fi | |
| - name: Package Device IPA | |
| run: | | |
| set -e | |
| ARCHIVE_PATH="$PWD/build/prostore.xcarchive" | |
| APP_PATH="$ARCHIVE_PATH/Products/Applications/prostore.app" | |
| OUTPUT_IPA="build/com.prostoreios.prostore-unsigned-ios.ipa" | |
| echo "Device app path: $APP_PATH" | |
| if [ ! -d "$APP_PATH" ]; then | |
| echo "ERROR: App not found at expected path. Listing archive contents:" | |
| ls -la "$ARCHIVE_PATH" || true | |
| exit 1 | |
| fi | |
| mkdir -p build/Payload | |
| rm -rf build/Payload/* || true | |
| cp -R "$APP_PATH" build/Payload/ | |
| (cd build && zip -r "$(basename "$OUTPUT_IPA")" Payload) || exit 1 | |
| echo "Created device ipa: $OUTPUT_IPA" | |
| ls -la "$OUTPUT_IPA" || true | |
| - name: Upload Device IPA | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: com.prostoreios.prostore-unsigned-ios.ipa | |
| path: build/com.prostoreios.prostore-unsigned-ios.ipa | |
| - name: Get App Version | |
| id: get_version | |
| run: | | |
| VERSION=$(yq '.targets.prostore.info.properties.CFBundleShortVersionString' project.yml) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Detected version: $VERSION" | |
| - name: Check Release Exists | |
| id: check_release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| TAG="v$VERSION" | |
| echo "Checking if release $TAG exists..." | |
| if command -v gh >/dev/null 2>&1 && gh release view "$TAG" >/dev/null 2>&1; then | |
| echo "exists=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create Changelog | |
| id: generate_changelog | |
| if: steps.check_release.outputs.exists == 'false' | |
| run: | | |
| set -e | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| CURRENT_VERSION="$VERSION" | |
| SINCE_COMMIT="" | |
| # Walk commits that touched project.yml from newest -> oldest | |
| for c in $(git rev-list HEAD -- project.yml); do | |
| file=$(git show "$c:project.yml" 2>/dev/null || true) | |
| if [ -z "$file" ]; then | |
| continue | |
| fi | |
| v=$(printf "%s" "$file" | yq '.targets.prostore.info.properties.CFBundleShortVersionString' 2>/dev/null || true) | |
| if [ -z "$v" ]; then | |
| continue | |
| fi | |
| if [ "$v" != "$CURRENT_VERSION" ]; then | |
| SINCE_COMMIT="$c" | |
| break | |
| fi | |
| done | |
| # Always capture HEAD message | |
| HEAD_MSG=$(git log -1 --pretty=format:%s HEAD || echo "") | |
| # Derive SINCE_DATE (ISO 8601) from SINCE_COMMIT | |
| if [ -n "$SINCE_COMMIT" ]; then | |
| SINCE_DATE=$(git show -s --format=%cI "$SINCE_COMMIT" 2>/dev/null || true) | |
| else | |
| SINCE_DATE="" | |
| fi | |
| # Determine repo owner/repo | |
| ORIGIN_URL=$(git remote get-url origin 2>/dev/null || true) | |
| OWNER_REPO=$(printf "%s" "$ORIGIN_URL" | sed -E 's#.*github.com[:/]+([^/]+/[^/]+)(\.git)?#\1#') | |
| # Fetch workflow runs | |
| RUNS_JSON="" | |
| if [ -n "$OWNER_REPO" ] && command -v gh >/dev/null 2>&1; then | |
| echo "Fetching recent workflow runs for ${OWNER_REPO}..." | |
| RUNS_JSON=$(gh api -H "Accept: application/vnd.github+json" \ | |
| /repos/"$OWNER_REPO"/actions/runs \ | |
| -f per_page=100 -f event=push 2>/dev/null || true) | |
| if [ -z "$RUNS_JSON" ] || [ "$(printf "%s" "$RUNS_JSON" | jq '.workflow_runs | length')" -eq 0 ]; then | |
| RUNS_JSON=$(gh api -H "Accept: application/vnd.github+json" \ | |
| /repos/"$OWNER_REPO"/actions/runs \ | |
| -f per_page=100 -f event=workflow_dispatch 2>/dev/null || true) | |
| fi | |
| fi | |
| WORKFLOW_LINES="" | |
| if [ -n "$RUNS_JSON" ] && printf "%s" "$RUNS_JSON" | jq -e '.workflow_runs | length > 0' >/dev/null 2>&1; then | |
| if [ -n "$SINCE_DATE" ]; then | |
| SINCE_DATE_UTC=$(date -u -j -f "%Y-%m-%dT%H:%M:%S%z" "$SINCE_DATE" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "$SINCE_DATE") | |
| WORKFLOW_LINES=$(printf "%s" "$RUNS_JSON" | jq -r --arg SINCE "$SINCE_DATE_UTC" ' | |
| [.workflow_runs[] | select(.created_at >= $SINCE)] | | |
| sort_by(.created_at)[] | | |
| ( "- " + (.head_commit.message // .name // .workflow_name) + | |
| " (#" + (.run_number|tostring) + ") — " + | |
| ((.conclusion // "in_progress") | tostring) + | |
| " — " + (.created_at // "") + | |
| " — branch: " + (.head_branch // "") )' || true) | |
| else | |
| WORKFLOW_LINES=$(printf "%s" "$RUNS_JSON" | jq -r ' | |
| [.workflow_runs[]] | sort_by(.created_at)[] | | |
| ( " - " + | |
| (if (.head_commit.message | length) > 0 then .head_commit.message | |
| else (if (.name|length) > 0 then .name else .workflow_name end) end) + | |
| " (#" + (.run_number|tostring) + ") — " + | |
| ((.conclusion // "in_progress") | tostring) + | |
| " — " + (.created_at // "") + | |
| " — branch: " + (.head_branch // "") )' || true) | |
| fi | |
| if [ -n "$WORKFLOW_LINES" ]; then | |
| WORKFLOW_LINES=$(printf "%s\n" "$WORKFLOW_LINES" | awk 'NF && !seen[$0]++ { print $0 }' || true) | |
| fi | |
| fi | |
| # Fallback to commit messages | |
| if [ -z "$WORKFLOW_LINES" ]; then | |
| if [ -n "$SINCE_COMMIT" ]; then | |
| COMMITS_RAW=$(git log --pretty=format:%s "${SINCE_COMMIT}..HEAD" --reverse 2>/dev/null || true) | |
| COMMITS_RAW=$(echo "$COMMITS_RAW" | grep -v "Update ProStore app repo to v" || true) | |
| else | |
| COMMITS_RAW="" | |
| fi | |
| fi | |
| # Build description | |
| printf -v DESC "What's new in Version %s?\n" "$VERSION" | |
| if [ -n "$HEAD_MSG" ]; then | |
| DESC+=$'- '"$HEAD_MSG"$'\n' | |
| fi | |
| if [ -n "$WORKFLOW_LINES" ]; then | |
| DESC+="${WORKFLOW_LINES}"$'\n' | |
| elif [ -n "$COMMITS_RAW" ]; then | |
| OTHER_LINES=$(printf "%s\n" "$COMMITS_RAW" | awk -v head="$HEAD_MSG" 'NF && $0!=head { print "- "$0 }' || true) | |
| if [ -n "$OTHER_LINES" ]; then | |
| DESC+="${OTHER_LINES}"$'\n' | |
| fi | |
| fi | |
| DESC="${DESC%$'\n'}" | |
| echo "CHANGELOG<<EOF" >> $GITHUB_OUTPUT | |
| printf '%s\n' "$DESC" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| shell: bash | |
| sign-ipas: | |
| name: Sign IPAs | |
| needs: build-unsigned-ipa | |
| runs-on: macos-15 | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Download Unsigned IPA | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: com.prostoreios.prostore-unsigned-ios.ipa | |
| path: build | |
| - name: Fetch Certificates List and Sign | |
| run: | | |
| set -euo pipefail | |
| UNSIGNED_IPA="build/com.prostoreios.prostore-unsigned-ios.ipa" | |
| if [ ! -f "$UNSIGNED_IPA" ]; then | |
| echo "ERROR: Unsigned IPA not found: $UNSIGNED_IPA" | |
| exit 1 | |
| fi | |
| # Fetch README.md containing the certificates table | |
| curl -s https://raw.githubusercontent.com/ProStore-iOS/certificates/refs/heads/main/README.md -o readme.md | |
| echo "----- README excerpt -----" | |
| sed -n '1,200p' readme.md || true | |
| echo "----- Matching lines (table rows) -----" | |
| # Print all data rows from the Markdown table: | |
| # lines that start with '|' but skip the alignment row and header row containing 'Company' | |
| awk -F'|' '/^\|/ && $2 !~ /Company/ && $2 !~ /^:/{ name=$2; gsub(/^[ \t]+|[ \t]+$/,"",name); print " " $0 }' readme.md || true | |
| # Extract company/display names (field 2) from every table data row (skip header & alignment) | |
| # This produces one company/display name per line. | |
| awk -F'|' '/^\|/ && $2 !~ /Company/ && $2 !~ /^:/{ name=$2; gsub(/^[ \t]+|[ \t]+$/,"",name); print name }' readme.md > cert-names.txt || true | |
| MATCH_COUNT=0 | |
| if [ -f cert-names.txt ]; then | |
| MATCH_COUNT=$(wc -l < cert-names.txt | tr -d ' ') | |
| fi | |
| echo "Found $MATCH_COUNT certificate line(s) in README." | |
| if [ "$MATCH_COUNT" -eq 0 ]; then | |
| echo "No certificate rows found. Exiting." | |
| exit 0 | |
| fi | |
| # Install dependencies (no-op if already installed) | |
| brew install pkg-config openssl minizip | |
| # Build zsign | |
| rm -rf zsign || true | |
| git clone https://github.com/zhlynn/zsign.git | |
| pushd zsign/build/macos >/dev/null | |
| make clean && make | |
| popd >/dev/null | |
| # Locate the zsign binary (expected at zsign/bin/zsign) | |
| ZSIGN_PATH="$(pwd)/zsign/bin/zsign" | |
| if [ ! -x "$ZSIGN_PATH" ]; then | |
| echo "zsign not found at expected path $ZSIGN_PATH; searching..." | |
| FOUND=$(find "$(pwd)/zsign" -type f -name zsign -perm -111 -print -quit || true) | |
| if [ -n "$FOUND" ]; then | |
| ZSIGN_PATH="$FOUND" | |
| else | |
| echo "zsign binary not found. Listing zsign tree for debugging:" | |
| ls -la zsign || true | |
| exit 1 | |
| fi | |
| fi | |
| echo "Using zsign: $ZSIGN_PATH" | |
| ls -l "$ZSIGN_PATH" || true | |
| # Prepare output directory for signed IPAs | |
| SIGNED_DIR="signed-ipas" | |
| mkdir -p "$SIGNED_DIR" | |
| # Iterate over every certificate name (one per line) and attempt to sign | |
| while IFS= read -r FULL_NAME || [ -n "$FULL_NAME" ]; do | |
| # skip empty lines | |
| if [ -z "${FULL_NAME// /}" ]; then | |
| echo "Skipping empty certificate name" | |
| continue | |
| fi | |
| echo "---- Processing: '$FULL_NAME' ----" | |
| # Create safe short name for filenames and dirs | |
| SHORT_NAME=$(echo "$FULL_NAME" | tr '[:upper:]' '[:lower:]' \ | |
| | sed -E 's/[^a-z0-9]+/-/g' | sed -E 's/^-+|-+$//g') | |
| # URL-encode the full display name for GitHub raw path | |
| ENCODED=$(printf '%s' "$FULL_NAME" | python3 -c 'import sys,urllib.parse as u; print(u.quote(sys.stdin.read().strip()))') | |
| CERT_DIR="certs/$SHORT_NAME" | |
| mkdir -p "$CERT_DIR" | |
| pushd "$CERT_DIR" >/dev/null | |
| # Try downloading the three required files. If any are missing, skip this cert. | |
| echo "Downloading assets for '$FULL_NAME' (encoded: $ENCODED)..." | |
| if ! curl -sS -fLO "https://github.com/ProStore-iOS/certificates/raw/refs/heads/main/${ENCODED}/${ENCODED}.mobileprovision"; then | |
| echo " -> Missing mobileprovision for '$FULL_NAME', skipping." | |
| popd >/dev/null | |
| continue | |
| fi | |
| if ! curl -sS -fLO "https://github.com/ProStore-iOS/certificates/raw/refs/heads/main/${ENCODED}/${ENCODED}.p12"; then | |
| echo " -> Missing .p12 for '$FULL_NAME', skipping." | |
| popd >/dev/null | |
| continue | |
| fi | |
| if ! curl -sS -fLO "https://github.com/ProStore-iOS/certificates/raw/refs/heads/main/${ENCODED}/password.txt"; then | |
| echo " -> Missing password.txt for '$FULL_NAME', skipping." | |
| popd >/dev/null | |
| continue | |
| fi | |
| popd >/dev/null | |
| SIGNED_IPA="${SIGNED_DIR}/com.prostoreios.prostore-signed-${SHORT_NAME}-ios.ipa" | |
| # Run zsign; ensure p12 password is read safely | |
| P12_PASS="$(cat "${CERT_DIR}/password.txt" || echo "")" | |
| if [ -z "$P12_PASS" ]; then | |
| echo " -> Empty password for ${FULL_NAME}, skipping." | |
| continue | |
| fi | |
| echo " -> Signing into $SIGNED_IPA ..." | |
| if "$ZSIGN_PATH" -k "${CERT_DIR}/${ENCODED}.p12" \ | |
| -p "$P12_PASS" \ | |
| -m "${CERT_DIR}/${ENCODED}.mobileprovision" \ | |
| -o "$SIGNED_IPA" \ | |
| "$UNSIGNED_IPA"; then | |
| echo " -> Signed OK: $SIGNED_IPA" | |
| else | |
| echo " -> zsign failed for $FULL_NAME; see zsign output above. Skipping." | |
| # don't exit whole job; continue with next cert | |
| continue | |
| fi | |
| done < cert-names.txt | |
| echo "Signing complete. Signed files:" | |
| ls -la "$SIGNED_DIR" || true | |
| - name: Upload signed IPAs | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: signed-ipas | |
| path: signed-ipas/*.ipa | |
| create-github-release: | |
| name: Create GitHub Release | |
| needs: [build-unsigned-ipa, sign-ipas] | |
| # job-level if must use expression syntax and reference the correct job id | |
| if: ${{ needs.build-unsigned-ipa.outputs.release_exists == 'false' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Install GitHub CLI | |
| run: | | |
| if ! command -v gh >/dev/null 2>&1; then | |
| echo "gh not found — attempting official installer script" | |
| curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg | |
| echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null | |
| sudo apt update | |
| sudo apt install gh -y || true | |
| fi | |
| echo "gh: $(gh --version 2>/dev/null || echo 'not installed')" | |
| - name: Download All Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Create Release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ needs.build-unsigned-ipa.outputs.version }} | |
| CHANGELOG: ${{ needs.build-unsigned-ipa.outputs.changelog }} | |
| run: | | |
| TAG="v$VERSION" | |
| echo "Creating release $TAG with notes:" | |
| printf '%s\n' "$CHANGELOG" | |
| IPAS=$(find artifacts -type f -name '*.ipa' -print0 | xargs -0) | |
| if [ -z "$IPAS" ]; then | |
| echo "No IPAs found to upload." | |
| exit 1 | |
| fi | |
| gh release create "$TAG" \ | |
| $IPAS \ | |
| --title "ProStore v$VERSION" \ | |
| --notes "$CHANGELOG" \ | |
| --repo "$GITHUB_REPOSITORY" | |
| shell: bash | |
| update-prostore-repo-json: | |
| name: Update ProStore Repo JSON | |
| needs: build-unsigned-ipa | |
| if: ${{ needs.build-unsigned-ipa.outputs.release_exists == 'false' }} | |
| runs-on: ubuntu-latest | |
| env: | |
| VERSION: ${{ needs.build-unsigned-ipa.outputs.version }} | |
| CHANGELOG: ${{ needs.build-unsigned-ipa.outputs.changelog }} | |
| steps: | |
| - name: Install jq | |
| run: | | |
| if ! command -v jq >/dev/null 2>&1; then | |
| echo "jq not found — attempting to install" | |
| sudo apt update | |
| sudo apt install jq -y || true | |
| fi | |
| echo "jq: $(jq --version 2>/dev/null || echo 'not installed')" | |
| - name: Download Device IPA | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: com.prostoreios.prostore-unsigned-ios.ipa | |
| path: build | |
| - name: Update Apps JSON in Pages Repo | |
| env: | |
| PAGES_PAT: ${{ secrets.PAGES_PAT }} | |
| run: | | |
| set -e | |
| IPA_PATH="$PWD/build/com.prostoreios.prostore-unsigned-ios.ipa" | |
| DOWNLOAD_URL="https://github.com/ProStore-iOS/ProStore/releases/download/v$VERSION/com.prostoreios.prostore-unsigned-ios.ipa" | |
| if [ -f "$IPA_PATH" ]; then | |
| IPA_SIZE=$(stat -c%s "$IPA_PATH") | |
| SHA256=$(sha256sum "$IPA_PATH" | awk '{print $1}') | |
| else | |
| IPA_SIZE=0 | |
| SHA256="" | |
| fi | |
| VERSION_DATE_ISO=$(date -u +"%Y-%m-%dT%H:%M:%S%z") | |
| MIN_OS="16.0" | |
| FULL_DATE=$(date +%Y%m%d%H%M%S) | |
| ICON_URL="https://raw.githubusercontent.com/ProStore-iOS/ProStore-iOS.github.io/refs/heads/main/ProStore_icon.png" | |
| BUNDLE="com.prostoreios.prostore" | |
| META_DESC="The BEST alternative app store for iOS!" | |
| DEVNAME="ProStore iOS" | |
| SCREENSHOTS='["https://raw.githubusercontent.com/ProStore-iOS/ProStore/refs/heads/main/gallery/Screenshot1.png","https://raw.githubusercontent.com/ProStore-iOS/ProStore/refs/heads/main/gallery/Screenshot2.png","https://raw.githubusercontent.com/ProStore-iOS/ProStore/refs/heads/main/gallery/Screenshot3.png","https://raw.githubusercontent.com/ProStore-iOS/ProStore/refs/heads/main/gallery/Screenshot4.png","https://raw.githubusercontent.com/ProStore-iOS/ProStore/refs/heads/main/gallery/Screenshot5.png"]' | |
| PAGES_REPO="ProStore-iOS/ProStore-iOS.github.io" | |
| PAGES_DIR=$(mktemp -d) | |
| git clone --depth 1 "https://x-access-token:${PAGES_PAT}@github.com/${PAGES_REPO}.git" "$PAGES_DIR" | |
| cd "$PAGES_DIR" | |
| REPO_FILE="apps.json" | |
| if [ ! -f "$REPO_FILE" ]; then | |
| jq -n --arg icon "$ICON_URL" '{ | |
| name: "Official ProStore Repo", | |
| identifier: "com.prostoreios.prostore.repo", | |
| sourceURL: "https://ProStore-iOS.github.io/apps.json", | |
| iconURL: $icon, | |
| website: "https://ProStore-iOS.github.io", | |
| subtitle: "The BEST alternative app store for iOS!", | |
| apps: [] | |
| }' > "$REPO_FILE" | |
| fi | |
| TMP=$(mktemp) | |
| NEW_VERSION=$(jq -c -n \ | |
| --arg version "$VERSION" \ | |
| --arg date "$VERSION_DATE_ISO" \ | |
| --arg desc "$CHANGELOG" \ | |
| --arg url "$DOWNLOAD_URL" \ | |
| --arg sha "$SHA256" \ | |
| --arg minos "$MIN_OS" \ | |
| --arg fulldate "$FULL_DATE" \ | |
| --argjson size "$IPA_SIZE" \ | |
| '{version: $version, date: $date, localizedDescription: $desc, downloadURL: $url, size: $size, sha256: $sha, minOSVersion: $minos, fullDate: $fulldate}') | |
| JQ_QUERY='(.apps //= []) | if ( .apps | map(.bundleIdentifier // .bundleID) | index($bundle) ) then .apps |= map( if ((.bundleIdentifier // .bundleID) == $bundle) then ( { "name": $name, "bundleIdentifier": $bundle, "developerName": $dev, "localizedDescription": $appdesc, "iconURL": $icon, "screenshotURLs": $screenshots } + { "versions": ( [ $newVer ] + ( .versions // [] ) ) } ) else . end ) else .apps += [ { "name": $name, "bundleIdentifier": $bundle, "developerName": $dev, "localizedDescription": $appdesc, "iconURL": $icon, "screenshotURLs": $screenshots, "versions": [ $newVer ] } ] end' | |
| jq --argjson newVer "$NEW_VERSION" \ | |
| --arg name "ProStore" \ | |
| --arg bundle "$BUNDLE" \ | |
| --arg dev "$DEVNAME" \ | |
| --arg appdesc "$META_DESC" \ | |
| --arg icon "$ICON_URL" \ | |
| --argjson screenshots "$SCREENSHOTS" \ | |
| "$JQ_QUERY" "$REPO_FILE" > "$TMP" && mv "$TMP" "$REPO_FILE" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add "$REPO_FILE" | |
| if git diff --quiet --cached; then | |
| echo "No changes to apps.json — nothing to commit/push." | |
| exit 0 | |
| fi | |
| git commit -m "Update apps.json for ProStore v${VERSION}" | |
| echo "Pushing apps.json to ${PAGES_REPO}:main" | |
| git push "https://x-access-token:${PAGES_PAT}@github.com/${PAGES_REPO}.git" HEAD:main | |
| shell: bash |