Skip to content

Commit 04794f6

Browse files
chore: multi-agent single page (#636)
1 parent 67b3496 commit 04794f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+975
-268
lines changed

.github/actions/build-ab/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

.github/actions/build-ab/action.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# This composite action finds, collects, and provides as outputs information
2+
# about a pull request that is currently opened for the branch targeted by
3+
# the workflow run ($GITHUB_REF). If no pull request is found, the action will
4+
# throw an error.
5+
6+
name: 'Find Branch Pull Request'
7+
8+
inputs:
9+
nr_environment:
10+
description: 'Target New Relic environment for the A/B script.'
11+
required: true
12+
nrba_current_script_url:
13+
description: 'URL for the script to use as the "current" version NRBA loader.'
14+
required: false
15+
default: https://js-agent.newrelic.com/nr-loader-spa-current.min.js
16+
nrba_next_script_url:
17+
description: 'URL for the script to use as the "next" version NRBA loader.'
18+
required: false
19+
default: https://js-agent.newrelic.com/dev/nr-loader-spa.min.js
20+
nrba_app_id:
21+
description: 'App id to insert into the NRBA configuration.'
22+
required: true
23+
nrba_license_key:
24+
description: 'License key to insert into the NRBA configuration.'
25+
required: true
26+
aws_access_key_id:
27+
description: 'AWS access key id used for authentication.'
28+
required: false
29+
aws_secret_access_key:
30+
description: 'AWS secret access key used for authentication.'
31+
required: false
32+
aws_region:
33+
description: "AWS region where S3 bucket is located."
34+
required: false
35+
default: us-east-1
36+
aws_role:
37+
description: "AWS role ARN that needs to be used for authentication."
38+
required: false
39+
aws_bucket_name:
40+
description: "S3 bucket name where files need to be uploaded."
41+
required: false
42+
43+
runs:
44+
using: "composite"
45+
steps:
46+
- name: Install dependencies
47+
run: npm install --prefix $GITHUB_ACTION_PATH
48+
shell: bash
49+
- name: Run action script
50+
id: action-script
51+
env:
52+
AWS_ACCESS_KEY_ID: ${{ inputs.aws_access_key_id }}
53+
AWS_SECRET_ACCESS_KEY: ${{ inputs.aws_secret_access_key }}
54+
run: |
55+
node $GITHUB_ACTION_PATH/index.js \
56+
--environment ${{ inputs.nr_environment }} \
57+
--current ${{ inputs.nrba_current_script_url }} \
58+
--next ${{ inputs.nrba_next_script_url }} \
59+
--app-id ${{ inputs.nrba_app_id }} \
60+
--license-key ${{ inputs.nrba_license_key }} \
61+
--region ${{ inputs.aws_region }} \
62+
--bucket ${{ inputs.aws_bucket_name || '' }} \
63+
--role ${{ inputs.aws_role || '' }} \
64+
shell: bash

.github/actions/build-ab/args.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import process from 'process'
2+
import yargs from 'yargs'
3+
import { hideBin } from 'yargs/helpers'
4+
5+
export const args = yargs(hideBin(process.argv))
6+
.usage('$0 [options]')
7+
8+
.choices('environment', ['dev', 'staging', 'prod', 'eu-prod'])
9+
.describe('environment', 'Which environment are we building the a/b script for?')
10+
11+
.string('current')
12+
.describe('current', 'current/stable build (defaults to -current)')
13+
.default('current', 'https://js-agent.newrelic.com/nr-loader-spa-current.min.js')
14+
15+
.string('next')
16+
.describe('next', 'next version to compare to stable version (defaults to /dev)')
17+
.default('next', 'https://js-agent.newrelic.com/dev/nr-loader-spa.min.js')
18+
19+
.string('app-id')
20+
.describe('Application ID to use in the environment NRBA configuration.')
21+
22+
.string('license-key')
23+
.describe('License key to use in the environment NRBA configuration.')
24+
25+
.string('role')
26+
.describe('role', 'S3 role ARN; used when including experiments in the ab script.')
27+
28+
.string('bucket')
29+
.describe('bucket', 'S3 bucket name; used when including experiments in the ab script.')
30+
31+
.string('region')
32+
.describe('region', 'AWS region location of S3 bucket. Defaults to us-east-1.Used when including experiments in the ab script.')
33+
.default('region', 'us-east-1')
34+
35+
.demandOption(['environment', 'app-id', 'license-key'])
36+
.argv

.github/actions/build-ab/index.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import fs from 'fs'
2+
import path from 'path'
3+
import url from 'url'
4+
import fetch from 'node-fetch'
5+
import { AssumeRoleCommand, STSClient } from '@aws-sdk/client-sts'
6+
import { S3Client, ListObjectsCommand } from '@aws-sdk/client-s3'
7+
import { args } from './args.js'
8+
9+
const config = {
10+
init: {
11+
distributed_tracing: {
12+
enabled: true
13+
},
14+
ajax: {
15+
deny_list: [
16+
'nr-data.net',
17+
'bam.nr-data.net',
18+
'staging-bam.nr-data.net',
19+
'bam-cell.nr-data.net'
20+
]
21+
},
22+
session_replay: {
23+
enabled: true,
24+
sampleRate: 0.5,
25+
errorSampleRate: 1
26+
}
27+
},
28+
29+
loader_config: {
30+
accountID: '1',
31+
trustKey: '1',
32+
agentID: args.appId,
33+
licenseKey: args.licenseKey,
34+
applicationID: args.appId
35+
},
36+
37+
info: {
38+
beacon: 'staging-bam.nr-data.net',
39+
errorBeacon: 'staging-bam.nr-data.net',
40+
licenseKey: args.licenseKey,
41+
applicationID: args.appId,
42+
sa: 1
43+
}
44+
}
45+
46+
// 0. Ensure the output directory is available and the target file does not exist
47+
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
48+
const outputFile = path.join(
49+
path.resolve(__dirname, '../../../temp'),
50+
`${args.environment}.js`
51+
)
52+
await fs.promises.mkdir(path.dirname(outputFile), { recursive: true })
53+
if (fs.existsSync(outputFile)) {
54+
await fs.promises.rm(outputFile)
55+
}
56+
57+
// 1. Write the NRBA configuration
58+
console.log('Writing configuration in A/B script.')
59+
await fs.promises.writeFile(
60+
outputFile,
61+
`window.NREUM=${JSON.stringify(config)}\n\n`,
62+
{ encoding: 'utf-8' }
63+
)
64+
65+
// 2. Write the current loader script
66+
console.log(`Writing current loader ${args.current} in A/B script.`)
67+
const currentScript = await fetch(args.current)
68+
await fs.promises.appendFile(
69+
outputFile,
70+
await currentScript.text() + '\n\n',
71+
{ encoding: 'utf-8' }
72+
)
73+
74+
// 3. Write the next loader script
75+
console.log(`Writing current loader ${args.next} in A/B script.`)
76+
const nextScript = await fetch(args.next)
77+
await fs.promises.appendFile(
78+
outputFile,
79+
await nextScript.text() + '\n\n',
80+
{ encoding: 'utf-8' }
81+
)
82+
83+
// 4. Find and write any experiments if env is not prod or eu-prod
84+
if (['dev', 'staging'].includes(args.environment)) {
85+
const stsClient = new STSClient({ region: args.region })
86+
const s3Credentials = await stsClient.send(new AssumeRoleCommand({
87+
RoleArn: args.role,
88+
RoleSessionName: 'downloadFromS3Session',
89+
DurationSeconds: 900
90+
}))
91+
92+
const s3Client = new S3Client({
93+
region: args.region,
94+
credentials: {
95+
accessKeyId: s3Credentials.Credentials.AccessKeyId,
96+
secretAccessKey: s3Credentials.Credentials.SecretAccessKey,
97+
sessionToken: s3Credentials.Credentials.SessionToken
98+
}
99+
})
100+
101+
let isTruncated = true
102+
const listCommand = new ListObjectsCommand({
103+
Bucket: args.bucket,
104+
Prefix: 'experiments/',
105+
Delimiter: '/'
106+
});
107+
let experimentsList = new Set()
108+
109+
while (isTruncated) {
110+
const { IsTruncated, NextMarker, CommonPrefixes } = await s3Client.send(listCommand)
111+
CommonPrefixes.forEach(prefix => experimentsList.add(prefix.Prefix))
112+
113+
if (IsTruncated) {
114+
listCommand.input.Marker = NextMarker
115+
} else {
116+
isTruncated = false
117+
}
118+
}
119+
120+
if (experimentsList.size === 0) {
121+
console.log('No experiments to include in A/B script.')
122+
} else {
123+
for (const experiment of experimentsList) {
124+
const experimentLoader = `https://js-agent.newrelic.com/${experiment}nr-loader-spa.min.js`
125+
console.log(`Writing experiment loader ${experimentLoader} in A/B script.`)
126+
const experimentScript = await fetch(experimentLoader)
127+
await fs.promises.appendFile(
128+
outputFile,
129+
await experimentScript.text() + '\n\n',
130+
{ encoding: 'utf-8' }
131+
)
132+
}
133+
}
134+
}

.github/actions/build-ab/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "@newrelic/browser-agent.actions.find-pull-request",
3+
"description": "",
4+
"private": true,
5+
"type": "module",
6+
"devDependencies": {
7+
"@aws-sdk/client-s3": "^3.385.0",
8+
"@aws-sdk/client-sts": "^3.385.0",
9+
"node-fetch": "^3.3.2",
10+
"yargs": "^17.7.2"
11+
}
12+
}

