From 5d4994b906043439ae9c62c2a29502f8ab663864 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Fri, 10 Jul 2026 16:55:55 -0300 Subject: [PATCH] revert: swift package release workflow and follow-ups Reverts the SPM release flow, which broke all builds: - 732c439 feat: swift package release workflow (#395) - 736365c ci: spm build - c453116 ci: next handling for build targets - e652dd0 ci: spm version handling - 838ed31 chore: allow local builds/packs to use local spm - 0d92c89 chore: ensure next tag gates targets during spm verifications Unrelated changes that touched the same workflow are preserved: the dependabot action bumps (#398, #400, #401) and the test timeout headroom from 54bcc22. --- .github/workflows/npm_release.yml | 450 +++--------------- build_all_ios.sh | 1 - build_all_vision.sh | 1 - build_npm_ios.sh | 61 +-- build_npm_vision.sh | 24 +- build_spm_artifacts.sh | 83 ---- .../project.pbxproj | 35 +- .../internal/nativescript-build.xcconfig | 7 +- .../project.pbxproj | 35 +- .../internal/nativescript-build.xcconfig | 5 +- scripts/stamp-spm-release.mjs | 138 ------ scripts/stamp-template-local-spm.mjs | 72 --- scripts/stamp-template-version.mjs | 33 -- 13 files changed, 109 insertions(+), 836 deletions(-) delete mode 100755 build_spm_artifacts.sh delete mode 100644 scripts/stamp-spm-release.mjs delete mode 100644 scripts/stamp-template-local-spm.mjs delete mode 100644 scripts/stamp-template-version.mjs diff --git a/.github/workflows/npm_release.yml b/.github/workflows/npm_release.yml index 36e8f93f..6d3f89db 100644 --- a/.github/workflows/npm_release.yml +++ b/.github/workflows/npm_release.yml @@ -1,112 +1,21 @@ on: push: branches: - - main # -> prerelease published under the "next" dist-tag + - main tags: - - "v*" # -> release published under the "latest" dist-tag - workflow_dispatch: - inputs: - version: - description: "Release version to cut, e.g. 9.1.0 (creates tag v and publishes 'latest'). Leave empty for a manual 'next' build." - required: false - default: "" + - "v*" env: NPM_TAG: "next" XCODE_VERSION: "^15.0" -# Minimal default token permissions for every job. Jobs that need more declare it -# locally (github-release: contents:write; publish: id-token:write). Cross-repo -# writes to ios-spm use a GitHub App token, not GITHUB_TOKEN. -permissions: - contents: read - -# The runtime xcframeworks are no longer shipped inside the npm packages. Each -# build publishes them as GitHub Release assets and points the SwiftPM manifest -# (github.com/NativeScript/ios-spm) at them via binaryTarget(url:checksum:). The -# slim npm package only carries the Xcode project template + metadata generator. -# -# Flow: setup → build (ios, visionos) → test → github-release (assets) → -# spm-update (stamp + tag ios-spm) → publish (npm) → verify-spm -# -# The release half (github-release, spm-update, publish, verify-spm) is gated on -# repo variable ENABLE_SPM_RELEASE. Until it is 'true' (and the ios-spm App -# credentials are set), the workflow runs setup/build/test only and publishes NOTHING — so the -# slim package can never ship before its matching ios-spm tag exists. Turn the -# variable on as part of the cutover. jobs: - setup: - name: Resolve version - runs-on: ubuntu-latest - outputs: - npm_version: ${{ steps.out.outputs.NPM_VERSION }} - npm_tag: ${{ steps.out.outputs.NPM_TAG }} - build_matrix: ${{ steps.out.outputs.BUILD_MATRIX }} - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 - with: - egress-policy: audit - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - fetch-depth: 0 - persist-credentials: false - - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 - with: - node-version: 22 - - name: Install deps for version scripts - run: npm install --no-audit --no-fund - - name: Compute version and tag - id: out - env: - INPUT_VERSION: ${{ inputs.version }} - run: | - if [ -n "$INPUT_VERSION" ]; then - # manual release: cut tag v and publish (latest unless prerelease) - NPM_VERSION="${INPUT_VERSION#v}" - elif [ "${GITHUB_REF#refs/tags/}" != "$GITHUB_REF" ]; then - # tag push (v*): the tag is authoritative. Strip the leading 'v' and - # assert it matches package.json so the release can't drift from its tag. - NPM_VERSION="${GITHUB_REF#refs/tags/}" - NPM_VERSION="${NPM_VERSION#v}" - PKG_VERSION=$(node -e "console.log(require('./package.json').version);") - if [ "$NPM_VERSION" != "$PKG_VERSION" ]; then - echo "::error::Tag v$NPM_VERSION does not match package.json version $PKG_VERSION. Bump package.json before tagging." >&2 - exit 1 - fi - else - # branch push (main) or manual run without a version -> "next" prerelease - NPM_VERSION=$(node ./scripts/get-next-version.js) - fi - NPM_TAG=$(NPM_VERSION=$NPM_VERSION node ./scripts/get-npm-tag.js) - echo "NPM_VERSION=$NPM_VERSION" >> $GITHUB_OUTPUT - echo "NPM_TAG=$NPM_TAG" >> $GITHUB_OUTPUT - # Target matrix: ios always builds/publishes. visionos is built and - # published ONLY for real releases (a v* tag push, or a manual dispatch - # with a version), never for the rolling "next" channel that every push - # to main produces. The discriminator is the resolved dist-tag: pushes - # to main (and dispatch without a version) -> "next" -> ios only. - if [ "$NPM_TAG" = "next" ]; then - BUILD_MATRIX='{"include":[{"target":"ios","script":"build-ios"}]}' - else - BUILD_MATRIX='{"include":[{"target":"ios","script":"build-ios"},{"target":"visionos","script":"build-vision"}]}' - fi - echo "BUILD_MATRIX=$BUILD_MATRIX" >> $GITHUB_OUTPUT - echo "Resolved $NPM_VERSION (tag: $NPM_TAG); build targets: $BUILD_MATRIX" - build: - name: Build ${{ matrix.target }} + name: Build runs-on: macos-14 - needs: setup - strategy: - fail-fast: false - # Computed in `setup`: ios always; visionos only for real releases - # (npm_tag != "next"), never for the rolling "next" channel. Each entry - # carries `target` (package identity, @nativescript/) and `script` - # (the npm build script; note the vision script is build-vision). - matrix: ${{ fromJSON(needs.setup.outputs.build_matrix) }} - env: - NPM_VERSION: ${{ needs.setup.outputs.npm_version }} + outputs: + npm_version: ${{ steps.npm_version_output.outputs.NPM_VERSION }} + npm_tag: ${{ steps.npm_version_output.outputs.NPM_TAG }} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 @@ -146,26 +55,34 @@ jobs: sudo mkdir -p /usr/local/bin sudo ln -sf "$(command -v cmake)" /usr/local/bin/cmake fi - - name: Set package version - run: npm version $NPM_VERSION --no-git-tag-version --allow-same-version - - name: Build (${{ matrix.target }}) - run: npm run ${{ matrix.script }} + - name: Get Current Version + run: | + NPM_VERSION=$(node -e "console.log(require('./package.json').version);") + echo NPM_VERSION=$NPM_VERSION >> $GITHUB_ENV + - name: Bump version for dev release + if: ${{ !contains(github.ref, 'refs/tags/') }} + run: | + NPM_VERSION=$(node ./scripts/get-next-version.js) + echo NPM_VERSION=$NPM_VERSION >> $GITHUB_ENV + npm version $NPM_VERSION --no-git-tag-version + - name: Output NPM Version and tag + id: npm_version_output + run: | + NPM_TAG=$(node ./scripts/get-npm-tag.js) + echo NPM_VERSION=$NPM_VERSION >> $GITHUB_OUTPUT + echo NPM_TAG=$NPM_TAG >> $GITHUB_OUTPUT + - name: Build + run: npm run build-ios - name: Upload npm package artifact uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: npm-package-${{ matrix.target }} - path: dist/nativescript-*-${{ env.NPM_VERSION }}.tgz - - name: Upload SwiftPM artifacts (xcframework zips + checksums) - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: spm-artifacts-${{ matrix.target }} - path: dist/artifacts/* + name: npm-package + path: dist/nativescript-ios-${{steps.npm_version_output.outputs.NPM_VERSION}}.tgz - name: Upload dSYMs artifact uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: dSYMs-${{ matrix.target }} + name: NativeScript-dSYMs path: dist/dSYMs - test: name: Test runs-on: macos-14 @@ -238,172 +155,18 @@ jobs: with: name: test-results path: ${{env.TEST_FOLDER}}/test_results.xcresult - - # Publish the xcframework zips + dSYMs as a GitHub Release asset for EVERY - # version (prerelease unless 'latest'), because the SwiftPM binaryTarget url - # must resolve for `next`/`pr` consumers too — not only tagged releases. - github-release: - name: GitHub Release (SPM assets) - runs-on: ubuntu-latest - # Master switch for the SPM release flow. When unset, the workflow runs - # setup/build/test only — nothing is released or published, so landing this - # on main before the token is configured is a no-op for consumers. - if: ${{ vars.ENABLE_SPM_RELEASE == 'true' }} - permissions: - contents: write - needs: - - setup - - build - - test - env: - NPM_VERSION: ${{ needs.setup.outputs.npm_version }} - NPM_TAG: ${{ needs.setup.outputs.npm_tag }} - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 - with: - egress-policy: audit - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - fetch-depth: 0 - persist-credentials: false - - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 - with: - node-version: 22 - - name: Setup - run: npm install --no-audit --no-fund - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - pattern: spm-artifacts-* - path: spm-artifacts - merge-multiple: true - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - pattern: dSYMs-* - path: dist/dSYMs - merge-multiple: true - - name: Zip dSYMs - working-directory: dist/dSYMs - run: find . -maxdepth 1 -name '*.dSYM' -print | xargs -I@ zip -r @.zip @ || true - - name: Partial Changelog - run: npx conventional-changelog -p angular -r2 > body.md - - name: Create / update release with SPM artifacts - uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0 - with: - tag: "v${{ env.NPM_VERSION }}" - name: "v${{ env.NPM_VERSION }}" - commit: ${{ github.sha }} - artifacts: "spm-artifacts/*.xcframework.zip,dist/dSYMs/*.zip" - bodyFile: "body.md" - prerelease: ${{ needs.setup.outputs.npm_tag != 'latest' }} - allowUpdates: true - - # Stamp + tag github.com/NativeScript/ios-spm to point at this release's assets. - # Cross-repo write uses a short-lived GitHub App installation token, minted per - # run and scoped to ios-spm only (no long-lived PAT to rotate). Enable by setting - # repo variable ENABLE_SPM_RELEASE=true plus the App credentials - # (variable APP_CLIENT_ID + secret APP_PRIVATE_KEY); the App must be installed on - # NativeScript/ios-spm with Contents: Read and write. - spm-update: - name: Update ios-spm manifest - runs-on: ubuntu-latest - if: ${{ vars.ENABLE_SPM_RELEASE == 'true' }} - needs: - - setup - - build - - test - - github-release - env: - NPM_VERSION: ${{ needs.setup.outputs.npm_version }} - NPM_TAG: ${{ needs.setup.outputs.npm_tag }} - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 - with: - egress-policy: audit - - name: Mint ios-spm App token (short-lived, scoped to ios-spm) - id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - with: - client-id: ${{ vars.APP_CLIENT_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - owner: NativeScript - repositories: ios-spm - permission-contents: write - - name: Checkout ios (for stamping script) - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - path: ios - persist-credentials: false - - name: Checkout ios-spm - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - repository: NativeScript/ios-spm - token: ${{ steps.app-token.outputs.token }} - path: ios-spm - persist-credentials: false - - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 - with: - node-version: 22 - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - pattern: spm-artifacts-* - path: spm-artifacts - merge-multiple: true - - name: Stamp Package.swift - run: | - STRICT="" - if [ "$NPM_TAG" = "latest" ]; then STRICT="--strict"; fi - CHECKSUM_ARGS="" - for f in spm-artifacts/checksums-*.env; do - [ -f "$f" ] && CHECKSUM_ARGS="$CHECKSUM_ARGS --checksums $f" - done - echo "Using checksum files:$CHECKSUM_ARGS" - if [ -z "$CHECKSUM_ARGS" ]; then echo "No checksum files found" >&2; exit 1; fi - node ios/scripts/stamp-spm-release.mjs \ - --package ios-spm/Package.swift \ - --version "$NPM_VERSION" \ - $CHECKSUM_ARGS $STRICT - - name: Commit and tag ios-spm - working-directory: ios-spm - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - git config user.name "NativeScript Bot" - git config user.email "oss@nativescript.org" - # persist-credentials:false keeps the token out of .git/config; push to a - # token-authenticated URL instead (the App token is masked in logs). - REMOTE="https://x-access-token:${GH_TOKEN}@github.com/NativeScript/ios-spm.git" - git add Package.swift - git commit -m "release: $NPM_VERSION" || echo "no changes to commit" - git tag -f "$NPM_VERSION" - git push "$REMOTE" HEAD:main - git push -f "$REMOTE" "refs/tags/$NPM_VERSION" - publish: - name: Publish ${{ matrix.target }} runs-on: ubuntu-latest environment: npm-publish - # Gated + ordered after spm-update so a slim package is never published before - # its matching ios-spm tag exists (which would make it unresolvable). - if: ${{ vars.ENABLE_SPM_RELEASE == 'true' }} needs: - - setup - build - test - - spm-update permissions: contents: read id-token: write - strategy: - fail-fast: false - # Same targets as the build matrix (computed in `setup`): visionos is - # published only for real releases, never for the "next" channel. The - # unused `script` key on each entry is harmless here. - matrix: ${{ fromJSON(needs.setup.outputs.build_matrix) }} env: - NPM_VERSION: ${{ needs.setup.outputs.npm_version }} - NPM_TAG: ${{ needs.setup.outputs.npm_tag }} + NPM_VERSION: ${{needs.build.outputs.npm_version}} + NPM_TAG: ${{needs.build.outputs.npm_tag}} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 @@ -415,7 +178,7 @@ jobs: registry-url: "https://registry.npmjs.org" - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: npm-package-${{ matrix.target }} + name: npm-package path: dist - name: Update npm (required for OIDC trusted publishing) run: | @@ -423,142 +186,65 @@ jobs: corepack install -g npm@11.5.1 test "$(npm --version)" = "11.5.1" test "$(npx --version)" = "11.5.1" - - name: Resolve package name - run: | - if [ "${{ matrix.target }}" = "ios" ]; then echo "PKG=ios" >> $GITHUB_ENV; else echo "PKG=visionos" >> $GITHUB_ENV; fi - name: Publish package (OIDC trusted publishing) if: ${{ vars.USE_NPM_TOKEN != 'true' }} run: | - echo "Publishing @nativescript/$PKG@$NPM_VERSION to NPM with tag $NPM_TAG via OIDC trusted publishing..." + echo "Publishing @nativescript/ios@$NPM_VERSION to NPM with tag $NPM_TAG via OIDC trusted publishing..." unset NODE_AUTH_TOKEN if [ -n "${NPM_CONFIG_USERCONFIG:-}" ]; then rm -f "$NPM_CONFIG_USERCONFIG" fi - npm publish ./dist/nativescript-${PKG}-${NPM_VERSION}.tgz --tag $NPM_TAG --access public --provenance + npm publish ./dist/nativescript-ios-${{env.NPM_VERSION}}.tgz --tag $NPM_TAG --access public --provenance env: NODE_AUTH_TOKEN: "" + - name: Publish package (granular token) if: ${{ vars.USE_NPM_TOKEN == 'true' }} run: | - echo "Publishing @nativescript/$PKG@$NPM_VERSION to NPM with tag $NPM_TAG via granular token..." - npm publish ./dist/nativescript-${PKG}-${NPM_VERSION}.tgz --tag $NPM_TAG --access public --provenance + echo "Publishing @nativescript/ios@$NPM_VERSION to NPM with tag $NPM_TAG via granular token..." + npm publish ./dist/nativescript-ios-${{env.NPM_VERSION}}.tgz --tag $NPM_TAG --access public --provenance env: NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} - - # Post-publish smoke test: resolve ios-spm at the released tag and verify the - # binary artifact downloads + checksum-validate against the real Release. - # - # Channel-aware, mirroring the build/publish matrix: `next` builds iOS only, so - # its Release has no visionos assets. `swift package resolve` eagerly downloads - # EVERY binaryTarget in a resolved package (not just the ones a referenced - # product needs), so resolving the full ios-spm manifest on a `next` version - # would try to fetch the visionos zips and 404. For `next` we therefore probe - # an iOS-only package; only real releases (v* tag / manual version) resolve the - # full manifest and thus also verify the visionos artifacts. - verify-spm: - name: Verify SPM resolution - runs-on: macos-14 - if: ${{ vars.ENABLE_SPM_RELEASE == 'true' }} + github-release: + runs-on: ubuntu-latest + # only runs on tagged commits + if: ${{ contains(github.ref, 'refs/tags/') }} + permissions: + contents: write needs: - - setup - - spm-update + - build + - test env: - NPM_VERSION: ${{ needs.setup.outputs.npm_version }} - NPM_TAG: ${{ needs.setup.outputs.npm_tag }} + NPM_VERSION: ${{needs.build.outputs.npm_version}} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 0 - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version: 22 - - name: Assert ios-spm manifest pins this release - run: | - # Guard against the manifest pointing at a STALE release — e.g. a stamp - # that no-ops and leaves a prior version's nsVersion + artifact - # URLs/checksums in place. Those still resolve and checksum-pass (they're - # internally consistent), so `swift package resolve` below won't catch - # it; this explicit version assertion does. - url="https://raw.githubusercontent.com/NativeScript/ios-spm/${NPM_VERSION}/Package.swift" - manifest="$(curl -fsSL "$url")" - if ! printf '%s\n' "$manifest" | grep -q "let nsVersion = \"${NPM_VERSION}\""; then - echo "::error::ios-spm@${NPM_VERSION} does not pin nsVersion=\"${NPM_VERSION}\" (stale stamp?). Found:" >&2 - printf '%s\n' "$manifest" | grep -n "nsVersion" >&2 || true - exit 1 - fi - echo "OK: ios-spm@${NPM_VERSION} pins nsVersion=\"${NPM_VERSION}\"" - - name: Generate a probe package that depends on ios-spm (real releases) - # Real release (v* tag / manual version): the Release carries every asset, - # so probe the full ios-spm manifest. `swift package resolve` eagerly - # downloads all binaryTargets, exercising the iOS AND visionos artifacts. - if: ${{ needs.setup.outputs.npm_tag != 'next' }} - run: | - node -e ' - const fs = require("fs"); - const v = process.env.NPM_VERSION; - fs.mkdirSync("spmverify/Sources/Probe", { recursive: true }); - fs.writeFileSync("spmverify/Package.swift", - "// swift-tools-version: 5.10\n" + - "import PackageDescription\n" + - "let package = Package(\n" + - " name: \"Probe\",\n" + - " platforms: [.iOS(.v13)],\n" + - " dependencies: [.package(url: \"https://github.com/NativeScript/ios-spm.git\", exact: \"" + v + "\")],\n" + - " targets: [.target(name: \"Probe\", dependencies: [.product(name: \"NativeScript\", package: \"ios-spm\")])]\n" + - ")\n"); - fs.writeFileSync("spmverify/Sources/Probe/Probe.swift", "// probe\n"); - ' - - name: Generate an iOS-only probe package (next channel) - # The "next" Release has no visionos assets (build matrix is iOS-only for - # next), and `swift package resolve` would eagerly try to fetch every - # binaryTarget in the full ios-spm manifest -> 404 on the visionos zips. - # So probe an iOS-only package whose binaryTargets are the iOS artifacts - # from the stamped manifest (real Release URLs + real checksums): resolve - # still downloads and checksum-verifies exactly what a next consumer gets, - # and never touches visionos. - if: ${{ needs.setup.outputs.npm_tag == 'next' }} - run: | - url="https://raw.githubusercontent.com/NativeScript/ios-spm/${NPM_VERSION}/Package.swift" - curl -fsSL "$url" -o manifest.swift - node -e ' - const fs = require("fs"); - const v = process.env.NPM_VERSION; - const body = fs.readFileSync("manifest.swift", "utf8"); - // Pull the checksum out of the binaryTarget whose url ends in the given - // artifact zip. The url is a Swift interpolation ("\(base)/"), so - // match up to the closing quote; anchoring on " keeps the iOS - // NativeScript slot from matching the visionos one (…visionos.xcframework.zip). - const ck = (artifact) => { - const re = new RegExp("url:\\s*\"[^\"]*" + artifact.replace(/\./g, "\\.") + "\"\\s*,\\s*checksum:\\s*\"([0-9a-f]{64})\""); - const m = body.match(re); - if (!m) { console.error("No iOS checksum for " + artifact + " in ios-spm@" + v); process.exit(1); } - return m[1]; - }; - const nsCk = ck("NativeScript.xcframework.zip"); - const tkCk = ck("TKLiveSync.xcframework.zip"); - fs.mkdirSync("spmverify/Sources/Probe", { recursive: true }); - fs.writeFileSync("spmverify/Package.swift", - "// swift-tools-version: 5.10\n" + - "import PackageDescription\n" + - "let base = \"https://github.com/NativeScript/ios/releases/download/v" + v + "\"\n" + - "let package = Package(\n" + - " name: \"Probe\",\n" + - " platforms: [.iOS(.v13)],\n" + - " targets: [\n" + - " .binaryTarget(name: \"NativeScript\", url: \"\\(base)/NativeScript.xcframework.zip\", checksum: \"" + nsCk + "\"),\n" + - " .binaryTarget(name: \"TKLiveSync\", url: \"\\(base)/TKLiveSync.xcframework.zip\", checksum: \"" + tkCk + "\"),\n" + - " .target(name: \"Probe\", dependencies: [\"NativeScript\", \"TKLiveSync\"])\n" + - " ]\n" + - ")\n"); - fs.writeFileSync("spmverify/Sources/Probe/Probe.swift", "// probe\n"); - ' - - name: Resolve (downloads the xcframework zips and verifies their checksums) - working-directory: spmverify - run: | - # Resolution fetches each binaryTarget's zip and verifies its SHA-256 - # against the stamped checksum; a mismatch or a missing release asset - # fails the release here. For next this covers the iOS artifacts only; - # real releases resolve the full manifest and also cover visionos. - swift package resolve - echo "ios-spm@$NPM_VERSION resolved and checksum-verified." + - name: Setup + run: npm install + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: npm-package + path: dist + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: NativeScript-dSYMs + path: dist/dSYMs + - name: Zip dSYMs + working-directory: dist/dSYMs + run: find . -maxdepth 1 -name '*.dSYM' -print | xargs -I@ zip -r @.zip @ + - name: Partial Changelog + run: npx conventional-changelog -p angular -r2 > body.md + - uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0 + with: + artifacts: "dist/nativescript-ios-*.tgz,dist/dSYMs/*.zip" + bodyFile: "body.md" + prerelease: ${{needs.build.outputs.npm_tag != 'latest'}} + allowUpdates: true diff --git a/build_all_ios.sh b/build_all_ios.sh index 832c38bb..e490f4a5 100755 --- a/build_all_ios.sh +++ b/build_all_ios.sh @@ -7,5 +7,4 @@ rm -rf ./dist ./build_nativescript.sh --no-vision ./build_tklivesync.sh --no-vision ./prepare_dSYMs.sh -./build_spm_artifacts.sh ios ./build_npm_ios.sh \ No newline at end of file diff --git a/build_all_vision.sh b/build_all_vision.sh index b8ef5b49..f5d1bd40 100755 --- a/build_all_vision.sh +++ b/build_all_vision.sh @@ -7,5 +7,4 @@ rm -rf ./dist ./build_nativescript.sh --no-catalyst --no-iphone --no-sim ./build_tklivesync.sh --no-catalyst --no-iphone --no-sim ./prepare_dSYMs.sh -./build_spm_artifacts.sh visionos ./build_npm_vision.sh \ No newline at end of file diff --git a/build_npm_ios.sh b/build_npm_ios.sh index ae62019f..8f36cbb0 100755 --- a/build_npm_ios.sh +++ b/build_npm_ios.sh @@ -11,65 +11,26 @@ cp ./package.json "$OUTPUT_DIR" cp -r "./project-template-ios/" "$OUTPUT_DIR/framework" -# The NativeScript / TKLiveSync xcframeworks are NO LONGER bundled in npm. They -# are published as GitHub Release artifacts and consumed via SwiftPM -# (github.com/NativeScript/ios-spm). Stamp the runtime version into the packaged -# template's SwiftPM reference so it resolves the matching release. -NPM_VERSION=$(node -e "console.log(require('./package.json').version)") -node ./scripts/stamp-template-version.mjs \ - "$OUTPUT_DIR/framework/__PROJECT_NAME__.xcodeproj/project.pbxproj" \ - "$NPM_VERSION" +cp -r "dist/NativeScript.xcframework" "$OUTPUT_DIR/framework/internal" +cp -r "dist/TKLiveSync.xcframework" "$OUTPUT_DIR/framework/internal" -# Local builds have no ios-spm release tag to resolve, so by default (outside -# CI) rewrite the template to a LOCAL SwiftPM package over the xcframeworks -# just built into dist/. Force with NS_SPM_LOCAL=1, disable with NS_SPM_LOCAL=0. -# The resulting .tgz embeds an absolute path into this checkout — local -# `ns platform add ios --framework-path=dist/nativescript-ios-*.tgz` use only. -if [[ "${NS_SPM_LOCAL:-}" == "1" || ( -z "${CI:-}" && "${NS_SPM_LOCAL:-}" != "0" ) ]]; then - LOCAL_SPM_DIR="$(pwd)/dist/local-spm" - rm -rf "$LOCAL_SPM_DIR" - mkdir -p "$LOCAL_SPM_DIR" - cp -R "dist/NativeScript.xcframework" "$LOCAL_SPM_DIR/" - cp -R "dist/TKLiveSync.xcframework" "$LOCAL_SPM_DIR/" - cat > "$LOCAL_SPM_DIR/Package.swift" <<'EOF' -// swift-tools-version: 5.10 -// Local dev override of github.com/NativeScript/ios-spm: same product shape, -// but binaryTargets point at the freshly built xcframeworks in this folder. -import PackageDescription - -let package = Package( - name: "NativeScriptSDK", - platforms: [ - .iOS(.v13), - .macCatalyst(.v13), - ], - products: [ - .library(name: "NativeScript", targets: ["NativeScript", "TKLiveSync"]), - .library(name: "NativeScriptSDK", targets: ["NativeScript", "TKLiveSync"]), - ], - dependencies: [], - targets: [ - .binaryTarget(name: "NativeScript", path: "NativeScript.xcframework"), - .binaryTarget(name: "TKLiveSync", path: "TKLiveSync.xcframework"), - ] -) -EOF - node ./scripts/stamp-template-local-spm.mjs \ - "$OUTPUT_DIR/framework/__PROJECT_NAME__.xcodeproj/project.pbxproj" \ - "$LOCAL_SPM_DIR" -fi - -# Build-time metadata generator is still shipped in npm (Phase 1). See the -# distribution plan for moving this to an on-demand artifact (Phase 2). mkdir -p "$OUTPUT_DIR/framework/internal/metadata-generator-x86_64" cp -r "metadata-generator/dist/x86_64/." "$OUTPUT_DIR/framework/internal/metadata-generator-x86_64" mkdir -p "$OUTPUT_DIR/framework/internal/metadata-generator-arm64" cp -r "metadata-generator/dist/arm64/." "$OUTPUT_DIR/framework/internal/metadata-generator-arm64" +# Add xcframeworks to .zip (NPM modules do not support symlinks, unzipping is done by {N} CLI) +( + set -e + cd $OUTPUT_DIR/framework/internal + zip -qr --symlinks XCFrameworks.zip *.xcframework + rm -rf *.xcframework +) + pushd "$OUTPUT_DIR" npm pack mv *.tgz ../ popd -checkpoint "npm package created." +checkpoint "npm package created." \ No newline at end of file diff --git a/build_npm_vision.sh b/build_npm_vision.sh index e8c52af7..8685cbcf 100755 --- a/build_npm_vision.sh +++ b/build_npm_vision.sh @@ -11,26 +11,26 @@ cp ./package.json "$OUTPUT_DIR" cp -r "./project-template-vision/" "$OUTPUT_DIR/framework" -# The NativeScript / TKLiveSync xcframeworks are NO LONGER bundled in npm. They -# are published as GitHub Release artifacts and consumed via SwiftPM -# (github.com/NativeScript/ios-spm). Stamp the runtime version into the packaged -# template's SwiftPM reference so it resolves the matching release. -NPM_VERSION=$(node -e "console.log(require('./package.json').version)") -node ./scripts/stamp-template-version.mjs \ - "$OUTPUT_DIR/framework/__PROJECT_NAME__.xcodeproj/project.pbxproj" \ - "$NPM_VERSION" - -# Build-time metadata generator is still shipped in npm (Phase 1). See the -# distribution plan for moving this to an on-demand artifact (Phase 2). +cp -r "dist/NativeScript.xcframework" "$OUTPUT_DIR/framework/internal" +cp -r "dist/TKLiveSync.xcframework" "$OUTPUT_DIR/framework/internal" + mkdir -p "$OUTPUT_DIR/framework/internal/metadata-generator-x86_64" cp -r "metadata-generator/dist/x86_64/." "$OUTPUT_DIR/framework/internal/metadata-generator-x86_64" mkdir -p "$OUTPUT_DIR/framework/internal/metadata-generator-arm64" cp -r "metadata-generator/dist/arm64/." "$OUTPUT_DIR/framework/internal/metadata-generator-arm64" +# Add xcframeworks to .zip (NPM modules do not support symlinks, unzipping is done by {N} CLI) +( + set -e + cd $OUTPUT_DIR/framework/internal + zip -qr --symlinks XCFrameworks.zip *.xcframework + rm -rf *.xcframework +) + pushd "$OUTPUT_DIR" npm pack mv *.tgz ../ popd -checkpoint "npm package created." +checkpoint "npm package created." \ No newline at end of file diff --git a/build_spm_artifacts.sh b/build_spm_artifacts.sh deleted file mode 100755 index 6d231c07..00000000 --- a/build_spm_artifacts.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash -# Package the built xcframeworks as SwiftPM binary-target artifacts: -# * a .zip per xcframework (framework at the zip root, symlinks preserved) -# * a SHA-256 checksum for each (the value SwiftPM's binaryTarget(checksum:) expects) -# -# Output goes to dist/artifacts/: -# .zip and a combined checksums.env (KEY=sha256 lines) -# -# Usage: ./build_spm_artifacts.sh [ios|visionos] (default: ios) -# -# These artifacts are uploaded to the GitHub Release and referenced by -# github.com/NativeScript/ios-spm (see scripts/stamp-spm-release.mjs). -set -e -source "$(dirname "$0")/build_utils.sh" - -TARGET="${1:-ios}" -DIST="$(pwd)/dist" -OUT="$DIST/artifacts" - -case "$TARGET" in - ios) - NS_ZIP="NativeScript.xcframework.zip" - TK_ZIP="TKLiveSync.xcframework.zip" - NS_KEY="NS_CHECKSUM_NATIVESCRIPT_IOS" - TK_KEY="NS_CHECKSUM_TKLIVESYNC_IOS" - ;; - visionos|vision|xr) - TARGET="visionos" - NS_ZIP="NativeScript.visionos.xcframework.zip" - TK_ZIP="TKLiveSync.visionos.xcframework.zip" - NS_KEY="NS_CHECKSUM_NATIVESCRIPT_VISIONOS" - TK_KEY="NS_CHECKSUM_TKLIVESYNC_VISIONOS" - ;; - *) - echo "Unknown target '$TARGET' (expected ios or visionos)" >&2 - exit 1 - ;; -esac - -checkpoint "Packaging SwiftPM artifacts for $TARGET..." -rm -rf "$OUT" -mkdir -p "$OUT" - -# SwiftPM's binaryTarget(checksum:) is the SHA-256 of the zip. `swift package -# compute-checksum` is the canonical producer; shasum -a 256 yields the same -# value and is the portable fallback. -compute_checksum() { - local zip="$1" - if command -v swift >/dev/null 2>&1 && swift package compute-checksum "$zip" >/dev/null 2>&1; then - swift package compute-checksum "$zip" - else - shasum -a 256 "$zip" | awk '{print $1}' - fi -} - -# zip_xcframework -zip_xcframework() { - local src="$1" zipname="$2" - if [ ! -d "$DIST/$src" ]; then - echo "Missing $DIST/$src — run the runtime build first." >&2 - exit 1 - fi - ( cd "$DIST" && zip -qr --symlinks "$OUT/$zipname" "$src" ) -} - -zip_xcframework "NativeScript.xcframework" "$NS_ZIP" -zip_xcframework "TKLiveSync.xcframework" "$TK_ZIP" - -NS_SUM="$(compute_checksum "$OUT/$NS_ZIP")" -TK_SUM="$(compute_checksum "$OUT/$TK_ZIP")" - -# Per-target filename so the iOS and visionOS env files don't collide when the -# release/stamp jobs merge both platforms' artifacts into one directory. -CHECKSUMS="$OUT/checksums-$TARGET.env" -{ - echo "${NS_KEY}=${NS_SUM}" - echo "${TK_KEY}=${TK_SUM}" -} > "$CHECKSUMS" - -checkpoint "SwiftPM artifacts ready in $OUT:" -( cd "$OUT" && ls -lh *.zip ) -echo "Checksums ($CHECKSUMS):" -cat "$CHECKSUMS" diff --git a/project-template-ios/__PROJECT_NAME__.xcodeproj/project.pbxproj b/project-template-ios/__PROJECT_NAME__.xcodeproj/project.pbxproj index 52bdac61..142e4274 100644 --- a/project-template-ios/__PROJECT_NAME__.xcodeproj/project.pbxproj +++ b/project-template-ios/__PROJECT_NAME__.xcodeproj/project.pbxproj @@ -7,7 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - AA10000000000000000000C1 /* NativeScript in Frameworks */ = {isa = PBXBuildFile; productRef = AA10000000000000000000B1 /* NativeScript */; }; + 39940D9122C4EF600050DDE1 /* NativeScript.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 39940D8C22C4EAAA0050DDE1 /* NativeScript.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 39940E1C22C5DFFF0050DDE1 /* TKLiveSync.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 39940E1B22C5DFFF0050DDE1 /* TKLiveSync.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 858B842D18CA22B800AB12DE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 858B833A18CA111C00AB12DE /* InfoPlist.strings */; }; AAA0AADB2A54B96B00EE55A4 /* NativeScriptStart.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA0AADA2A54B96B00EE55A4 /* NativeScriptStart.m */; }; CD45EE7C18DC2D5800FB50C0 /* app in Resources */ = {isa = PBXBuildFile; fileRef = CD45EE7A18DC2D5800FB50C0 /* app */; }; @@ -21,6 +22,8 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 39940D9122C4EF600050DDE1 /* NativeScript.xcframework in Embed Frameworks */, + 39940E1C22C5DFFF0050DDE1 /* TKLiveSync.xcframework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -32,6 +35,8 @@ 391174B721F1D99900BA2583 /* plugins-release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "plugins-release.xcconfig"; sourceTree = SOURCE_ROOT; }; 391174B821F1D99900BA2583 /* plugins-debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "plugins-debug.xcconfig"; sourceTree = SOURCE_ROOT; }; 39940D8122C4E84C0050DDE1 /* __PROJECT_NAME__.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = __PROJECT_NAME__.entitlements; sourceTree = ""; }; + 39940D8C22C4EAAA0050DDE1 /* NativeScript.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = NativeScript.xcframework; path = internal/NativeScript.xcframework; sourceTree = ""; }; + 39940E1B22C5DFFF0050DDE1 /* TKLiveSync.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = TKLiveSync.xcframework; path = internal/TKLiveSync.xcframework; sourceTree = ""; }; 42C751E2232B769100186695 /* nativescript-pre-link */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "nativescript-pre-link"; path = "internal/nativescript-pre-link"; sourceTree = SOURCE_ROOT; }; 42C751E3232B769100186695 /* strip-dynamic-framework-architectures.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = "strip-dynamic-framework-architectures.sh"; path = "internal/strip-dynamic-framework-architectures.sh"; sourceTree = SOURCE_ROOT; }; 42C751E4232B769100186695 /* nsld.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = nsld.sh; path = internal/nsld.sh; sourceTree = SOURCE_ROOT; }; @@ -58,7 +63,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AA10000000000000000000C1 /* NativeScript in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -111,6 +115,8 @@ 858B833018CA111C00AB12DE /* Frameworks */ = { isa = PBXGroup; children = ( + 39940E1B22C5DFFF0050DDE1 /* TKLiveSync.xcframework */, + 39940D8C22C4EAAA0050DDE1 /* NativeScript.xcframework */, ); name = Frameworks; sourceTree = ""; @@ -170,9 +176,6 @@ dependencies = ( ); name = __PROJECT_NAME__; - packageProductDependencies = ( - AA10000000000000000000B1 /* NativeScript */, - ); productName = JDBridgeApp; productReference = 858B843318CA22B800AB12DE /* __PROJECT_NAME__.app */; productType = "com.apple.product-type.application"; @@ -203,9 +206,6 @@ Base, ); mainGroup = 858B832518CA111C00AB12DE; - packageReferences = ( - AA10000000000000000000A1 /* XCRemoteSwiftPackageReference "ios-spm" */, - ); productRefGroup = 858B832F18CA111C00AB12DE /* Products */; projectDirPath = ""; projectRoot = ""; @@ -498,25 +498,6 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - AA10000000000000000000A1 /* XCRemoteSwiftPackageReference "ios-spm" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/NativeScript/ios-spm.git"; - requirement = { - kind = exactVersion; - version = "__NS_RUNTIME_VERSION__"; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - AA10000000000000000000B1 /* NativeScript */ = { - isa = XCSwiftPackageProductDependency; - package = AA10000000000000000000A1 /* XCRemoteSwiftPackageReference "ios-spm" */; - productName = NativeScript; - }; -/* End XCSwiftPackageProductDependency section */ }; rootObject = 858B832618CA111C00AB12DE /* Project object */; } diff --git a/project-template-ios/internal/nativescript-build.xcconfig b/project-template-ios/internal/nativescript-build.xcconfig index 6a2167c8..8a3fc311 100644 --- a/project-template-ios/internal/nativescript-build.xcconfig +++ b/project-template-ios/internal/nativescript-build.xcconfig @@ -1,11 +1,6 @@ // * NativeScript build related flags // * Add [sdk=*] after each one to avoid conflict with CocoaPods flags -// * NativeScript + TKLiveSync are provided by the SwiftPM "NativeScript" product -// * (github.com/NativeScript/ios-spm), so SwiftPM links/embeds them automatically. -// * The explicit -framework NativeScript / -framework TKLiveSync / -F internal are -// * intentionally omitted. SwiftPM stages the resolved framework slice into -// * CONFIGURATION_BUILD_DIR (below), which is where the metadata generator finds it. -OTHER_LDFLAGS[sdk=*] = $(inherited) -ObjC -sectcreate __DATA __TNSMetadata "$(CONFIGURATION_BUILD_DIR)/metadata-$(CURRENT_ARCH).bin" -licucore -lz -lc++ -framework Foundation -framework UIKit -framework CoreGraphics -framework CoreServices -framework Security +OTHER_LDFLAGS[sdk=*] = $(inherited) -ObjC -sectcreate __DATA __TNSMetadata "$(CONFIGURATION_BUILD_DIR)/metadata-$(CURRENT_ARCH).bin" -framework NativeScript -framework TKLiveSync -F"$(SRCROOT)/internal" -licucore -lz -lc++ -framework Foundation -framework UIKit -framework CoreGraphics -framework CoreServices -framework Security // We need to add CONFIGURATION_BUILD_DIR here so that we can explicitly quote-escape any paths in it, because the implicitly added path by Xcode is not always escaped FRAMEWORK_SEARCH_PATHS[sdk=*] = $(inherited) "$(SRCROOT)/internal/" "$(CONFIGURATION_BUILD_DIR)" diff --git a/project-template-vision/__PROJECT_NAME__.xcodeproj/project.pbxproj b/project-template-vision/__PROJECT_NAME__.xcodeproj/project.pbxproj index e549122c..01de986a 100644 --- a/project-template-vision/__PROJECT_NAME__.xcodeproj/project.pbxproj +++ b/project-template-vision/__PROJECT_NAME__.xcodeproj/project.pbxproj @@ -7,7 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - AA10000000000000000000C1 /* NativeScriptVisionOS in Frameworks */ = {isa = PBXBuildFile; productRef = AA10000000000000000000B1 /* NativeScriptVisionOS */; }; + 39940D9122C4EF600050DDE1 /* NativeScript.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 39940D8C22C4EAAA0050DDE1 /* NativeScript.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 39940E1C22C5DFFF0050DDE1 /* TKLiveSync.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 39940E1B22C5DFFF0050DDE1 /* TKLiveSync.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 858B842D18CA22B800AB12DE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 858B833A18CA111C00AB12DE /* InfoPlist.strings */; }; AAA0AADB2A54B96B00EE55A4 /* NativeScriptStart.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA0AADA2A54B96B00EE55A4 /* NativeScriptStart.m */; }; CD45EE7C18DC2D5800FB50C0 /* app in Resources */ = {isa = PBXBuildFile; fileRef = CD45EE7A18DC2D5800FB50C0 /* app */; }; @@ -20,6 +21,8 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 39940D9122C4EF600050DDE1 /* NativeScript.xcframework in Embed Frameworks */, + 39940E1C22C5DFFF0050DDE1 /* TKLiveSync.xcframework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -31,6 +34,8 @@ 391174B721F1D99900BA2583 /* plugins-release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "plugins-release.xcconfig"; sourceTree = SOURCE_ROOT; }; 391174B821F1D99900BA2583 /* plugins-debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "plugins-debug.xcconfig"; sourceTree = SOURCE_ROOT; }; 39940D8122C4E84C0050DDE1 /* __PROJECT_NAME__.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = __PROJECT_NAME__.entitlements; sourceTree = ""; }; + 39940D8C22C4EAAA0050DDE1 /* NativeScript.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = NativeScript.xcframework; path = internal/NativeScript.xcframework; sourceTree = ""; }; + 39940E1B22C5DFFF0050DDE1 /* TKLiveSync.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = TKLiveSync.xcframework; path = internal/TKLiveSync.xcframework; sourceTree = ""; }; 42C751E2232B769100186695 /* nativescript-pre-link */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "nativescript-pre-link"; path = "internal/nativescript-pre-link"; sourceTree = SOURCE_ROOT; }; 42C751E3232B769100186695 /* strip-dynamic-framework-architectures.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = "strip-dynamic-framework-architectures.sh"; path = "internal/strip-dynamic-framework-architectures.sh"; sourceTree = SOURCE_ROOT; }; 42C751E4232B769100186695 /* nsld.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = nsld.sh; path = internal/nsld.sh; sourceTree = SOURCE_ROOT; }; @@ -56,7 +61,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AA10000000000000000000C1 /* NativeScriptVisionOS in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -108,6 +112,8 @@ 858B833018CA111C00AB12DE /* Frameworks */ = { isa = PBXGroup; children = ( + 39940E1B22C5DFFF0050DDE1 /* TKLiveSync.xcframework */, + 39940D8C22C4EAAA0050DDE1 /* NativeScript.xcframework */, ); name = Frameworks; sourceTree = ""; @@ -167,9 +173,6 @@ dependencies = ( ); name = __PROJECT_NAME__; - packageProductDependencies = ( - AA10000000000000000000B1 /* NativeScriptVisionOS */, - ); productName = JDBridgeApp; productReference = 858B843318CA22B800AB12DE /* __PROJECT_NAME__.app */; productType = "com.apple.product-type.application"; @@ -200,9 +203,6 @@ Base, ); mainGroup = 858B832518CA111C00AB12DE; - packageReferences = ( - AA10000000000000000000A1 /* XCRemoteSwiftPackageReference "ios-spm" */, - ); productRefGroup = 858B832F18CA111C00AB12DE /* Products */; projectDirPath = ""; projectRoot = ""; @@ -504,25 +504,6 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - AA10000000000000000000A1 /* XCRemoteSwiftPackageReference "ios-spm" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/NativeScript/ios-spm.git"; - requirement = { - kind = exactVersion; - version = "__NS_RUNTIME_VERSION__"; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - AA10000000000000000000B1 /* NativeScriptVisionOS */ = { - isa = XCSwiftPackageProductDependency; - package = AA10000000000000000000A1 /* XCRemoteSwiftPackageReference "ios-spm" */; - productName = NativeScriptVisionOS; - }; -/* End XCSwiftPackageProductDependency section */ }; rootObject = 858B832618CA111C00AB12DE /* Project object */; } diff --git a/project-template-vision/internal/nativescript-build.xcconfig b/project-template-vision/internal/nativescript-build.xcconfig index c9033349..8a3fc311 100644 --- a/project-template-vision/internal/nativescript-build.xcconfig +++ b/project-template-vision/internal/nativescript-build.xcconfig @@ -1,9 +1,6 @@ // * NativeScript build related flags // * Add [sdk=*] after each one to avoid conflict with CocoaPods flags -// * NativeScript + TKLiveSync are provided by the SwiftPM "NativeScriptVisionOS" product -// * (github.com/NativeScript/ios-spm); SwiftPM links/embeds them automatically. The -// * explicit -framework NativeScript / -framework TKLiveSync / -F internal are omitted. -OTHER_LDFLAGS[sdk=*] = $(inherited) -ObjC -sectcreate __DATA __TNSMetadata "$(CONFIGURATION_BUILD_DIR)/metadata-$(CURRENT_ARCH).bin" -licucore -lz -lc++ -framework Foundation -framework UIKit -framework CoreGraphics -framework CoreServices -framework Security +OTHER_LDFLAGS[sdk=*] = $(inherited) -ObjC -sectcreate __DATA __TNSMetadata "$(CONFIGURATION_BUILD_DIR)/metadata-$(CURRENT_ARCH).bin" -framework NativeScript -framework TKLiveSync -F"$(SRCROOT)/internal" -licucore -lz -lc++ -framework Foundation -framework UIKit -framework CoreGraphics -framework CoreServices -framework Security // We need to add CONFIGURATION_BUILD_DIR here so that we can explicitly quote-escape any paths in it, because the implicitly added path by Xcode is not always escaped FRAMEWORK_SEARCH_PATHS[sdk=*] = $(inherited) "$(SRCROOT)/internal/" "$(CONFIGURATION_BUILD_DIR)" diff --git a/scripts/stamp-spm-release.mjs b/scripts/stamp-spm-release.mjs deleted file mode 100644 index ed0f022c..00000000 --- a/scripts/stamp-spm-release.mjs +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env node -// Stamp the released version + artifact checksums into ios-spm/Package.swift. -// -// The manifest ships with replaceable tokens: -// let nsVersion = "NS_SPM_VERSION" -// checksum: "NS_CHECKSUM_NATIVESCRIPT_IOS" (and TKLIVESYNC_IOS, *_VISIONOS) -// -// This script (run by the release flow against a checkout of NativeScript/ios-spm) -// replaces them with the version being released and the SHA-256 of each uploaded -// xcframework zip. Checksums come from one or more `KEY=sha256` env files produced -// by build_spm_artifacts.sh (one per platform: iOS job + visionOS job). -// -// Usage: -// node scripts/stamp-spm-release.mjs \ -// --package /path/to/ios-spm/Package.swift \ -// --version 9.1.0 \ -// --checksums ios-checksums.env [--checksums vision-checksums.env] \ -// [--strict] -// -// --strict fails if any NS_SPM_VERSION / NS_CHECKSUM_* token is left unstamped -// (use it for a full iOS + visionOS release so a placeholder can never ship). -import fs from "node:fs"; - -const args = process.argv.slice(2); -const opts = { checksums: [] }; -for (let i = 0; i < args.length; i++) { - const a = args[i]; - if (a === "--package") opts.package = args[++i]; - else if (a === "--version") opts.version = args[++i]; - else if (a === "--checksums") opts.checksums.push(args[++i]); - else if (a === "--strict") opts.strict = true; - else { - console.error(`Unknown argument: ${a}`); - process.exit(1); - } -} - -if (!opts.package || !opts.version) { - console.error( - "Usage: stamp-spm-release.mjs --package --version --checksums [--checksums ] [--strict]" - ); - process.exit(1); -} - -const SHA256_RE = /^[0-9a-f]{64}$/; -const checksums = {}; -for (const file of opts.checksums) { - const text = fs.readFileSync(file, "utf8"); - for (const line of text.split("\n")) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#")) continue; - const eq = trimmed.indexOf("="); - if (eq === -1) continue; - const key = trimmed.slice(0, eq).trim(); - const value = trimmed.slice(eq + 1).trim(); - if (!key) continue; - // A binaryTarget checksum must be a 64-char lowercase hex SHA-256. Reject - // anything else now (empty/truncated/uppercase) so we can't stamp a manifest - // that resolves to a checksum mismatch later. - if (key.startsWith("NS_CHECKSUM_") && !SHA256_RE.test(value)) { - console.error( - `ERROR: ${key} in ${file} is not a valid SHA-256 checksum: "${value}"` - ); - process.exit(1); - } - checksums[key] = value; - } -} - -let manifest = fs.readFileSync(opts.package, "utf8"); - -// Stamping is IDEMPOTENT: each slot is rewritten whether it still holds the -// NS_SPM_VERSION / NS_CHECKSUM_* token or an already-stamped concrete value. -// This matters because the release flow pushes the stamped manifest back to -// `main`, so by the second release there are no tokens left. A one-shot token -// replace would then silently no-op, the "no changes to commit" tag would land -// on the prior commit, and every new tag would resolve to the FIRST release's -// artifacts (the 9.0.4-next.* incident). Anchoring on the structural shape -// instead of the token lets us re-stamp correctly forever. -const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); - -// Each checksum env key ↔ the artifact zip its binaryTarget references (the -// pairing baked into the manifest template). Lets us find the right checksum -// slot by URL once the NS_CHECKSUM_* tokens are gone. -const KEY_TO_ARTIFACT = { - NS_CHECKSUM_NATIVESCRIPT_IOS: "NativeScript.xcframework.zip", - NS_CHECKSUM_TKLIVESYNC_IOS: "TKLiveSync.xcframework.zip", - NS_CHECKSUM_NATIVESCRIPT_VISIONOS: "NativeScript.visionos.xcframework.zip", - NS_CHECKSUM_TKLIVESYNC_VISIONOS: "TKLiveSync.visionos.xcframework.zip", -}; - -// Version: rewrite the value inside `let nsVersion = "..."`. -const versionRe = /(let\s+nsVersion\s*=\s*")[^"]*(")/; -if (!versionRe.test(manifest)) { - console.error(`ERROR: could not find 'let nsVersion = "..."' in ${opts.package}`); - process.exit(1); -} -manifest = manifest.replace(versionRe, `$1${opts.version}$2`); - -// Checksums: for each provided checksum, rewrite the value in the binaryTarget -// whose url points at the matching artifact zip. -const applied = []; -for (const [key, value] of Object.entries(checksums)) { - const artifact = KEY_TO_ARTIFACT[key]; - if (!artifact) { - console.error(`ERROR: no artifact mapping for checksum key ${key}; update KEY_TO_ARTIFACT.`); - process.exit(1); - } - const re = new RegExp( - `(url:\\s*"[^"]*${escapeRegExp(artifact)}",\\s*checksum:\\s*")[^"]*(")` - ); - if (!re.test(manifest)) { - console.error(`ERROR: no binaryTarget checksum slot for ${artifact} in ${opts.package}`); - process.exit(1); - } - manifest = manifest.replace(re, `$1${value}$2`); - applied.push(key); -} - -fs.writeFileSync(opts.package, manifest); - -console.log(`Stamped ${opts.package}`); -console.log(` version: ${opts.version}`); -console.log(` checksums applied: ${applied.length ? applied.join(", ") : "(none)"}`); - -// Safety net: no placeholder tokens may remain (they'd resolve to a broken URL -// or a checksum mismatch). With idempotent stamping a leftover token signals a -// real manifest/key drift (e.g. a missing platform's checksums), not a routine -// 2nd-release no-op. -const leftover = [...new Set(manifest.match(/NS_SPM_VERSION|NS_CHECKSUM_[A-Z_]+/g) || [])]; -if (leftover.length) { - const msg = `Unstamped tokens remain: ${leftover.join(", ")}`; - if (opts.strict) { - console.error(`ERROR: ${msg}`); - process.exit(1); - } - console.warn(`WARNING: ${msg}`); -} diff --git a/scripts/stamp-template-local-spm.mjs b/scripts/stamp-template-local-spm.mjs deleted file mode 100644 index 1264a051..00000000 --- a/scripts/stamp-template-local-spm.mjs +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env node -// Stamp a packaged project template to consume the runtime via a LOCAL SwiftPM -// package instead of the released ios-spm tag (the D6 "dev/offline override" -// from SPM_DISTRIBUTION_PLAN.md). -// -// Local `npm run build-ios` produces xcframeworks in dist/ but no ios-spm -// release tag, so the template's XCRemoteSwiftPackageReference (exactVersion -// pinned by stamp-template-version.mjs) can never resolve. This script rewrites -// that reference into an XCLocalSwiftPackageReference pointing at the local-spm -// package the build just created (dist/local-spm — Package.swift + binary -// targets over the built xcframeworks). -// -// The resulting npm package is machine-specific (it embeds an absolute path -// into this checkout) and is only meant for `ns platform add ios -// --framework-path=dist/nativescript-ios-.tgz` style local testing. -// -// Usage: node scripts/stamp-template-local-spm.mjs -import fs from "node:fs"; -import path from "node:path"; - -const [, , pbxPath, localSpmPath] = process.argv; - -if (!pbxPath || !localSpmPath) { - console.error("Usage: stamp-template-local-spm.mjs "); - process.exit(1); -} - -if (!path.isAbsolute(localSpmPath)) { - console.error(`local-spm path must be absolute, got: ${localSpmPath}`); - process.exit(1); -} - -if (!fs.existsSync(path.join(localSpmPath, "Package.swift"))) { - console.error(`No Package.swift found in ${localSpmPath} — run the runtime build first.`); - process.exit(1); -} - -let contents = fs.readFileSync(pbxPath, "utf8"); - -const REMOTE_REF_RE = - /\/\* Begin XCRemoteSwiftPackageReference section \*\/[\s\S]*?\/\* End XCRemoteSwiftPackageReference section \*\//; - -if (!REMOTE_REF_RE.test(contents)) { - console.error(`No XCRemoteSwiftPackageReference section found in ${pbxPath} (already stamped local?).`); - process.exit(1); -} - -// The template uses a fixed UUID for the package reference; keep it so the -// packageReferences list and product dependency keep resolving. -const refUuidMatch = contents.match(/([0-9A-F]{24}) \/\* XCRemoteSwiftPackageReference "ios-spm" \*\//); -if (!refUuidMatch) { - console.error(`Could not find the "ios-spm" package reference UUID in ${pbxPath}.`); - process.exit(1); -} -const refUuid = refUuidMatch[1]; - -contents = contents.replace( - REMOTE_REF_RE, - `/* Begin XCLocalSwiftPackageReference section */ -\t\t${refUuid} /* XCLocalSwiftPackageReference "local-spm" */ = { -\t\t\tisa = XCLocalSwiftPackageReference; -\t\t\trelativePath = ${JSON.stringify(localSpmPath)}; -\t\t}; -/* End XCLocalSwiftPackageReference section */` -); - -// Update the comment annotations everywhere the reference UUID appears -// (packageReferences list + XCSwiftPackageProductDependency). -contents = contents.split(`${refUuid} /* XCRemoteSwiftPackageReference "ios-spm" */`).join(`${refUuid} /* XCLocalSwiftPackageReference "local-spm" */`); - -fs.writeFileSync(pbxPath, contents); -console.log(`Stamped ${pbxPath} → local SwiftPM package at ${localSpmPath}`); diff --git a/scripts/stamp-template-version.mjs b/scripts/stamp-template-version.mjs deleted file mode 100644 index bff2b32f..00000000 --- a/scripts/stamp-template-version.mjs +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env node -// Stamp the runtime version into a packaged project template's SwiftPM reference. -// -// The source templates ship with `version = "__NS_RUNTIME_VERSION__";` in their -// XCRemoteSwiftPackageReference. At npm-pack time we replace that placeholder -// with the concrete version being published, so `@nativescript/ios@X` always -// resolves the matching `ios-spm` tag `X` (and therefore the xcframework built -// for X). The {N} CLI copies the stamped template verbatim — no CLI change. -// -// Usage: node scripts/stamp-template-version.mjs -import fs from "node:fs"; - -const [, , pbxPath, version] = process.argv; - -if (!pbxPath || !version) { - console.error("Usage: stamp-template-version.mjs "); - process.exit(1); -} - -const PLACEHOLDER = "__NS_RUNTIME_VERSION__"; -let contents = fs.readFileSync(pbxPath, "utf8"); - -if (!contents.includes(PLACEHOLDER)) { - console.error( - `No '${PLACEHOLDER}' placeholder found in ${pbxPath}. ` + - `Either it was already stamped or the SwiftPM reference is missing.` - ); - process.exit(1); -} - -contents = contents.split(PLACEHOLDER).join(version); -fs.writeFileSync(pbxPath, contents); -console.log(`Stamped ${pbxPath} → ios-spm exactVersion ${version}`);