Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 37 additions & 22 deletions .github/workflows/build-sample-apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,21 @@ jobs:
sample-app:
# List all sample apps you want to have compiled.
# List item is name of directory inside of "Apps" directory for the corresponding app to compile.
- "APN"
- "FCM"
- name: "APN"
cio-workspace-name: "Mobile: React Native"
- name: "FCM"
cio-workspace-name: "Mobile: xReact Native FCM workspace"
defaults:
run:
working-directory: apps/${{ matrix.sample-app }}
working-directory: apps/${{ matrix.sample-app.name }}
runs-on: macos-14
name: Building sample app ${{ matrix.sample-app }}
name: Building sample app ${{ matrix.sample-app.name }}

steps:
- uses: actions/checkout@v4
- name: Check out code with conditional fetch-depth
uses: actions/checkout@v4
with:
fetch-depth: 0 # Workaround for bug https://github.com/actions/checkout/issues/1471

# Install CLI tools, Ruby, and Ruby dependencies for Fastlane

Expand All @@ -80,7 +85,7 @@ jobs:
NEXT_BUILDS_GROUP: next
PUBLIC_BUILDS_GROUP: public
# Input variables
IS_PRIMARY_APP: ${{ matrix.sample-app == 'APN' }}
IS_PRIMARY_APP: ${{ matrix.sample-app.name == 'APN' }}
CURRENT_BRANCH: ${{ github.ref }}
run: |
# Initialize with the default distribution group
Expand All @@ -107,21 +112,21 @@ jobs:
with:
ruby-version: ${{ env.RUBY_VERSION }}
bundler-cache: true # cache tools to make builds faster in future
working-directory: apps/${{ matrix.sample-app }}
working-directory: apps/${{ matrix.sample-app.name }}

# Update version numbers and workspace credentials before building the app

- name: Generate New Version
uses: maierj/[email protected]
with:
subdirectory: Apps/${{ matrix.sample-app }}
subdirectory: Apps/${{ matrix.sample-app.name }}
lane: "generate_new_version"
options: '{"branch_name":"${{ github.ref_name }}", "pull_request_number":"${{ github.event.pull_request.number }}"}'

- name: Update React Native SDK Version
uses: maierj/[email protected]
with:
subdirectory: Apps/${{ matrix.sample-app }}
subdirectory: Apps/${{ matrix.sample-app.name }}
lane: "update_react_native_sdk_version"
env:
SDK_VERSION_NAME: ${{ env.SDK_VERSION_NAME }}
Expand All @@ -131,14 +136,17 @@ jobs:
- name: Update Sample App Version
uses: maierj/[email protected]
with:
subdirectory: Apps/${{ matrix.sample-app }}
subdirectory: Apps/${{ matrix.sample-app.name }}
lane: "update_react_native_app_version"
env:
SDK_VERSION_NAME: ${{ env.SDK_VERSION_NAME }}
APP_VERSION_NAME: ${{ env.APP_VERSION_NAME }}
APP_VERSION_CODE: ${{ env.APP_VERSION_CODE }}

- name: Setup workspace credentials in React Native environment files
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
COMMIT_HASH: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
run: |
# Determine the correct file extension (.js or .ts)
if [ -f "env.sample.js" ]; then
Expand All @@ -153,15 +161,22 @@ jobs:
fi

# Update keys in the environment file
sd "siteId: '.*'" "siteId: '${{ secrets[format('CUSTOMERIO_{0}_WORKSPACE_SITE_ID', matrix.sample-app)] }}'" "$ENV_FILE"
sd "cdpApiKey: '.*'" "cdpApiKey: '${{ secrets[format('CUSTOMERIO_{0}_WORKSPACE_CDP_API_KEY', matrix.sample-app)] }}'" "$ENV_FILE"
sd "buildTimestamp: .*" "buildTimestamp: $(date +%s)," "$ENV_FILE"
sd "cdpApiKey: '.*'" "cdpApiKey: '${{ secrets[format('CUSTOMERIO_{0}_WORKSPACE_CDP_API_KEY', matrix.sample-app.name)] }}'" "$ENV_FILE"
sd "siteId: '.*'" "siteId: '${{ secrets[format('CUSTOMERIO_{0}_WORKSPACE_SITE_ID', matrix.sample-app.name)] }}'" "$ENV_FILE"
sd "workspaceName: '.*'" "workspaceName: '${{ matrix.sample-app.cio-workspace-name }}'" "$ENV_FILE"
sd "branchName: '.*'" "branchName: '$BRANCH_NAME'" "$ENV_FILE"
sd "commitHash: '.*'" "commitHash: '${COMMIT_HASH:0:7}'" "$ENV_FILE"
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "untagged")
COMMITS_AHEAD=$(git rev-list $LAST_TAG..HEAD --count 2>/dev/null || echo "untracked")
sd "commitsAheadCount: '.*'" "commitsAheadCount: '$COMMITS_AHEAD'" "$ENV_FILE"

