fix(release): auto-release to Maven Central (automaticRelease = true) #19
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| # Cancel in-progress CI runs for the same ref when a new commit lands. | |
| # Saves GitHub Actions minutes and keeps PR feedback focused on the | |
| # latest commit. | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| lint: | |
| name: Lint (detekt + Android lint + import boundary) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK 17 (Temurin) | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Set up Gradle (with caching) | |
| # setup-gradle handles ~/.gradle/caches/ and ~/.gradle/wrapper/ on its own — | |
| # do NOT layer actions/cache on top or cache keys collide. | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Ensure gradlew is executable | |
| # Defensive — actions/checkout@v4 should preserve exec bit but some self-hosted runners strip it. | |
| run: chmod +x ./gradlew | |
| - name: Enforce packages/core import boundary | |
| # Runs before Gradle so a forbidden android.* import is flagged even if compilation fails. | |
| run: | | |
| set -euo pipefail | |
| violations=$(grep -rn -E "^import (android|androidx)\." packages/core/src/ || true) | |
| if [ -n "$violations" ]; then | |
| echo "ERROR: packages/core is a pure Kotlin module — Android imports are forbidden. Move the code to packages/sdk or introduce a port interface." | |
| echo "$violations" | |
| exit 1 | |
| fi | |
| echo "OK: packages/core has no Android imports." | |
| - name: Enforce generated-file header (OpenAPI types) | |
| # Catches hand-edits to files under packages/core/.../model/generated/. | |
| # Every .kt file there must start with the "auto-generated by | |
| # openapi-generator" marker (prepended by the backend's | |
| # prependKotlinHeader.js step). Files that lack the header are | |
| # either (a) hand-edited after regeneration, or (b) new files | |
| # mistakenly added to the generated/ directory. Both cases are | |
| # PR blockers — types must be regenerated in backend/apiDoc/serving | |
| # and re-synced, never edited in place. Story 1.5, AC-6. | |
| run: | | |
| set -euo pipefail | |
| GEN_DIR=packages/core/src/main/kotlin/com/convert/sdk/core/model/generated | |
| if [ ! -d "$GEN_DIR" ]; then | |
| echo "ERROR: generated directory not found: $GEN_DIR" | |
| exit 1 | |
| fi | |
| missing=0 | |
| while IFS= read -r -d '' file; do | |
| if ! head -1 "$file" | grep -q "auto-generated by openapi-generator"; then | |
| echo "ERROR: $file is missing the auto-generated header." | |
| echo " Regenerate via 'yarn generateKotlinTypes' in backend/apiDoc/serving" | |
| echo " and re-sync per the README in $GEN_DIR. Do not hand-edit." | |
| missing=1 | |
| fi | |
| done < <(find "$GEN_DIR" -name '*.kt' -print0) | |
| if [ "$missing" -ne 0 ]; then | |
| exit 1 | |
| fi | |
| echo "OK: every .kt file under $GEN_DIR carries the auto-generated header." | |
| - name: Run detekt | |
| run: ./gradlew detekt --no-daemon | |
| - name: Run Android Lint (Debug variant) | |
| run: ./gradlew :packages:sdk:lintDebug --no-daemon | |
| - name: Build Dokka HTML API reference | |
| # Story 6.1 AC-7. Fails if Dokka can't build — catches a malformed | |
| # KDoc reference, a broken `@sample` link, or a plugin mis-config. | |
| # V2 task name is `dokkaGenerate` (aggregates every format); the | |
| # legacy `dokkaHtml` alias was removed in Dokka 2.2.0. Outputs | |
| # land under `packages/{core,sdk}/build/dokka/html/` and are | |
| # consumed by vanniktech's JavadocJar.Dokka("dokkaGenerateHtml") | |
| # hook at publish time. | |
| run: ./gradlew dokkaGenerate --no-daemon | |
| test-core: | |
| name: Test :packages:core (JVM) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK 17 (Temurin) | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Set up Gradle (with caching) | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Ensure gradlew is executable | |
| run: chmod +x ./gradlew | |
| - name: Test + Kover XML report | |
| run: ./gradlew :packages:core:test :packages:core:koverXmlReport --no-daemon | |
| - name: Upload test report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-core-report | |
| path: packages/core/build/reports/tests/test/ | |
| retention-days: 7 | |
| test-sdk: | |
| name: Test :packages:sdk (JVM / Robolectric-ready) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK 17 (Temurin) | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Set up Gradle (with caching) | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Ensure gradlew is executable | |
| run: chmod +x ./gradlew | |
| - name: Test + Kover XML report | |
| run: ./gradlew :packages:sdk:testDebugUnitTest :packages:sdk:koverXmlReport --no-daemon | |
| - name: Test :packages:sdk-lint (Story 6.3 custom lint rules) | |
| # Exercises ConvertSdkInitializedBeforeUseDetector and | |
| # ConvertSdkNotInApplicationOnCreateDetector against inline | |
| # Kotlin fixtures via LintDetectorTest. Separate from the SDK | |
| # unit test step so the report artefacts stay distinct. | |
| run: ./gradlew :packages:sdk-lint:test --no-daemon | |
| - name: Validate :packages:sdk lint output (Story 6.3 AC-3) | |
| # Runs the published lint rules (lintPublish in sdk/build.gradle.kts | |
| # bundles sdk-lint's JAR into the AAR) on the sdk module itself. | |
| # A registry misconfiguration — wrong META-INF/services FQN, | |
| # mis-matched lint-api ABI, malformed Issue constants — would | |
| # crash this step. Green here = consumer apps will load the rules | |
| # correctly. | |
| run: ./gradlew :packages:sdk:lintDebug --no-daemon | |
| - name: Upload test report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-sdk-report | |
| path: packages/sdk/build/reports/tests/testDebugUnitTest/ | |
| retention-days: 7 | |
| - name: Upload sdk-lint test report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-sdk-lint-report | |
| path: packages/sdk-lint/build/reports/tests/test/ | |
| retention-days: 7 | |
| coverage: | |
| name: Enforce coverage thresholds | |
| runs-on: ubuntu-latest | |
| needs: [test-core, test-sdk] | |
| steps: | |
| - name: Check out | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK 17 (Temurin) | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Set up Gradle (with caching) | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Ensure gradlew is executable | |
| run: chmod +x ./gradlew | |
| - name: Generate Kover XML reports | |
| # `koverVerify` does not emit report.xml — only `koverXmlReport` does. | |
| # Generate the XML first so the reports exist for the upload step even | |
| # when `koverVerify` trips a threshold below. | |
| run: ./gradlew koverXmlReport --no-daemon | |
| - name: Enforce Kover thresholds | |
| # `koverVerify` runs each module's `minBound` rule — currently 85 for | |
| # :packages:core and 50 for :packages:sdk (will ratchet to 70 per | |
| # NFR19 when Robolectric-backed tests land in Story 2.2+). | |
| run: ./gradlew koverVerify --no-daemon | |
| - name: Ensure coverage XML reports exist | |
| # Fail loudly if a path changes upstream — this catches silent drift | |
| # in the Kover plugin's report layout before the artifact upload does. | |
| run: | | |
| ls -la packages/core/build/reports/kover/report.xml packages/sdk/build/reports/kover/report.xml | |
| - name: Upload coverage reports | |
| # Upload even on failure — when `koverVerify` trips a threshold, the | |
| # reports are exactly what PR reviewers need to diagnose the gap. | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-reports | |
| path: | | |
| packages/core/build/reports/kover/report.xml | |
| packages/sdk/build/reports/kover/report.xml | |
| retention-days: 30 | |
| # The XML files may legitimately be absent if an earlier step failed | |
| # *before* Kover produced them. Don't fail the upload on missing files. | |
| if-no-files-found: warn |