diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..aa8f08c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,101 @@ +name: CI + +on: + pull_request: + branches: [ main ] + +jobs: + jvm: + runs-on: ubuntu-latest + env: + TEST_API_KEY: ${{ secrets.ALPHA_TEST_AUTH_TOKEN }} + TEST_CACHE_NAME: kotlin-integration-test-jvm-ci-${{ github.sha }} + + steps: + - name: Checkout project + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: 'corretto' + + # The Android SDK is required to build the project, even if we are not running Android tests. + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + +# - name: Verify README generation +# uses: momentohq/standards-and-practices/github-actions/oss-readme-template@gh-actions-v2 +# with: +# project_status: official +# project_stability: stable +# project_type: sdk +# sdk_language: Java +# dev_docs_slug: java + + - name: Commitlint and Other Shared Build Steps + uses: momentohq/standards-and-practices/github-actions/shared-build@gh-actions-v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and test project + uses: gradle/gradle-build-action@v2.11.1 + with: + arguments: clean build + + android: + # The Android emulator only has hardware acceleration on macOS. + runs-on: macos-latest + strategy: + matrix: + api-level: [ 23 ] + env: + TEST_API_KEY: ${{ secrets.ALPHA_TEST_AUTH_TOKEN }} + TEST_CACHE_NAME: kotlin-integration-test-android-ci-${{ github.sha }} + + steps: + - name: Checkout project + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: 'corretto' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Build project + uses: gradle/gradle-build-action@v2.11.1 + with: + arguments: clean build -x jvmTest -x testDebugUnitTest -x testReleaseUnitTest + + - name: AVD cache + uses: actions/cache@v3 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-${{ matrix.api-level }} + + - name: create AVD and generate snapshot for caching + if: steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + force-avd-creation: false + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: false + script: echo "Generated AVD snapshot for caching." + + - name: run tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + force-avd-creation: false + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + script: ./gradlew connectedCheck diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..cc1849f --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,73 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: CodeQL + +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + schedule: + - cron: '38 23 * * 2' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + env: + TEST_AUTH_TOKEN: ${{ secrets.ALPHA_TEST_AUTH_TOKEN }} + TEST_CACHE_NAME: dummy + + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'java-kotlin' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: 'corretto' + + - name: Build project + uses: gradle/gradle-build-action@v2.11.1 + with: + arguments: clean build -x jvmTest -x testDebugUnitTest -x testReleaseUnitTest + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..530f07f --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,23 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable +# versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: Dependency Review +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Dependency Review + uses: actions/dependency-review-action@v3 diff --git a/build.gradle.kts b/build.gradle.kts index c9713f3..e7419fa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,6 +25,7 @@ android { minSdk = 23 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments["TestApiKey"] = System.getenv("TEST_API_KEY") ?: "noApiKeySet" + testInstrumentationRunnerArguments["TestCacheName"] = System.getenv("TEST_CACHE_NAME") ?: "test-android-cache" } testOptions { @@ -90,6 +91,14 @@ kotlin { } } } + + targets.forEach { + it.compilations.all { + kotlinOptions { + freeCompilerArgs += "-Xexpect-actual-classes" + } + } + } } tasks.withType().configureEach { diff --git a/src/androidInstrumentedTest/kotlin/software/momento/kotlin/sdk/BaseAndroidTestClass.kt b/src/androidInstrumentedTest/kotlin/software/momento/kotlin/sdk/BaseAndroidTestClass.kt index 6759456..2d5ff79 100644 --- a/src/androidInstrumentedTest/kotlin/software/momento/kotlin/sdk/BaseAndroidTestClass.kt +++ b/src/androidInstrumentedTest/kotlin/software/momento/kotlin/sdk/BaseAndroidTestClass.kt @@ -11,17 +11,19 @@ import kotlin.time.Duration.Companion.seconds open class BaseAndroidTestClass { companion object { - val cacheName: String = System.getenv("TEST_CACHE_NAME") ?: "kotlin-android-integration-${UUID.randomUUID()}" - @JvmStatic protected lateinit var credentialProvider: CredentialProvider lateinit var cacheClient: CacheClient + lateinit var cacheName: String @JvmStatic @BeforeClass fun createCacheClient() { + // Instrumented Android tests cannot access environment variables directly, so we + // pass them in as arguments to the test runner. They are defined in build.gradle.kts. val arguments = InstrumentationRegistry.getArguments() val apiKey = arguments.getString("TestApiKey")!! + cacheName = arguments.getString("TestCacheName")!! credentialProvider = CredentialProvider.fromString(apiKey) cacheClient = CacheClient( credentialProvider = credentialProvider, diff --git a/src/androidMain/kotlin/software/momento/kotlin/sdk/internal/InternalTopicClient.android.kt b/src/androidMain/kotlin/software/momento/kotlin/sdk/internal/InternalTopicClient.android.kt index 97ce704..826f93e 100644 --- a/src/androidMain/kotlin/software/momento/kotlin/sdk/internal/InternalTopicClient.android.kt +++ b/src/androidMain/kotlin/software/momento/kotlin/sdk/internal/InternalTopicClient.android.kt @@ -159,7 +159,7 @@ internal actual class InternalTopicClient actual constructor( this.cacheName = cacheName this.topic = topicName if (lastSequenceNumber != null) { - this.resumeAtTopicSequenceNumber = lastSequenceNumber as Long + this.resumeAtTopicSequenceNumber = lastSequenceNumber } }.build() } diff --git a/src/jvmMain/kotlin/software/momento/kotlin/sdk/internal/InternalTopicClient.jvm.kt b/src/jvmMain/kotlin/software/momento/kotlin/sdk/internal/InternalTopicClient.jvm.kt index 4d76a4b..1dfe4a9 100644 --- a/src/jvmMain/kotlin/software/momento/kotlin/sdk/internal/InternalTopicClient.jvm.kt +++ b/src/jvmMain/kotlin/software/momento/kotlin/sdk/internal/InternalTopicClient.jvm.kt @@ -159,7 +159,7 @@ internal actual class InternalTopicClient actual constructor( this.cacheName = cacheName this.topic = topicName if (lastSequenceNumber != null) { - this.resumeAtTopicSequenceNumber = lastSequenceNumber as Long + this.resumeAtTopicSequenceNumber = lastSequenceNumber } }.build() }