Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,12 @@ steps:
plugins: *plugins

- label: ':swift: Test Swift Package'
command: swift test
command: make build REFRESH_L10N=1 REFRESH_JS_BUILD=1 && make test-swift-package
plugins: *plugins

- label: ':package: Build XCFramework'
command: make build-resources-xcframework
artifact_paths:
- 'GutenbergKitResources-*.xcframework.zip'
- 'GutenbergKitResources-*.xcframework.zip.checksum.txt'
plugins: *plugins
12 changes: 9 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,15 @@ local.properties
/android/Gutenberg/src/main/assets/assets
/android/Gutenberg/src/main/assets/index.html

# Disabled removing these files until this is published like Android in CI.
# /ios/Sources/GutenbergKit/Gutenberg/assets
# /ios/Sources/GutenbergKit/Gutenberg/index.html
/ios/Sources/GutenbergKit/Gutenberg/assets
/ios/Sources/GutenbergKit/Gutenberg/index.html
/ios/Sources/GutenbergKitResources/Resources/assets
/ios/Sources/GutenbergKitResources/Resources/index.html

# XCFramework build output
*.xcframework
*.xcframework.zip
*.xcframework.zip.checksum.txt

# Translation files
src/translations/
Expand Down
6 changes: 6 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

source 'https://rubygems.org'

gem 'fastlane', '~> 2.230'
gem 'fastlane-plugin-wpmreleasetoolkit', '~> 13.8'
22 changes: 19 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.DEFAULT_GOAL := help

SIMULATOR_DESTINATION := OS=26.0,name=iPhone 17
SIMULATOR_DESTINATION := OS=26.1,name=iPhone 17

.PHONY: help
help: ## Display this help menu
Expand All @@ -12,12 +12,15 @@ help: ## Display this help menu
sort
@echo ""

export GUTENBERGKIT_SWIFT_USE_LOCAL_RESOURCES := 1

define XCODEBUILD_CMD
@set -o pipefail && \
xcodebuild $(1) \
-scheme GutenbergKit \
-sdk iphonesimulator \
-destination '${SIMULATOR_DESTINATION}' \
CODE_SIGNING_ALLOWED=NO \
| xcbeautify
endef

Expand Down Expand Up @@ -76,8 +79,10 @@ build: npm-dependencies prep-translations ## Build the project for all platforms
echo "--- :node: Building Gutenberg"; \
npm run build; \
echo "--- :open_file_folder: Copying Build Products into place"; \
rm -rf ./ios/Sources/GutenbergKit/Gutenberg/ ./android/Gutenberg/src/main/assets/; \
rm -rf ./ios/Sources/GutenbergKit/Gutenberg/ ./ios/Sources/GutenbergKitResources/Resources/ ./android/Gutenberg/src/main/assets/; \
mkdir -p ./ios/Sources/GutenbergKitResources/Resources; \
cp -r ./dist/. ./ios/Sources/GutenbergKit/Gutenberg/; \
cp -r ./dist/. ./ios/Sources/GutenbergKitResources/Resources/; \
cp -r ./dist/. ./android/Gutenberg/src/main/assets; \
else \
echo "--- :white_check_mark: Skipping JS build (dist already exists). Use REFRESH_JS_BUILD=1 to force refresh."; \
Expand All @@ -87,6 +92,11 @@ build: npm-dependencies prep-translations ## Build the project for all platforms
build-swift-package: build ## Build the Swift package for iOS
$(call XCODEBUILD_CMD, build)

.PHONY: build-resources-xcframework
build-resources-xcframework: build ## Build GutenbergKitResources XCFramework
@echo "--- :swift: Building GutenbergKitResources XCFramework"
./build_xcframework.sh

.PHONY: local-android-library
local-android-library: build ## Build the Android library to local Maven
@echo "--- :android: Building Library"
Expand Down Expand Up @@ -146,7 +156,13 @@ test-js-watch: npm-dependencies ## Run JavaScript tests in watch mode

.PHONY: test-swift-package
test-swift-package: build ## Run Swift package tests
$(call XCODEBUILD_CMD, test)
@set -o pipefail && \
xcodebuild test \
-scheme GutenbergKitTests \
-sdk iphonesimulator \
-destination '${SIMULATOR_DESTINATION}' \
CODE_SIGNING_ALLOWED=NO \
| xcbeautify

.PHONY: test-android
test-android: ## Run Android tests
Expand Down
36 changes: 32 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
// swift-tools-version: 6.2
// The swift-tools-version declares the minimum version of Swift required to build this package.

