From ad586a552a2b20975a90fa91cd429309630410c3 Mon Sep 17 00:00:00 2001 From: Rehan Date: Fri, 7 Feb 2025 18:13:41 +0500 Subject: [PATCH 1/4] chore: sample app build info --- .../workflows/reusable_build_sample_apps.yml | 7 +- .../buildinfo/BuildInfoMetadata.java | 77 +++++++++++++++++++ .../buildinfo/BuildInfoMetadataUtils.java | 46 +++++++++++ .../sample/java_layout/utils/ViewUtils.java | 40 +--------- samples/sample-app.gradle | 35 ++++++++- 5 files changed, 162 insertions(+), 43 deletions(-) create mode 100644 samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java create mode 100644 samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadataUtils.java diff --git a/.github/workflows/reusable_build_sample_apps.yml b/.github/workflows/reusable_build_sample_apps.yml index 7fcde66e1..8b7a5d6b9 100644 --- a/.github/workflows/reusable_build_sample_apps.yml +++ b/.github/workflows/reusable_build_sample_apps.yml @@ -22,9 +22,11 @@ jobs: - "kotlin_compose" include: # Add additional variables to each sample app build: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrixinclude - sample-app: "java_layout" + cio-workspace-name: "Mobile: Native iOS & Android" cio-cdpapikey-secret-key: "CUSTOMERIO_JAVA_WORKSPACE_CDP_API_KEY" cio-siteid-secret-key: "CUSTOMERIO_JAVA_WORKSPACE_SITE_ID" - sample-app: "kotlin_compose" + cio-workspace-name: "Mobile: xiOS CocoaPods FCM + Kotlin Android" cio-cdpapikey-secret-key: "CUSTOMERIO_KOTLIN_WORKSPACE_CDP_API_KEY" cio-siteid-secret-key: "CUSTOMERIO_KOTLIN_WORKSPACE_SITE_ID" @@ -91,8 +93,9 @@ jobs: touch "samples/local.properties" echo "cdpApiKey=${{ secrets[matrix.cio-cdpapikey-secret-key] }}" >> "samples/local.properties" echo "siteId=${{ secrets[matrix.cio-siteid-secret-key] }}" >> "samples/local.properties" - echo "branch=$BRANCH_NAME" >> "samples/local.properties" - echo "commit=${COMMIT_HASH:0:7}" >> "samples/local.properties" + echo "workspace=${{ matrix.cio-workspace-name }}" >> "samples/local.properties" + echo "branchName=$BRANCH_NAME" >> "samples/local.properties" + echo "commitHash=${COMMIT_HASH:0:7}" >> "samples/local.properties" if [ "${{ inputs.use_latest_sdk_version == true }}" ]; then echo "sdkVersion=${{ steps.latest-sdk-version-step.outputs.LATEST_TAG }}" >> "samples/local.properties" fi diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java new file mode 100644 index 000000000..5de7a0904 --- /dev/null +++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java @@ -0,0 +1,77 @@ +package io.customer.android.sample.java_layout.buildinfo; + +import android.graphics.Typeface; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.StyleSpan; + +import androidx.annotation.NonNull; + +import java.util.Locale; + +import io.customer.android.sample.java_layout.BuildConfig; +import io.customer.sdk.Version; + +/** + * Contains metadata about the build environment. + */ +public class BuildInfoMetadata { + private final String sdkVersion; + private final String appVersion; + private final String buildDate; + private final String gitMetadata; + private final String defaultWorkspace; + private final String language; + private final String uiFramework; + private final String sdkIntegration; + + public BuildInfoMetadata() { + this.sdkVersion = BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.SDK_VERSION, () -> Version.version + " (as source)"); + this.appVersion = BuildConfig.VERSION_NAME; + this.buildDate = BuildInfoMetadataUtils.formatBuildDateWithRelativeTime(BuildConfig.BUILD_TIMESTAMP); + this.gitMetadata = String.format(Locale.ENGLISH, "%s-%s", + BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.BRANCH_NAME, () -> "working branch"), + BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.COMMIT_HASH, () -> "untracked")); + this.defaultWorkspace = BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.DEFAULT_WORKSPACE); + this.language = BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.LANGUAGE); + this.uiFramework = BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.UI_FRAMEWORK); + this.sdkIntegration = BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.SDK_INTEGRATION); + } + + @NonNull + @Override + public String toString() { + return toFormattedString().toString(); + } + + @NonNull + public CharSequence toFormattedString() { + SpannableStringBuilder builder = new SpannableStringBuilder(); + + appendBold(builder, "SDK Version: "); + builder.append(sdkVersion).append(" \t"); + appendBold(builder, "App version: "); + builder.append(appVersion).append("\n"); + appendBold(builder, "Build Date: "); + builder.append(buildDate).append("\n"); + appendBold(builder, "Branch: "); + builder.append(gitMetadata).append("\n"); + appendBold(builder, "Default Workspace: "); + builder.append(defaultWorkspace).append("\n"); + appendBold(builder, "Language: "); + builder.append(language).append(" \t"); + appendBold(builder, "UI Framework: "); + builder.append(uiFramework).append("\n"); + appendBold(builder, "SDK Integration: "); + builder.append(sdkIntegration); + + return builder; + } + + private void appendBold(@NonNull SpannableStringBuilder builder, @NonNull String text) { + SpannableString spannable = new SpannableString(text); + spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.append(spannable); + } +} diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadataUtils.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadataUtils.java new file mode 100644 index 000000000..6744b941d --- /dev/null +++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadataUtils.java @@ -0,0 +1,46 @@ +package io.customer.android.sample.java_layout.buildinfo; + +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +public class BuildInfoMetadataUtils { + public static String resolveValidOrElse(@Nullable String text) { + return resolveValidOrElse(text, () -> "unknown"); + } + + public static String resolveValidOrElse(@Nullable String text, @NonNull ValueProvider fallbackProvider) { + // When local properties are not set, they have a string value of "null" + if (!TextUtils.isEmpty(text) && !"null".equalsIgnoreCase(text)) { + return text; + } + + return fallbackProvider.get(); + } + + public static String formatBuildDateWithRelativeTime(long buildTimestamp) { + Date buildDate = new Date(buildTimestamp); + String formattedDate = DateFormat.getDateTimeInstance().format(buildDate); + + long diffInMillis = System.currentTimeMillis() - buildTimestamp; + long daysAgo = TimeUnit.MILLISECONDS.toDays(diffInMillis); + String relativeTime = daysAgo == 0 ? "(Today)" : String.format(Locale.ENGLISH, "(%d days ago)", daysAgo); + + return String.format(Locale.ENGLISH, "%s %s", formattedDate, relativeTime); + } + + /** + * Provides a value when the original value is not valid using lambda expressions. + * This can be simplified with Java 8+ or Kotlin later if needed. + */ + public interface ValueProvider { + @NonNull + T get(); + } +} diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/ViewUtils.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/ViewUtils.java index c98fc1beb..fc505e289 100644 --- a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/ViewUtils.java +++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/ViewUtils.java @@ -15,12 +15,8 @@ import com.google.android.material.textfield.TextInputEditText; import com.google.android.material.textfield.TextInputLayout; -import java.text.DateFormat; -import java.util.Date; -import java.util.Locale; - -import io.customer.android.sample.java_layout.BuildConfig; import io.customer.android.sample.java_layout.R; +import io.customer.android.sample.java_layout.buildinfo.BuildInfoMetadata; public class ViewUtils { public static void prepareForAutomatedTests(@NonNull View view, @StringRes int contentDescResId) { @@ -55,38 +51,8 @@ public static void setError(@NonNull TextInputLayout textInputLayout, @Nullable } public static void setBuildInfo(@NonNull TextView textView) { - String buildInfo = String.format( - Locale.ENGLISH, - "SDK version: %s\n" + - "Build date: %s\n" + - "Branch: %s\n" + - "Default workspace: Native iOS & Android\n" + - "App version: %s", - getSdkVersion(), - getBuildTime(), - getBranchName(), - BuildConfig.VERSION_CODE - ); - textView.setText(buildInfo); - } - - private static String getBuildTime() { - return DateFormat.getDateTimeInstance().format(new Date(BuildConfig.BUILD_TIMESTAMP)); - } - - private static String getSdkVersion() { - if (isEmptyOrUnset(BuildConfig.SDK_VERSION)) return "as source code"; - return BuildConfig.SDK_VERSION; - } - - private static String getBranchName() { - if (isEmptyOrUnset(BuildConfig.BRANCH)) return "local development"; - return BuildConfig.BRANCH + "." + BuildConfig.COMMIT; - } - - private static boolean isEmptyOrUnset(String text) { - // When local properties are not set, they have a string value of "null" - return TextUtils.isEmpty(text) || "null".equalsIgnoreCase(text); + BuildInfoMetadata buildInfo = new BuildInfoMetadata(); + textView.setText(buildInfo.toFormattedString()); } @NonNull diff --git a/samples/sample-app.gradle b/samples/sample-app.gradle index b424a3c53..78c4126e6 100644 --- a/samples/sample-app.gradle +++ b/samples/sample-app.gradle @@ -13,6 +13,25 @@ android { Closure getConfigWithPrefix = { String key -> localProperties."${configKeyPrefix}${key}" ?: localProperties."${key}" } + // Helper methods to retrieve language and UI framework from prefix + Closure getLanguageFromPrefix = { String prefix -> + String normalizedPrefix = prefix.toLowerCase() + if (normalizedPrefix.startsWith("java")) { + return "Java" + } else if (normalizedPrefix.startsWith("kotlin")) { + return "Kotlin" + } + return null + } + Closure getUIFrameworkFromPrefix = { String prefix -> + String normalizedPrefix = prefix.toLowerCase() + if (normalizedPrefix.contains("layout")) { + return "Android XML" + } else if (normalizedPrefix.contains("compose")) { + return "Jetpack Compose" + } + return null + } // Retrieve API keys using the helper method to allow key prefixing // e.g. Java Layout sample app has prefix javaLayout_ for API keys @@ -20,16 +39,24 @@ android { // cdpApiKey=KEY can be used as a fallback for all sample apps String cdpApiKey = getConfigWithPrefix("cdpApiKey") String siteId = getConfigWithPrefix("siteId") + String workspace = getConfigWithPrefix("workspace") + String language = getConfigWithPrefix("language") ?: getLanguageFromPrefix(configKeyPrefix) + String uiFramework = getConfigWithPrefix("uiFramework") ?: getUIFrameworkFromPrefix(configKeyPrefix) + String sdkIntegration = "Maven" String sdkVersion = localProperties["sdkVersion"] - String branch = localProperties["branch"] - String commit = localProperties["commit"] + String branchName = localProperties["branchName"] + String commitHash = localProperties["commitHash"] // Set build config fields for API keys buildConfigField "String", "CDP_API_KEY", "\"${cdpApiKey}\"" buildConfigField "String", "SITE_ID", "\"${siteId}\"" + buildConfigField "String", "DEFAULT_WORKSPACE", "\"${workspace}\"" + buildConfigField "String", "LANGUAGE", "\"${language}\"" + buildConfigField "String", "UI_FRAMEWORK", "\"${uiFramework}\"" + buildConfigField "String", "SDK_INTEGRATION", "\"${sdkIntegration}\"" buildConfigField "String", "SDK_VERSION", "\"${sdkVersion}\"" - buildConfigField "String", "BRANCH", "\"${branch}\"" - buildConfigField "String", "COMMIT", "\"${commit}\"" + buildConfigField "String", "BRANCH_NAME", "\"${branchName}\"" + buildConfigField "String", "COMMIT_HASH", "\"${commitHash}\"" buildConfigField "long", "BUILD_TIMESTAMP", System.currentTimeMillis() + "L" } // Avoid redefining signing configs in sample apps to avoid breaking release From 74eaf253dfc7b1c366453d1d1ae948f0f7e8cc53 Mon Sep 17 00:00:00 2001 From: Rehan Date: Fri, 7 Feb 2025 18:41:59 +0500 Subject: [PATCH 2/4] added commit count --- .github/workflows/reusable_build_sample_apps.yml | 1 + .../sample/java_layout/buildinfo/BuildInfoMetadata.java | 6 ++++-- samples/sample-app.gradle | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable_build_sample_apps.yml b/.github/workflows/reusable_build_sample_apps.yml index 8b7a5d6b9..d84978267 100644 --- a/.github/workflows/reusable_build_sample_apps.yml +++ b/.github/workflows/reusable_build_sample_apps.yml @@ -96,6 +96,7 @@ jobs: echo "workspace=${{ matrix.cio-workspace-name }}" >> "samples/local.properties" echo "branchName=$BRANCH_NAME" >> "samples/local.properties" echo "commitHash=${COMMIT_HASH:0:7}" >> "samples/local.properties" + echo "commitsAheadCount=$(git rev-list $(git describe --tags --abbrev=0)..${{ env.BRANCH_NAME }} --count)" >> samples/local.properties if [ "${{ inputs.use_latest_sdk_version == true }}" ]; then echo "sdkVersion=${{ steps.latest-sdk-version-step.outputs.LATEST_TAG }}" >> "samples/local.properties" fi diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java index 5de7a0904..6ab99d101 100644 --- a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java +++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java @@ -27,8 +27,10 @@ public class BuildInfoMetadata { private final String sdkIntegration; public BuildInfoMetadata() { - this.sdkVersion = BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.SDK_VERSION, () -> Version.version + " (as source)"); - this.appVersion = BuildConfig.VERSION_NAME; + this.sdkVersion = String.format(Locale.ENGLISH, "%s-%s", + BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.SDK_VERSION, () -> Version.version), + BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.COMMITS_AHEAD_COUNT, () -> "as-source")); + this.appVersion = String.valueOf(BuildConfig.VERSION_CODE); this.buildDate = BuildInfoMetadataUtils.formatBuildDateWithRelativeTime(BuildConfig.BUILD_TIMESTAMP); this.gitMetadata = String.format(Locale.ENGLISH, "%s-%s", BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.BRANCH_NAME, () -> "working branch"), diff --git a/samples/sample-app.gradle b/samples/sample-app.gradle index 78c4126e6..2d2951441 100644 --- a/samples/sample-app.gradle +++ b/samples/sample-app.gradle @@ -46,6 +46,7 @@ android { String sdkVersion = localProperties["sdkVersion"] String branchName = localProperties["branchName"] String commitHash = localProperties["commitHash"] + String commitsAheadCount = localProperties["commitsAheadCount"] // Set build config fields for API keys buildConfigField "String", "CDP_API_KEY", "\"${cdpApiKey}\"" @@ -57,6 +58,7 @@ android { buildConfigField "String", "SDK_VERSION", "\"${sdkVersion}\"" buildConfigField "String", "BRANCH_NAME", "\"${branchName}\"" buildConfigField "String", "COMMIT_HASH", "\"${commitHash}\"" + buildConfigField "String", "COMMITS_AHEAD_COUNT", "\"${commitsAheadCount}\"" buildConfigField "long", "BUILD_TIMESTAMP", System.currentTimeMillis() + "L" } // Avoid redefining signing configs in sample apps to avoid breaking release From 3e8f82d7cc2d1b97f66697ded4f95b10c9e433c6 Mon Sep 17 00:00:00 2001 From: Rehan Date: Fri, 7 Feb 2025 18:47:29 +0500 Subject: [PATCH 3/4] fixed sdk version --- .../sample/java_layout/buildinfo/BuildInfoMetadata.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java index 6ab99d101..808af3bc6 100644 --- a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java +++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/buildinfo/BuildInfoMetadata.java @@ -27,9 +27,10 @@ public class BuildInfoMetadata { private final String sdkIntegration; public BuildInfoMetadata() { - this.sdkVersion = String.format(Locale.ENGLISH, "%s-%s", - BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.SDK_VERSION, () -> Version.version), - BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.COMMITS_AHEAD_COUNT, () -> "as-source")); + this.sdkVersion = BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.SDK_VERSION, () -> String.format( + Locale.ENGLISH, "%s-%s", + Version.version, + BuildInfoMetadataUtils.resolveValidOrElse(BuildConfig.COMMITS_AHEAD_COUNT, () -> "as-source"))); this.appVersion = String.valueOf(BuildConfig.VERSION_CODE); this.buildDate = BuildInfoMetadataUtils.formatBuildDateWithRelativeTime(BuildConfig.BUILD_TIMESTAMP); this.gitMetadata = String.format(Locale.ENGLISH, "%s-%s", From 986e53b85090426a8fdc24ef9f4c2ac9b04ff386 Mon Sep 17 00:00:00 2001 From: Rehan Date: Fri, 7 Feb 2025 18:59:13 +0500 Subject: [PATCH 4/4] fix count --- .github/workflows/reusable_build_sample_apps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable_build_sample_apps.yml b/.github/workflows/reusable_build_sample_apps.yml index d84978267..128d8afe9 100644 --- a/.github/workflows/reusable_build_sample_apps.yml +++ b/.github/workflows/reusable_build_sample_apps.yml @@ -96,7 +96,7 @@ jobs: echo "workspace=${{ matrix.cio-workspace-name }}" >> "samples/local.properties" echo "branchName=$BRANCH_NAME" >> "samples/local.properties" echo "commitHash=${COMMIT_HASH:0:7}" >> "samples/local.properties" - echo "commitsAheadCount=$(git rev-list $(git describe --tags --abbrev=0)..${{ env.BRANCH_NAME }} --count)" >> samples/local.properties + echo "commitsAheadCount=$(git rev-list $(git describe --tags --abbrev=0)..HEAD --count)" >> samples/local.properties if [ "${{ inputs.use_latest_sdk_version == true }}" ]; then echo "sdkVersion=${{ steps.latest-sdk-version-step.outputs.LATEST_TAG }}" >> "samples/local.properties" fi