Skip to content

Commit de17a79

Browse files
authored
Merge pull request #12 from oddbit/app-configuration
App configuration
2 parents 6ae4ce8 + 22f2c35 commit de17a79

File tree

12 files changed

+166
-370
lines changed

12 files changed

+166
-370
lines changed

extension.yaml

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,35 @@ params:
8686
required: true
8787
immutable: false
8888

89-
- param: APP_CONFIG_COLLECTION
90-
label: Apps configuration collection
91-
description: The Firestore collection to keep apps configuration data.
89+
- param: APP_ID
90+
label: Firebase App ID
91+
description: The Firebase app ID from console (e.g `1:269808624035:android:296863cf1f5b6817c87a16`)
9292
type: string
93-
default: firebase-alerts-apps-config
9493
required: true
9594
immutable: false
9695

96+
- param: APP_BUNDLE_ID
97+
label: Bundle ID
98+
description: |
99+
The app bundle ID as identified by your build configuration (e.g `id.oddbit.hello_world`)
100+
101+
For web apps this is a random string that you will have to look for in
102+
URL when you are selecting the web app in the Firebase settings page.
103+
104+
Look for the last part of the URL where `your-web-app-bundle-id` is your
105+
web app's "bundle id". Go to the console to find something like this:
106+
https://console.firebase.google.com/project/${PROJECT_ID}/settings/general/web:{your-web-app-bundle-id}
107+
type: string
108+
required: true
109+
immutable: false
110+
111+
- param: REPOSITORY_URL
112+
label: Repository URL
113+
description: URL to your git repository
114+
type: string
115+
required: false
116+
immutable: false
117+
97118
- param: WEBHOOK_MANDATORY
98119
label: Mandatory webhook
99120
description: Mandatory webhook for Slack, Discord, or Google Chat

functions/src/alerts/crashlytics.ts

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11

