diff --git a/.github/workflows/gradle-publish.yml b/.github/workflows/gradle-publish.yml index abf0a827..fe4a3828 100644 --- a/.github/workflows/gradle-publish.yml +++ b/.github/workflows/gradle-publish.yml @@ -1,7 +1,6 @@ -# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created -# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle +# This workflow will build a package using Gradle and then publish it to Maven Central when a release is published. -name: Gradle Package +name: Publish to Maven Central on: release: @@ -16,13 +15,14 @@ jobs: packages: write steps: - - uses: actions/checkout@v4 + - name: Check out repo + uses: actions/checkout@v4 + - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' - server-id: github # Value of the distributionManagement/repository/id field of the pom.xml cache: gradle - name: Grant execute permission for gradlew @@ -36,11 +36,10 @@ jobs: run: touch local.properties working-directory: android - # The USERNAME and TOKEN need to correspond to the credentials environment variables used in - # the publishing section of your build.gradle - - name: Publish to GitHub Packages - run: ./gradlew publish - working-directory: android + - name: Publish to Maven Central + run: ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache env: - GITHUB_ACTOR: ${{ github.actor }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_TOKEN }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_GPG_SECRET_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_GPG_PASSPHRASE }} diff --git a/Package.swift b/Package.swift index dba32907..c98c7160 100644 --- a/Package.swift +++ b/Package.swift @@ -16,7 +16,7 @@ if useLocalFramework { path: "./common/target/ios/libferrostar-rs.xcframework" ) } else { - let releaseTag = "0.7.2" + let releaseTag = "0.8.0" let releaseChecksum = "b63a45c82d3b645d1367c7a5b700511a7c7803e4757afae5cff71ad4acb761c9" binaryTarget = .binaryTarget( name: "FerrostarCoreRS", diff --git a/RELEASE.md b/RELEASE.md index 385d3ccd..cf9d9d1b 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -7,3 +7,18 @@ When cutting a release, follow this checklist: 3. Create a GitHub release and use the new version as the tag name (not that it must be in X.Y.Z format to please SPM). 4. Sit back and watch. GitHub actions take care of the rest. Note that iOS CI ends up adding a commit due to the way binary checksumming works. + +## GPG + +Maven Central requires all packages to be signed. +This necessarily means the headache of key management. +Fortunately keys don't need to be regenerated very often, +but here are some notes for whenever it's required again. + +Sonatype has good [docs](https://central.sonatype.org/publish/requirements/gpg/) on generating a key. +To export the private key for use in CI, +you can run the following command. + +```shell +gpg --armor --export-secret-key you@example.com | grep -v '\-\-' | grep -v '^=.' | tr -d '\n' +``` diff --git a/android/build.gradle b/android/build.gradle index 664cc010..afca0ee3 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -7,23 +7,10 @@ plugins { alias libs.plugins.ktfmt apply false alias libs.plugins.paparazzi apply false alias libs.plugins.compose.compiler apply false - id 'maven-publish' -} - -publishing { - repositories { - maven { - name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/stadiamaps/ferrostar") - credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") - } - } - } + alias libs.plugins.mavenPublish apply false } allprojects { group = "com.stadiamaps.ferrostar" - version = "0.7.2" + version = "0.8.0" } diff --git a/android/common-pom.gradle b/android/common-pom.gradle new file mode 100644 index 00000000..309b9ce8 --- /dev/null +++ b/android/common-pom.gradle @@ -0,0 +1,40 @@ +ext { + // Add an optional parameter includeGoogleRepo with a default value of false + commonPomConfig = { pom, includeGoogleRepo = false -> + pom.url = "https://github.com/stadiamaps/ferrostar" + pom.inceptionYear = "2023" + pom.licenses { + license { + name = "BSD-3-Clause" + url = "https://spdx.org/licenses/BSD-3-Clause.html" + } + } + pom.developers { + developer { + name = "Ian Wagner" + organization = "Stadia Maps" + organizationUrl = "https://stadiamaps.com/" + } + developer { + name = "Jacob Fielding" + organization = "Rallista" + organizationUrl = "https://rallista.app/" + } + } + pom.scm { + connection = "scm:git:https://github.com/stadiamaps/ferrostar.git" + developerConnection = "scm:git:ssh://github.com/stadiamaps/ferrostar.git" + url = "http://github.com/stadiamaps/ferrostar" + } + + // Conditional inclusion of the Google repository + if (includeGoogleRepo) { + pom.withXml { + def repo = asNode().appendNode('repositories').appendNode('repository') + repo.appendNode('name', 'Google') + repo.appendNode('id', 'google') + repo.appendNode('url', 'https://maven.google.com/') + } + } + } +} diff --git a/android/composeui/build.gradle b/android/composeui/build.gradle index b24da458..c33d1546 100644 --- a/android/composeui/build.gradle +++ b/android/composeui/build.gradle @@ -1,9 +1,13 @@ +import com.vanniktech.maven.publish.AndroidMultiVariantLibrary +import com.vanniktech.maven.publish.SonatypeHost + plugins { alias libs.plugins.androidLibrary alias libs.plugins.jetbrainsKotlinAndroid alias libs.plugins.ktfmt alias libs.plugins.paparazzi alias libs.plugins.compose.compiler + alias libs.plugins.mavenPublish } android { @@ -34,12 +38,6 @@ android { buildFeatures { compose true } - publishing { - singleVariant('release') { - withSourcesJar() - withJavadocJar() - } - } } dependencies { @@ -69,21 +67,22 @@ dependencies { androidTestImplementation libs.androidx.test.espresso implementation libs.androidx.compose.ui.tooling.preview - debugImplementation libs.androidx.compose.ui.tooling + debugImplementation libs.androidx.compose.ui.tooling debugImplementation libs.androidx.compose.ui.test.manifest } -publishing { - publications { - "${project.name}-release"(MavenPublication) { - groupId = 'com.stadiamaps.ferrostar' - artifactId = 'composeui' - version = project.version +mavenPublishing { + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + signAllPublications() - afterEvaluate { - from components.release - } - } + configure(new AndroidMultiVariantLibrary(true, true)) + + apply from: "${rootProject.projectDir}/common-pom.gradle" + + pom { + name = "Ferrostar Composable UI" + description = "Composable non-map UI components for Ferrostar" + commonPomConfig(it, true) } -} \ No newline at end of file +} diff --git a/android/core/build.gradle b/android/core/build.gradle index fa5b5695..d0f070d3 100644 --- a/android/core/build.gradle +++ b/android/core/build.gradle @@ -1,8 +1,12 @@ +import com.vanniktech.maven.publish.AndroidMultiVariantLibrary +import com.vanniktech.maven.publish.SonatypeHost + plugins { alias libs.plugins.androidLibrary alias libs.plugins.jetbrainsKotlinAndroid alias libs.plugins.cargo.ndk alias libs.plugins.ktfmt + alias libs.plugins.mavenPublish } android { @@ -32,12 +36,6 @@ android { kotlinOptions { jvmTarget = '1.8' } - publishing { - singleVariant('release') { - withSourcesJar() - withJavadocJar() - } - } } dependencies { @@ -77,9 +75,10 @@ cargoNdk { } android.libraryVariants.all { variant -> + def bDir = layout.buildDirectory.dir("generated/source/uniffi/${variant.name}/java").get() def generateBindings = tasks.register("generate${variant.name.capitalize()}UniFFIBindings", Exec) { workingDir '../../common' - commandLine 'cargo', 'run', '-p', 'uniffi-bindgen', 'generate', '--library', '../android/core/src/main/jniLibs/arm64-v8a/libferrostar.so', '--language', 'kotlin', '--out-dir', "${buildDir}/generated/source/uniffi/${variant.name}/java" + commandLine 'cargo', 'run', '-p', 'uniffi-bindgen', 'generate', '--library', '../android/core/src/main/jniLibs/arm64-v8a/libferrostar.so', '--language', 'kotlin', '--out-dir', bDir dependsOn "buildCargoNdk${variant.name.capitalize()}" } @@ -103,20 +102,19 @@ android.libraryVariants.all { variant -> // to a good solution for forcing the directory to be marked as generated (short of checking in // project files, I suppose). // idea.module.generatedSourceDirs += file("${buildDir}/generated/source/uniffi/${variant.name}/java/uniffi") - - sourceSet.java.srcDir 'src/main/java' } -publishing { - publications { - "${project.name}-release"(MavenPublication) { - groupId = 'com.stadiamaps.ferrostar' - artifactId = 'core' - version = project.version +mavenPublishing { + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + signAllPublications() - afterEvaluate { - from components.release - } - } + configure(new AndroidMultiVariantLibrary(true, true)) + + apply from: "${rootProject.projectDir}/common-pom.gradle" + + pom { + name = "Ferrostar Core" + description = "Core libray, models, and navigation business logic for Ferrostar" + commonPomConfig(it) } } diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index e45d5d72..2ff195cd 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -3,14 +3,14 @@ agp = "8.5.2" kotlin = "2.0.0" cargo-ndk = "0.3.4" ktfmt = "0.19.0" -lifecycleRuntimeComposeAndroid = "2.8.3" +androidx-lifecycle = "2.8.4" paparazzi = "1.3.4" desugar_jdk_libs = "2.0.4" ktx = "1.13.1" kotlinx-coroutines = "1.8.1" kotlinx-datetime = "0.6.0" androidx-appcompat = "1.7.0" -androidx-activity-compose = "1.9.0" +androidx-activity-compose = "1.9.1" compose = "2024.06.00" okhttp = "4.12.0" moshi = "1.15.1" @@ -20,6 +20,7 @@ junitVersion = "1.2.1" junitCompose = "1.6.8" espressoCore = "3.6.1" okhttp-mock = "2.0.0" +mavenPublish = "0.29.0" [libraries] desugar_jdk_libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar_jdk_libs" } @@ -31,10 +32,10 @@ kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", # AndroidX androidx-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "ktx" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } -androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx" } -androidx-lifecycle-runtime-compose-android = { module = "androidx.lifecycle:lifecycle-runtime-compose-android", version.ref = "lifecycleRuntimeComposeAndroid" } -androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx" } -androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-runtime-compose-android = { module = "androidx.lifecycle:lifecycle-runtime-compose-android", version.ref = "androidx-lifecycle" } +androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } # Jetpack Compose androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidx-activity-compose" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose" } @@ -66,4 +67,5 @@ compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = " androidLibrary = { id = "com.android.library", version.ref = "agp" } cargo-ndk = { id = "com.github.willir.rust.cargo-ndk-android", version.ref = "cargo-ndk" } ktfmt = { id = "com.ncorti.ktfmt.gradle", version.ref = "ktfmt" } -paparazzi = { id = "app.cash.paparazzi", version.ref = "paparazzi" } \ No newline at end of file +paparazzi = { id = "app.cash.paparazzi", version.ref = "paparazzi" } +mavenPublish = { id = "com.vanniktech.maven.publish", version.ref = "mavenPublish" } diff --git a/android/maplibreui/build.gradle b/android/maplibreui/build.gradle index 7707412c..851e9835 100644 --- a/android/maplibreui/build.gradle +++ b/android/maplibreui/build.gradle @@ -1,8 +1,12 @@ +import com.vanniktech.maven.publish.AndroidMultiVariantLibrary +import com.vanniktech.maven.publish.SonatypeHost + plugins { alias libs.plugins.androidLibrary alias libs.plugins.jetbrainsKotlinAndroid alias libs.plugins.ktfmt alias libs.plugins.compose.compiler + alias libs.plugins.mavenPublish } android { @@ -33,12 +37,6 @@ android { buildFeatures { compose true } - publishing { - singleVariant('release') { - withSourcesJar() - withJavadocJar() - } - } } dependencies { @@ -66,19 +64,22 @@ dependencies { testImplementation libs.junit androidTestImplementation libs.androidx.test.junit androidTestImplementation libs.androidx.test.espresso + debugImplementation libs.androidx.compose.ui.test.manifest } -publishing { - publications { - "${project.name}-release"(MavenPublication) { - groupId = 'com.stadiamaps.ferrostar' - artifactId = 'maplibreui' - version = project.version +mavenPublishing { + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + signAllPublications() - afterEvaluate { - from components.release - } - } + configure(new AndroidMultiVariantLibrary(true, true)) + + apply from: "${rootProject.projectDir}/common-pom.gradle" + + pom { + name = "Ferrostar MapLibre UI" + description = "Composable map UI components for Ferrostar built with MapLibre" + + commonPomConfig(it, true) } } diff --git a/common/Cargo.lock b/common/Cargo.lock index 79e2b13d..abd31ae5 100644 --- a/common/Cargo.lock +++ b/common/Cargo.lock @@ -328,7 +328,7 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "ferrostar" -version = "0.7.2" +version = "0.8.0" dependencies = [ "assert-json-diff", "geo", diff --git a/common/ferrostar/Cargo.toml b/common/ferrostar/Cargo.toml index ff60ebf6..64e0c290 100644 --- a/common/ferrostar/Cargo.toml +++ b/common/ferrostar/Cargo.toml @@ -2,7 +2,7 @@ lints.workspace = true [package] name = "ferrostar" -version = "0.7.2" +version = "0.8.0" readme = "README.md" description = "The core of modern turn-by-turn navigation." keywords = ["navigation", "routing", "valhalla", "osrm"] diff --git a/guide/src/android-getting-started.md b/guide/src/android-getting-started.md index 3e103d2c..38c40aff 100644 --- a/guide/src/android-getting-started.md +++ b/guide/src/android-getting-started.md @@ -7,12 +7,11 @@ We'll cover the "batteries included" approach, but flag areas for customization ### GitHub Packages -Ferrostar releases are hosted on GitHub Packages. -You’ll need to authenticate first in order to access them. -GitHub has a [guide on setting this up](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#authenticating-to-github-packages). - -(We’re [working on getting a Maven Central account](https://github.com/stadiamaps/ferrostar/issues/139) to make this easier) +Ferrostar releases (since 0.8.0) are hosted on Maven Central. +However, we are still in the process of transitioning the MapLibre composable UI wrapper. +In the meantime, you will still need to set up GitHub Packages, which requires authentication. +GitHub has a [guide on setting this up](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#authenticating-to-github-packages). Once you’ve configured GitHub credentials as project properties or environment variables, add the repository to your build script. @@ -23,14 +22,6 @@ you’ll end up with something like along these lines: dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { - maven { - url = 'https://maven.pkg.github.com/stadiamaps/ferrostar' - credentials { - username = settings.ext.find('gpr.user') ?: System.getenv('GITHUB_ACTOR') - password = settings.ext.find('gpr.token') ?: System.getenv('GITHUB_TOKEN') - } - } - // For the MapLibre compose integration maven { url = 'https://maven.pkg.github.com/Rallista/maplibre-compose-playground' @@ -52,14 +43,6 @@ And if you’re doing this directly in `build.gradle`, things look slightly diff repositories { google() mavenCentral() - - maven { - url = uri("https://maven.pkg.github.com/stadiamaps/ferrostar") - credentials { - username = project.findProperty("gpr.user") ?: System.getenv("GITHUB_ACTOR") - password = project.findProperty("gpr.token") ?: System.getenv("GITHUB_TOKEN") - } - } // For the MapLibre compose integration maven {