From 116499b3287041956b9a14b80286378929587d56 Mon Sep 17 00:00:00 2001 From: Christian Falch Date: Tue, 3 Nov 2026 17:39:04 +0100 Subject: [PATCH] Check in CI that `spm deinit` takes the template app back to CocoaPods No CI job tested the CocoaPods opt-out: after the SwiftPM build, nothing ran `spm deinit` or looked at the files it leaves. The template app job now records the Podfile and ios/.gitignore checksums before `spm add`, runs `spm deinit` after the app upload, and checks that the Podfile and .gitignore are unchanged, the marker and ReactNativeSPM/ are gone, and the Xcode project and shared scheme have no SwiftPM references left. The check reads files only; `deinit` does not run `pod install`. --- .github/workflow-scripts/assert-spm-deinit.sh | 82 +++++++++++++++++++ .github/workflows/e2e-ios-templateapp.yml | 14 ++++ 2 files changed, 96 insertions(+) create mode 100755 .github/workflow-scripts/assert-spm-deinit.sh diff --git a/.github/workflow-scripts/assert-spm-deinit.sh b/.github/workflow-scripts/assert-spm-deinit.sh new file mode 100755 index 00000000000..d4d9de66ebf --- /dev/null +++ b/.github/workflow-scripts/assert-spm-deinit.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Checks that `npx react-native spm deinit` left an iOS app with only its +# CocoaPods files. It checks only what deinit removes; `pod install` restores +# the CocoaPods references, so they are not checked here. +# +# Usage: assert-spm-deinit.sh + +if [ $# -ne 4 ]; then + echo "Usage: $0 " + exit 2 +fi + +IOS_DIR=$1 +XCODEPROJ="$IOS_DIR/$2" +EXPECTED_PODFILE_SHA256=$3 +EXPECTED_GITIGNORE_SHA256=$4 +PBXPROJ="$XCODEPROJ/project.pbxproj" +FAILED=0 + +fail() { + echo "::error::$1" + FAILED=1 +} + +sha256_or_absent() { + if [ -f "$1" ]; then + shasum -a 256 "$1" | cut -d ' ' -f 1 + else + echo absent + fi +} + +ACTUAL_PODFILE_SHA256=$(sha256_or_absent "$IOS_DIR/Podfile") +if [ "$ACTUAL_PODFILE_SHA256" != "$EXPECTED_PODFILE_SHA256" ]; then + fail "Podfile changed: sha256 is '$ACTUAL_PODFILE_SHA256', expected '$EXPECTED_PODFILE_SHA256'." +fi + +ACTUAL_GITIGNORE_SHA256=$(sha256_or_absent "$IOS_DIR/.gitignore") +if [ "$ACTUAL_GITIGNORE_SHA256" != "$EXPECTED_GITIGNORE_SHA256" ]; then + fail ".gitignore changed: sha256 is '$ACTUAL_GITIGNORE_SHA256', expected '$EXPECTED_GITIGNORE_SHA256'." +fi + +if [ -e "$XCODEPROJ/.spm-injected.json" ]; then + fail "$XCODEPROJ/.spm-injected.json is still there." +fi + +if [ -e "$IOS_DIR/ReactNativeSPM" ]; then + fail "$IOS_DIR/ReactNativeSPM is still there." +fi + +if [ ! -f "$PBXPROJ" ]; then + fail "$PBXPROJ is missing." +else + for INJECTED in \ + XCLocalSwiftPackageReference \ + XCSwiftPackageProductDependency \ + packageReferences \ + packageProductDependencies \ + ReactNativeSPM \ + "Sync SPM Autolinking" \ + "Embed React Native Flavored Frameworks"; do + if grep -qF "$INJECTED" "$PBXPROJ"; then + fail "$PBXPROJ still contains '$INJECTED'." + fi + done +fi + +for SCHEME in "$XCODEPROJ"/xcshareddata/xcschemes/*.xcscheme; do + if [ -f "$SCHEME" ] && grep -qF 'title = "Sync SPM Autolinking"' "$SCHEME"; then + fail "$SCHEME still has the Sync SPM Autolinking pre-action." + fi +done + +if [ $FAILED -ne 0 ]; then + exit 1 +fi +echo "spm deinit removed every SwiftPM change." diff --git a/.github/workflows/e2e-ios-templateapp.yml b/.github/workflows/e2e-ios-templateapp.yml index 235126474ab..ec5f5ace527 100644 --- a/.github/workflows/e2e-ios-templateapp.yml +++ b/.github/workflows/e2e-ios-templateapp.yml @@ -64,6 +64,15 @@ jobs: uses: ./.github/actions/setup-spm-artifacts with: working-directory: /tmp/RNTestProject/ios + - name: Record the Podfile and .gitignore checksums + working-directory: /tmp/RNTestProject/ios + run: | + echo "PODFILE_SHA256=$(shasum -a 256 Podfile | cut -d ' ' -f 1)" >> "$GITHUB_ENV" + if [ -f .gitignore ]; then + echo "GITIGNORE_SHA256=$(shasum -a 256 .gitignore | cut -d ' ' -f 1)" >> "$GITHUB_ENV" + else + echo "GITIGNORE_SHA256=absent" >> "$GITHUB_ENV" + fi - name: Convert the app to SwiftPM working-directory: /tmp/RNTestProject/ios run: LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 RN_STRICT_API=1 npx react-native spm add --deintegrate --artifacts /tmp/spm-artifacts --download skip @@ -83,6 +92,11 @@ jobs: name: RNTestProject-${{ matrix.flavor }} overwrite: true path: /tmp/RNTestProject/Build/Products/${{ matrix.flavor }}-iphonesimulator/RNTestProject.app + - name: Take the app back to CocoaPods + working-directory: /tmp/RNTestProject/ios + run: npx react-native spm deinit + - name: Check that only the CocoaPods files are left + run: ./.github/workflow-scripts/assert-spm-deinit.sh /tmp/RNTestProject/ios RNTestProject.xcodeproj "$PODFILE_SHA256" "$GITIGNORE_SHA256" - name: Report status id: report-status if: always()