import Foundation
import PackageDescription

/// When set, `GutenbergKitResources` is built from local source + resources.
/// When unset, it resolves to a pre-built XCFramework fetched from CDN.
let useLocalResources = Context.environment["GUTENBERGKIT_SWIFT_USE_LOCAL_RESOURCES"] != nil

// MARK: - Resources target

/// Pre-built XCFramework version for tagged releases.
/// Updated by the Fastlane `release` lane.
let resourcesVersion = "0.0.0"
let resourcesChecksum = "0000000000000000000000000000000000000000000000000000000000000000"

let gutenbergKitResources: Target = useLocalResources
? .target(
name: "GutenbergKitResources",
path: "ios/Sources/GutenbergKitResources",
resources: [.copy("Resources")]
)
: .binaryTarget(
name: "GutenbergKitResources",
url: "https://cdn.a8c-ci.services/gutenbergkit/\(resourcesVersion)/GutenbergKitResources.xcframework.zip",
checksum: resourcesChecksum
)

// MARK: - Package

let package = Package(
name: "GutenbergKit",
platforms: [.iOS(.v17), .macOS(.v14)],
products: [
.library(name: "GutenbergKit", targets: ["GutenbergKit"])
.library(name: "GutenbergKit", targets: ["GutenbergKit"]),
.library(name: "GutenbergKitResources", targets: ["GutenbergKitResources"]),
],
dependencies: [
.package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.7.5"),
Expand All @@ -16,11 +43,12 @@ let package = Package(
targets: [
.target(
name: "GutenbergKit",
dependencies: ["SwiftSoup", "SVGView"],
dependencies: ["SwiftSoup", "SVGView", "GutenbergKitResources"],
path: "ios/Sources/GutenbergKit",
exclude: [],
resources: [.copy("Gutenberg")]
exclude: ["Gutenberg"],
packageAccess: false
),
gutenbergKitResources,
.testTarget(
name: "GutenbergKitTests",
dependencies: ["GutenbergKit"],
Expand Down
152 changes: 152 additions & 0 deletions build_xcframework.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#!/usr/bin/env bash

# Builds a GutenbergKitResources XCFramework from the local source target.
#
# Prerequisites:
# - Built web assets in ios/Sources/GutenbergKitResources/Resources/
# - GUTENBERGKIT_SWIFT_USE_LOCAL_RESOURCES=1 must be set
#
# Output:
# - GutenbergKitResources-<git-sha>.xcframework.zip
# - GutenbergKitResources-<git-sha>.xcframework.zip.checksum.txt
#
# Adapted from:
# https://github.com/OpenSwiftUIProject/ProtobufKit/blob/937eae542/Scripts/build_xcframework.sh
# https://docs.emergetools.com/docs/analyzing-a-spm-framework-ios

set -euo pipefail

SCHEME="GutenbergKitResources"
BUILD_DIR="$(pwd)/build"
OUTPUT_DIR="${1:-$(pwd)}"
DERIVED_DATA_PATH="${BUILD_DIR}/DerivedData"

GIT_SHA="$(git rev-parse --short HEAD)"
XCFRAMEWORK_NAME="${SCHEME}-${GIT_SHA}.xcframework"
ZIP_NAME="${XCFRAMEWORK_NAME}.zip"

build_framework() {
local sdk="$1"
local destination="$2"
local archive_path="${BUILD_DIR}/${SCHEME}-${sdk}.xcarchive"

echo "--- Building ${SCHEME} for ${sdk}"

rm -rf "${archive_path}"

xcodebuild archive \
-scheme "${SCHEME}" \
-archivePath "${archive_path}" \
-derivedDataPath "${DERIVED_DATA_PATH}" \
-sdk "${sdk}" \
-destination "${destination}" \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
INSTALL_PATH='Library/Frameworks' \
OTHER_SWIFT_FLAGS=-no-verify-emitted-module-interface \
CODE_SIGN_IDENTITY="-" \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NO \
| xcbeautify

# SPM archives don't produce a .framework — assemble it from DerivedData
local intermediates="${DERIVED_DATA_PATH}/Build/Intermediates.noindex/ArchiveIntermediates/${SCHEME}"
local build_products="${intermediates}/BuildProductsPath/Release-${sdk}"
local generated_maps="${intermediates}/IntermediateBuildFilesPath/GeneratedModuleMaps-${sdk}"

local framework_path="${BUILD_DIR}/frameworks/${sdk}/${SCHEME}.framework"
rm -rf "${framework_path}"
mkdir -p "${framework_path}/Modules"
mkdir -p "${framework_path}/Headers"

# Binary (SPM produces a .o object file — rename to framework name)
cp "${build_products}/${SCHEME}.o" "${framework_path}/${SCHEME}"

# Swift module
cp -r "${build_products}/${SCHEME}.swiftmodule" "${framework_path}/Modules/${SCHEME}.swiftmodule"
rm -f "${framework_path}/Modules/${SCHEME}.swiftmodule"/*.package.swiftinterface
rm -f "${framework_path}/Modules/${SCHEME}.swiftmodule"/*.private.swiftinterface

# Module map and generated header
cp "${generated_maps}/${SCHEME}.modulemap" "${framework_path}/Modules/module.modulemap"
cp "${generated_maps}/${SCHEME}-Swift.h" "${framework_path}/Headers/${SCHEME}-Swift.h"

# Minimal Info.plist
cat > "${framework_path}/Info.plist" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>org.wordpress.GutenbergKitResources</string>
<key>CFBundleName</key>
<string>${SCHEME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
</dict>
</plist>
PLIST
}

copy_resource_bundles() {
local sdk="$1"
local framework_path="${BUILD_DIR}/frameworks/${sdk}/${SCHEME}.framework"
local bundle_path="${DERIVED_DATA_PATH}/Build/Intermediates.noindex/ArchiveIntermediates/${SCHEME}/IntermediateBuildFilesPath/UninstalledProducts/${sdk}"

echo "--- Copying resource bundles for ${sdk}"

if [ -d "${bundle_path}" ]; then
find "${bundle_path}" -name "*.bundle" -maxdepth 1 -type d -print0 | while IFS= read -r -d '' bundle; do
bundle_name=$(basename "${bundle}")
echo " ${bundle_name} -> ${framework_path}/"
rm -rf "${framework_path:?}/${bundle_name}"
cp -R "${bundle}" "${framework_path}/"
done
else
echo " Warning: bundle path not found: ${bundle_path}"
fi
}

# Build for both platforms
build_framework "iphoneos" "generic/platform=iOS"
copy_resource_bundles "iphoneos"

build_framework "iphonesimulator" "generic/platform=iOS Simulator"
copy_resource_bundles "iphonesimulator"

# Create XCFramework
echo "--- Creating XCFramework"

DEVICE_FRAMEWORK="${BUILD_DIR}/frameworks/iphoneos/${SCHEME}.framework"
SIM_FRAMEWORK="${BUILD_DIR}/frameworks/iphonesimulator/${SCHEME}.framework"
XCFRAMEWORK_PATH="${BUILD_DIR}/${XCFRAMEWORK_NAME}"

rm -rf "${XCFRAMEWORK_PATH}"
xcodebuild -create-xcframework \
-framework "${DEVICE_FRAMEWORK}" \
-framework "${SIM_FRAMEWORK}" \
-output "${XCFRAMEWORK_PATH}"

# Copy dSYMs into xcframework slices
DEVICE_DSYMS="${BUILD_DIR}/${SCHEME}-iphoneos.xcarchive/dSYMs"
SIM_DSYMS="${BUILD_DIR}/${SCHEME}-iphonesimulator.xcarchive/dSYMs"

if [ -d "${DEVICE_DSYMS}" ]; then
cp -r "${DEVICE_DSYMS}" "${XCFRAMEWORK_PATH}/ios-arm64/"
fi
if [ -d "${SIM_DSYMS}" ]; then
cp -r "${SIM_DSYMS}" "${XCFRAMEWORK_PATH}/ios-arm64_x86_64-simulator/"
fi

# Create ZIP archive
echo "--- Creating ZIP archive"
(cd "${BUILD_DIR}" && zip -r "${ZIP_NAME}" "$(basename "${XCFRAMEWORK_PATH}")" > /dev/null)
cp "${BUILD_DIR}/${ZIP_NAME}" "${OUTPUT_DIR}/${ZIP_NAME}"

# Compute checksum
echo "--- Computing checksum"
CHECKSUM=$(swift package compute-checksum "${OUTPUT_DIR}/${ZIP_NAME}")
echo "${CHECKSUM}" > "${OUTPUT_DIR}/${ZIP_NAME}.checksum.txt"

echo ""
echo "XCFramework: ${OUTPUT_DIR}/${ZIP_NAME}"
echo "Checksum: ${CHECKSUM}"
Loading
Loading