diff --git a/.github/workflows/gradle_task.yml b/.github/workflows/run_gradle_task.yml similarity index 56% rename from .github/workflows/gradle_task.yml rename to .github/workflows/run_gradle_task.yml index e799f7e8..5dcc824d 100644 --- a/.github/workflows/gradle_task.yml +++ b/.github/workflows/run_gradle_task.yml @@ -5,7 +5,6 @@ run-name: "Gradle Task ${{ inputs.gradle-task }} @ ${{ inputs.runs-on }}" on: workflow_dispatch: - workflow_call: inputs: gradle-task: @@ -20,12 +19,13 @@ on: concurrency: # note: the Workflow inputs are also included in the concurrency group - group: "${{ github.workflow }} ${{ join(inputs.*) }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + group: "Gradle Task: ${{ github.workflow }} ${{ join(inputs.*) }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" cancel-in-progress: true permissions: contents: read + checks: write # required by mikepenz/action-junit-report jobs: @@ -35,19 +35,21 @@ jobs: name: "./gradlew ${{ inputs.gradle-task}} @ ${{ inputs.runs-on }}" timeout-minutes: 60 steps: + + ### Gradle task ### + - name: Checkout the repo uses: actions/checkout@v3 + - name: Validate Gradle Wrapper + uses: gradle/wrapper-validation-action@v1 + - name: Setup JDK uses: actions/setup-java@v3 with: distribution: temurin java-version: 11 - - uses: gradle/gradle-build-action@v2 - with: - gradle-home-cache-cleanup: true - - name: Cache NPM uses: actions/cache@v3 env: @@ -61,14 +63,32 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- - - name: Run ${{ inputs.gradle-task }} - run: >- - ./gradlew ${{ inputs.gradle-task }} + - uses: gradle/gradle-build-action@v2 + with: + gradle-home-cache-cleanup: true + arguments: ${{ inputs.gradle-task }} + env: + ORG_GRADLE_PROJECT_sonatypeRepositoryUsername: ${{ secrets.MAVEN_SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_sonatypeRepositoryPassword: ${{ secrets.MAVEN_SONATYPE_PASSWORD }} + "ORG_GRADLE_PROJECT_signing.keyId": ${{ secrets.MAVEN_SONATYPE_SIGNING_KEY_ID }} + "ORG_GRADLE_PROJECT_signing.key": ${{ secrets.MAVEN_SONATYPE_SIGNING_KEY }} + "ORG_GRADLE_PROJECT_signing.password": ${{ secrets.MAVEN_SONATYPE_SIGNING_PASSWORD }} - name: Upload build reports if: failure() uses: actions/upload-artifact@v3 with: - name: build-report-${{ runner.os }}-${{ github.action }} - path: "**/build/reports/" + name: build-report-${{ runner.os }}${{ github.action }} + path: | + **/build/reports/ + **/*.hprof + **/*.log if-no-files-found: ignore + + - name: Publish Test Reports + uses: mikepenz/action-junit-report@v3 + if: always() + with: + report_paths: | + **/build/test-results/**/TEST-*.xml + require_tests: false diff --git a/.github/workflows/run_publish_maven.yml b/.github/workflows/run_publish_maven.yml new file mode 100644 index 00000000..6b79b4bd --- /dev/null +++ b/.github/workflows/run_publish_maven.yml @@ -0,0 +1,33 @@ +name: Publish Maven + + +on: + workflow_dispatch: + workflow_call: + + +concurrency: + group: "Publish Maven: ${{ github.workflow }}" + cancel-in-progress: false + + +permissions: + contents: write + packages: write + checks: write + + +jobs: + + sonatype-release: + if: github.ref == 'refs/heads/main' + permissions: + contents: read + packages: write + checks: write + uses: ./.github/workflows/run_gradle_task.yml + secrets: inherit + with: + runs-on: macos-latest # only macOS supports building all Kotlin targets + gradle-task: >- + publishAllPublicationsToSonatypeReleaseRepository --stacktrace --no-configuration-cache --no-parallel diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/run_publish_site.yml similarity index 83% rename from .github/workflows/deploy-site.yml rename to .github/workflows/run_publish_site.yml index 616157c5..66c4e1f3 100644 --- a/.github/workflows/deploy-site.yml +++ b/.github/workflows/run_publish_site.yml @@ -1,15 +1,13 @@ -name: Deploy Site +name: Publish Site + on: workflow_dispatch: workflow_call: - push: - tags: - - "v[0-9]+.[0-9]+.[0-9]+" concurrency: - group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + group: "Publish Site: ${{ github.workflow }}" cancel-in-progress: true @@ -21,16 +19,15 @@ jobs: - name: Checkout the repo uses: actions/checkout@v3 + - name: Validate Gradle Wrapper + uses: gradle/wrapper-validation-action@v1 + - name: Setup JDK uses: actions/setup-java@v3 with: distribution: temurin java-version: 11 - - uses: gradle/gradle-build-action@v2 - with: - gradle-home-cache-cleanup: true - - name: Cache NPM uses: actions/cache@v3 env: @@ -45,7 +42,10 @@ jobs: ${{ runner.os }}- - name: docusaurus build - run: ./gradlew docusaurusBuild + uses: gradle/gradle-build-action@v2 + with: + gradle-home-cache-cleanup: true + arguments: docusaurusBuild - uses: actions/upload-pages-artifact@v2 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/run_tests.yml similarity index 58% rename from .github/workflows/tests.yml rename to .github/workflows/run_tests.yml index 25ce5c59..870e9438 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/run_tests.yml @@ -1,22 +1,17 @@ name: Tests on: - pull_request: workflow_dispatch: workflow_call: - merge_group: - push: - branches: - - "main" - - "renovate/**" concurrency: - group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + group: "Tests: ${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" cancel-in-progress: true permissions: contents: read + checks: write # required by mikepenz/action-junit-report jobs: @@ -26,14 +21,15 @@ jobs: matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] fail-fast: false - uses: ./.github/workflows/gradle_task.yml + uses: ./.github/workflows/run_gradle_task.yml with: runs-on: ${{ matrix.os }} gradle-task: >- check -Pkxstsgen_enableTsCompileTests=true --stacktrace build-site: - uses: ./.github/workflows/gradle_task.yml + # verify that the site can be built, but don't deploy it + uses: ./.github/workflows/run_gradle_task.yml with: runs-on: ubuntu-latest gradle-task: docusaurusBuild diff --git a/.github/workflows/workflow_pull_request.yml b/.github/workflows/workflow_pull_request.yml new file mode 100644 index 00000000..e8c7ac96 --- /dev/null +++ b/.github/workflows/workflow_pull_request.yml @@ -0,0 +1,20 @@ +name: Pull Requests + + +on: + workflow_dispatch: + pull_request: + + +concurrency: + group: "Pull Requests: ${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + cancel-in-progress: true + + +jobs: + + tests: + uses: ./.github/workflows/run_tests.yml + permissions: + contents: read + checks: write diff --git a/.github/workflows/workflow_release.yml b/.github/workflows/workflow_release.yml new file mode 100644 index 00000000..0e5a7173 --- /dev/null +++ b/.github/workflows/workflow_release.yml @@ -0,0 +1,45 @@ +name: Releases + + +on: + workflow_dispatch: + push: + branches: [ main ] + release: + types: [ created ] + + +concurrency: + group: "Releases: ${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + cancel-in-progress: true + + +jobs: + + tests: + uses: ./.github/workflows/run_tests.yml + permissions: + checks: write + contents: read + + publish-maven: + needs: tests + if: github.ref == 'refs/heads/main' + uses: ./.github/workflows/run_publish_maven.yml + secrets: inherit + permissions: + checks: write + contents: write + packages: write + + publish-site: + needs: tests + # only publish site when releasing + if: github.ref == 'refs/heads/main' && github.event_name == 'release' && github.event.action == 'created' + uses: ./.github/workflows/run_publish_site.yml + permissions: + checks: write + contents: read + id-token: write # to verify the deployment originates from an appropriate source + packages: write + pages: write # to deploy to Pages diff --git a/buildSrc/src/main/kotlin/buildsrc/config/publishing.kt b/buildSrc/src/main/kotlin/buildsrc/config/publishing.kt deleted file mode 100644 index 755dae73..00000000 --- a/buildSrc/src/main/kotlin/buildsrc/config/publishing.kt +++ /dev/null @@ -1,34 +0,0 @@ -package buildsrc.config - -import org.gradle.api.Project -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.getByType -import org.gradle.plugins.signing.SigningExtension - - -fun MavenPublication.createKxsTsGenPom(): Unit = pom { - name.set("Kotlinx Serialization Typescript Generator") - description.set("KxsTsGen creates TypeScript interfaces from Kotlinx Serialization @Serializable classes") - url.set("https://github.com/adamko-dev/kotlinx-serialization-typescript-generator") - - licenses { - license { - name.set("The Apache License, Version 2.0") - url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") - } - } - - developers { - developer { - email.set("adam@adamko.dev") - } - } - - scm { - connection.set("scm:git:git://github.com/adamko-dev/kotlinx-serialization-typescript-generator.git") - developerConnection.set("scm:git:ssh://github.com:adamko-dev/kotlinx-serialization-typescript-generator.git") - url.set("https://github.com/adamko-dev/kotlinx-serialization-typescript-generator") - } -} diff --git a/buildSrc/src/main/kotlin/buildsrc/convention/maven-publish.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/convention/maven-publish.gradle.kts index a2c94c35..a17145dc 100644 --- a/buildSrc/src/main/kotlin/buildsrc/convention/maven-publish.gradle.kts +++ b/buildSrc/src/main/kotlin/buildsrc/convention/maven-publish.gradle.kts @@ -1,6 +1,5 @@ package buildsrc.convention -import buildsrc.config.createKxsTsGenPom import buildsrc.config.credentialsAction import buildsrc.config.isKotlinMultiplatformJavaEnabled import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin @@ -14,36 +13,44 @@ plugins { val sonatypeRepositoryCredentials: Provider> = providers.credentialsAction("sonatypeRepository") +val projectVersion: Provider = provider { project.version.toString() } -val sonatypeRepositoryReleaseUrl: Provider = provider { - if (version.toString().endsWith("SNAPSHOT")) { - "https://s01.oss.sonatype.org/content/repositories/snapshots/" - } else { +val sonatypeRepositoryReleaseUrl: Provider = projectVersion.map { version -> + val isRelease = version.endsWith("SNAPSHOT") + if (isRelease) { "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" + } else { + "https://s01.oss.sonatype.org/content/repositories/snapshots/" } } +//region Signing val signingKeyId: Provider = providers.gradleProperty("signing.keyId") val signingKey: Provider = providers.gradleProperty("signing.key") val signingPassword: Provider = providers.gradleProperty("signing.password") -val signingSecretKeyRingFile: Provider = - providers.gradleProperty("signing.secretKeyRingFile") - signing { - if (sonatypeRepositoryCredentials.isPresent()) { - if (signingKeyId.isPresent() && signingKey.isPresent() && signingPassword.isPresent()) { - useInMemoryPgpKeys(signingKeyId.get(), signingKey.get(), signingPassword.get()) - } else { - useGpgCmd() - } + logger.info("maven-publishing.gradle.kts enabled signing for ${project.path}") + + val keyId = signingKeyId.orNull + val key = signingKey.orNull + val password = signingPassword.orNull + + if (!keyId.isNullOrBlank() && !key.isNullOrBlank() && !password.isNullOrBlank()) { + useInMemoryPgpKeys(keyId, key, password) } -} + // only require signing when publishing to Sonatype + setRequired({ + gradle.taskGraph.allTasks.filterIsInstance().any { + it.repository.name == "SonatypeRelease" + } + }) +} afterEvaluate { // Register signatures afterEvaluate, otherwise the signing plugin creates the signing tasks @@ -51,13 +58,12 @@ afterEvaluate { // Use .all { }, not .configureEach { }, otherwise the signing plugin doesn't create the tasks // soon enough. - if (sonatypeRepositoryCredentials.isPresent()) { - publishing.publications.withType().all { - signing.sign(this) - logger.lifecycle("configuring signature for publication ${this.name}") - } + publishing.publications.withType().all { + signing.sign(this) + logger.lifecycle("configuring signature for publication ${this.name}") } } +//endregion //region Javadoc JAR stub // use creating, not registering, because the signing plugin doesn't accept task providers @@ -66,24 +72,14 @@ val javadocJarStub by tasks.creating(Jar::class) { description = "Stub javadoc.jar artifact (required by Maven Central)" archiveClassifier.set("javadoc") } - -tasks.withType().all { - dependsOn(javadocJarStub) -} - -if (sonatypeRepositoryCredentials.isPresent()) { - val signingTasks = signing.sign(javadocJarStub) - tasks.withType().all { - signingTasks.forEach { dependsOn(it) } - } -} //endregion + publishing { if (sonatypeRepositoryCredentials.isPresent()) { repositories { maven(sonatypeRepositoryReleaseUrl) { - name = "sonatype" + name = "SonatypeRelease" credentials(sonatypeRepositoryCredentials.get()) } // // publish to local dir, for testing @@ -92,7 +88,30 @@ publishing { // } } publications.withType().configureEach { - createKxsTsGenPom() + pom { + name.set("Kotlinx Serialization Typescript Generator") + description.set("KxsTsGen creates TypeScript interfaces from Kotlinx Serialization @Serializable classes") + url.set("https://github.com/adamko-dev/kotlinx-serialization-typescript-generator") + + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + + developers { + developer { + email.set("adam@adamko.dev") + } + } + + scm { + connection.set("scm:git:git://github.com/adamko-dev/kotlinx-serialization-typescript-generator.git") + developerConnection.set("scm:git:ssh://github.com:adamko-dev/kotlinx-serialization-typescript-generator.git") + url.set("https://github.com/adamko-dev/kotlinx-serialization-typescript-generator") + } + } artifact(javadocJarStub) } } @@ -126,6 +145,7 @@ plugins.withType().configureEach { } } + //region Fix Gradle warning about signing tasks using publishing task outputs without explicit dependencies // https://youtrack.jetbrains.com/issue/KT-46466 https://github.com/gradle/gradle/issues/26091 tasks.withType().configureEach { @@ -134,6 +154,7 @@ tasks.withType().configureEach { } //endregion + //region publishing logging tasks.withType().configureEach { val publicationGAV = provider { publication?.run { "$group:$artifactId:$version" } } @@ -145,6 +166,7 @@ tasks.withType().configureEach { } //endregion + //region IJ workarounds // manually define the Kotlin DSL accessors because IntelliJ _still_ doesn't load them properly fun Project.publishing(configure: PublishingExtension.() -> Unit): Unit =