- name: Setup workspace credentials in iOS environment files
working-directory: Apps/${{ matrix.sample-app }}/ios
working-directory: Apps/${{ matrix.sample-app.name }}/ios
run: |
cp "Env.swift.example" "Env.swift"
sd 'siteId: String = ".*"' "siteId: String = \"${{ secrets[format('CUSTOMERIO_{0}_WORKSPACE_SITE_ID', matrix.sample-app)] }}\"" "Env.swift"
sd 'cdpApiKey: String = ".*"' "cdpApiKey: String = \"${{ secrets[format('CUSTOMERIO_{0}_WORKSPACE_CDP_API_KEY', matrix.sample-app)] }}\"" "Env.swift"
sd 'siteId: String = ".*"' "siteId: String = \"${{ secrets[format('CUSTOMERIO_{0}_WORKSPACE_SITE_ID', matrix.sample-app.name)] }}\"" "Env.swift"
sd 'cdpApiKey: String = ".*"' "cdpApiKey: String = \"${{ secrets[format('CUSTOMERIO_{0}_WORKSPACE_CDP_API_KEY', matrix.sample-app.name)] }}\"" "Env.swift"

# Make sure to fetch dependencies only after updating version numbers and workspace credentials

Expand All @@ -175,10 +190,10 @@ jobs:
- name: Cache CocoaPods downloaded dependencies for faster builds in the future
uses: actions/cache@v4
with:
path: Apps/${{ matrix.sample-app }}/Pods
key: ${{ runner.os }}-${{ matrix.sample-app }}-Pods-${{ github.ref }}
path: Apps/${{ matrix.sample-app.name }}/Pods
key: ${{ runner.os }}-${{ matrix.sample-app.name }}-Pods-${{ github.ref }}
restore-keys: |
${{ runner.os }}-${{ matrix.sample-app }}-Pods
${{ runner.os }}-${{ matrix.sample-app.name }}-Pods

- name: Install dependencies to build SDK
run: npm ci
Expand All @@ -196,7 +211,7 @@ jobs:
id: android_build
uses: maierj/[email protected]
with:
subdirectory: Apps/${{ matrix.sample-app }}
subdirectory: Apps/${{ matrix.sample-app.name }}
lane: 'android build'
options: '{"distribution_groups": "${{ env.firebase_distribution_groups }}"}'
env:
Expand All @@ -214,7 +229,7 @@ jobs:
id: ios_build
uses: maierj/[email protected]
with:
subdirectory: Apps/${{ matrix.sample-app }}
subdirectory: Apps/${{ matrix.sample-app.name }}
lane: "ios build"
options: '{"distribution_groups": "${{ env.firebase_distribution_groups }}"}'
env:
Expand All @@ -238,7 +253,7 @@ jobs:
issue-number: ${{ github.event.pull_request.number }}
# the variables APP_VERSION_NAME, APP_VERSION_CODE are generated above in generate_new_version lane
body: |
* ${{ matrix.sample-app }}: `${{ env.APP_VERSION_NAME }} (${{ env.APP_VERSION_CODE }})`
* ${{ matrix.sample-app.name }}: `${{ env.APP_VERSION_NAME }} (${{ env.APP_VERSION_CODE }})`
edit-mode: append # append new line to the existing PR comment to build a list of all sample app builds.

- name: Update sample builds PR comment with build failure message
Expand All @@ -248,5 +263,5 @@ jobs:
comment-id: ${{ needs.update-pr-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: |
* ${{ matrix.sample-app }}: Build failed. See [CI job logs](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}) to determine the issue and try re-building.
* ${{ matrix.sample-app.name }}: Build failed. See [CI job logs](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}) to determine the issue and try re-building.
edit-mode: append # append new line to the existing PR comment to build a list of all sample app builds.
9 changes: 7 additions & 2 deletions Apps/APN/env.sample.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const Env = {
siteId: 'YourSiteId',
cdpApiKey: 'YourCdpApiKey',
buildTimestamp: Math.floor(Date.now() / 1000),
cdpApiKey: 'CDP_API_KEY',
siteId: 'SITE_ID',
workspaceName: 'WORKSPACE_NAME',
branchName: 'BRANCH_NAME',
commitHash: 'COMMIT_HASH',
commitsAheadCount: 'COMMITS_AHEAD_COUNT',
};

