diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index e3cf9b3..934fb16 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -1,56 +1,91 @@ name: Pre-Release Build on: - workflow_dispatch: + workflow_dispatch: # Allows manual triggering of the workflow push: branches-ignore: [ "master" ] tags: [ "*-pre-release" ] + pull_request: + branches-ignore: [ "master" ] jobs: build: runs-on: ubuntu-latest permissions: - contents: write + contents: write # Needed for creating a GitHub Release steps: - - name: Extract tag name - if: startsWith(github.ref, 'refs/tags/') - run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV - - name: Set up environment variables - run: | - echo "GPR_USER=${{ github.actor }}" >> $GITHUB_ENV - echo "GPR_KEY=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV - echo "KEY_ALIAS=${{ secrets.KEY_ALIAS }}" >> $GITHUB_ENV - echo "KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> $GITHUB_ENV - echo "KEYSTORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> $GITHUB_ENV - echo "KEYSTORE_BASE64=${{ secrets.KEYSTORE_BASE64 }}" >> $GITHUB_ENV - echo "BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV - - uses: actions/checkout@v4 - - name: set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - cache: gradle - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - name: Build with Gradle - run: ./gradlew build - - - name: Archive APK - uses: actions/upload-artifact@v4 - with: - name: app-release.apk - path: app/build/outputs/apk/release/app-release.apk - - - name: Create Release - id: create_release - uses: ncipollo/release-action@v1 - if: startsWith(github.ref, 'refs/tags/') - with: - name: ${{ github.ref_name }} - prerelease: true - generateReleaseNotes: true - artifacts: app/build/outputs/apk/release/app-release.apk, app/manifest.json - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Extract tag name + # This step only runs if the workflow was triggered by a tag push. + if: startsWith(github.ref, 'refs/tags/') + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + - name: Set up environment variables + # These environment variables are set for the entire job. + run: | + echo "GPR_USER=${{ github.actor }}" >> $GITHUB_ENV + echo "GPR_KEY=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + echo "KEY_ALIAS=${{ secrets.KEY_ALIAS }}" >> $GITHUB_ENV + echo "KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> $GITHUB_ENV + echo "KEYSTORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> $GITHUB_ENV + echo "KEYSTORE_BASE64=${{ secrets.KEYSTORE_BASE64 }}" >> $GITHUB_ENV + echo "BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV + + - uses: actions/checkout@v4 + # This action checks out the code. + # If triggered by a tag, it checks out the exact commit the tag points to. + # If triggered by a branch push, it checks out that branch. + + # NEW STEP: Check if the tagged commit is already on the master branch + - name: Check if tagged commit is on master branch + id: check_master_tag + # This step only runs if the workflow was triggered by a tag push. + if: startsWith(github.ref, 'refs/tags/') + run: | + # Fetch all remote branches to ensure 'git branch --contains' has full context + # This is crucial for accurately checking if the commit is on origin/master. + git fetch origin --prune + + # Check if the commit pointed to by the tag (${{ github.sha }}) is contained within 'origin/master'. + # If 'origin/master' contains the commit, it means the tagged code is already part of the master branch's history. + if git branch -r --contains ${{ github.sha }} | grep -q "origin/master"; then + echo "IS_ON_MASTER=true" >> $GITHUB_ENV + echo "Tagged commit ${{ github.sha }} IS on origin/master. A release will NOT be created." + else + echo "IS_ON_MASTER=false" >> $GITHUB_ENV + echo "Tagged commit ${{ github.sha }} is NOT on origin/master. A release WILL be created." + fi + # This environment variable (IS_ON_MASTER) will be used in the 'Create Release' step's condition. + + - name: set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle + run: ./gradlew build -PpreReleaseVersion=${{ env.RELEASE_VERSION }} + + - name: Archive APK + uses: actions/upload-artifact@v4 + with: + name: app-release.apk + path: app/build/outputs/apk/release/app-release.apk + + - name: Create Release + id: create_release + uses: ncipollo/release-action@v1 + # IMPORTANT: The release will now ONLY be created if: + # 1. The workflow was triggered by a tag (startsWith(github.ref, 'refs/tags/')) + # 2. AND the commit pointed to by that tag is NOT already on the 'master' branch (env.IS_ON_MASTER == 'false'). + if: startsWith(github.ref, 'refs/tags/') && env.IS_ON_MASTER == 'false' + with: + name: ${{ github.ref_name }} + prerelease: true + generateReleaseNotes: true + artifacts: app/build/outputs/apk/release/app-release.apk, app/manifest.json, config_screen.png, config_screen2.png, example1.png, example2.png, example3.png, example4.png + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-comments.yml b/.github/workflows/release-comments.yml index 41394a7..2b8071d 100644 --- a/.github/workflows/release-comments.yml +++ b/.github/workflows/release-comments.yml @@ -15,8 +15,8 @@ jobs: comment-on-fixed: runs-on: ubuntu-latest permissions: - pull-requests: write - issues: write + pull-requests: write + issues: write steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9cc3c2e..30aa328 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,45 +14,45 @@ jobs: permissions: contents: write steps: - - name: Extract tag name - if: startsWith(github.ref, 'refs/tags/') - run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV - - name: Set up environment variables - run: | - echo "GPR_USER=${{ github.actor }}" >> $GITHUB_ENV - echo "GPR_KEY=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV - echo "KEY_ALIAS=${{ secrets.KEY_ALIAS }}" >> $GITHUB_ENV - echo "KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> $GITHUB_ENV - echo "KEYSTORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> $GITHUB_ENV - echo "KEYSTORE_BASE64=${{ secrets.KEYSTORE_BASE64 }}" >> $GITHUB_ENV - echo "BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV - - uses: actions/checkout@v4 - - name: set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - cache: gradle + - name: Extract tag name + if: startsWith(github.ref, 'refs/tags/') + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + - name: Set up environment variables + run: | + echo "GPR_USER=${{ github.actor }}" >> $GITHUB_ENV + echo "GPR_KEY=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + echo "KEY_ALIAS=${{ secrets.KEY_ALIAS }}" >> $GITHUB_ENV + echo "KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> $GITHUB_ENV + echo "KEYSTORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> $GITHUB_ENV + echo "KEYSTORE_BASE64=${{ secrets.KEYSTORE_BASE64 }}" >> $GITHUB_ENV + echo "BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV + - uses: actions/checkout@v4 + - name: set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: gradle - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - name: Build with Gradle - run: ./gradlew build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew build - - name: Archive APK - uses: actions/upload-artifact@v4 - with: - name: app-release.apk - path: app/build/outputs/apk/release/app-release.apk + - name: Archive APK + uses: actions/upload-artifact@v4 + with: + name: app-release.apk + path: app/build/outputs/apk/release/app-release.apk - - name: Create Release - id: create_release - uses: ncipollo/release-action@v1 - if: startsWith(github.ref, 'refs/tags/') - with: - name: ${{ github.ref_name }} - prerelease: false - generateReleaseNotes: true - artifacts: app/build/outputs/apk/release/app-release.apk, app/manifest.json - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Create Release + id: create_release + uses: ncipollo/release-action@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + name: ${{ github.ref_name }} + prerelease: false + generateReleaseNotes: true + artifacts: app/build/outputs/apk/release/app-release.apk, app/manifest.json, config_screen.png, config_screen2.png, example1.png, example2.png, example3.png, example4.png + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 421f23e..e206c2f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,4 @@ +import groovy.json.JsonBuilder import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { @@ -13,6 +14,20 @@ kotlin { } } +val projectName = "karoo-ext-template" +val screenshotBaseNames = listOf( + "example1.png" +) +val projectLabel = "Karoo Extension Template" +val projectDescription = "Karoo Extension template" +val projectDeveloper = "currand" + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget("17") + } +} + android { namespace = "com.currand60.karooexttemplate" compileSdk = 36 @@ -61,35 +76,73 @@ dependencies { implementation(libs.bundles.androidx.lifeycle) implementation(libs.androidx.activity.compose) implementation(libs.bundles.compose.ui) + implementation(libs.androidx.activity.compose) + implementation(libs.androidx.datastore.preferences) + implementation(libs.androidx.glance.appwidget) + implementation(libs.androidx.glance.preview) + implementation(libs.androidx.glance.appwidget.preview) + implementation(libs.androidx.navigation.runtime.android) + implementation(libs.javax.inject) + implementation(libs.timber) + implementation(libs.kotlinx.coroutines.debug) + implementation(libs.koin.android) + implementation(libs.koin.androidx.compose) + implementation(libs.androidx.material.icons.extended) } tasks.register("generateManifest") { description = "Generates manifest.json with current version information" group = "build" + // Retrieve the preReleaseVersion property at configuration time. + // This makes it a declared input to the task. + val preReleaseVersion = project.providers.gradleProperty("preReleaseVersion") + .getOrElse("") + + // Declare the preReleaseVersion as an input property for Gradle's up-to-date checks. + // If this value doesn't change, the task won't re-run. + inputs.property("preReleaseVersion", preReleaseVersion) + val manifestOutputFile = layout.projectDirectory.file("manifest.json") + outputs.file(manifestOutputFile).withPropertyName("manifestFile") + + // The task action, equivalent to the @TaskAction method in the class-based approach. doLast { - val manifestFile = file("$projectDir/manifest.json") + val androidExtension = project.extensions.getByName("android") as com.android.build.gradle.AppExtension + val defaultConfig = androidExtension.defaultConfig + + val manifestFile = manifestOutputFile.asFile + + // Use the 'preReleaseVersion' value obtained at configuration time + val currentPreReleaseVersion = preReleaseVersion.takeIf { it.isNotBlank() } + println("Debug: preReleaseVersion from task input: $currentPreReleaseVersion") + + val releasePathComponent = if (currentPreReleaseVersion != null) { + "download/$currentPreReleaseVersion" // e.g., "download/v0.4.2-pre-release" + } else { + "latest/download" // Default for stable releases or local builds + } + + val baseUrl = "https://github.com/$projectDeveloper/$projectName/releases/$releasePathComponent" + val apkFileName = "app-release.apk" + + val screenshotUrls = screenshotBaseNames.map { "$baseUrl/$it" } + + // Construct the manifest as a Map val manifest = mapOf( - "label" to "Karoo Template", - "packageName" to android.namespace, - "latestApkUrl" to "https://github.com/currand/karoo-ext-template/releases/latest/download/app-release.apk", - "latestVersion" to android.defaultConfig.versionName, - "latestVersionCode" to android.defaultConfig.versionCode, - "developer" to "currand", - "description" to "Template Karoo Extension", -// "screenshotUrls" to listOf( -// "https://github.com/currand/karoo-colorspeed/releases/latest/download/example1.png", -// "https://github.com/currand/karoo-colorspeed/releases/latest/download/example2.png", -// "https://github.com/currand/karoo-colorspeed/releases/latest/download/example3.png", -// "https://github.com/currand/karoo-colorspeed/releases/latest/download/example4.png", -// "https://github.com/currand/karoo-colorspeed/releases/latest/download/config_screen.png", -// "https://github.com/currand/karoo-colorspeed/releases/latest/download/config_screen2.png" -// ), + "label" to projectLabel, + "packageName" to androidExtension.namespace, + "latestApkUrl" to "$baseUrl/$apkFileName", + "latestVersion" to defaultConfig.versionName, + "latestVersionCode" to defaultConfig.versionCode, + "developer" to projectDeveloper, + "description" to projectDescription, + "screenshotUrls" to screenshotUrls ) - val gson = groovy.json.JsonBuilder(manifest).toPrettyString() + // Use groovy.json.JsonBuilder to serialize the Map to a pretty-printed JSON string + val gson = JsonBuilder(manifest).toPrettyString() manifestFile.writeText(gson) - println("Generated manifest.json with version ${android.defaultConfig.versionName} (${android.defaultConfig.versionCode})") + println("Generated manifest.json with download path: $releasePathComponent at ${manifestFile.absolutePath}") } } @@ -101,22 +154,4 @@ java { toolchain { languageVersion = JavaLanguageVersion.of(17) } -} - -dependencies { - implementation(libs.hammerhead.karoo.ext) - implementation(libs.androidx.core.ktx) - implementation(libs.bundles.androidx.lifeycle) - implementation(libs.androidx.activity.compose) - implementation(libs.bundles.compose.ui) - implementation(libs.androidx.datastore.preferences) - implementation(libs.androidx.glance.appwidget) - implementation(libs.androidx.glance.preview) - implementation(libs.androidx.glance.appwidget.preview) - implementation(libs.androidx.navigation.runtime.android) - implementation(libs.javax.inject) - implementation(libs.timber) - implementation(libs.kotlinx.coroutines.debug) - implementation(libs.koin.android) - implementation(libs.koin.androidx.compose) } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a15de6f..72c990e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,18 +3,19 @@ agp = "8.11.2" kotlin = "2.2.20" datastorePreferences = "1.1.7" kotlinxCoroutinesDebug = "1.10.2" -navigationRuntimeAndroid = "2.9.4" +materialIconsExtended = "1.7.8" +navigationRuntimeAndroid = "2.9.5" javaxInject = "1" androidxCore = "1.17.0" androidxLifecycle = "2.9.4" androidxActivity = "1.11.0" -androidxComposeUi = "1.9.1" -androidxComposeMaterial = "1.3.2" +androidxComposeUi = "1.9.3" +androidxComposeMaterial = "1.4.0" glance = "1.1.1" timber = "5.0.1" koin-bom = "4.1.1" glancePreview = "1.1.1" -hammerHeadExt = "1.1.5" +hammerHeadExt = "1.1.6" [plugins] @@ -23,8 +24,8 @@ jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } google-devtools-ksp = { id = "com.google.devtools.ksp", version = "2.2.20-2.0.3" } - [libraries] +androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" } hammerhead-karoo-ext = { group = "io.hammerhead", name = "karoo-ext", version.ref = "hammerHeadExt" } androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" } javax-inject = { group = "javax.inject", name = "javax.inject", version.ref = "javaxInject" }