From 4fdc5299a04f93013e7a32e46496da28bac01e6b Mon Sep 17 00:00:00 2001 From: Georgi Christov <7644787+gchristov@users.noreply.github.com> Date: Thu, 21 Mar 2024 21:04:44 +0100 Subject: [PATCH] Make guardian API key secret and tidy up CI (#29) --- .github/workflows/check.yml | 247 ++++++++++++++++++ .github/workflows/check_build.yml | 218 ---------------- .gitignore | 1 + android/feed/feature/build.gradle.kts | 4 - ...{BaseExtensions.kt => BaseExtensionExt.kt} | 0 .../{ProjectExtensions.kt => ProjectExt.kt} | 21 +- multiplatform/common/network/build.gradle.kts | 16 +- .../common/network/MplCommonNetworkModule.kt | 6 + .../common/network/NetworkConfig.kt | 6 + .../multiplatform/feed/data/FeedApi.kt | 16 +- .../feed/data/MplFeedDataModule.kt | 16 +- .../post/data/MplPostDataModule.kt | 16 +- .../multiplatform/post/data/PostApi.kt | 19 +- secrets.sh | 7 + settings.gradle.kts | 12 + 15 files changed, 345 insertions(+), 260 deletions(-) create mode 100644 .github/workflows/check.yml delete mode 100644 .github/workflows/check_build.yml rename gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/{BaseExtensions.kt => BaseExtensionExt.kt} (100%) rename gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/{ProjectExtensions.kt => ProjectExt.kt} (59%) create mode 100644 multiplatform/common/network/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/common/network/NetworkConfig.kt create mode 100644 secrets.sh diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..1d4b38a --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,247 @@ +name: check + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + JAVA_VERSION: "17" + JAVA_DISTRIBUTION: "zulu" + XCODE_VERSION: "13.3" + XCODE_CACHE: "CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++" + IOS_SIMULATOR: "platform=iOS Simulator,name=iPhone 11,OS=15.4" + ANDROID_COMPILE_SDK: "31" + ANDROID_EMULATOR_ARCHITECTURE: "x86_64" + GUARDIAN_API_KEY: ${{ secrets.GUARDIAN_API_KEY }} + GUARDIAN_API_URL: ${{ secrets.GUARDIAN_API_URL }} + +jobs: + check-unit-test: + runs-on: ubuntu-20.04 + concurrency: + group: ${{ github.ref }}-check-unit-test + cancel-in-progress: true + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 # By default, cache is only saved on the 'master' branch + - name: Set up Konan + uses: actions/cache@v4 + id: check-unit-test-konan + with: + path: '~/.konan/**' + key: check-unit-test-konan + - name: Set up secrets + run: | + bash secrets.sh + - name: Unit test + run: | + set -o pipefail && + ./gradlew --no-daemon --continue testDebugUnitTest + - name: Generate test report + uses: mikepenz/action-junit-report@v4 + if: always() # Ensure all test reports are collected, even after errors + with: + report_paths: | + **/TEST-*.xml + check_name: 'check-unit-test-results' + - name: Artifacts + uses: actions/upload-artifact@v4 + if: always() # Ensure all artifacts are collected, even after errors + with: + name: Unit tests + path: | + **/TEST-*.xml + + ios-check-build: + runs-on: macos-12 + concurrency: + group: ${{ github.ref }}-ios-check-build + cancel-in-progress: true + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 # By default, cache is only saved on the 'master' branch + - name: Set up Konan + uses: actions/cache@v4 + id: ios-check-build-konan + with: + path: '~/.konan/**' + key: ios-check-build-konan + - name: Set up secrets + run: | + bash secrets.sh + - name: Set up Xcode version + run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app + - name: Set up Xcode + uses: mikehardy/buildcache-action@v2 + - name: Compile iOS app + run: | + cd appIos && + set -o pipefail && + xcodebuild ${{ env.XCODE_CACHE }} -workspace appIos.xcworkspace -scheme "appIos" -sdk iphonesimulator -destination '${{ env.IOS_SIMULATOR }}' build | tee xcodebuild.log | xcpretty && + cd .. + - name: Artifacts + uses: actions/upload-artifact@v4 + if: always() # Ensure all artifacts are collected, even after errors + with: + name: iOS Build + path: | + appIos/xcodebuild.log + ~/Library/Developer/Xcode/DerivedData/**/Build/Products/**/appIos.app + ~/Library/Developer/Xcode/DerivedData/**/Build/Products/**/appIos.app.dSYM + **/build + **/secrets.properties + + ios-check-test: + runs-on: macos-12 + concurrency: + group: ${{ github.ref }}-ios-check-test + cancel-in-progress: true + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 # By default, cache is only saved on the 'master' branch + - name: Set up Konan + uses: actions/cache@v4 + id: ios-check-test-konan + with: + path: '~/.konan/**' + key: ios-check-test-konan + - name: Set up secrets + run: | + bash secrets.sh + - name: Set up Xcode version + run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app + - name: Set up Xcode + uses: mikehardy/buildcache-action@v2 + - name: iOS tests + run: | + cd appIos && + set -o pipefail && + xcodebuild ${{ env.XCODE_CACHE }} -workspace appIos.xcworkspace -scheme "appIos" -sdk iphonesimulator -destination '${{ env.IOS_SIMULATOR }}' test | tee xcodebuild.log | xcpretty && + cd .. + - name: Artifacts + uses: actions/upload-artifact@v4 + if: always() # Ensure all artifacts are collected, even after errors + with: + name: iOS Tests + path: | + appIos/xcodebuild.log + + android-check-build: + runs-on: ubuntu-20.04 + concurrency: + group: ${{ github.ref }}-android-check-build + cancel-in-progress: true + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 # By default, cache is only saved on the 'master' branch + - name: Set up Konan + uses: actions/cache@v4 + id: android-check-build-konan + with: + path: '~/.konan/**' + key: android-check-build-konan + - name: Set up secrets + run: | + bash secrets.sh + - name: Compile Android app + run: | + set -o pipefail && + ./gradlew android:app:assembleDebug + - name: Artifacts + uses: actions/upload-artifact@v4 + if: always() # Ensure all artifacts are collected, even after errors + with: + name: Android Build + path: | + **/*.apk + **/build + **/secrets.properties + + android-check-test: + runs-on: macos-11 # Allows Android emulator hardware acceleration + concurrency: + group: ${{ github.ref }}-android-check-test + cancel-in-progress: true + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 # By default, cache is only saved on the 'master' branch + - name: Set up Konan + uses: actions/cache@v4 + id: android-check-test-konan + with: + path: '~/.konan/**' + key: android-check-test-konan + - name: Set up secrets + run: | + bash secrets.sh + - name: Set up AVD + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-${{ env.ANDROID_COMPILE_SDK }} + - name: Generate AVD cache snapshot + if: steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ env.ANDROID_COMPILE_SDK }} + arch: ${{ env.ANDROID_EMULATOR_ARCHITECTURE }} + 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 cache snapshot" + - name: Android tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ env.ANDROID_COMPILE_SDK }} + arch: ${{ env.ANDROID_EMULATOR_ARCHITECTURE }} + 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: set -o pipefail && ./gradlew connectedAndroidTest + - name: Artifacts + uses: actions/upload-artifact@v4 + if: always() # Ensure all artifacts are collected, even after errors + with: + name: Android Tests + path: | + **/test-result.pb diff --git a/.github/workflows/check_build.yml b/.github/workflows/check_build.yml deleted file mode 100644 index ecc04f7..0000000 --- a/.github/workflows/check_build.yml +++ /dev/null @@ -1,218 +0,0 @@ -name: Check Build - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -env: - JAVA_VERSION: "17" - XCODE_VERSION: "13.3" - XCODE_CACHE: "CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++" - IOS_SIMULATOR: "platform=iOS Simulator,name=iPhone 11,OS=15.4" - ANDROID_COMPILE_SDK: "31" - ANDROID_EMULATOR_ARCHITECTURE: "x86_64" - -jobs: - kmmTest: - runs-on: ubuntu-20.04 - concurrency: - group: ${{ github.ref }}_kmmTest - cancel-in-progress: true - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup Java - uses: actions/setup-java@v2 - with: - distribution: 'zulu' - java-version: ${{ env.JAVA_VERSION }} - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - - name: KMM cache - uses: actions/cache@v2 - id: konan-kmm - with: - path: '~/.konan/**' - key: konan-kmm - - name: KMM tests - run: set -o pipefail && ./gradlew --continue testDebugUnitTest - # Always run this job even if the previous steps fail to collect all test reports - - name: Generate KMM test report - uses: mikepenz/action-junit-report@v3 - if: always() - with: - report_paths: | - **/TEST-*.xml - check_name: 'kmmTestResults' - # Always run this job even if the previous steps fail to collect all artifacts - - name: Save artifacts - uses: actions/upload-artifact@v3 - if: always() - with: - name: KMM test results - path: | - **/TEST-*.xml - - iosBuild: - runs-on: macos-12 - concurrency: - group: ${{ github.ref }}_iosBuild - cancel-in-progress: true - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup Java - uses: actions/setup-java@v2 - with: - distribution: 'zulu' - java-version: ${{ env.JAVA_VERSION }} - - name: Setup Xcode - run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - - name: KMM cache - uses: actions/cache@v2 - id: konan-ios - with: - path: '~/.konan/**' - key: konan-ios - - name: Xcode cache - uses: mikehardy/buildcache-action@v2 - - name: Compile iOS app - run: | - cd appIos - set -o pipefail && xcodebuild ${{ env.XCODE_CACHE }} -workspace appIos.xcworkspace -scheme "appIos" -sdk iphonesimulator -destination '${{ env.IOS_SIMULATOR }}' build | tee xcodebuild.log | xcpretty - - name: Save artifacts - uses: actions/upload-artifact@v3 - with: - name: iOS build - path: | - appIos/xcodebuild.log - ~/Library/Developer/Xcode/DerivedData/**/Build/Products/**/appIos.app - ~/Library/Developer/Xcode/DerivedData/**/Build/Products/**/appIos.app.dSYM - - iosTest: - runs-on: macos-12 - concurrency: - group: ${{ github.ref }}_iosTest - cancel-in-progress: true - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup Java - uses: actions/setup-java@v2 - with: - distribution: 'zulu' - java-version: ${{ env.JAVA_VERSION }} - - name: Setup Xcode - run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - - name: KMM cache - uses: actions/cache@v2 - id: konan-ios-test - with: - path: '~/.konan/**' - key: konan-ios-test - - name: Xcode cache - uses: mikehardy/buildcache-action@v2 - - name: iOS tests - run: | - cd appIos - set -o pipefail && xcodebuild ${{ env.XCODE_CACHE }} -workspace appIos.xcworkspace -scheme "appIos" -sdk iphonesimulator -destination '${{ env.IOS_SIMULATOR }}' test | tee xcodebuild.log | xcpretty - - name: Save artifacts - uses: actions/upload-artifact@v3 - with: - name: iOS test results - path: | - appIos/xcodebuild.log - - androidBuild: - runs-on: ubuntu-20.04 - concurrency: - group: ${{ github.ref }}_androidBuild - cancel-in-progress: true - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup Java - uses: actions/setup-java@v2 - with: - distribution: 'zulu' - java-version: ${{ env.JAVA_VERSION }} - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - - name: KMM cache - uses: actions/cache@v2 - id: konan-android - with: - path: '~/.konan/**' - key: konan-android - - name: Compile Android app - run: set -o pipefail && ./gradlew android:app:assembleDebug - - name: Save artifacts - uses: actions/upload-artifact@v3 - with: - name: Android build - path: | - **/*.apk - - androidTest: - # Needed because of hardware acceleration for the emulator - runs-on: macos-11 - concurrency: - group: ${{ github.ref }}_androidTest - cancel-in-progress: true - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup Java - uses: actions/setup-java@v2 - with: - distribution: 'zulu' - java-version: ${{ env.JAVA_VERSION }} - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - - name: KMM cache - uses: actions/cache@v2 - id: konan-android-test - with: - path: '~/.konan/**' - key: konan-android-test - - name: AVD cache - uses: actions/cache@v2 - id: avd-cache - with: - path: | - ~/.android/avd/* - ~/.android/adb* - key: avd-${{ env.ANDROID_COMPILE_SDK }} - - name: Generate AVD cache snapshot - if: steps.avd-cache.outputs.cache-hit != 'true' - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: ${{ env.ANDROID_COMPILE_SDK }} - arch: ${{ env.ANDROID_EMULATOR_ARCHITECTURE }} - 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 cache snapshot" - - name: Android tests - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: ${{ env.ANDROID_COMPILE_SDK }} - arch: ${{ env.ANDROID_EMULATOR_ARCHITECTURE }} - 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: set -o pipefail && ./gradlew connectedAndroidTest - # Always run this job even if the previous steps fail to collect all artifacts - - name: Save artifacts - uses: actions/upload-artifact@v3 - if: always() - with: - name: Android test results - path: | - **/test-result.pb diff --git a/.gitignore b/.gitignore index a633f38..33b65e5 100755 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ appIos/common-design/common-design.xcodeproj/xcuserdata appIos/common-swiftui-test/common-swiftui-test.xcodeproj/xcuserdata appIos/feed-test-fixtures/feed-test-fixtures.xcodeproj/xcuserdata appIos/post-test-fixtures/post-test-fixtures.xcodeproj/xcuserdata +secrets.properties diff --git a/android/feed/feature/build.gradle.kts b/android/feed/feature/build.gradle.kts index acbb0c0..932fe0c 100755 --- a/android/feed/feature/build.gradle.kts +++ b/android/feed/feature/build.gradle.kts @@ -5,10 +5,6 @@ plugins { android { defaultConfig { namespace = "com.gchristov.newsfeed.android.feed.feature" - buildConfigField("int", "PAGE_SIZE", "10") - } - buildFeatures { - buildConfig = true } } diff --git a/gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/BaseExtensions.kt b/gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/BaseExtensionExt.kt similarity index 100% rename from gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/BaseExtensions.kt rename to gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/BaseExtensionExt.kt diff --git a/gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/ProjectExtensions.kt b/gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/ProjectExt.kt similarity index 59% rename from gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/ProjectExtensions.kt rename to gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/ProjectExt.kt index c993fa3..3623214 100644 --- a/gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/ProjectExtensions.kt +++ b/gradle-plugins/conventions/src/main/kotlin/com/gchristov/newsfeed/gradleplugins/ProjectExt.kt @@ -7,6 +7,8 @@ import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import java.io.FileInputStream +import java.util.Properties internal val Project.libs get(): VersionCatalog = extensions.getByType().named("libs") @@ -16,14 +18,17 @@ internal fun Project.configureKotlin() { tasks.withType().configureEach { kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() -// // Treat all Kotlin warnings as errors (disabled by default) -// // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties -// val warningsAsErrors: String? by project -// allWarningsAsErrors = warningsAsErrors.toBoolean() -// freeCompilerArgs = freeCompilerArgs + listOf( -// // Enable experimental coroutines APIs, including Flow -// "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", -// ) } } +} + +fun Project.envSecret(key: String): String { + val propFile = file("./secrets.properties") + val properties = Properties() + properties.load(FileInputStream(propFile)) + val property = properties.getProperty(key) + if (property.isNullOrBlank()) { + throw IllegalStateException("Required property is missing: property=$key") + } + return property } \ No newline at end of file diff --git a/multiplatform/common/network/build.gradle.kts b/multiplatform/common/network/build.gradle.kts index 311ab6a..c279a06 100755 --- a/multiplatform/common/network/build.gradle.kts +++ b/multiplatform/common/network/build.gradle.kts @@ -1,3 +1,5 @@ +import com.gchristov.newsfeed.gradleplugins.envSecret + val packageId = "com.gchristov.newsfeed.multiplatform.common.network" plugins { @@ -30,21 +32,17 @@ kotlin { buildkonfig { packageName = packageId + exposeObjectWithName = "BuildConfig" defaultConfigs { buildConfigField( type = com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING, - name = "API_KEY", - value = "86cb30cc-1eb4-478f-a147-f73e02862a2e" - ) - buildConfigField( - type = com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING, - name = "API_URL", - value = "https://content.guardianapis.com" + name = "GUARDIAN_API_KEY", + value = project.envSecret("GUARDIAN_API_KEY") ) buildConfigField( type = com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING, - name = "API_AUTH_HEADER", - value = "api-key" + name = "GUARDIAN_API_URL", + value = project.envSecret("GUARDIAN_API_URL") ) } } diff --git a/multiplatform/common/network/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/common/network/MplCommonNetworkModule.kt b/multiplatform/common/network/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/common/network/MplCommonNetworkModule.kt index 0089fc5..e6d043c 100755 --- a/multiplatform/common/network/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/common/network/MplCommonNetworkModule.kt +++ b/multiplatform/common/network/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/common/network/MplCommonNetworkModule.kt @@ -12,6 +12,7 @@ object MplCommonNetworkModule : DependencyModule() { override fun bindDependencies(builder: DI.Builder) { builder.apply { + bindSingleton { provideNetworkConfig() } bindSingleton { provideJsonNetworkClient( log = instance(), @@ -21,6 +22,11 @@ object MplCommonNetworkModule : DependencyModule() { } } + private fun provideNetworkConfig(): NetworkConfig = NetworkConfig( + guardianApiKey = BuildConfig.GUARDIAN_API_KEY, + guardianApiUrl = BuildConfig.GUARDIAN_API_URL, + ) + private fun provideJsonNetworkClient( log: Logger, jsonSerializer: JsonSerializer.Default, diff --git a/multiplatform/common/network/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/common/network/NetworkConfig.kt b/multiplatform/common/network/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/common/network/NetworkConfig.kt new file mode 100644 index 0000000..2b22394 --- /dev/null +++ b/multiplatform/common/network/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/common/network/NetworkConfig.kt @@ -0,0 +1,6 @@ +package com.gchristov.newsfeed.multiplatform.common.network + +data class NetworkConfig( + val guardianApiKey: String, + val guardianApiUrl: String, +) diff --git a/multiplatform/feed/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/feed/data/FeedApi.kt b/multiplatform/feed/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/feed/data/FeedApi.kt index 85a9afc..5c9cf75 100755 --- a/multiplatform/feed/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/feed/data/FeedApi.kt +++ b/multiplatform/feed/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/feed/data/FeedApi.kt @@ -1,26 +1,26 @@ package com.gchristov.newsfeed.multiplatform.feed.data import com.gchristov.newsfeed.multiplatform.common.network.NetworkClient +import com.gchristov.newsfeed.multiplatform.common.network.NetworkConfig import io.ktor.client.request.get import io.ktor.client.request.header import io.ktor.client.statement.HttpResponse -internal class FeedApi(private val client: NetworkClient.Json) { +internal class FeedApi( + private val client: NetworkClient.Json, + private val config: NetworkConfig, +) { suspend fun feed( pageId: Int, feedQuery: String ): HttpResponse = client.http.get( - "${Domain}/search?" + "${config.guardianApiUrl}/search?" + "order-by=newest" + "&show-fields=headline,thumbnail" + "&page-size=20" + "&page=$pageId" + "&q=$feedQuery" ) { - // TODO: Make this secret - header("api-key", "86cb30cc-1eb4-478f-a147-f73e02862a2e") + header("api-key", config.guardianApiKey) } -} - -// TODO: Make this secret -private const val Domain = "https://content.guardianapis.com" \ No newline at end of file +} \ No newline at end of file diff --git a/multiplatform/feed/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/feed/data/MplFeedDataModule.kt b/multiplatform/feed/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/feed/data/MplFeedDataModule.kt index 57886f1..dde1066 100755 --- a/multiplatform/feed/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/feed/data/MplFeedDataModule.kt +++ b/multiplatform/feed/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/feed/data/MplFeedDataModule.kt @@ -2,6 +2,7 @@ package com.gchristov.newsfeed.multiplatform.feed.data import com.gchristov.newsfeed.multiplatform.common.kotlin.di.DependencyModule import com.gchristov.newsfeed.multiplatform.common.network.NetworkClient +import com.gchristov.newsfeed.multiplatform.common.network.NetworkConfig import com.gchristov.newsfeed.multiplatform.common.persistence.SqlDriverProperties import com.gchristov.newsfeed.multiplatform.feed.data.usecase.BuildSectionedFeedUseCase import com.gchristov.newsfeed.multiplatform.feed.data.usecase.FlattenSectionedFeedUseCase @@ -22,7 +23,12 @@ object MplFeedDataModule : DependencyModule() { override fun bindDependencies(builder: DI.Builder) { builder.apply { - bindSingleton { provideFeedApi(networkClient = instance()) } + bindSingleton { + provideFeedApi( + networkClient = instance(), + networkConfig = instance(), + ) + } bindSingleton { provideFeedRepository( api = instance(), @@ -71,7 +77,13 @@ object MplFeedDataModule : DependencyModule() { sharedPreferences = sharedPreferences ) - private fun provideFeedApi(networkClient: NetworkClient.Json) = FeedApi(networkClient) + private fun provideFeedApi( + networkClient: NetworkClient.Json, + networkConfig: NetworkConfig, + ) = FeedApi( + client = networkClient, + config = networkConfig, + ) private fun provideBuildSectionedFeedUseCase() = BuildSectionedFeedUseCase( dispatcher = Dispatchers.Default, diff --git a/multiplatform/post/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/post/data/MplPostDataModule.kt b/multiplatform/post/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/post/data/MplPostDataModule.kt index 17b090d..4b1c35e 100755 --- a/multiplatform/post/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/post/data/MplPostDataModule.kt +++ b/multiplatform/post/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/post/data/MplPostDataModule.kt @@ -2,6 +2,7 @@ package com.gchristov.newsfeed.multiplatform.post.data import com.gchristov.newsfeed.multiplatform.common.kotlin.di.DependencyModule import com.gchristov.newsfeed.multiplatform.common.network.NetworkClient +import com.gchristov.newsfeed.multiplatform.common.network.NetworkConfig import com.gchristov.newsfeed.multiplatform.common.persistence.SqlDriverProperties import com.russhwolf.settings.Settings import kotlinx.coroutines.Dispatchers @@ -14,7 +15,12 @@ object MplPostDataModule : DependencyModule() { override fun bindDependencies(builder: DI.Builder) { builder.apply { - bindSingleton { providePostApi(networkClient = instance()) } + bindSingleton { + providePostApi( + networkClient = instance(), + networkConfig = instance(), + ) + } bindSingleton { providePostRepository( api = instance(), @@ -43,5 +49,11 @@ object MplPostDataModule : DependencyModule() { database = database ) - private fun providePostApi(networkClient: NetworkClient.Json) = PostApi(networkClient) + private fun providePostApi( + networkClient: NetworkClient.Json, + networkConfig: NetworkConfig, + ) = PostApi( + client = networkClient, + config = networkConfig, + ) } diff --git a/multiplatform/post/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/post/data/PostApi.kt b/multiplatform/post/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/post/data/PostApi.kt index fba6a7f..339c2ec 100755 --- a/multiplatform/post/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/post/data/PostApi.kt +++ b/multiplatform/post/data/src/commonMain/kotlin/com/gchristov/newsfeed/multiplatform/post/data/PostApi.kt @@ -1,19 +1,20 @@ package com.gchristov.newsfeed.multiplatform.post.data import com.gchristov.newsfeed.multiplatform.common.network.NetworkClient +import com.gchristov.newsfeed.multiplatform.common.network.NetworkConfig import io.ktor.client.request.get import io.ktor.client.request.header import io.ktor.client.statement.HttpResponse -internal class PostApi(private val client: NetworkClient.Json) { +internal class PostApi( + private val client: NetworkClient.Json, + private val config: NetworkConfig, +) { suspend fun post( postUrl: String, postMetadataFields: String, - ): HttpResponse = client.http.get("${Domain}/$postUrl?show-fields=$postMetadataFields") { - // TODO: Make this secret - header("api-key", "86cb30cc-1eb4-478f-a147-f73e02862a2e") - } -} - -// TODO: Make this secret -private const val Domain = "https://content.guardianapis.com" \ No newline at end of file + ): HttpResponse = + client.http.get("${config.guardianApiUrl}/$postUrl?show-fields=$postMetadataFields") { + header("api-key", config.guardianApiKey) + } +} \ No newline at end of file diff --git a/secrets.sh b/secrets.sh new file mode 100644 index 0000000..e8e7712 --- /dev/null +++ b/secrets.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e +# Exports required CI environment secrets to local secrets so that the project can use them + +# network credentials (the > is intentional to support concurrent writes) +echo GUARDIAN_API_KEY="$GUARDIAN_API_KEY" > ./multiplatform/common/network/secrets.properties +echo GUARDIAN_API_URL="$GUARDIAN_API_URL" >> ./multiplatform/common/network/secrets.properties diff --git a/settings.gradle.kts b/settings.gradle.kts index 025235e..4bf37ef 100755 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,6 +9,10 @@ pluginManagement { } } +plugins { + id("com.gradle.enterprise") version("3.16.2") +} + dependencyResolutionManagement { repositories { google() @@ -17,6 +21,14 @@ dependencyResolutionManagement { } } +gradleEnterprise { + buildScan { + termsOfServiceUrl = "https://gradle.com/terms-of-service" + termsOfServiceAgree = "yes" + publishAlways() + } +} + rootProject.name = "newsfeed-kotlin-multiplatform" // Multiplatform