2-
import {firestore} from "firebase-admin";
32
import {logger} from "firebase-functions/v2";
43
import {crashlytics} from "firebase-functions/v2/alerts";
54
import {post} from "request";
65
import {AppCrash} from "../models/app-crash";
7-
import {AppInfo, IAppInfo} from "../models/app-info";
86
import {Webhook} from "../models/webhook";
9-
import {makeFirebaseAppsSettingsUrl, makeFirestoreAppInfoUrl} from "../urls";
107
import {EnvConfig} from "../utils/env-config";
118
import {DiscordWebhook} from "../webhook-plugins/discord";
129
import {GoogleChatWebhook} from "../webhook-plugins/google-chat";
@@ -48,35 +45,13 @@ async function handleCrashlyticsEvent(appCrash: AppCrash):
4845
Promise<object | void> {
4946
logger.debug("[handleCrashlyticsEvent]", appCrash);
5047

51-
// Update and ensure that there is a Firestore document for this app id
52-
await firestore()
53-
.collection("apps")
54-
.doc(appCrash.appId)
55-
.set({
56-
appId: appCrash.appId,
57-
lastIssue: firestore.FieldValue.serverTimestamp(),
58-
issueCount: firestore.FieldValue.increment(1),
59-
}, {merge: true});
60-
61-
62-
const appInfoSnap = await firestore()
63-
.collection("apps")
64-
.doc(appCrash.appId)
65-
.get();
66-
67-
logger.debug("[handleCrashlyticsEvent] App info", appInfoSnap.data());
68-
69-
const appInfo = new AppInfo(appInfoSnap.data() as IAppInfo);
70-
if (!appInfo.bundleId) {
71-
// Will need to add this information explicitly by copying the bundle id
72-
// from Firebase Console project overview. The console log below will
73-
// provide links to add the configuration.
74-
logger.warn(
75-
"[handleCrashlyticsEvent] No bundle id for app. Fix it manually", {
76-
appInfo,
77-
settings: makeFirebaseAppsSettingsUrl(),
78-
firestore: makeFirestoreAppInfoUrl(appInfo),
48+
if (appCrash.appId !== EnvConfig.appId) {
49+
logger.debug(
50+
"[handleCrashlyticsEvent] Skipping crash for different app", {
51+
appId: appCrash.appId,
52+
expectedAppId: EnvConfig.appId,
7953
});
54+
return;
8055
}
8156

8257
const webhooks: Webhook[] = EnvConfig.webhooks.map(webhookPluginFromUrl);
@@ -88,8 +63,9 @@ async function handleCrashlyticsEvent(appCrash: AppCrash):
8863
const promises = [];
8964
for (const webhook of webhooks) {
9065
logger.debug("[handleCrashlyticsEvent] Webhook", webhook);
66+
const crashlyticsMessage = webhook.createCrashlyticsMessage(appCrash);
9167
const webhookPayload = {
92-
body: JSON.stringify(webhook.createCrashlyticsMessage(appInfo, appCrash)),
68+
body: JSON.stringify(crashlyticsMessage),
9369
};
9470

9571
try {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export enum AppPlatform {
2+
iOS = "ios",
3+
Android = "android",
4+
Web = "web",
5+
Unknown = "unknown",
6+
}

functions/src/models/app-info.ts

Lines changed: 0 additions & 88 deletions
This file was deleted.

functions/src/models/github.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.

functions/src/models/webhook.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import {AppInfo} from "./app-info";
21
import {AppCrash} from "./app-crash";
32
import {Localization} from "../utils/localization";
43

@@ -27,12 +26,10 @@ export abstract class Webhook implements IWebhook {
2726
/**
2827
* Create message payload for the webhook to send a crashlytics message
2928
*
30-
* @param {AppInfo} appInfo
3129
* @param {AppCrash} appCrash
3230
* @return {object} Webhook body payload
3331
*/
3432
public abstract createCrashlyticsMessage(
35-
appInfo: AppInfo,
3633
appCrash: AppCrash,
3734
): object;
3835
}

functions/src/urls.ts

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import {AppInfo} from "./models/app-info";
21
import {AppCrash} from "./models/app-crash";
32
import {EnvConfig} from "./utils/env-config";
43

@@ -7,14 +6,11 @@ export const crashlyticsImgUrl = "https://github.com/oddbit/firebase-alerts/raw/
76
/**
87
* Generate a URL to Firebase Console for the issue
98
*
10-
* @param {AppInfo} appInfo
119
* @param {AppCrash} appCrash
1210
* @return {string} URL to Firebase console
1311
*/
14-
export function makeCrashlyticsIssueUrl(
15-
appInfo: AppInfo,
16-
appCrash: AppCrash,): string {
17-
return `https://console.firebase.google.com/project/${EnvConfig.projectId}/crashlytics/app/${appInfo.platform}:${appInfo.bundleId}/issues/${appCrash.issueId}`;
12+
export function makeCrashlyticsIssueUrl(appCrash: AppCrash): string {
13+
return `https://console.firebase.google.com/project/${EnvConfig.projectId}/crashlytics/app/${EnvConfig.platform}:${EnvConfig.bundleId}/issues/${appCrash.issueId}`;
1814
}
1915

2016
/**
@@ -27,43 +23,37 @@ export function makeFirebaseAppsSettingsUrl(): string {
2723
}
2824

2925
/**
30-
* Generate a URL to Firestore app info document
26+
* Make a repository URL to create an issue from this app crash
3127
*
32-
* @param {AppInfo} appInfo
33-
* @return {string} URL to Firebase console
34-
*/
35-
export function makeFirestoreAppInfoUrl(appInfo: AppInfo): string {
36-
return `https://console.firebase.google.com/project/${EnvConfig.projectId}/firestore/data/~2F${process.env.EXT_INSTANCE_ID}-apps~2F${appInfo.appId}`;
37-
}
38-
39-
/**
40-
* Make an Github URL to create an issue from this app crash
41-
*
42-
* @param {AppInfo} appInfo
4328
* @param {AppCrash} appCrash
4429
* @return {string} URL to create a github issue
4530
*/
46-
export function makeGithubIssueUrl(
47-
appInfo: AppInfo,
48-
appCrash: AppCrash,): string {
49-
const attributes = [
50-
`title=${encodeURI(appCrash.issueTitle)}`,
51-
`labels=${appCrash.tags.map((tag) => encodeURI(tag)).join(",")}`,
52-
];
53-
54-
return `https://github.com/${appInfo.github?.repo}/issues/new?${attributes.join("&")}`;
31+
export function makeRepositoryIssueUrl(appCrash: AppCrash): string {
32+
const repositoryUrl = EnvConfig.repositoryUrl;
33+
if (repositoryUrl.startsWith("https://github.com")) {
34+
const attributes = [
35+
`title=${encodeURI(appCrash.issueTitle)}`,
36+
`labels=${appCrash.tags.map((tag) => encodeURI(tag)).join(",")}`,
37+
];
38+
39+
return `${repositoryUrl}/issues/new?${attributes.join("&")}`;
40+
}
41+
42+
throw new Error("Unknown repository type: " + repositoryUrl);
5543
}
5644

5745
/**
58-
* Make an Github URL to search for issues from this app crash
46+
* Make a repository URL to search for issues from this app crash
5947
*
60-
* @param {AppInfo} appInfo
6148
* @param {AppCrash} appCrash
6249
* @return {string} URL to search for github issues
6350
*/
64-
export function makeGithubSearchUrl(
65-
appInfo: AppInfo,
66-
appCrash: AppCrash,): string {
67-
return `https://github.com/${appInfo.github?.repo}/issues?q=${encodeURI(appCrash.issueTitle)}`;
51+
export function makeRepositorySearchUrl(appCrash: AppCrash): string {
52+
const repositoryUrl = EnvConfig.repositoryUrl;
53+
if (repositoryUrl.startsWith("https://github.com")) {
54+
return `${repositoryUrl}/issues?q=${encodeURI(appCrash.issueTitle)}`;
55+
}
56+
57+
throw new Error("Unknown repository type: " + repositoryUrl);
6858
}
6959

functions/src/utils/env-config.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { AppPlatform } from "../definitions/app-platform.enum";
2+
13
/**
24
* Environment configuration settings and variables
35
* This class abstracts the source of getting the values and provides helpful
@@ -32,6 +34,45 @@ export class EnvConfig {
3234
return projectId;
3335
}
3436

37+
/**
38+
* Get repository URL
39+
*/
40+
static get repositoryUrl(): string {
41+
const repo = EnvConfig.getEnv("REPOSITORY_URL");
42+
const repoWithHttps = repo.startsWith("https://") ? repo : `https://${repo}`;
43+
return repoWithHttps.endsWith("/") ? repoWithHttps.slice(0, -1) : repoWithHttps;
44+
}
45+
46+
/**
47+
* Get bundle ID
48+
*/
49+
static get bundleId(): string {
50+
return EnvConfig.getEnv("APP_BUNDLE_ID");
51+
}
52+
53+
/**
54+
* Get app ID
55+
*/
56+
static get appId(): string {
57+
return EnvConfig.getEnv("APP_ID");
58+
}
59+
60+
/**
61+
* Get platform
62+
*/
63+
static get platform(): AppPlatform {
64+
const appId = EnvConfig.getEnv("APP_ID");
65+
if (appId.includes("android")) {
66+
return AppPlatform.Android;
67+
} else if (appId.includes("ios")) {
68+
return AppPlatform.iOS;
69+
} else if (appId.includes("web")) {
70+
return AppPlatform.Web;
71+
}
72+
73+
return AppPlatform.Unknown;
74+
}
75+
3576
/**
3677
* Get language for webhooks
3778
*/

0 commit comments

Comments
 (0)