1
1
import {
2
2
onInAppFeedbackPublished } from "firebase-functions/v2/alerts/appDistribution" ;
3
+ import { defineInt , defineSecret , defineString } from "firebase-functions/params" ;
4
+ import logger from "firebase-functions/logger" ;
3
5
import fetch from "node-fetch" ;
4
6
import { FormData } from "formdata-polyfill/esm.min.js" ;
5
- import logger from "firebase-functions/logger" ;
6
7
7
- const JIRA_URI = "https://mysite.atlassian.net" ;
8
- const PROJECT_KEY = "XY" ;
9
- const ISSUE_TYPE_ID = "10001" ;
10
- const ISSUE_LABELS = [ "in-app" ] ;
11
- const API_KEY_OWNER = "user@e,mail" ;
12
- const API_KEY = "am9zaHVhIHBhc3N3b3JkMTIz" ;
13
- const AUTH_HEADER = "Basic " +
14
- Buffer . from ( `${ API_KEY_OWNER } :${ API_KEY } ` ) . toString ( "base64" ) ;
8
+ // The keys are either defined in .env or they are created
9
+ // via prompt in the CLI before deploying
10
+ const jiraUriConfig = defineString ( "JIRA_URI" , {
11
+ description : "URI of your Jira instance (e.g. 'https://mysite.atlassian.net')" ,
12
+ input : {
13
+ text : {
14
+ validationRegex : / ^ h t t p s : \/ \/ .* / ,
15
+ validationErrorMessage : "Please enter an 'https://' URI" ,
16
+ } ,
17
+ } ,
18
+ } ) ;
19
+ const projectKeyConfig = defineString ( "PROJECT_KEY" , {
20
+ description : "Project key of your Jira instance (e.g. 'XY')" ,
21
+ } ) ;
22
+ const issueTypeIdConfig = defineInt ( "ISSUE_TYPE_ID" , {
23
+ description : "Issue type ID for the Jira issues being created" ,
24
+ default : 10001 ,
25
+ } ) ;
26
+ const issueLabelConfig = defineString ( "ISSUE_LABEL" , {
27
+ description : "Label for the Jira issues being created" ,
28
+ default : "in-app" ,
29
+ } ) ;
30
+ const apiKeyOwnerConfig = defineString ( "API_KEY_OWNER" , {
31
+ description : "Owner of the Jira API key" ,
32
+ input : {
33
+ text : {
34
+ validationRegex :
35
+ / ^ [ a - z A - Z 0 - 9 . ! # $ % & ’ * + / = ? ^ _ ` { | } ~ - ] + @ [ a - z A - Z 0 - 9 - ] + (?: \. [ a - z A - Z 0 - 9 - ] + ) * $ / ,
36
+ validationErrorMessage : "Please enter a valid email address" ,
37
+ } ,
38
+ } ,
39
+ } ) ;
40
+ const apiKeyConfig = defineSecret ( "API_KEY" , {
41
+ description : "Jira API key" ,
42
+ } ) ;
15
43
16
44
export const handleInAppFeedback = async ( event ) => {
17
45
const issueUri = await createIssue ( event ) ;
@@ -21,7 +49,18 @@ export const handleInAppFeedback = async (event) => {
21
49
return true ;
22
50
} ;
23
51
24
- export const feedbacktojira = onInAppFeedbackPublished ( handleInAppFeedback ) ;
52
+ export const feedbacktojira =
53
+ onInAppFeedbackPublished ( { secrets : [ apiKeyConfig ] } , handleInAppFeedback ) ;
54
+
55
+ /**
56
+ * Creates "Authorization" header value.
57
+ * @return {string } Basic, base64-encoded "Authorization" header value
58
+ */
59
+ function authHeader ( ) {
60
+ return "Basic " + Buffer
61
+ . from ( apiKeyOwnerConfig . value ( ) + ":" + apiKeyConfig . value ( ) )
62
+ . toString ( "base64" ) ;
63
+ }
25
64
26
65
/**
27
66
* Creates new issue in Jira.
@@ -31,10 +70,10 @@ async function createIssue(event) {
31
70
const requestJson = await buildCreateIssueRequest ( event ) ;
32
71
const requestBody = JSON . stringify ( requestJson ) ;
33
72
const response =
34
- await fetch ( "https://eventarc.atlassian.net /rest/api/3/issue" , {
73
+ await fetch ( ` ${ jiraUriConfig . value ( ) } /rest/api/3/issue` , {
35
74
method : "POST" ,
36
75
headers : {
37
- "Authorization" : AUTH_HEADER ,
76
+ "Authorization" : authHeader ( ) ,
38
77
"Accept" : "application/json" ,
39
78
"Content-Type" : "application/json" ,
40
79
} ,
@@ -68,7 +107,7 @@ async function uploadScreenshot(issueUri, screenshotUri) {
68
107
method : "POST" ,
69
108
body : form ,
70
109
headers : {
71
- "Authorization" : AUTH_HEADER ,
110
+ "Authorization" : authHeader ( ) ,
72
111
"Accept" : "application/json" ,
73
112
"X-Atlassian-Token" : "no-check" ,
74
113
} ,
@@ -85,10 +124,14 @@ async function uploadScreenshot(issueUri, screenshotUri) {
85
124
*/
86
125
async function lookupReporter ( testerEmail ) {
87
126
const response =
88
- await fetch ( `${ JIRA_URI } /rest/api/3/user/search?query=${ testerEmail } ` , {
89
- method : "GET" ,
90
- headers : { "Authorization" : AUTH_HEADER , "Accept" : "application/json" } ,
91
- } ) ;
127
+ await fetch (
128
+ `${ jiraUriConfig . value ( ) } /rest/api/3/user/search` +
129
+ `?query=${ testerEmail } ` , {
130
+ method : "GET" ,
131
+ headers : {
132
+ "Authorization" : authHeader ( ) ,
133
+ "Accept" : "application/json" ,
134
+ } } ) ;
92
135
if ( ! response . ok ) {
93
136
logger . info ( `Failed to find Jira user for '${ testerEmail } ':` +
94
137
`${ response . status } ${ response . statusText } ` ) ;
@@ -112,10 +155,10 @@ async function buildCreateIssueRequest(event) {
112
155
"fields" : {
113
156
"summary" : summary ,
114
157
"issuetype" : {
115
- "id" : ISSUE_TYPE_ID ,
158
+ "id" : issueTypeIdConfig . value ( ) ,
116
159
} ,
117
160
"project" : {
118
- "key" : PROJECT_KEY ,
161
+ "key" : projectKeyConfig . value ( ) ,
119
162
} ,
120
163
"description" : {
121
164
"type" : "doc" ,
@@ -231,7 +274,7 @@ async function buildCreateIssueRequest(event) {
231
274
} ,
232
275
] ,
233
276
} ,
234
- "labels" : ISSUE_LABELS ,
277
+ "labels" : [ issueLabelConfig . value ( ) ] ,
235
278
} ,
236
279
} ;
237
280
const reporter = await lookupReporter ( event . data . payload . testerEmail ) ;
0 commit comments