export default Env;
24 changes: 9 additions & 15 deletions Apps/APN/src/components/BuildInfoText.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { getBuildNumber, getVersion } from 'react-native-device-info';
import { BuildMetadata } from '../utils/build';
import { Caption } from './Text';

const BuildInfoText = () => {
const [buildInfo, setBuildInfo] = useState('');

useEffect(() => {
const sdkPackageJson = require('customerio-reactnative/package.json');

const value =
`Customer.io` +
` React Native SDK ${sdkPackageJson.version}` +
` APN Sample ${getVersion()} (${getBuildNumber()})`;
setBuildInfo(value);
}, [buildInfo]);
const metadata = BuildMetadata.toString();

return (
<View style={styles.buildInfoContainer}>
<Caption>{buildInfo}</Caption>
<Caption style={styles.buildInfoText}>{metadata}</Caption>
</View>
);
};
Expand All @@ -27,9 +17,13 @@ const styles = StyleSheet.create({
buildInfoContainer: {
alignItems: 'center',
justifyContent: 'center',
marginBottom: 32,
marginBottom: 16,
paddingHorizontal: 16,
},
buildInfoText: {
width: '100%',
textAlign: 'left',
},
});

export default BuildInfoText;
91 changes: 91 additions & 0 deletions Apps/APN/src/utils/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { getVersion } from 'react-native-device-info';
import Env from '../../env';

const BuildMetadata = {
sdkVersion: getSdkVersion(),
appVersion: resolveValidOrElse(getVersion()),
buildDate: formatBuildDateWithRelativeTime(Env.buildTimestamp),
gitMetadata: `${resolveValidOrElse(
Env.branchName,
() => 'development build'
)}-${resolveValidOrElse(Env.commitHash, () => 'untracked')}`,
defaultWorkspace: resolveValidOrElse(Env.workspaceName),
language: 'JavaScript',
uiFramework: 'React Native',
sdkIntegration: 'npm',

toString() {
return `
SDK Version: ${this.sdkVersion} \tApp Version: ${this.appVersion}
Build Date: ${this.buildDate}
Branch: ${this.gitMetadata}
Default Workspace: ${this.defaultWorkspace}
Language: ${this.language} \tUI Framework: ${this.uiFramework}
SDK Integration: ${this.sdkIntegration}
`;
},
};

function resolveValidOrElse(value, fallback = () => 'unknown') {
return value && value.trim() ? value : fallback();
}

function formatBuildDateWithRelativeTime(timestamp) {
if (!timestamp) return 'unavailable';
const parsedTimestamp = parseInt(timestamp, 10);
if (isNaN(parsedTimestamp)) return 'invalid timestamp';

const buildDate = new Date(parsedTimestamp * 1000);
const now = new Date();
const daysAgo = Math.floor((now - buildDate) / (1000 * 60 * 60 * 24));

return `${buildDate.toLocaleString()} ${
daysAgo === 0 ? '(Today)' : `(${daysAgo} days ago)`
}`;
}

function getSdkVersion() {
const sdkPackageName = 'customerio-reactnative';
try {
const sdkPackage = getSdkMetadataFromPackageLock(sdkPackageName);
if (!sdkPackage) {
console.warn(`${sdkPackageName} not found in package-lock.json`);
return undefined;
}

const version = resolveValidOrElse(sdkPackage.version);
const isPathDependency =
sdkPackage.resolved && sdkPackage.resolved.startsWith('file:');
if (isPathDependency) {
return `${version}-${resolveValidOrElse(
Env.commitsAheadCount,
() => 'as-source'
)}`;
}

return version;
} catch (error) {
console.warn(
`Failed to read ${sdkPackageName} sdk version: ${error.message}`
);
return undefined;
}
}

function getSdkMetadataFromPackageLock(packageName) {
const packageLockPath = '../../package-lock.json';
try {
const packageLock = require(packageLockPath);
const packages = packageLock.packages || {};
const resolvedPackageName = `node_modules/${packageName}`;
const sdkPackage = packages[resolvedPackageName];
if (sdkPackage) {
return sdkPackage;
}
} catch (error) {
console.warn(`Failed to read ${packageLockPath}: ${error.message}`);
}
return undefined;
}

export { BuildMetadata };
Loading