Compare commits
2 Commits
maplibre-p
...
release/pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f5edd74a1 | ||
|
|
aca1364241 |
@@ -6,7 +6,7 @@ const marker = "// MapLibreParticleRNTestHost NavSea Particle release SDK";
|
||||
module.exports = function withParticleNativeAndroid(config) {
|
||||
return withProjectBuildGradle(config, (project) => {
|
||||
if (project.modResults.contents.includes(marker)) return project;
|
||||
project.modResults.contents += `\n${marker}\ngradle.projectsEvaluated {\n allprojects { p ->\n p.repositories.maven { repository -> repository.url = p.uri("https://pbf.jpcn.ccwu.cc/maven") }\n p.configurations.configureEach { configuration ->\n configuration.resolutionStrategy.dependencySubstitution {\n substitute module("org.maplibre.gl:android-sdk-opengl") using module("cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.7")\n }\n }\n }\n}\nrootProject.ext.set("org.maplibre.reactnative.nativeVersion", "13.4.1")\nrootProject.ext.set("org.maplibre.reactnative.nativeVariant", "opengl")\n`;
|
||||
project.modResults.contents += `\n${marker}\ngradle.projectsEvaluated {\n allprojects { p ->\n p.repositories.maven { repository -> repository.url = p.uri("https://pbf.jpcn.ccwu.cc/maven") }\n p.configurations.configureEach { configuration ->\n configuration.resolutionStrategy.dependencySubstitution {\n substitute module("org.maplibre.gl:android-sdk-opengl") using module("cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.6")\n }\n }\n }\n}\nrootProject.ext.set("org.maplibre.reactnative.nativeVersion", "13.4.1")\nrootProject.ext.set("org.maplibre.reactnative.nativeVariant", "opengl")\n`;
|
||||
return project;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 13.4.1-particle.7(Android / iOS 统一发行)
|
||||
## 13.4.1-particle.6(iOS RN / Metal 接入发行)
|
||||
|
||||
- Mac unified release pipeline 统一生成 Android Native、RN package 与 iOS SwiftPM/XCFramework;共享 Particle revision 7。
|
||||
## 13.4.1-particle.6(历史 iOS 过渡发行)
|
||||
|
||||
- 已公开的 RN `.6` 与 iOS Metal `.6` 用于 iOS 接入验证;RN `.6` 仍显式依赖 Android Native `.5`,因此 `.6` 不是 Android/iOS 统一发行版,且不得覆盖重发。
|
||||
- 新增 iOS `WeatherRuntimeBridge` RN 0.85 codegen TurboModule,实现既有 V3/V4 与视觉控制 ABI;每个命令从当前 Fabric/UIManager view registry 重新解析 MLRN MapView,不缓存 map/runtime 指针。
|
||||
- 新增 iOS pod/autolinking/codegen provider。pod 复用 `MapLibreReactNative` 的唯一 MapLibre product,不嵌入第二份 framework。
|
||||
- iOS Podfile 的 post-install 现在必须同时调用 `$MLRN.post_install(installer)` 和 `$MLRN_PARTICLE.post_install(installer)`;两者消费同一 `$MLRN_SPM_SPEC`,以让 MLRN、App 与 Particle pod target 共享一个 MapLibre package/product。
|
||||
- Android Native 与 RN package 同步发布为 `13.4.1-particle.6`;Android 继续使用已验证的 OpenGL Renderer 代码路径,本次通过新坐标重新构建并发布,不复用 `.5` 坐标。
|
||||
- iOS binary distribution 同步使用 `6.28.0-particle.6`,固定为 Metal renderer,并与 RN `.6` 作为同一 release train。
|
||||
|
||||
## 13.4.1-particle.5(当前 Android QBIN V4 Renderer 基线)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# @navsea/maplibre-particle-rn
|
||||
|
||||
当前版本:`13.4.1-particle.7`。Android Native 必须配套 `cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.7`。本包是 React Native 的薄控制面,不负责 Map 组件、provider、HTTP、manifest、下载、缓存或 NavSea 业务策略。
|
||||
当前版本:`13.4.1-particle.6`。本版本作为 Android+iOS 统一接入发行版:Android Native 配套 `cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.6`,iOS 使用 `6.28.0-particle.6` 的 Metal SwiftPM binary distribution。本包是 React Native 的薄控制面,不负责 Map 组件、provider、HTTP、manifest、下载、缓存或 NavSea 业务策略。
|
||||
|
||||
## 当前推荐主链:QBIN V4
|
||||
|
||||
@@ -37,7 +37,7 @@ Podfile 的 `post_install do |installer|` 必须同时调用 `$MLRN.post_install
|
||||
RN tgz:
|
||||
|
||||
```text
|
||||
https://pbf.jpcn.ccwu.cc/npm/navsea-maplibre-particle-rn-13.4.1-particle.7.tgz
|
||||
https://pbf.jpcn.ccwu.cc/npm/navsea-maplibre-particle-rn-13.4.1-particle.6.tgz
|
||||
```
|
||||
|
||||
Native Maven repository:
|
||||
@@ -49,7 +49,7 @@ https://pbf.jpcn.ccwu.cc/maven
|
||||
Native coordinate:
|
||||
|
||||
```text
|
||||
cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.7
|
||||
cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.6
|
||||
```
|
||||
|
||||
Expo plugin 与 `android/build.gradle` 必须指向同一 `.7`。正常 Consumer 不复制 AAR、不依赖 MapLibreParticleLab 源码路径,也不以 Maven Local 作为公网验证主路径。完整 Linux 发布与 Win11 验证流程见 `docs/50_Step记录/STEP-080_Android_AAR与RNTestHost标准构建流水线_v2.md`。
|
||||
Expo plugin 与 `android/build.gradle` 必须指向同一 Android Native `.6`。正常 Consumer 不复制 AAR、不依赖 MapLibreParticleLab 源码路径,也不以 Maven Local 作为公网验证主路径。完整 Linux 发布与 Win11 验证流程见 `docs/50_Step记录/STEP-080_Android_AAR与RNTestHost标准构建流水线_v2.md`。
|
||||
|
||||
@@ -14,7 +14,7 @@ android {
|
||||
dependencies {
|
||||
implementation "com.facebook.react:react-android"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.20"
|
||||
implementation "cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.7"
|
||||
implementation "cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.6"
|
||||
compileOnly project(":maplibre_maplibre-react-native")
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const iosTag = "navsea-maplibre-particle-rn-maplibre-spm";
|
||||
module.exports = function withNavSeaMapLibreParticle(config) {
|
||||
config = withProjectBuildGradle(config, (project) => {
|
||||
if (project.modResults.contents.includes(androidMarker)) return project;
|
||||
project.modResults.contents += `\n${androidMarker}\ngradle.projectsEvaluated {\n allprojects { p ->\n p.repositories.maven { repository -> repository.url = p.uri("https://pbf.jpcn.ccwu.cc/maven") }\n p.configurations.configureEach { configuration ->\n configuration.resolutionStrategy.dependencySubstitution {\n substitute module("org.maplibre.gl:android-sdk-opengl") using module("cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.7")\n }\n }\n }\n}\nrootProject.ext.set("org.maplibre.reactnative.nativeVersion", "13.4.1")\nrootProject.ext.set("org.maplibre.reactnative.nativeVariant", "opengl")\n`;
|
||||
project.modResults.contents += `\n${androidMarker}\ngradle.projectsEvaluated {\n allprojects { p ->\n p.repositories.maven { repository -> repository.url = p.uri("https://pbf.jpcn.ccwu.cc/maven") }\n p.configurations.configureEach { configuration ->\n configuration.resolutionStrategy.dependencySubstitution {\n substitute module("org.maplibre.gl:android-sdk-opengl") using module("cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.6")\n }\n }\n }\n}\nrootProject.ext.set("org.maplibre.reactnative.nativeVersion", "13.4.1")\nrootProject.ext.set("org.maplibre.reactnative.nativeVariant", "opengl")\n`;
|
||||
return project;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navsea/maplibre-particle-rn",
|
||||
"version": "13.4.1-particle.7",
|
||||
"version": "13.4.1-particle.6",
|
||||
"description": "NavSea MapLibre Particle React Native pure Field Renderer API.",
|
||||
"license": "BSD-2-Clause",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1 +1 @@
|
||||
13.4.1-particle.7
|
||||
13.4.1-particle.6
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Replace every <...> placeholder only after a reproducible XCFramework zip exists.
|
||||
// The module/product name must remain MapLibre for MLRN compatibility.
|
||||
// swift-tools-version: 5.7
|
||||
import PackageDescription
|
||||
|
||||
@@ -9,8 +11,8 @@ let package = Package(
|
||||
targets: [
|
||||
.binaryTarget(
|
||||
name: "MapLibre",
|
||||
url: "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.7/MapLibre.dynamic.xcframework.zip",
|
||||
checksum: "08cf09d1152e249b4a459bf30e765a0816acfd90390855b3f092077ff171ec11"
|
||||
url: "<https://example.invalid/maplibre/MapLibre.dynamic.xcframework.zip>",
|
||||
checksum: "<SHA256_OF_REAL_ZIP>"
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
# MapLibre Particle iOS 发行
|
||||
# MapLibre Particle iOS Binary Distribution 基线
|
||||
|
||||
当前正式发行:6.28.0-particle.7
|
||||
本目录只保存后续独立 distribution repository 所需的可审计模板;不发布二进制、不创建远端仓库,也不改变 MapLibre iOS 上游版本号。
|
||||
|
||||
- Renderer:Metal
|
||||
- Product / Module:MapLibre
|
||||
- Binary:https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.7/MapLibre.dynamic.xcframework.zip
|
||||
- SHA-256:08cf09d1152e249b4a459bf30e765a0816acfd90390855b3f092077ff171ec11
|
||||
- SwiftPM:https://pbf.jpcn.ccwu.cc/swift/maplibre-particle-spm.git
|
||||
- Exact Version:6.28.0-particle.7
|
||||
- Source Commit:de935818d94b027c3c18427238a284fdc9ee7271
|
||||
模块和 product 始终为 `MapLibre`。MLRN 11.3.6 与后续 Particle Bridge 必须通过同一份自定义 MapLibre binary 消费,不能再链接第二个同功能但不同模块名的 framework。
|
||||
|
||||
构建命令固定为:
|
||||
Particle iOS 发行固定使用 Metal renderer。必须在 macOS 对目标 commit 执行:
|
||||
|
||||
```sh
|
||||
bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic
|
||||
```
|
||||
|
||||
不得用默认 OpenGL XCFramework 覆盖同版本。新版本必须使用新的 Particle revision。
|
||||
裸命令 `bazel build //platform/ios:MapLibre.dynamic` 会采用默认 OpenGL renderer;即使成功生成 XCFramework,也不得作为 Particle iOS 发行基线。发行前还应核验 device binary 含 `MLNMapView`、Metal/`MTLDevice` 与 `ParticleGPU` 标记,且无 OpenGL marker。
|
||||
|
||||
发布时:
|
||||
|
||||
1. 在 macOS 上从对应 Git commit 成功生成 `MapLibre.dynamic.xcframework`;
|
||||
2. 压缩为 `MapLibre.dynamic.xcframework.zip`,对 zip 计算 SHA-256;
|
||||
3. 用真实 URL、checksum、commit 和构建记录填充 `release-manifest.json`;
|
||||
4. 将相同 URL/checksum 代入 `Package.swift.template`,再在独立 distribution repository 发布。
|
||||
|
||||
外部 binary distribution 版本独立于 `platform/ios/VERSION`;当前统一发行坐标为 `6.28.0-particle.6`,与 RN/Android 的 `13.4.1-particle.6` 共用 Particle release revision `.6`。Metal XCFramework 已在 Pleiades iPad mini 5 RN Test Host signed Release 路径验证;正式发行必须使用远端 HTTPS binary URL 和 SwiftPM checksum。
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"status": "PUBLISHED_PUBLIC_READBACK_PASS",
|
||||
"distributionVersion": "6.28.0-particle.7",
|
||||
"schemaVersion": 1,
|
||||
"status": "VALIDATED",
|
||||
"distributionVersion": "6.28.0-particle.1",
|
||||
"moduleName": "MapLibre",
|
||||
"artifact": {
|
||||
"fileName": "MapLibre.dynamic.xcframework.zip",
|
||||
"sizeBytes": 24941382,
|
||||
"sha256": "08cf09d1152e249b4a459bf30e765a0816acfd90390855b3f092077ff171ec11",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.7/MapLibre.dynamic.xcframework.zip"
|
||||
"url": "LOCAL_BUILD",
|
||||
"sizeBytes": 24943196,
|
||||
"sha256": "ae88975fc20f4d9961b95079638d0e9c0d8e61d4394d5c0a8ffcc48d173a827f"
|
||||
},
|
||||
"sourceCommit": "de935818d94b027c3c18427238a284fdc9ee7271",
|
||||
"swiftPackage": {
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle-spm.git",
|
||||
"requirement": "exactVersion",
|
||||
"version": "6.28.0-particle.7",
|
||||
"productName": "MapLibre"
|
||||
},
|
||||
"notes": "Metal renderer release built with bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic"
|
||||
"sourceCommit": "bdd7f40f9029031816c9bf4db6e1cd6c7c69b7bd",
|
||||
"notes": "Metal renderer artifact built with bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic. Validated by the Pleiades iPad mini 5 RN Test Host signed Release path; user confirmed particle rendering recovered. The artifact has not been published; no remote URL is available."
|
||||
}
|
||||
|
||||
@@ -1,51 +1,132 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"releaseState": "PUBLISHED_PUBLIC_READBACK_PASS",
|
||||
"particleRevision": 7,
|
||||
"sourceCommit": "de935818d94b027c3c18427238a284fdc9ee7271",
|
||||
"generatedAtUtc": "2026-09-19T01:30:21.118772+00:00",
|
||||
"reactNative": {
|
||||
"release": "13.4.1-particle.3",
|
||||
"releaseState": "android_device_acceptance_pass",
|
||||
"upstreamMapLibreNative": "13.4.1",
|
||||
"upstreamCoreCommit": "18545ca10d296704b2cba675b182ff2c8da24588",
|
||||
"extensionLine": "particle",
|
||||
"extensionRevision": 3,
|
||||
"platform": {
|
||||
"android": {
|
||||
"renderer": "opengl"
|
||||
}
|
||||
},
|
||||
"reactNativePackage": {
|
||||
"name": "@navsea/maplibre-particle-rn",
|
||||
"version": "13.4.1-particle.7",
|
||||
"artifact": {
|
||||
"fileName": "navsea-maplibre-particle-rn-13.4.1-particle.7.tgz",
|
||||
"sizeBytes": 23018,
|
||||
"sha256": "12a6c8ca8d4933040b1311d25693c047f998f6c8a01b05cfdecf3f06099d3722",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/npm/navsea-maplibre-particle-rn-13.4.1-particle.7.tgz"
|
||||
},
|
||||
"version": "13.4.1-particle.3",
|
||||
"mapLibreReactNative": "11.3.6"
|
||||
},
|
||||
"android": {
|
||||
"version": "13.4.1-particle.7",
|
||||
"coordinate": "cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.7",
|
||||
"renderer": "opengl",
|
||||
"artifact": {
|
||||
"fileName": "android-sdk-particle-opengl-13.4.1-particle.7.aar",
|
||||
"sizeBytes": 167980881,
|
||||
"sha256": "e5ce55067e961107900b27b42f5f95fcd68dd6a42f9cd68a1374bd63028f7bde",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/maven/cc/navsea/maplibre/android-sdk-particle-opengl/13.4.1-particle.7/android-sdk-particle-opengl-13.4.1-particle.7.aar"
|
||||
},
|
||||
"ndk": "28.2.13676358",
|
||||
"gradle": "9.5.1",
|
||||
"jdk": "openjdk version \"17.0.20.1\" 2026-08-18"
|
||||
"nativeArtifact": {
|
||||
"group": "cc.navsea.maplibre",
|
||||
"artifact": "android-sdk-particle-opengl",
|
||||
"version": "13.4.1-particle.2",
|
||||
"state": "published_validated"
|
||||
},
|
||||
"ios": {
|
||||
"distributionVersion": "6.28.0-particle.7",
|
||||
"renderer": "metal",
|
||||
"moduleName": "MapLibre",
|
||||
"artifact": {
|
||||
"fileName": "MapLibre.dynamic.xcframework.zip",
|
||||
"sizeBytes": 24941382,
|
||||
"sha256": "08cf09d1152e249b4a459bf30e765a0816acfd90390855b3f092077ff171ec11",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.7/MapLibre.dynamic.xcframework.zip"
|
||||
"releaseRelationship": "13.4.1-particle.3 的 v2 multi-plane RN/TS API 目标为新的 Native artifact 13.4.1-particle.2;不得复用、覆盖或宣称发布旧 13.4.1-particle.1。",
|
||||
"canonicalField": {
|
||||
"schema": "maplibre-particle-field/v2",
|
||||
"transport": "metadataJson + validity local ref + optional scalar/vector local refs",
|
||||
"encoding": "float32-le",
|
||||
"layout": "plane-specific; vector is interleaved-uv"
|
||||
},
|
||||
"validation": {
|
||||
"android": {
|
||||
"status": "pass",
|
||||
"required": [
|
||||
"Native .2 Release OpenGL AAR build and Maven Local publish",
|
||||
"AAR SHA consistency check",
|
||||
"javap WeatherRuntime v2 API check",
|
||||
"Test Host clean prebuild/build/install/start",
|
||||
"five field datasets and Runtime READY acceptance"
|
||||
],
|
||||
"validatedBuildEnvironment": {
|
||||
"gradle": "8.14.3",
|
||||
"agp": "8.12.0",
|
||||
"kotlin": "2.1.20",
|
||||
"jdk": "17.0.18",
|
||||
"ndk": "27.1.12297006",
|
||||
"compileSdk": 36,
|
||||
"targetSdk": 36,
|
||||
"minSdk": 24
|
||||
},
|
||||
"buildResult": {
|
||||
"status": "pass",
|
||||
"task": ":app:assembleDebug",
|
||||
"duration": "6m20s",
|
||||
"apkSha256": "49824062CAB72771282294114B5A818D2067F9B786B8697D2D2A983BF0B743E2",
|
||||
"apkSizeBytes": 185729464
|
||||
},
|
||||
"deviceAcceptance": {
|
||||
"status": "pass",
|
||||
"validatedAt": "2026-09-11",
|
||||
"device": "192.168.1.146",
|
||||
"package": "org.maplibre.particle.rntesthost",
|
||||
"datasets": [
|
||||
"wind-real",
|
||||
"rain-decoder-fixture",
|
||||
"wave-real",
|
||||
"tide-real",
|
||||
"wave-synthetic-independence"
|
||||
],
|
||||
"runtimeGate": {
|
||||
"T0": "ACCEPTED_PENDING_INITIAL_WINDOW",
|
||||
"T1": "INITIAL_WINDOW_READY",
|
||||
"final": "READY"
|
||||
},
|
||||
"controls": [
|
||||
"PLAY/PAUSE",
|
||||
"HALF/NORMAL/DOUBLE",
|
||||
"FPS AUTO/30/60",
|
||||
"seek T0/T1",
|
||||
"Field/Particle visibility",
|
||||
"Field stops",
|
||||
"Particle color",
|
||||
"Trail color",
|
||||
"Apply visual"
|
||||
],
|
||||
"fatalScan": "pass"
|
||||
}
|
||||
},
|
||||
"swiftPackage": {
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle-spm.git",
|
||||
"requirement": "exactVersion",
|
||||
"version": "6.28.0-particle.7",
|
||||
"productName": "MapLibre"
|
||||
"previousBaseline": {
|
||||
"reactNativePackage": "13.4.1-particle.2",
|
||||
"nativeArtifact": "13.4.1-particle.1",
|
||||
"status": "pass",
|
||||
"validatedAt": "2026-09-10",
|
||||
"consumer": "integration/react-native/MapLibreParticlePackageConsumerTestHost",
|
||||
"dataset": "ECMWF HRES 20260807 T0-T3",
|
||||
"transport": "FILE_REF / FLOAT32_LE / INTERLEAVED_UV",
|
||||
"checks": [
|
||||
"FieldRuntime attach",
|
||||
"T0-T3 ordered submit",
|
||||
"runtime READY",
|
||||
"field and particle independent visibility",
|
||||
"no fatal native bridge errors"
|
||||
],
|
||||
"releaseTag": "maplibre-particle/rn/13.4.1-particle.2",
|
||||
"releaseSourceCommit": "e43b58707cfd0f87965424477ed3f95625b3f724",
|
||||
"npmTarball": "https://pbf.jpcn.ccwu.cc/npm/navsea-maplibre-particle-rn-13.4.1-particle.2.tgz",
|
||||
"npmTarballSha256": "ace9e0401824839d18a93cc4201c1f5d4cccbff0636570cfde82fd80b60779b5",
|
||||
"npmTarballSizeBytes": 10660,
|
||||
"publicHttpStatus": 200,
|
||||
"publicBytesVerified": true
|
||||
}
|
||||
},
|
||||
"publication": {
|
||||
"nativeArtifact": {
|
||||
"status": "published",
|
||||
"aarSha256": "f890f834692d3cacb8a281b2d0f82cf4a7f8ba7756132092be800505b961e9a2",
|
||||
"aarSizeBytes": 166519805,
|
||||
"publishedAt": "2026-09-11",
|
||||
"publicHttpStatus": 200,
|
||||
"publicBytesVerified": true
|
||||
},
|
||||
"xcode": "Xcode 26.3 Build version 17C529 ",
|
||||
"bazel": "bazel 8.6.0"
|
||||
"releaseTag": null,
|
||||
"reactNativePackage": {
|
||||
"status": "published",
|
||||
"tarball": "https://pbf.jpcn.ccwu.cc/npm/navsea-maplibre-particle-rn-13.4.1-particle.3.tgz",
|
||||
"sha256": "16e5dab86aac9832f7a48d8c35dd9821f80f52e7e53ff4e0e6c98724781eda3a",
|
||||
"sizeBytes": 12849,
|
||||
"publicHttpStatus": 200,
|
||||
"publicBytesVerified": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
# MapLibre Particle 统一发行流水线
|
||||
|
||||
本目录用于在 Mac release builder 上统一生成并发布 Android Native、React Native package 和 iOS Metal XCFramework。
|
||||
|
||||
## 唯一输入
|
||||
|
||||
只输入 Particle revision,例如:
|
||||
|
||||
tools/particle_release_pipeline/release.sh 7
|
||||
|
||||
版本自动推导:
|
||||
|
||||
- Android Native / RN:13.4.1-particle.7
|
||||
- iOS SwiftPM:6.28.0-particle.7
|
||||
|
||||
以后升级到 .8 时只输入 8,不再手工维护多个平台版本号。
|
||||
|
||||
## 固定构建环境
|
||||
|
||||
- macOS release builder
|
||||
- JDK 17
|
||||
- Gradle Wrapper 9.5.1
|
||||
- Android SDK 36
|
||||
- Android NDK 28.2.13676358
|
||||
- CMake 3.31.6
|
||||
- Android renderer:OpenGL
|
||||
- iOS renderer:Metal
|
||||
- iOS binary build:bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic
|
||||
|
||||
## 发布目标
|
||||
|
||||
- Android Maven:https://pbf.jpcn.ccwu.cc/maven
|
||||
- RN tgz:https://pbf.jpcn.ccwu.cc/npm
|
||||
- iOS binary:https://pbf.jpcn.ccwu.cc/swift/maplibre-particle
|
||||
- SwiftPM Git:https://pbf.jpcn.ccwu.cc/swift/maplibre-particle-spm.git
|
||||
|
||||
## 不可变规则
|
||||
|
||||
同一个版本号禁止覆盖。任一公网目标已经存在时,prepare/publish 阶段直接失败;必须增加 Particle revision。
|
||||
|
||||
流水线从同一个版本冻结 Git commit 构建 Android 与 iOS。发布后必须从公网重新下载 artifact,并与本地产物逐字节比较;只有 public readback 通过才生成最终 release manifest 和 tag。
|
||||
|
||||
## 阶段
|
||||
|
||||
可单独执行:
|
||||
|
||||
release.sh 7 prepare
|
||||
release.sh 7 build
|
||||
release.sh 7 publish
|
||||
release.sh 7 finalize
|
||||
|
||||
完整执行:
|
||||
|
||||
release.sh 7
|
||||
|
||||
prepare 会产生版本冻结 commit;finalize 会产生最终 manifest commit、tag,并推送 particle/main。发布工作必须在干净 release worktree 中运行。
|
||||
|
||||
## .6 历史说明
|
||||
|
||||
13.4.1-particle.6 是 iOS 接入过渡发行。公开 RN .6 仍依赖 Android Native .5,因此不得把 .6 重新定义或覆盖成统一双平台发行。
|
||||
|
||||
第一个由本流水线定义的 Android/iOS 统一发行是 Particle revision 7。
|
||||
@@ -1,178 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
PUBLIC = "https://pbf.jpcn.ccwu.cc"
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
h = hashlib.sha256()
|
||||
with path.open("rb") as handle:
|
||||
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
||||
h.update(chunk)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def base_version(value: str) -> str:
|
||||
return re.sub(r"-particle\.\d+$", "", value.strip())
|
||||
|
||||
|
||||
def artifact(path: Path, url: str) -> dict:
|
||||
return {
|
||||
"fileName": path.name,
|
||||
"sizeBytes": path.stat().st_size,
|
||||
"sha256": sha256(path),
|
||||
"url": url,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if len(sys.argv) != 4:
|
||||
raise SystemExit(
|
||||
"usage: finalize_release.py <revision> <source-commit> <artifact-dir>"
|
||||
)
|
||||
|
||||
revision = int(sys.argv[1])
|
||||
source_commit = sys.argv[2]
|
||||
artifact_dir = Path(sys.argv[3])
|
||||
|
||||
android_base = base_version((ROOT / "platform/android/VERSION").read_text())
|
||||
ios_base = base_version((ROOT / "platform/ios/VERSION").read_text())
|
||||
android_version = f"{android_base}-particle.{revision}"
|
||||
ios_version = f"{ios_base}-particle.{revision}"
|
||||
|
||||
aar_name = f"android-sdk-particle-opengl-{android_version}.aar"
|
||||
tgz_name = f"navsea-maplibre-particle-rn-{android_version}.tgz"
|
||||
ios_name = "MapLibre.dynamic.xcframework.zip"
|
||||
|
||||
aar = artifact(
|
||||
artifact_dir / aar_name,
|
||||
f"{PUBLIC}/maven/cc/navsea/maplibre/android-sdk-particle-opengl/"
|
||||
f"{android_version}/{aar_name}",
|
||||
)
|
||||
tgz = artifact(
|
||||
artifact_dir / tgz_name,
|
||||
f"{PUBLIC}/npm/{tgz_name}",
|
||||
)
|
||||
ios = artifact(
|
||||
artifact_dir / ios_name,
|
||||
f"{PUBLIC}/swift/maplibre-particle/{ios_version}/{ios_name}",
|
||||
)
|
||||
|
||||
manifest = {
|
||||
"schemaVersion": 2,
|
||||
"releaseState": "PUBLISHED_PUBLIC_READBACK_PASS",
|
||||
"particleRevision": revision,
|
||||
"sourceCommit": source_commit,
|
||||
"generatedAtUtc": datetime.now(timezone.utc).isoformat(),
|
||||
"reactNative": {
|
||||
"name": "@navsea/maplibre-particle-rn",
|
||||
"version": android_version,
|
||||
"artifact": tgz,
|
||||
"mapLibreReactNative": "11.3.6",
|
||||
},
|
||||
"android": {
|
||||
"version": android_version,
|
||||
"coordinate": (
|
||||
"cc.navsea.maplibre:android-sdk-particle-opengl:"
|
||||
+ android_version
|
||||
),
|
||||
"renderer": "opengl",
|
||||
"artifact": aar,
|
||||
"ndk": os.environ.get("PARTICLE_NDK_VERSION"),
|
||||
"gradle": os.environ.get("PARTICLE_GRADLE_VERSION"),
|
||||
"jdk": os.environ.get("PARTICLE_JDK_VERSION"),
|
||||
},
|
||||
"ios": {
|
||||
"distributionVersion": ios_version,
|
||||
"renderer": "metal",
|
||||
"moduleName": "MapLibre",
|
||||
"artifact": ios,
|
||||
"swiftPackage": {
|
||||
"url": f"{PUBLIC}/swift/maplibre-particle-spm.git",
|
||||
"requirement": "exactVersion",
|
||||
"version": ios_version,
|
||||
"productName": "MapLibre",
|
||||
},
|
||||
"xcode": os.environ.get("PARTICLE_XCODE_VERSION"),
|
||||
"bazel": os.environ.get("PARTICLE_BAZEL_VERSION"),
|
||||
},
|
||||
}
|
||||
|
||||
(ROOT / "release/maplibre-particle/release-manifest.json").write_text(
|
||||
json.dumps(manifest, ensure_ascii=False, indent=2) + "\n"
|
||||
)
|
||||
|
||||
ios_manifest = {
|
||||
"schemaVersion": 2,
|
||||
"status": "PUBLISHED_PUBLIC_READBACK_PASS",
|
||||
"distributionVersion": ios_version,
|
||||
"moduleName": "MapLibre",
|
||||
"artifact": ios,
|
||||
"sourceCommit": source_commit,
|
||||
"swiftPackage": manifest["ios"]["swiftPackage"],
|
||||
"notes": (
|
||||
"Metal renderer release built with "
|
||||
"bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic"
|
||||
),
|
||||
}
|
||||
(ROOT / "release/maplibre-particle/ios/release-manifest.json").write_text(
|
||||
json.dumps(ios_manifest, ensure_ascii=False, indent=2) + "\n"
|
||||
)
|
||||
|
||||
package_template = f"""// swift-tools-version: 5.7
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "MapLibreDistribution",
|
||||
products: [
|
||||
.library(name: "MapLibre", targets: ["MapLibre"]),
|
||||
],
|
||||
targets: [
|
||||
.binaryTarget(
|
||||
name: "MapLibre",
|
||||
url: "{ios['url']}",
|
||||
checksum: "{ios['sha256']}"
|
||||
),
|
||||
]
|
||||
)
|
||||
"""
|
||||
(ROOT / "release/maplibre-particle/ios/Package.swift.template").write_text(
|
||||
package_template
|
||||
)
|
||||
|
||||
release_readme = f"""# MapLibre Particle iOS 发行
|
||||
|
||||
当前正式发行:{ios_version}
|
||||
|
||||
- Renderer:Metal
|
||||
- Product / Module:MapLibre
|
||||
- Binary:{ios['url']}
|
||||
- SHA-256:{ios['sha256']}
|
||||
- SwiftPM:{PUBLIC}/swift/maplibre-particle-spm.git
|
||||
- Exact Version:{ios_version}
|
||||
- Source Commit:{source_commit}
|
||||
|
||||
构建命令固定为:
|
||||
|
||||
bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic
|
||||
|
||||
不得用默认 OpenGL XCFramework 覆盖同版本。新版本必须使用新的 Particle revision。
|
||||
"""
|
||||
(ROOT / "release/maplibre-particle/ios/README.md").write_text(
|
||||
release_readme
|
||||
)
|
||||
|
||||
print(json.dumps(manifest, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,99 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
ANDROID_VERSION_FILE = ROOT / "platform/android/VERSION"
|
||||
IOS_VERSION_FILE = ROOT / "platform/ios/VERSION"
|
||||
RN_ROOT = ROOT / "packages/maplibre-particle-rn"
|
||||
|
||||
|
||||
def die(message: str) -> None:
|
||||
raise SystemExit(f"PREPARE_RELEASE_ERROR: {message}")
|
||||
|
||||
|
||||
def base_version(value: str) -> str:
|
||||
return re.sub(r"-particle\.\d+$", "", value.strip())
|
||||
|
||||
|
||||
def replace_current_particle(path: Path, base: str, target: str) -> None:
|
||||
text = path.read_text()
|
||||
pattern = rf"{re.escape(base)}-particle\.\d+"
|
||||
updated, count = re.subn(pattern, target, text)
|
||||
if count == 0:
|
||||
die(f"no particle version reference found in {path}")
|
||||
path.write_text(updated)
|
||||
|
||||
def update_changelog(target: str, revision: int) -> None:
|
||||
path = RN_ROOT / "CHANGELOG.md"
|
||||
text = path.read_text()
|
||||
heading = f"## {target}(Android / iOS 统一发行)"
|
||||
if heading in text:
|
||||
return
|
||||
marker = "## Unreleased\n\n"
|
||||
if marker not in text:
|
||||
die("CHANGELOG missing Unreleased heading")
|
||||
entry = (
|
||||
marker
|
||||
+ heading
|
||||
+ "\n\n"
|
||||
+ "- Mac unified release pipeline 统一生成 Android Native、RN package 与 iOS SwiftPM/XCFramework;"
|
||||
+ f"共享 Particle revision {revision}。\n"
|
||||
)
|
||||
path.write_text(text.replace(marker, entry, 1))
|
||||
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if len(sys.argv) != 2 or not sys.argv[1].isdigit():
|
||||
die("usage: prepare_release.py <particle-revision>")
|
||||
revision = int(sys.argv[1])
|
||||
if revision < 1:
|
||||
die("revision must be positive")
|
||||
|
||||
android_base = base_version(ANDROID_VERSION_FILE.read_text())
|
||||
ios_base = base_version(IOS_VERSION_FILE.read_text())
|
||||
android_version = f"{android_base}-particle.{revision}"
|
||||
ios_version = f"{ios_base}-particle.{revision}"
|
||||
|
||||
ANDROID_VERSION_FILE.write_text(android_version + "\n")
|
||||
|
||||
package_path = RN_ROOT / "package.json"
|
||||
package = json.loads(package_path.read_text())
|
||||
package["version"] = android_version
|
||||
package_path.write_text(json.dumps(package, ensure_ascii=False, indent=2) + "\n")
|
||||
|
||||
for relative in (
|
||||
"packages/maplibre-particle-rn/android/build.gradle",
|
||||
"packages/maplibre-particle-rn/app.plugin.js",
|
||||
"integration/react-native/MapLibreParticleRNTestHost/plugins/withParticleNativeAndroid.js",
|
||||
):
|
||||
replace_current_particle(ROOT / relative, android_base, android_version)
|
||||
|
||||
readme = RN_ROOT / "README.md"
|
||||
readme_text = readme.read_text()
|
||||
readme_text = re.sub(
|
||||
rf"{re.escape(android_base)}-particle\.\d+",
|
||||
android_version,
|
||||
readme_text,
|
||||
)
|
||||
readme_text = re.sub(
|
||||
r"必须指向同一 `\.\d+`",
|
||||
f"必须指向同一 `.{revision}`",
|
||||
readme_text,
|
||||
)
|
||||
readme.write_text(readme_text)
|
||||
|
||||
update_changelog(android_version, revision)
|
||||
|
||||
print(f"PARTICLE_REVISION={revision}")
|
||||
print(f"ANDROID_RN_VERSION={android_version}")
|
||||
print(f"IOS_DISTRIBUTION_VERSION={ios_version}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
PUBLIC_ROOT = "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle"
|
||||
GIT_REMOTE = "nas:/volume1/work/pbf/swift/maplibre-particle-spm.git"
|
||||
WORK = Path.home() / "dev/MapLibreParticleDistribution"
|
||||
|
||||
|
||||
def run(*args: str, cwd: Path | None = None) -> str:
|
||||
result = subprocess.run(
|
||||
args,
|
||||
cwd=cwd,
|
||||
check=True,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
return result.stdout
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if len(sys.argv) != 3:
|
||||
raise SystemExit("usage: publish_swiftpm.py <ios-version> <zip-sha256>")
|
||||
version, checksum = sys.argv[1], sys.argv[2]
|
||||
if not WORK.exists():
|
||||
run("git", "clone", GIT_REMOTE, str(WORK))
|
||||
|
||||
run("git", "fetch", "origin", cwd=WORK)
|
||||
run("git", "checkout", "main", cwd=WORK)
|
||||
run("git", "pull", "--ff-only", "origin", "main", cwd=WORK)
|
||||
|
||||
tag_check = subprocess.run(
|
||||
["git", "ls-remote", "--tags", "origin", f"refs/tags/{version}"],
|
||||
cwd=WORK,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
check=True,
|
||||
).stdout.strip()
|
||||
if tag_check:
|
||||
raise SystemExit(f"SwiftPM tag already exists: {version}")
|
||||
|
||||
url = f"{PUBLIC_ROOT}/{version}/MapLibre.dynamic.xcframework.zip"
|
||||
package = f'''// swift-tools-version: 5.7
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "MapLibreDistribution",
|
||||
products: [
|
||||
.library(name: "MapLibre", targets: ["MapLibre"]),
|
||||
],
|
||||
targets: [
|
||||
.binaryTarget(
|
||||
name: "MapLibre",
|
||||
url: "{url}",
|
||||
checksum: "{checksum}"
|
||||
),
|
||||
]
|
||||
)
|
||||
'''
|
||||
|
||||
(WORK / "Package.swift").write_text(package)
|
||||
(WORK / "README.md").write_text(
|
||||
"# MapLibre Particle SwiftPM Distribution\n\n"
|
||||
"该仓库只保存 NavSea MapLibre Particle iOS binary distribution 的 SwiftPM manifest。\n"
|
||||
"产品和模块名固定为 MapLibre,供 MapLibre React Native 11.3.6 消费。\n\n"
|
||||
f"当前版本:{version}。\n"
|
||||
f"对应 binary:{url}\n"
|
||||
)
|
||||
run("git", "add", "Package.swift", "README.md", cwd=WORK)
|
||||
run("git", "commit", "-m", f"release: MapLibre Particle iOS {version}", cwd=WORK)
|
||||
run("git", "tag", "-a", version, "-m", f"MapLibre Particle iOS {version}", cwd=WORK)
|
||||
run("git", "push", "origin", "main", cwd=WORK)
|
||||
run("git", "push", "origin", version, cwd=WORK)
|
||||
run(
|
||||
"ssh", "nas",
|
||||
"git --git-dir=/volume1/work/pbf/swift/maplibre-particle-spm.git "
|
||||
"symbolic-ref HEAD refs/heads/main && "
|
||||
"git --git-dir=/volume1/work/pbf/swift/maplibre-particle-spm.git update-server-info",
|
||||
)
|
||||
print(f"SWIFTPM_PUBLISHED={version}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,230 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT="$(cd -- "$SCRIPT_DIR/../.." && pwd)"
|
||||
REV="${1:-}"
|
||||
PHASE="${2:-all}"
|
||||
|
||||
die() { echo "RELEASE_ERROR: $*" >&2; exit 1; }
|
||||
note() { echo "RELEASE: $*"; }
|
||||
require() { command -v "$1" >/dev/null 2>&1 || die "missing command: $1"; }
|
||||
|
||||
[[ "$REV" =~ ^[0-9]+$ ]] || die "usage: release.sh <particle-revision> [prepare|build|publish|finalize|all]"
|
||||
[[ "$PHASE" =~ ^(prepare|build|publish|finalize|all)$ ]] || die "invalid phase: $PHASE"
|
||||
[[ "$(uname -s)" == "Darwin" ]] || die "unified release builder must run on macOS"
|
||||
|
||||
export JAVA_HOME="${JAVA_HOME:-/usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home}"
|
||||
export ANDROID_HOME="${ANDROID_HOME:-$HOME/Library/Android/sdk}"
|
||||
export ANDROID_SDK_ROOT="$ANDROID_HOME"
|
||||
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/28.2.13676358"
|
||||
export PATH="$JAVA_HOME/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/cmake/3.31.6/bin:$PATH"
|
||||
if [[ -d /usr/local/opt/gnu-sed/libexec/gnubin ]]; then
|
||||
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
|
||||
fi
|
||||
|
||||
for cmd in git python3 node npm java curl ssh shasum bazel xcodebuild ruby tar cmp awk sed; do require "$cmd"; done
|
||||
[[ -d "$ANDROID_NDK_HOME" ]] || die "NDK missing: $ANDROID_NDK_HOME"
|
||||
[[ -x "$ROOT/platform/android/gradlew" ]] || die "Gradle wrapper missing"
|
||||
|
||||
ANDROID_BASE="$(sed -E 's/-particle\.[0-9]+$//' "$ROOT/platform/android/VERSION")"
|
||||
IOS_BASE="$(sed -E 's/-particle\.[0-9]+$//' "$ROOT/platform/ios/VERSION")"
|
||||
ANDROID_VERSION="$ANDROID_BASE-particle.$REV"
|
||||
IOS_VERSION="$IOS_BASE-particle.$REV"
|
||||
RN_ROOT="$ROOT/packages/maplibre-particle-rn"
|
||||
ARTIFACT_DIR="$ROOT/artifacts/maplibre-particle/$ANDROID_VERSION"
|
||||
M2_DIR="$HOME/.m2/repository/cc/navsea/maplibre/android-sdk-particle-opengl/$ANDROID_VERSION"
|
||||
AAR_NAME="android-sdk-particle-opengl-$ANDROID_VERSION.aar"
|
||||
TGZ_NAME="navsea-maplibre-particle-rn-$ANDROID_VERSION.tgz"
|
||||
IOS_ZIP_NAME="MapLibre.dynamic.xcframework.zip"
|
||||
ANDROID_URL="https://pbf.jpcn.ccwu.cc/maven/cc/navsea/maplibre/android-sdk-particle-opengl/$ANDROID_VERSION/$AAR_NAME"
|
||||
RN_URL="https://pbf.jpcn.ccwu.cc/npm/$TGZ_NAME"
|
||||
IOS_URL="https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/$IOS_VERSION/$IOS_ZIP_NAME"
|
||||
SPM_URL="https://pbf.jpcn.ccwu.cc/swift/maplibre-particle-spm.git"
|
||||
|
||||
public_status() { curl -L -s -o /dev/null -w '%{http_code}' "$1"; }
|
||||
require_absent() {
|
||||
local code; code="$(public_status "$1")"
|
||||
[[ "$code" == "404" ]] || die "target already published (HTTP $code): $1"
|
||||
}
|
||||
require_clean() {
|
||||
[[ -z "$(git -C "$ROOT" status --porcelain=v1)" ]] || die "release worktree must be clean"
|
||||
}
|
||||
require_target_versions() {
|
||||
[[ "$(tr -d '\r\n' < "$ROOT/platform/android/VERSION")" == "$ANDROID_VERSION" ]] || die "Android VERSION mismatch"
|
||||
[[ "$(node -p "require(process.argv[1]).version" "$RN_ROOT/package.json")" == "$ANDROID_VERSION" ]] || die "RN version mismatch"
|
||||
grep -Fq "android-sdk-particle-opengl:$ANDROID_VERSION" "$RN_ROOT/android/build.gradle" || die "RN Android coordinate mismatch"
|
||||
grep -Fq "android-sdk-particle-opengl:$ANDROID_VERSION" "$RN_ROOT/app.plugin.js" || die "Expo plugin coordinate mismatch"
|
||||
}
|
||||
|
||||
prepare_release() {
|
||||
require_clean
|
||||
require_absent "$ANDROID_URL"
|
||||
require_absent "$RN_URL"
|
||||
require_absent "$IOS_URL"
|
||||
[[ -z "$(git ls-remote --tags "$SPM_URL" "refs/tags/$IOS_VERSION")" ]] || die "SwiftPM tag already exists: $IOS_VERSION"
|
||||
python3 "$SCRIPT_DIR/prepare_release.py" "$REV"
|
||||
git -C "$ROOT" diff --check
|
||||
require_target_versions
|
||||
git -C "$ROOT" add \
|
||||
platform/android/VERSION \
|
||||
packages/maplibre-particle-rn/package.json \
|
||||
packages/maplibre-particle-rn/android/build.gradle \
|
||||
packages/maplibre-particle-rn/app.plugin.js \
|
||||
packages/maplibre-particle-rn/README.md \
|
||||
packages/maplibre-particle-rn/CHANGELOG.md \
|
||||
integration/react-native/MapLibreParticleRNTestHost/plugins/withParticleNativeAndroid.js
|
||||
if ! git -C "$ROOT" diff --cached --quiet; then
|
||||
git -C "$ROOT" commit -m "release: prepare unified particle.$REV"
|
||||
fi
|
||||
require_clean
|
||||
note "prepared sourceCommit=$(git -C "$ROOT" rev-parse HEAD)"
|
||||
}
|
||||
|
||||
build_release() {
|
||||
require_clean
|
||||
require_target_versions
|
||||
git -C "$ROOT" submodule update --init --recursive
|
||||
rm -rf "$ARTIFACT_DIR"
|
||||
mkdir -p "$ARTIFACT_DIR"
|
||||
printf 'sdk.dir=%s\n' "$ANDROID_HOME" > "$ROOT/platform/android/local.properties"
|
||||
note "building Android OpenGL four-ABI release"
|
||||
(cd "$ROOT/platform/android" && RENDERER=opengl BUILDTYPE=Release make apackage)
|
||||
note "publishing Android artifact to Maven Local"
|
||||
"$ROOT/platform/android/gradlew" -p "$ROOT/platform/android" -Pmaplibre.abis=all \
|
||||
:MapLibreAndroid:publishOpenglreleasePublicationToMavenLocal --console=plain
|
||||
for f in "$AAR_NAME" "android-sdk-particle-opengl-$ANDROID_VERSION.pom" "android-sdk-particle-opengl-$ANDROID_VERSION.module"; do
|
||||
[[ -f "$M2_DIR/$f" ]] || die "missing Maven Local artifact: $M2_DIR/$f"
|
||||
cp "$M2_DIR/$f" "$ARTIFACT_DIR/"
|
||||
done
|
||||
|
||||
note "building iOS Metal XCFramework"
|
||||
(cd "$ROOT" && bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic)
|
||||
IOS_SOURCE="$ROOT/bazel-out/darwin_x86_64-fastbuild/bin/platform/ios/$IOS_ZIP_NAME"
|
||||
[[ -f "$IOS_SOURCE" ]] || die "iOS XCFramework zip missing"
|
||||
cp "$IOS_SOURCE" "$ARTIFACT_DIR/$IOS_ZIP_NAME"
|
||||
|
||||
note "packing RN package"
|
||||
(cd "$RN_ROOT" && npm pack --pack-destination "$ARTIFACT_DIR")
|
||||
[[ -f "$ARTIFACT_DIR/$TGZ_NAME" ]] || die "RN tgz missing"
|
||||
tar -xOf "$ARTIFACT_DIR/$TGZ_NAME" package/package.json | node -e 'let s="";process.stdin.on("data",d=>s+=d);process.stdin.on("end",()=>{let j=JSON.parse(s);if(j.version!==process.argv[1])process.exit(2)})' "$ANDROID_VERSION"
|
||||
tar -xOf "$ARTIFACT_DIR/$TGZ_NAME" package/android/build.gradle | grep -Fq "android-sdk-particle-opengl:$ANDROID_VERSION" || die "packed RN points to wrong Android version"
|
||||
ruby -c "$RN_ROOT/MapLibreParticleRN.podspec" >/dev/null
|
||||
shasum -a 256 "$ARTIFACT_DIR/$AAR_NAME" "$ARTIFACT_DIR/$TGZ_NAME" "$ARTIFACT_DIR/$IOS_ZIP_NAME"
|
||||
note "build complete sourceCommit=$(git -C "$ROOT" rev-parse HEAD)"
|
||||
}
|
||||
|
||||
verify_public_file() {
|
||||
local local_file="$1" url="$2" tmp
|
||||
tmp="$(mktemp)"
|
||||
curl -fL "$url?nocache=$(date +%s)" -o "$tmp"
|
||||
cmp -s "$local_file" "$tmp" || { rm -f "$tmp"; die "public readback mismatch: $url"; }
|
||||
rm -f "$tmp"
|
||||
}
|
||||
|
||||
publish_release() {
|
||||
require_clean
|
||||
require_target_versions
|
||||
[[ -f "$ARTIFACT_DIR/$AAR_NAME" && -f "$ARTIFACT_DIR/$TGZ_NAME" && -f "$ARTIFACT_DIR/$IOS_ZIP_NAME" ]] || die "build artifacts missing"
|
||||
require_absent "$ANDROID_URL"
|
||||
require_absent "$RN_URL"
|
||||
require_absent "$IOS_URL"
|
||||
|
||||
local source_commit
|
||||
local android_root android_final android_tmp
|
||||
local rn_final rn_tmp
|
||||
local ios_root ios_final ios_tmp
|
||||
local aar_sha rn_sha ios_sha
|
||||
local remote_aar_sha remote_rn_sha remote_ios_sha
|
||||
local pom_name module_name
|
||||
|
||||
source_commit="$(git -C "$ROOT" rev-parse HEAD)"
|
||||
android_root="/volume1/work/pbf/maven/cc/navsea/maplibre/android-sdk-particle-opengl"
|
||||
android_final="$android_root/$ANDROID_VERSION"
|
||||
android_tmp="$android_root/.$ANDROID_VERSION.uploading"
|
||||
rn_final="/volume1/work/pbf/npm/$TGZ_NAME"
|
||||
rn_tmp="/volume1/work/pbf/npm/.$TGZ_NAME.uploading"
|
||||
ios_root="/volume1/work/pbf/swift/maplibre-particle"
|
||||
ios_final="$ios_root/$IOS_VERSION"
|
||||
ios_tmp="$ios_root/.$IOS_VERSION.uploading"
|
||||
pom_name="android-sdk-particle-opengl-$ANDROID_VERSION.pom"
|
||||
module_name="android-sdk-particle-opengl-$ANDROID_VERSION.module"
|
||||
|
||||
ssh nas "test ! -e '$android_final'" || die "remote Android version exists"
|
||||
ssh nas "test ! -e '$rn_final'" || die "remote RN tgz exists"
|
||||
ssh nas "test ! -e '$ios_final'" || die "remote iOS version exists"
|
||||
|
||||
aar_sha="$(shasum -a 256 "$ARTIFACT_DIR/$AAR_NAME" | awk '{print $1}')"
|
||||
rn_sha="$(shasum -a 256 "$ARTIFACT_DIR/$TGZ_NAME" | awk '{print $1}')"
|
||||
ios_sha="$(shasum -a 256 "$ARTIFACT_DIR/$IOS_ZIP_NAME" | awk '{print $1}')"
|
||||
printf '%s %s\n' "$ios_sha" "$IOS_ZIP_NAME" > "$ARTIFACT_DIR/$IOS_ZIP_NAME.sha256"
|
||||
|
||||
note "uploading release artifacts through SSH staging paths"
|
||||
ssh nas "rm -rf '$android_tmp' '$ios_tmp' '$rn_tmp'; mkdir -p '$android_tmp' '$ios_tmp'"
|
||||
tar -C "$M2_DIR" -cf - . | ssh nas "tar -C '$android_tmp' -xf -"
|
||||
ssh nas "cat > '$rn_tmp'" < "$ARTIFACT_DIR/$TGZ_NAME"
|
||||
ssh nas "cat > '$ios_tmp/$IOS_ZIP_NAME'" < "$ARTIFACT_DIR/$IOS_ZIP_NAME"
|
||||
ssh nas "cat > '$ios_tmp/$IOS_ZIP_NAME.sha256'" < "$ARTIFACT_DIR/$IOS_ZIP_NAME.sha256"
|
||||
|
||||
remote_aar_sha="$(ssh nas "sha256sum '$android_tmp/$AAR_NAME' | awk '{print \$1}'")"
|
||||
remote_rn_sha="$(ssh nas "sha256sum '$rn_tmp' | awk '{print \$1}'")"
|
||||
remote_ios_sha="$(ssh nas "sha256sum '$ios_tmp/$IOS_ZIP_NAME' | awk '{print \$1}'")"
|
||||
[[ "$remote_aar_sha" == "$aar_sha" ]] || die "NAS Android checksum mismatch"
|
||||
[[ "$remote_rn_sha" == "$rn_sha" ]] || die "NAS RN checksum mismatch"
|
||||
[[ "$remote_ios_sha" == "$ios_sha" ]] || die "NAS iOS checksum mismatch"
|
||||
|
||||
note "atomically promoting NAS staging paths"
|
||||
ssh nas "test ! -e '$android_final' && test ! -e '$rn_final' && test ! -e '$ios_final' && mv '$android_tmp' '$android_final' && mv '$rn_tmp' '$rn_final' && mv '$ios_tmp' '$ios_final'"
|
||||
|
||||
verify_public_file "$ARTIFACT_DIR/$AAR_NAME" "$ANDROID_URL"
|
||||
verify_public_file "$M2_DIR/$pom_name" "https://pbf.jpcn.ccwu.cc/maven/cc/navsea/maplibre/android-sdk-particle-opengl/$ANDROID_VERSION/$pom_name"
|
||||
verify_public_file "$M2_DIR/$module_name" "https://pbf.jpcn.ccwu.cc/maven/cc/navsea/maplibre/android-sdk-particle-opengl/$ANDROID_VERSION/$module_name"
|
||||
verify_public_file "$ARTIFACT_DIR/$TGZ_NAME" "$RN_URL"
|
||||
verify_public_file "$ARTIFACT_DIR/$IOS_ZIP_NAME" "$IOS_URL"
|
||||
verify_public_file "$ARTIFACT_DIR/$IOS_ZIP_NAME.sha256" "$IOS_URL.sha256"
|
||||
|
||||
python3 "$SCRIPT_DIR/publish_swiftpm.py" "$IOS_VERSION" "$ios_sha"
|
||||
git ls-remote "$SPM_URL" "refs/tags/$IOS_VERSION" | grep -q . || die "public SwiftPM tag missing"
|
||||
|
||||
export PARTICLE_NDK_VERSION="28.2.13676358"
|
||||
export PARTICLE_GRADLE_VERSION="$("$ROOT/platform/android/gradlew" -p "$ROOT/platform/android" --version | awk '/^Gradle /{print $2; exit}')"
|
||||
export PARTICLE_JDK_VERSION="$(java -version 2>&1 | head -1)"
|
||||
export PARTICLE_XCODE_VERSION="$(xcodebuild -version | tr '\n' ' ')"
|
||||
export PARTICLE_BAZEL_VERSION="$(bazel --version)"
|
||||
python3 "$SCRIPT_DIR/finalize_release.py" "$REV" "$source_commit" "$ARTIFACT_DIR"
|
||||
git -C "$ROOT" diff --check
|
||||
note "publish and public readback passed"
|
||||
}
|
||||
|
||||
finalize_release() {
|
||||
git -C "$ROOT" add \
|
||||
release/maplibre-particle/release-manifest.json \
|
||||
release/maplibre-particle/ios/release-manifest.json \
|
||||
release/maplibre-particle/ios/Package.swift.template \
|
||||
release/maplibre-particle/ios/README.md
|
||||
if ! git -C "$ROOT" diff --cached --quiet; then git -C "$ROOT" commit -m "release: finalize unified particle.$REV"; fi
|
||||
TAG="maplibre-particle/rn/$ANDROID_VERSION"
|
||||
git -C "$ROOT" fetch origin particle/main
|
||||
git -C "$ROOT" merge-base --is-ancestor origin/particle/main HEAD || die "origin/particle/main is not an ancestor of release HEAD"
|
||||
if [[ -n "$(git -C "$ROOT" tag -l "$TAG")" ]]; then
|
||||
[[ "$(git -C "$ROOT" rev-list -n 1 "$TAG")" == "$(git -C "$ROOT" rev-parse HEAD)" ]] || die "local tag points to a different commit: $TAG"
|
||||
else
|
||||
git -C "$ROOT" tag -a "$TAG" -m "Unified Android/iOS Particle release $ANDROID_VERSION"
|
||||
fi
|
||||
git -C "$ROOT" push origin HEAD:particle/main
|
||||
git -C "$ROOT" push origin "$TAG"
|
||||
note "RELEASE_PASS version=$ANDROID_VERSION ios=$IOS_VERSION tag=$TAG"
|
||||
}
|
||||
|
||||
case "$PHASE" in
|
||||
prepare) prepare_release ;;
|
||||
build) build_release ;;
|
||||
publish) publish_release ;;
|
||||
finalize) finalize_release ;;
|
||||
all)
|
||||
prepare_release
|
||||
build_release
|
||||
publish_release
|
||||
finalize_release
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user