.github/actions/comment-pull-request/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
"devDependencies": {
77
"@actions/core": "^1.10.0",
88
"@actions/github": "^5.1.1",
9-
"yargs": "^17.6.2"
9+
"yargs": "^17.7.2"
1010
}
1111
}

.github/actions/fastly-purge/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This composite action is used to purge one or more files in a fastly service cache.
2+
3+
name: 'Fastly Purge'
4+
5+
inputs:
6+
fastly_key:
7+
description: 'Fastly access key used for authentication.'
8+
required: true
9+
fastly_service:
10+
description: 'Fastly service to perform the purge on.'
11+
required: true
12+
purge_path:
13+
description: 'Path(s) to be purged. Separate multiple items by a space'
14+
required: true
15+
16+
runs:
17+
using: "composite"
18+
steps:
19+
- name: Install dependencies
20+
run: npm install --prefix $GITHUB_ACTION_PATH
21+
shell: bash
22+
- name: Run action script
23+
id: action-script
24+
env:
25+
FASTLY_API_TOKEN: ${{ inputs.fastly_key }}
26+
run: |
27+
node $GITHUB_ACTION_PATH/index.js \
28+
--service ${{ inputs.fastly_service }} \
29+
--purge-path ${{ inputs.purge_path }}
30+
shell: bash

