Increase Gradle heap size from 2GB to 8GB, enable parallel builds with 4 workers, and update JVM options for faster CI pipeline execution. This reduces build times by utilizing more available resources in the build container.
311 lines
11 KiB
YAML
311 lines
11 KiB
YAML
name: Frontend CI
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
- master
|
|
- develop
|
|
- dev
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
- master
|
|
workflow_dispatch:
|
|
inputs:
|
|
publish_ota:
|
|
description: 'Publish Android OTA'
|
|
required: false
|
|
default: 'true'
|
|
|
|
env:
|
|
REGISTRY: code.littlelan.cn
|
|
IMAGE_NAME: carrot_bbs/frontend-web
|
|
OTA_PLATFORM: android
|
|
OTA_PUBLISH_URL: https://updates.littlelan.cn/admin/publish
|
|
OTA_MANIFEST_URL: https://updates.littlelan.cn/api/manifest
|
|
|
|
jobs:
|
|
ota-android:
|
|
runs-on: ubuntu-latest
|
|
if: github.event_name != 'pull_request' && (github.event_name != 'workflow_dispatch' || github.event.inputs.publish_ota == 'true')
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '25.6.1'
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Resolve runtime version
|
|
id: runtime
|
|
run: |
|
|
RUNTIME_VERSION="$(node -p "require('./app.json').expo.version")"
|
|
echo "runtime_version=${RUNTIME_VERSION}" >> "$GITHUB_OUTPUT"
|
|
echo "Resolved runtimeVersion: ${RUNTIME_VERSION}"
|
|
|
|
- name: Export Android update bundle
|
|
run: |
|
|
rm -rf dist-android dist-android-update.zip
|
|
npx expo export --platform android --output-dir dist-android
|
|
npx expo config --type public --json > dist-android/expoConfig.json
|
|
|
|
- name: Archive Android update bundle
|
|
run: |
|
|
python - <<'PY'
|
|
import os
|
|
import zipfile
|
|
|
|
with zipfile.ZipFile('dist-android-update.zip', 'w', zipfile.ZIP_DEFLATED) as zf:
|
|
for root, _, files in os.walk('dist-android'):
|
|
for name in files:
|
|
src = os.path.join(root, name)
|
|
arc = os.path.relpath(src, 'dist-android')
|
|
zf.write(src, arc)
|
|
PY
|
|
|
|
- name: Publish OTA
|
|
env:
|
|
OTA_AUTH_TOKEN: ${{ secrets.OTA_AUTH_TOKEN }}
|
|
run: |
|
|
test -n "${OTA_AUTH_TOKEN}" || (echo "Missing secret OTA_AUTH_TOKEN" && exit 1)
|
|
curl -fSs -X POST "${OTA_PUBLISH_URL}?runtimeVersion=${{ steps.runtime.outputs.runtime_version }}&platform=${OTA_PLATFORM}" \
|
|
-H "Authorization: Bearer ${OTA_AUTH_TOKEN}" \
|
|
-H "Content-Type: application/zip" \
|
|
--data-binary @"dist-android-update.zip"
|
|
|
|
- name: Verify OTA manifest
|
|
run: |
|
|
REMOTE="$(curl -sS "${OTA_MANIFEST_URL}" \
|
|
-H "expo-platform: ${OTA_PLATFORM}" \
|
|
-H "expo-runtime-version: ${{ steps.runtime.outputs.runtime_version }}" \
|
|
-H "expo-protocol-version: 1" \
|
|
| python -c "import sys, json, re; s=sys.stdin.read(); m=re.search(r'\\{\\\"id\\\":.*\\\"extra\\\":\\{.*\\}\\}', s); j=json.loads(m.group(0)); print(j['launchAsset']['url'].split('/')[-1].split('&')[0])")"
|
|
LOCAL="$(python -c "import json; m=json.load(open('dist-android/metadata.json')); print(m['fileMetadata']['android']['bundle'].split('/')[-1])")"
|
|
echo "Remote bundle: ${REMOTE}"
|
|
echo "Local bundle: ${LOCAL}"
|
|
test "${REMOTE}" = "${LOCAL}"
|
|
|
|
build-android-apk:
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: reactnativecommunity/react-native-android:latest
|
|
env:
|
|
GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=4 -Xmx8g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:SoftRefLRUPolicyMSPerMB=0 -XX:ReservedCodeCacheSize=512m"
|
|
_JAVA_OPTIONS: "-Xmx8g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:SoftRefLRUPolicyMSPerMB=0 -XX:ReservedCodeCacheSize=512m"
|
|
NODE_OPTIONS: "--max-old-space-size=8192"
|
|
NODE_ENV: "production"
|
|
NDK_NUM_JOBS: "4"
|
|
CMAKE_BUILD_PARALLEL_LEVEL: "4"
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Java
|
|
uses: actions/setup-java@v4
|
|
with:
|
|
distribution: temurin
|
|
java-version: '21'
|
|
|
|
- name: Set up Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '25.6.1'
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Generate Android native project
|
|
run: npx expo prebuild --platform android
|
|
|
|
- name: Configure Gradle with Aliyun Maven mirror
|
|
run: |
|
|
cd android
|
|
|
|
# Update settings.gradle with Aliyun Maven mirror
|
|
cat > settings.gradle << 'SETTINGS_EOF'
|
|
pluginManagement {
|
|
repositories {
|
|
google()
|
|
mavenCentral()
|
|
gradlePluginPortal()
|
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
|
maven { url 'https://maven.aliyun.com/repository/google' }
|
|
maven { url 'https://maven.aliyun.com/repository/central' }
|
|
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
|
|
}
|
|
def reactNativeGradlePlugin = new File(
|
|
providers.exec {
|
|
workingDir(rootDir)
|
|
commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })")
|
|
}.standardOutput.asText.get().trim()
|
|
).getParentFile().absolutePath
|
|
includeBuild(reactNativeGradlePlugin)
|
|
|
|
def expoPluginsPath = new File(
|
|
providers.exec {
|
|
workingDir(rootDir)
|
|
commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })")
|
|
}.standardOutput.asText.get().trim(),
|
|
"../android/expo-gradle-plugin"
|
|
).absolutePath
|
|
includeBuild(expoPluginsPath)
|
|
}
|
|
|
|
plugins {
|
|
id("com.facebook.react.settings")
|
|
id("expo-autolinking-settings")
|
|
}
|
|
|
|
extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
|
|
if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
|
|
ex.autolinkLibrariesFromCommand()
|
|
} else {
|
|
ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand)
|
|
}
|
|
}
|
|
expoAutolinking.useExpoModules()
|
|
|
|
rootProject.name = '萝卜社区'
|
|
|
|
expoAutolinking.useExpoVersionCatalog()
|
|
|
|
include ':app'
|
|
includeBuild(expoAutolinking.reactNativeGradlePlugin)
|
|
SETTINGS_EOF
|
|
|
|
# Update build.gradle with Aliyun Maven mirror
|
|
cat > build.gradle << 'BUILD_EOF'
|
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
|
|
|
buildscript {
|
|
repositories {
|
|
google()
|
|
mavenCentral()
|
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
|
maven { url 'https://maven.aliyun.com/repository/google' }
|
|
maven { url 'https://maven.aliyun.com/repository/central' }
|
|
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
|
|
}
|
|
dependencies {
|
|
classpath('com.android.tools.build:gradle')
|
|
classpath('com.facebook.react:react-native-gradle-plugin')
|
|
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
|
|
}
|
|
}
|
|
|
|
allprojects {
|
|
repositories {
|
|
google()
|
|
mavenCentral()
|
|
maven { url 'https://www.jitpack.io' }
|
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
|
maven { url 'https://maven.aliyun.com/repository/google' }
|
|
maven { url 'https://maven.aliyun.com/repository/central' }
|
|
}
|
|
}
|
|
|
|
apply plugin: "expo-root-project"
|
|
apply plugin: "com.facebook.react.rootproject"
|
|
BUILD_EOF
|
|
|
|
# Update gradle.properties
|
|
cat > gradle.properties << 'PROPS_EOF'
|
|
org.gradle.daemon=false
|
|
org.gradle.parallel=true
|
|
org.gradle.configureondemand=true
|
|
org.gradle.workers.max=4
|
|
org.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:SoftRefLRUPolicyMSPerMB=0 -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
|
android.enableJetifier=false
|
|
android.useAndroidX=true
|
|
hermesEnabled=true
|
|
reactNativeArchitectures=arm64-v8a
|
|
newArchEnabled=true
|
|
edgeToEdgeEnabled=true
|
|
expo.gif.enabled=true
|
|
expo.webp.enabled=true
|
|
expo.webp.animated=false
|
|
expo.useLegacyPackaging=false
|
|
PROPS_EOF
|
|
|
|
- name: Build Android release APK (arm64 only)
|
|
run: |
|
|
cd android
|
|
chmod +x gradlew
|
|
./gradlew :app:assembleRelease -PreactNativeArchitectures=arm64-v8a --max-workers=4 --parallel
|
|
|
|
- name: Upload APK artifact
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: carrot-bbs-android-release-apk
|
|
path: android/app/build/outputs/apk/release/app-release.apk
|
|
|
|
build-and-push-web:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Log in to Gitea Container Registry
|
|
if: github.event_name != 'pull_request'
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ secrets.GIT_USERNAME }}
|
|
password: ${{ secrets.GIT_TOKEN }}
|
|
|
|
- name: Extract metadata for Docker
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
tags: |
|
|
type=raw,value=latest,enable={{is_default_branch}}
|
|
type=ref,event=branch
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=sha
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Build and push Docker image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
file: Dockerfile.web
|
|
push: ${{ github.event_name != 'pull_request' }}
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
platforms: linux/amd64
|
|
provenance: false
|
|
|
|
- name: Show image tags
|
|
run: |
|
|
echo "Built image tags:"
|
|
echo "${{ steps.meta.outputs.tags }}"
|
|
echo "Digest: ${{ steps.meta.outputs.digest }}"
|
|
|
|
- name: Summary
|
|
if: always()
|
|
run: |
|
|
echo "## Frontend CI Summary" >> "$GITHUB_STEP_SUMMARY"
|
|
echo "" >> "$GITHUB_STEP_SUMMARY"
|
|
echo "**Web image:** ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" >> "$GITHUB_STEP_SUMMARY"
|
|
echo "**Tags:**" >> "$GITHUB_STEP_SUMMARY"
|
|
echo "${{ steps.meta.outputs.tags }}" >> "$GITHUB_STEP_SUMMARY"
|
|
echo "**Digest:** ${{ steps.meta.outputs.digest }}" >> "$GITHUB_STEP_SUMMARY"
|