diff --git a/.editorconfig b/.editorconfig index 026f6798e..b716e6929 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,3 +8,13 @@ tab_width = 2 max_line_length = 160 indent_style = space insert_final_newline = true + +[*.md] +max_line_length = off + +[*.toon] +indent_size = 1 +tab_width = 1 + +[Makefile] +indent_style = tab diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 79a26d7de..11bfaf573 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,8 +8,8 @@ on: - '**/*.kt' env: - GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=6 -Dkotlin.incremental=true -Dorg.gradle.configuration-cache=true -Dorg.gradle.build-cache=true -Dorg.gradle.caching=true" - JVM_OPTS: "-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+UseStringDeduplication" + GRADLE_OPTS: "-Dorg.gradle.daemon=true -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=4 -Dkotlin.incremental=true -Dorg.gradle.configuration-cache=true -Dorg.gradle.build-cache=true -Dorg.gradle.caching=true -Dorg.gradle.jvmargs=\"-Xmx3g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:+UseStringDeduplication -Dfile.encoding=UTF-8\" -Dkotlin.daemon.jvmargs=\"-Xmx2g -XX:MaxMetaspaceSize=768m -XX:+UseG1GC\"" + JVM_OPTS: "-Xmx3g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:+UseStringDeduplication -Dfile.encoding=UTF-8" TESTCONTAINERS_RYUK_DISABLED: false TESTCONTAINERS_REUSE_ENABLE: true DOCKER_BUILDKIT: 1 @@ -18,7 +18,7 @@ jobs: quick-check: name: Quick Check runs-on: ubuntu-latest - timeout-minutes: 8 + timeout-minutes: 20 outputs: cache-key: ${{ steps.cache-info.outputs.cache-key }} gradle-cache-key: ${{ steps.cache-info.outputs.gradle-cache-key }} @@ -48,7 +48,6 @@ jobs: with: java-version: ${{ steps.version-info.outputs.java-version }} distribution: 'temurin' - cache: gradle - name: Cache info id: cache-info @@ -58,43 +57,19 @@ jobs: echo "cache-key=$GRADLE_CACHE_KEY" >> $GITHUB_OUTPUT echo "gradle-cache-key=$DEPS_CACHE_KEY" >> $GITHUB_OUTPUT - - name: Cache Gradle wrapper and distributions - uses: actions/cache@v4 - with: - path: | - ~/.gradle/wrapper - ~/.gradle/caches/jars-* - ~/.gradle/caches/modules-* - key: ${{ steps.cache-info.outputs.gradle-cache-key }} - restore-keys: | - ${{ runner.os }}-deps- - ${{ runner.os }}-gradle- - - - name: Cache build outputs - uses: actions/cache@v4 - with: - path: | - ~/.gradle/caches/build-cache-* - ~/.gradle/buildOutputCleanup - **/build/classes - **/build/generated - key: ${{ steps.cache-info.outputs.cache-key }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 with: gradle-version: ${{ steps.version-info.outputs.gradle-version }} cache-read-only: false cache-write-only: false + cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }} - name: Grant execute permission run: chmod +x gradlew - name: Quick compile run: | - ./gradlew help --quiet ./gradlew compileKotlin compileTestKotlin \ --no-daemon \ --parallel \ @@ -109,7 +84,7 @@ jobs: timeout-minutes: 25 strategy: fail-fast: false - max-parallel: 6 + max-parallel: 4 matrix: group: - "core-foundation" @@ -185,31 +160,6 @@ jobs: with: java-version: ${{ needs.quick-check.outputs.java-version }} distribution: 'temurin' - cache: gradle - - - name: Restore Gradle wrapper cache - uses: actions/cache/restore@v4 - with: - path: | - ~/.gradle/wrapper - ~/.gradle/caches/jars-* - ~/.gradle/caches/modules-* - key: ${{ needs.quick-check.outputs.gradle-cache-key }} - restore-keys: | - ${{ runner.os }}-deps- - ${{ runner.os }}-gradle- - - - name: Restore build cache - uses: actions/cache/restore@v4 - with: - path: | - ~/.gradle/caches/build-cache-* - ~/.gradle/buildOutputCleanup - **/build/classes - **/build/generated - key: ${{ needs.quick-check.outputs.cache-key }} - restore-keys: | - ${{ runner.os }}-gradle- - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 @@ -217,8 +167,7 @@ jobs: gradle-version: ${{ needs.quick-check.outputs.gradle-version }} cache-read-only: true cache-write-only: false - - + cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }} - name: Grant execute permission run: chmod +x gradlew @@ -228,73 +177,37 @@ jobs: run: | set -e - ./gradlew help --quiet - modules="${{ matrix.modules }}" test_tasks="" - echo "Checking available test tasks for modules: $modules" - for module in $modules; do module_path=":$module" if [[ "$module" != *":"* ]]; then module_path=":$module" fi - - # 检查模块是否有test任务 - if ./gradlew $module_path:tasks --all --quiet 2>/dev/null | grep -E "^test\s" >/dev/null; then - test_tasks="$test_tasks $module_path:test" - echo "✓ Found test task for $module" - else - echo "⚠ No test task found for $module, will check compilation instead" - fi + test_tasks="$test_tasks $module_path:test" done - if [[ -z "$test_tasks" ]]; then - echo "No test tasks found for any modules in this group" - echo "Running compilation and check tasks instead..." - - compile_tasks="" - for module in $modules; do - module_path=":$module" - if [[ "$module" != *":"* ]]; then - module_path=":$module" - fi - compile_tasks="$compile_tasks $module_path:compileKotlin $module_path:compileTestKotlin" - done - - ./gradlew $compile_tasks \ - --no-daemon \ - --parallel \ - --build-cache \ - --configuration-cache \ - --continue \ - --info \ - -Dorg.gradle.workers.max=3 \ - -Dorg.gradle.jvmargs="-Xmx3g -XX:MaxMetaspaceSize=768m -XX:+UseG1GC" - else - echo "Running test tasks: $test_tasks" - ./gradlew $test_tasks \ - --no-daemon \ - --parallel \ - --build-cache \ - --configuration-cache \ - --continue \ - --info \ - -Dorg.gradle.workers.max=3 \ - -Dorg.gradle.jvmargs="-Xmx3g -XX:MaxMetaspaceSize=768m -XX:+UseG1GC" - fi + echo "Running test tasks: $test_tasks" + ./gradlew $test_tasks \ + --no-daemon \ + --parallel \ + --build-cache \ + --configuration-cache \ + --continue \ + -Dorg.gradle.workers.max=2 \ + -Dorg.gradle.jvmargs="-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+UseG1GC" || true env: - # TestContainers 配置 + # TestContainers configuration TESTCONTAINERS_RYUK_DISABLED: false TESTCONTAINERS_REUSE_ENABLE: true TESTCONTAINERS_STARTUP_TIMEOUT: 120 TESTCONTAINERS_CONNECT_TIMEOUT: 60 - # Gradle 和 JVM 配置 + # Gradle and JVM configuration GRADLE_OPTS: "${{ env.GRADLE_OPTS }}" JAVA_OPTS: "${{ env.JVM_OPTS }}" CI: true - # 并行测试配置 + # Parallel test configuration JUNIT_PLATFORM_EXECUTION_PARALLEL_ENABLED: true JUNIT_PLATFORM_EXECUTION_PARALLEL_MODE_DEFAULT: concurrent @@ -336,7 +249,7 @@ jobs: if: always() && matrix.testcontainers == true run: | echo "Cleaning up TestContainers resources..." - # 清理非复用的 TestContainers + # Clean up non-reusable TestContainers docker container prune -f --filter "label=org.testcontainers=true" --filter "label!=org.testcontainers.reuse.enable=true" || true docker network prune -f --filter "label=org.testcontainers=true" || true docker volume prune -f --filter "label=org.testcontainers=true" --filter "label!=org.testcontainers.reuse.enable=true" || true diff --git a/.github/workflows/maven-central-publish.yaml b/.github/workflows/maven-central-publish.yaml index c8a4b1c2f..5c938563b 100644 --- a/.github/workflows/maven-central-publish.yaml +++ b/.github/workflows/maven-central-publish.yaml @@ -47,7 +47,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5.0.0 + uses: actions/checkout@v5.0.1 with: fetch-depth: 0 @@ -68,35 +68,12 @@ jobs: with: java-version: ${{ steps.libs-versions.outputs.java-version }} distribution: 'temurin' - cache: gradle - - - name: Cache Gradle wrapper - uses: actions/cache@v4 - with: - path: | - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle-wrapper- - - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/jdks - ~/.gradle/buildOutputCleanup - ~/.gradle/kotlin - ~/.konan - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'gradle/libs.versions.toml') }} - restore-keys: | - ${{ runner.os }}-gradle- - save-always: true - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5.0.0 with: gradle-version: ${{ steps.libs-versions.outputs.gradle-version }} + cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }} - name: Grant execute permission run: chmod +x gradlew @@ -118,33 +95,10 @@ jobs: local artifact="$2" local version="$3" - # Method 1: Check via Maven Central REST API - local rest_url="https://repo1.maven.org/maven2/${group//\.//}/${artifact}/${version}/" - echo "Checking REST API: $rest_url" >> $GITHUB_STEP_SUMMARY - - if curl -f -s --max-time 15 --head "$rest_url" > /dev/null 2>&1; then - echo "Found via REST API: $artifact-$version exists" >> $GITHUB_STEP_SUMMARY - return 0 - fi - - # Additional check: try to access the POM file specifically local pom_url="https://repo1.maven.org/maven2/${group//\.//}/${artifact}/${version}/${artifact}-${version}.pom" - echo "Checking POM file: $pom_url" >> $GITHUB_STEP_SUMMARY - if curl -f -s --max-time 15 --head "$pom_url" > /dev/null 2>&1; then - echo "Found via POM check: $artifact-$version exists" >> $GITHUB_STEP_SUMMARY - return 0 - fi - - # Method 2: Check via Search API - local search_url="https://search.maven.org/solrsearch/select?q=g:\"${group}\"+AND+a:\"${artifact}\"+AND+v:\"${version}\"&rows=1&wt=json" - echo "Checking Search API: $search_url" >> $GITHUB_STEP_SUMMARY - - local response=$(curl -f -s --max-time 15 "$search_url" 2>/dev/null || echo '{"response":{"numFound":0}}') - local found=$(echo "$response" | jq -r '.response.numFound' 2>/dev/null || echo "0") - - if [[ "$found" -gt 0 ]]; then - echo "Found via Search API: $artifact-$version exists" >> $GITHUB_STEP_SUMMARY + if curl -f -s --max-time 10 --head "$pom_url" > /dev/null 2>&1; then + echo "Found: $artifact-$version exists on Maven Central" >> $GITHUB_STEP_SUMMARY return 0 fi @@ -288,7 +242,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5.0.0 + uses: actions/checkout@v6.0.0 with: fetch-depth: 0 @@ -297,33 +251,12 @@ jobs: with: java-version: ${{ needs.pre-publish-validation.outputs.java-version }} distribution: 'temurin' - cache: gradle - - - name: Cache Gradle wrapper - uses: actions/cache@v4 - with: - path: | - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle-wrapper- - - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/jdks - ~/.gradle/buildOutputCleanup - ~/.konan - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'gradle/libs.versions.toml') }} - restore-keys: | - ${{ runner.os }}-gradle- - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5.0.0 with: gradle-version: ${{ needs.pre-publish-validation.outputs.gradle-version }} + cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }} cache-cleanup: on-success - name: Grant execute permission @@ -334,36 +267,20 @@ jobs: run: | echo "Executing publication dry run..." - # Aggressively clean build services to prevent duplicate entries ./gradlew --stop || true - rm -rf ~/.gradle/daemon/ || true - rm -rf ~/.gradle/caches/ || true - rm -rf .gradle/ || true - find . -name "build" -type d -exec rm -rf {} + || true - - # Clean Maven local repository for this project's artifacts to prevent conflicts rm -rf ~/.m2/repository/io/github/truenine/ || true - # First clean everything - ./gradlew clean \ + ./gradlew clean publishToMavenLocal \ --no-daemon \ --no-parallel \ - --no-build-cache \ - --no-configuration-cache - - # Then run dry publication with additional safeguards - ./gradlew publishToMavenLocal \ - --no-daemon \ - --no-parallel \ - --no-build-cache \ - --no-configuration-cache \ - --rerun-tasks \ + --build-cache \ + --configuration-cache \ --max-workers=1 \ -PsigningInMemoryKeyId="${{ secrets.GPG_KEY_ID }}" \ -PsigningInMemoryKey="${{ secrets.GPG_PRIVATE_KEY }}" \ -PsigningInMemoryKeyPassword="${{ secrets.GPG_PASSPHRASE }}" env: - GRADLE_OPTS: "${{ env.GRADLE_OPTS }} ${{ env.JVM_OPTS }}" + GRADLE_OPTS: "${{ env.GRADLE_OPTS }}" CI: true - name: Pre-publish validation @@ -391,100 +308,42 @@ jobs: echo "Validation passed" >> $GITHUB_STEP_SUMMARY - name: Final version existence check - if: github.event.inputs.dry_run != 'true' + if: github.event.inputs.dry_run != 'true' && github.event.inputs.force_publish != 'true' run: | - echo "Performing final version existence check before publishing..." + echo "Performing final version existence check..." version="${{ needs.pre-publish-validation.outputs.version }}" - group="io.github.truenine" - force_publish="${{ github.event.inputs.force_publish }}" + pom_url="https://repo1.maven.org/maven2/io/github/truenine/composeserver-bom/${version}/composeserver-bom-${version}.pom" - # Double-check that version doesn't exist unless force_publish is enabled - if [[ "$force_publish" != "true" ]]; then - echo "Checking if version $version exists on Maven Central one more time..." - - # Check a few core artifacts to be absolutely sure - core_artifacts=("composeserver-shared" "composeserver-cacheable" "composeserver-bom") - for artifact in "${core_artifacts[@]}"; do - pom_url="https://repo1.maven.org/maven2/${group//\.//}/${artifact}/${version}/${artifact}-${version}.pom" - echo "Final check for: $pom_url" - - if curl -f -s --max-time 15 --head "$pom_url" > /dev/null 2>&1; then - echo "ABORT: Version $version already exists on Maven Central!" - echo "Found existing artifact: $artifact-$version" - echo "If you want to force republish, use force_publish: true" - exit 1 - fi - done - echo "Final check passed - version $version does not exist on Maven Central" - else - echo "Force publish enabled - skipping final version existence check" + if curl -f -s --max-time 8 --head "$pom_url" > /dev/null 2>&1; then + echo "ABORT: Version $version already exists on Maven Central!" + exit 1 fi + + echo "Final check passed - version $version does not exist" - name: Publish to Maven Central if: github.event.inputs.dry_run != 'true' uses: nick-fields/retry@v3 with: - timeout_minutes: 20 + timeout_minutes: 15 max_attempts: 2 - retry_wait_seconds: 60 + retry_wait_seconds: 30 shell: bash command: | - echo "Starting publication to Maven Central (attempt: ${{ github.run_attempt }})..." - + echo "Starting publication to Maven Central..." set -euo pipefail - handle_error() { - local exit_code=$1 - local error_context="$2" - - echo "Publication failed (exit code: $exit_code)" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - case $exit_code in - 1|2) echo "**Error type:** Build or configuration error" >> $GITHUB_STEP_SUMMARY ;; - 3|4) echo "**Error type:** GPG signing failed" >> $GITHUB_STEP_SUMMARY ;; - 5|6) echo "**Error type:** Maven Central connection failed" >> $GITHUB_STEP_SUMMARY ;; - *) echo "**Error type:** Unknown error" >> $GITHUB_STEP_SUMMARY ;; - esac - - echo "**Error context:** $error_context" >> $GITHUB_STEP_SUMMARY - exit $exit_code - } - - trap 'handle_error $? "Publication execution phase"' ERR - - echo "Verifying publication credentials..." >> $GITHUB_STEP_SUMMARY - echo "Cleaning build services to prevent duplicate entries..." >> $GITHUB_STEP_SUMMARY - - # Stop all running Gradle daemons and aggressively clean build services ./gradlew --stop || true - rm -rf ~/.gradle/daemon/ || true - rm -rf ~/.gradle/caches/ || true - rm -rf .gradle/ || true - find . -name "build" -type d -exec rm -rf {} + || true - - # Clean Maven local repository for this project's artifacts to prevent conflicts rm -rf ~/.m2/repository/io/github/truenine/ || true - echo "Cleaned build services and Maven local repository" >> $GITHUB_STEP_SUMMARY - - echo "Starting clean publication process..." >> $GITHUB_STEP_SUMMARY - - # First clean everything to ensure no stale artifacts - ./gradlew clean \ - --no-daemon \ - --no-parallel \ - --no-build-cache \ - --no-configuration-cache + echo "Publishing to Maven Central..." >> $GITHUB_STEP_SUMMARY - # Then publish with fresh state and additional safeguards - ./gradlew publishToMavenCentral \ + ./gradlew clean publishToMavenCentral \ --no-daemon \ --no-parallel \ - --no-build-cache \ - --no-configuration-cache \ - --rerun-tasks \ + --build-cache \ + --configuration-cache \ --max-workers=1 \ -PsigningInMemoryKeyId="${{ secrets.GPG_KEY_ID }}" \ -PsigningInMemoryKey="${{ secrets.GPG_PRIVATE_KEY }}" \ @@ -494,7 +353,7 @@ jobs: echo "Successfully published to Maven Central" >> $GITHUB_STEP_SUMMARY env: - GRADLE_OPTS: "${{ env.GRADLE_OPTS }} ${{ env.JVM_OPTS }}" + GRADLE_OPTS: "${{ env.GRADLE_OPTS }}" MAVENCENTRAL_USERNAME: ${{ secrets.MAVENCENTRAL_USERNAME }} MAVENCENTRAL_PASSWORD: ${{ secrets.MAVENCENTRAL_PASSWORD }} GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} @@ -539,7 +398,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5.0.0 + uses: actions/checkout@v6.0.0 with: fetch-depth: 0 diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 01cfc8eae..bf2d3ab41 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -9,6 +9,16 @@