.github/actions/fastly-purge/args.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import process from 'process'
2+
import yargs from 'yargs'
3+
import { hideBin } from 'yargs/helpers'
4+
5+
export const args = yargs(hideBin(process.argv))
6+
.usage('$0 [options]')
7+
8+
.string('service')
9+
.describe('service', 'Name of the fastly service to perform the purge on.')
10+
11+
.array('purge-path')
12+
.describe('purge-path', 'Path(s) to purge in fastly.')
13+
14+
.demandOption(['service', 'purge-path'])
15+
.argv

.github/actions/fastly-purge/index.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Fastly from 'fastly'
2+
import { args } from './args.js'
3+
4+
const fastly = new Fastly.PurgeApi()
5+
await Promise.all(args.purgePath
6+
.map(assetPath => {
7+
console.log(`Purging path ${args.service}/${assetPath}`)
8+
return fastly.purgeSingleUrl({
9+
cached_url: `${args.service}/${assetPath}`,
10+
fastly_soft_purge: 1
11+
})
12+
})
13+
)
14+
15+
console.log(`Successfully purged fastly cache for ${args.purgePath.length} entities.`)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "@newrelic/browser-agent.actions.fastly-purge",
3+
"description": "",
4+
"private": true,
5+
"type": "module",
6+
"devDependencies": {
7+
"fastly": "^6.0.0",
8+
"yargs": "^17.7.2"
9+
}
10+
}

.github/actions/fastly-verify/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This composite action is used to verify one or more files are available via fastly cache.
2+
3+
name: 'Fastly Verify'
4+
5+
inputs:
6+
fastly_key:
7+
description: 'Fastly access key used for authentication.'
8+
required: true
9+
fastly_service:
10+
description: 'Fastly service to perform the purge on.'
11+
required: true
12+
asset_path:
13+
description: 'Path(s) to be verified. Separate multiple items by a space'
14+
required: true
15+
16+
runs:
17+
using: "composite"
18+
steps:
19+
- name: Install dependencies
20+
run: npm install --prefix $GITHUB_ACTION_PATH
21+
shell: bash
22+
- name: Run action script
23+
id: action-script
24+
env:
25+
FASTLY_API_TOKEN: ${{ inputs.fastly_key }}
26+
run: |
27+
node $GITHUB_ACTION_PATH/index.js \
28+
--service ${{ inputs.fastly_service }} \
29+
--asset-path ${{ inputs.asset_path }}
30+
shell: bash

.github/actions/fastly-verify/args.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import process from 'process'
2+
import yargs from 'yargs'
3+
import { hideBin } from 'yargs/helpers'
4+
5+
export const args = yargs(hideBin(process.argv))
6+
.usage('$0 [options]')
7+
8+
.string('service')
9+
.describe('service', 'Name of the fastly service to verify the asset(s) in.')
10+
11+
.array('asset-path')
12+
.describe('asset-path', 'Path(s) to verfy in fastly.')
13+
14+
.demandOption(['service', 'asset-path'])
15+
.argv

0 commit comments

Comments
 (0)