From a6a1bb76754b76a6650ba0f64b2f6ff08d6702d2 Mon Sep 17 00:00:00 2001 From: ptang-nr Date: Mon, 23 Dec 2024 12:25:18 -0800 Subject: [PATCH 1/4] chore: Add delete experiment GHA (#1288) --- .github/actions/s3-delete/action.yml | 52 +++++++++++++ .github/actions/s3-delete/args.js | 27 +++++++ .github/actions/s3-delete/index.js | 99 +++++++++++++++++++++++++ .github/workflows/branch-cleanup.yml | 38 ++++++++++ .github/workflows/delete-experiment.yml | 37 +++++++++ 5 files changed, 253 insertions(+) create mode 100644 .github/actions/s3-delete/action.yml create mode 100644 .github/actions/s3-delete/args.js create mode 100644 .github/actions/s3-delete/index.js create mode 100644 .github/workflows/branch-cleanup.yml create mode 100644 .github/workflows/delete-experiment.yml diff --git a/.github/actions/s3-delete/action.yml b/.github/actions/s3-delete/action.yml new file mode 100644 index 000000000..cb98bd34a --- /dev/null +++ b/.github/actions/s3-delete/action.yml @@ -0,0 +1,52 @@ +# This composite action is used to delete files from a S3 bucket. + +name: 'S3 File Deletion' + +inputs: + aws_access_key_id: + description: 'AWS access key id used for authentication.' + required: true + aws_secret_access_key: + description: 'AWS secret access key used for authentication.' + required: true + aws_region: + description: "AWS region where S3 bucket is located." + required: false + default: us-east-1 + aws_role: + description: "AWS role ARN that needs to be used for authentication." + required: true + aws_bucket_name: + description: "S3 bucket name where files need to be deleted." + required: true + dry_run: + description: "Indicates if we should just list files to deleted without actually deleting them." + required: false + bucket_dir: + description: 'A sub directory where the files are located within the S3 bucket.' + required: false + +outputs: + results: + description: "Array of objects containing information about each file uploaded" + value: ${{ steps.action-script.outputs.results }} + +runs: + using: "composite" + steps: + - name: Install dependencies + run: npm install --silent --no-progress --prefix $GITHUB_ACTION_PATH/.. + shell: bash + - name: Run action script + id: action-script + env: + AWS_ACCESS_KEY_ID: ${{ inputs.aws_access_key_id }} + AWS_SECRET_ACCESS_KEY: ${{ inputs.aws_secret_access_key }} + run: | + node $GITHUB_ACTION_PATH/index.js \ + --region ${{ inputs.aws_region }} \ + --bucket ${{ inputs.aws_bucket_name }} \ + --role ${{ inputs.aws_role }} \ + ${{ inputs.dry_run && '--dry' || '' }} \ + ${{ inputs.bucket_dir && format('--dir {0}', inputs.bucket_dir) || '' }} + shell: bash diff --git a/.github/actions/s3-delete/args.js b/.github/actions/s3-delete/args.js new file mode 100644 index 000000000..e3e8a4d7c --- /dev/null +++ b/.github/actions/s3-delete/args.js @@ -0,0 +1,27 @@ +import process from 'process' +import yargs from 'yargs' +import { hideBin } from 'yargs/helpers' + +export const args = yargs(hideBin(process.argv)) + .usage('$0 [options]') + + .string('role') + .describe('role', 'S3 role ARN') + + .string('bucket') + .describe('bucket', 'S3 bucket name') + + .string('region') + .describe('region', 'AWS region location of S3 bucket. Defaults to us-east-1.') + .default('region', 'us-east-1') + + .boolean('dry') + .default('dry', false) + .describe('dry', 'Runs the action script without actually uploading files.') + .alias('dry', 'dry-run') + + .string('dir') + .describe('dir', 'Bucket sub-directory name. Leave empty to refer to the root of the bucket.') + + .demandOption(['bucket', 'role']) + .argv diff --git a/.github/actions/s3-delete/index.js b/.github/actions/s3-delete/index.js new file mode 100644 index 000000000..fc73eb2ef --- /dev/null +++ b/.github/actions/s3-delete/index.js @@ -0,0 +1,99 @@ +import * as core from '@actions/core' +import { AssumeRoleCommand, STSClient } from '@aws-sdk/client-sts' +import { S3Client, S3ServiceException, paginateListObjectsV2, DeleteObjectsCommand, waitUntilObjectNotExists } from '@aws-sdk/client-s3' +import { args } from './args.js' + +const stsClient = new STSClient({ region: args.region }) +const s3Credentials = await stsClient.send(new AssumeRoleCommand({ + RoleArn: args.role, + RoleSessionName: 'deleteExperimentFromS3Session', + DurationSeconds: 900 +})) + +const s3Client = new S3Client({ + region: args.region, + credentials: { + accessKeyId: s3Credentials.Credentials.AccessKeyId, + secretAccessKey: s3Credentials.Credentials.SecretAccessKey, + sessionToken: s3Credentials.Credentials.SessionToken + } +}) + +async function collectKeysToDelete(bucketName, bucketDir) { + const keys = [] + core.info("Bucket name: " + bucketName) + core.info(`Looking up files with prefix '${bucketDir}'`) + + try { + const params = { + Bucket: bucketName, + Prefix:bucketDir + } + const paginator = paginateListObjectsV2({ client: s3Client }, params) + for await (const page of paginator) { + page.Contents?.forEach(obj => { + keys.push(obj.Key) + }) + } + core.info(`Found ${keys.length} matching files`) + core.info(keys.map(k => ` • ${k}`).join('\n')) + return keys + } catch (err) { + if (err instanceof S3ServiceException) { + core.setFailed( + `Error from S3 while listing objects for "${bucketName}". ${err.name}: ${err.message}`, + ) + } else { + core.setFailed(`Error while listing objects for "${bucketName}". ${err.name}: ${err.message}`) + } + process.exit(1) + } +} + +async function deleteFiles(bucketName, keys) { + try { + core.info('Deleting...') + + const { Deleted } = await s3Client.send( + new DeleteObjectsCommand({ + Bucket: bucketName, + Delete: { + Objects: keys.map((k) => ({ Key: k })), + }, + }), + ) + + for (const key in keys) { + await waitUntilObjectNotExists( + { client: s3Client }, + { Bucket: bucketName, Key: key }, + ) + } + core.info( + `Successfully deleted ${Deleted?.length || 0} objects.`, + ) + core.info(Deleted?.map((d) => ` • ${d.Key}`).join("\n")) + } catch (err) { + if (err instanceof S3ServiceException) { + core.setFailed( + `Error from S3 while deleting objects for "${bucketName}". ${err.name}: ${err.message}`, + ) + } else { + core.setFailed(`Error while deleting objects for "${bucketName}". ${err.name}: ${err.message}`) + } + process.exit(1) + } +} + +if (args.dry) { + core.info('This is a dry run.') +} +const keysToBeDeleted = await collectKeysToDelete(args.bucket, args.dir) +if (!args.dry) { + if (keysToBeDeleted.length > 0) { + await deleteFiles(args.bucket, keysToBeDeleted) + } else { + core.info('No files found to delete') + } +} +core.info('Completed successfully') diff --git a/.github/workflows/branch-cleanup.yml b/.github/workflows/branch-cleanup.yml new file mode 100644 index 000000000..880e098f3 --- /dev/null +++ b/.github/workflows/branch-cleanup.yml @@ -0,0 +1,38 @@ +# This workflow will run automatically when a branch is deleted. + +name: Branch Cleanup + +on: delete + +jobs: + branch-delete: + if: github.event.ref_type == 'branch' + runs-on: ubuntu-latest + timeout-minutes: 5 + defaults: + run: + shell: bash + steps: + - name: Clean up for deleted branch + id: cleanup-start + run: echo "Clean up for branch ${{ github.event.ref }}" + - name: Delete dev experiment + id: s3-delete-dev + uses: ./.github/actions/s3-delete + with: + aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws_role: ${{ secrets.AWS_ROLE_ARN }} + aws_bucket_name: ${{ secrets.AWS_BUCKET }} + bucket_dir: experiments/dev/${{ github.event.ref }} + dry_run: true + - name: Delete staging experiment + id: s3-delete-staging + uses: ./.github/actions/s3-delete + with: + aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws_role: ${{ secrets.AWS_ROLE_ARN }} + aws_bucket_name: ${{ secrets.AWS_BUCKET }} + bucket_dir: experiments/staging/${{ github.event.ref }} + dry_run: true diff --git a/.github/workflows/delete-experiment.yml b/.github/workflows/delete-experiment.yml new file mode 100644 index 000000000..5f818ca93 --- /dev/null +++ b/.github/workflows/delete-experiment.yml @@ -0,0 +1,37 @@ +# This workflow can be run on any branch. +# Given an environment, this workflow will delete the branch's experiment from S3 + +name: Delete Experiment + +on: + workflow_dispatch: + inputs: + nr_environment: + description: 'Target New Relic environment' + required: true + type: choice + options: + - dev + - staging + +jobs: + delete-experiment-on-s3: + runs-on: ubuntu-latest + timeout-minutes: 5 + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v4 + - name: Clean branch name + id: clean-branch-name + run: echo "results=$(echo '${{ github.ref }}' | sed 's/refs\/heads\///g' | sed 's/[^[:alnum:].-]/-/g')" >> $GITHUB_OUTPUT + - name: Delete experiment + id: s3-delete + uses: ./.github/actions/s3-delete + with: + aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws_role: ${{ secrets.AWS_ROLE_ARN }} + aws_bucket_name: ${{ secrets.AWS_BUCKET }} + bucket_dir: experiments/${{ inputs.nr_environment }}/${{ steps.clean-branch-name.outputs.results }} From 714dac431d6ccc20fec680da7e45d3ec7bf90e33 Mon Sep 17 00:00:00 2001 From: Browser Agent Team Bot <129139683+newrelic-browser-agent-team@users.noreply.github.com> Date: Tue, 24 Dec 2024 12:11:59 -0700 Subject: [PATCH 2/4] chore: Post release repo updates (#1290) --- package-lock.json | 6 +++--- third_party_manifest.json | 2 +- tools/lambda-test/webview-asset-ids.mjs | 2 +- tools/test-builds/browser-agent-wrapper/package.json | 2 +- tools/test-builds/library-wrapper/package.json | 2 +- tools/test-builds/raw-src-wrapper/package.json | 2 +- tools/test-builds/vite-react-wrapper/package.json | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index e43eed525..b59f61e44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9366,9 +9366,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001689", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001689.tgz", - "integrity": "sha512-CmeR2VBycfa+5/jOfnp/NpWPGd06nf1XYiefUvhXFfZE4GkRc9jv+eGPS4nT558WS/8lYCzV8SlANCIPvbWP1g==", + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", "dev": true, "funding": [ { diff --git a/third_party_manifest.json b/third_party_manifest.json index ec4edbb1e..afa9f2c07 100644 --- a/third_party_manifest.json +++ b/third_party_manifest.json @@ -1,5 +1,5 @@ { - "lastUpdated": "Tue Dec 17 2024 16:31:01 GMT+0000 (Coordinated Universal Time)", + "lastUpdated": "Thu Dec 19 2024 20:09:27 GMT+0000 (Coordinated Universal Time)", "projectName": "New Relic Browser Agent", "projectUrl": "https://github.com/newrelic/newrelic-browser-agent", "includeOptDeps": true, diff --git a/tools/lambda-test/webview-asset-ids.mjs b/tools/lambda-test/webview-asset-ids.mjs index a53382f5f..3398af5c8 100644 --- a/tools/lambda-test/webview-asset-ids.mjs +++ b/tools/lambda-test/webview-asset-ids.mjs @@ -1 +1 @@ -export default { androidID: 'lt://APP10160341241734453059148955', iosID: 'lt://APP10160542501734453056523348' } +export default { androidID: 'lt://APP10160541191734638965500740', iosID: 'lt://APP10160542501734638964688891' } diff --git a/tools/test-builds/browser-agent-wrapper/package.json b/tools/test-builds/browser-agent-wrapper/package.json index 9cfd59210..aeb81fa79 100644 --- a/tools/test-builds/browser-agent-wrapper/package.json +++ b/tools/test-builds/browser-agent-wrapper/package.json @@ -9,6 +9,6 @@ "author": "", "license": "ISC", "dependencies": { - "@newrelic/browser-agent": "file:../../../temp/newrelic-browser-agent-1.276.0.tgz" + "@newrelic/browser-agent": "file:../../../temp/newrelic-browser-agent-1.277.0.tgz" } } diff --git a/tools/test-builds/library-wrapper/package.json b/tools/test-builds/library-wrapper/package.json index 32f4a2294..9aa9742ee 100644 --- a/tools/test-builds/library-wrapper/package.json +++ b/tools/test-builds/library-wrapper/package.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "@apollo/client": "^3.8.8", - "@newrelic/browser-agent": "file:../../../temp/newrelic-browser-agent-1.276.0.tgz", + "@newrelic/browser-agent": "file:../../../temp/newrelic-browser-agent-1.277.0.tgz", "graphql": "^16.8.1" } } diff --git a/tools/test-builds/raw-src-wrapper/package.json b/tools/test-builds/raw-src-wrapper/package.json index 9aeca23b4..1075d21ab 100644 --- a/tools/test-builds/raw-src-wrapper/package.json +++ b/tools/test-builds/raw-src-wrapper/package.json @@ -9,6 +9,6 @@ "author": "", "license": "ISC", "dependencies": { - "@newrelic/browser-agent": "file:../../../temp/newrelic-browser-agent-1.276.0.tgz" + "@newrelic/browser-agent": "file:../../../temp/newrelic-browser-agent-1.277.0.tgz" } } diff --git a/tools/test-builds/vite-react-wrapper/package.json b/tools/test-builds/vite-react-wrapper/package.json index 9c9f470c8..326702c1e 100644 --- a/tools/test-builds/vite-react-wrapper/package.json +++ b/tools/test-builds/vite-react-wrapper/package.json @@ -4,7 +4,7 @@ "main": "index.js", "license": "MIT", "dependencies": { - "@newrelic/browser-agent": "file:../../../temp/newrelic-browser-agent-1.276.0.tgz", + "@newrelic/browser-agent": "file:../../../temp/newrelic-browser-agent-1.277.0.tgz", "react": "18.2.0", "react-dom": "18.2.0" }, From fd024149dd2c4c4d045dc2261accf079e3121807 Mon Sep 17 00:00:00 2001 From: Jordan Porter Date: Tue, 24 Dec 2024 15:10:12 -0700 Subject: [PATCH 3/4] chore: add action to track nr bundle size (#1289) --- .../actions/nr-report-build-size/action.yml | 47 +++++++++++++++++++ .github/workflows/publish-dev.yml | 14 ++++++ .github/workflows/pull-request-checks.yml | 4 ++ 3 files changed, 65 insertions(+) create mode 100644 .github/actions/nr-report-build-size/action.yml diff --git a/.github/actions/nr-report-build-size/action.yml b/.github/actions/nr-report-build-size/action.yml new file mode 100644 index 000000000..d5a70790a --- /dev/null +++ b/.github/actions/nr-report-build-size/action.yml @@ -0,0 +1,47 @@ +# This composite action is used to report the local build size to New Relic +# You must build the agent before running this action + +name: 'Report Build Size to New Relic' + +inputs: + nr-api-key: + description: 'NR API Key for reporting events' + required: true + +runs: + using: "composite" + steps: + - name: Install dependencies + run: npm install --silent --no-progress --prefix $GITHUB_ACTION_PATH/.. + shell: bash + - name: Get local stats + id: get-stats + shell: bash + run: | + rum=$(cat ./build/nr-rum-standard.stats.json); echo "rum=$rum" >> $GITHUB_OUTPUT; + full=$(cat ./build/nr-full-standard.stats.json); echo "full=$full" >> $GITHUB_OUTPUT; + spa=$(cat ./build/nr-spa-standard.stats.json); echo "spa=$spa" >> $GITHUB_OUTPUT; + - name: Report rum size to NR + uses: metal-messiah/webpack-build-size-action@main + with: + nr-api-key: ${{ inputs.nr-api-key }} + nr-account-id: '550352' + nr-env: 'staging' + analysis-file-contents: ${{ steps.get-stats.outputs.rum }} + file-name-filter: '.min.js' + - name: Report full size to NR + uses: metal-messiah/webpack-build-size-action@main + with: + nr-api-key: ${{ inputs.nr-api-key }} + nr-account-id: '550352' + nr-env: 'staging' + analysis-file-contents: ${{ steps.get-stats.outputs.full }} + file-name-filter: '.min.js' + - name: Report spa size to NR + uses: metal-messiah/webpack-build-size-action@main + with: + nr-api-key: ${{ inputs.nr-api-key }} + nr-account-id: '550352' + nr-env: 'staging' + analysis-file-contents: ${{ steps.get-stats.outputs.spa }} + file-name-filter: '.min.js' diff --git a/.github/workflows/publish-dev.yml b/.github/workflows/publish-dev.yml index 326d9ecb1..7408eed32 100644 --- a/.github/workflows/publish-dev.yml +++ b/.github/workflows/publish-dev.yml @@ -90,6 +90,20 @@ jobs: fastly_key: ${{ secrets.FASTLY_PURGE_KEY }} fastly_service: staging-js-agent.newrelic.com asset_path: ${{ join(fromJson(steps.s3-upload.outputs.results).*.Key, ' ') }} + # This step creates a new Change Tracking Marker + - name: New Relic Application Deployment Marker + uses: newrelic/deployment-marker-action@v2.3.0 + with: + apiKey: ${{ secrets.INTERNAL_STAGING_INGEST_LICENSE_KEY }} + guid: NTUwMzUyfEJST1dTRVJ8QVBQTElDQVRJT058ODkzODM5MjI + commit: "${{ github.sha }}" + version: "${{ github.ref_name }}" + user: "${{ github.actor }}" + # track build size as custom event + - name: Report local stats as NR event + uses: './.github/actions/nr-report-build-size' + with: + nr-api-key: ${{ secrets.INTERNAL_STAGING_INGEST_LICENSE_KEY }} # Publish dev to staging NRDB # publish-dev-nr: diff --git a/.github/workflows/pull-request-checks.yml b/.github/workflows/pull-request-checks.yml index 76b83ae97..2e70e552c 100644 --- a/.github/workflows/pull-request-checks.yml +++ b/.github/workflows/pull-request-checks.yml @@ -97,6 +97,10 @@ jobs: pr_number: ${{ github.event.number }} comment: ${{ steps.asset-size-report.outputs.results }} comment_tag: + - name: Report local stats as NR event + uses: './.github/actions/nr-report-build-size' + with: + nr-api-key: ${{ secrets.INTERNAL_STAGING_INGEST_LICENSE_KEY }} # Jobs for workflow_dispatch events From c2c05a14b5f6f2427d49f5ab2da3527c0a8c75f5 Mon Sep 17 00:00:00 2001 From: ptang-nr Date: Fri, 27 Dec 2024 10:00:58 -0800 Subject: [PATCH 4/4] chore: Add missing GHA deps (#1297) --- .github/workflows/branch-cleanup.yml | 4 ++++ .github/workflows/delete-experiment.yml | 3 +++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/branch-cleanup.yml b/.github/workflows/branch-cleanup.yml index 880e098f3..2f60f89ac 100644 --- a/.github/workflows/branch-cleanup.yml +++ b/.github/workflows/branch-cleanup.yml @@ -13,6 +13,10 @@ jobs: run: shell: bash steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22.11.0 # See package.json for the stable node version that works with our testing. Do not change this unless you know what you are doing as some node versions do not play nicely with our testing server. - name: Clean up for deleted branch id: cleanup-start run: echo "Clean up for branch ${{ github.event.ref }}" diff --git a/.github/workflows/delete-experiment.yml b/.github/workflows/delete-experiment.yml index 5f818ca93..309501669 100644 --- a/.github/workflows/delete-experiment.yml +++ b/.github/workflows/delete-experiment.yml @@ -23,6 +23,9 @@ jobs: shell: bash steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22.11.0 # See package.json for the stable node version that works with our testing. Do not change this unless you know what you are doing as some node versions do not play nicely with our testing server. - name: Clean branch name id: clean-branch-name run: echo "results=$(echo '${{ github.ref }}' | sed 's/refs\/heads\///g' | sed 's/[^[:alnum:].-]/-/g')" >> $GITHUB_OUTPUT