diff --git a/app/package.json b/app/package.json index 14d16077..ba3603b2 100644 --- a/app/package.json +++ b/app/package.json @@ -15,7 +15,7 @@ "dependencies": { "@atlassiansox/analytics-node-client": "^4.1.1", "@forge/api": "3.0.0", - "@forge/metrics": "0.2.0", + "@forge/metrics": "^0.2.2", "@forge/resolver": "1.5.14", "atlassian-jwt": "^2.0.2", "crypto": "^1.0.1", diff --git a/app/src/check-permissions.ts b/app/src/check-permissions.ts index de64d21f..c9583e9b 100644 --- a/app/src/check-permissions.ts +++ b/app/src/check-permissions.ts @@ -1,4 +1,6 @@ import api, { route } from '@forge/api'; +import { internalMetrics } from '@forge/metrics'; +import { metricFailedRequests } from './common/metric-names'; // Forge does not export their Request type, so we have to resort to 'any' for now. export const adminPermissionCheck = async (req: any): Promise => { @@ -21,6 +23,7 @@ export const adminPermissionCheck = async (req: any): Promise => { }); if (permissions.status === 403) { + internalMetrics.counter(metricFailedRequests.notJiraAdminError).incr(); throw new Error('Only Jira administrators can access the Jenkins for Jira admin page.'); } diff --git a/app/src/common/metric-names.ts b/app/src/common/metric-names.ts index a6bc2b42..17bc1792 100644 --- a/app/src/common/metric-names.ts +++ b/app/src/common/metric-names.ts @@ -13,5 +13,30 @@ export const metricResolverEmitter = { export const metricFailedRequests = { sendEventToJiraUnauthorizedError: `${server}.sendEventToJiraUnauthorized.failure`, - sendEventToJiraError: `${server}.sendEventToJira.failure` + sendEventToJiraError: `${server}.sendEventToJira.failure`, + notJiraAdminError: `${server}.error.not-jira-admin`, + jenkinsAppError: `${server}.error.jenkins-app-error`, + unexpectedWebTriggerError: `${server}.error.upexpected-webtrigger-error`, + resetJenkinsRequestNoUuidError: `${server}.error.reset-jenkins-request-no-uuid`, + unsupportedResetJenkinsRequestError: `${server}.error.reset-jenkins-request-unsupported-request`, + unexpectedResetJenkinsRequestError: `${server}.error.reset-jenkins-request-unexpected-request`, + resetJenkinsServerInvocationError: `${server}.error.reset-jenkins-server-invocation-error`, + deleteBuildsAndDeploymentsError: `${server}.error.delete-builds-and-deployments-error`, + connectJenkinsServerError: `${server}.error.connect-jenkins--server-error`, + disconnectJenkinsServerError: `${server}.error.disconnect-jenkins-server-error`, + getAllJenkinsServerError: `${server}.error.get-all-jenkins-server-error`, + getJenkinsServerWithSecretError: `${server}.error.get-jenkins-server-with-secret-error`, + updateJenkinsServerError: `${server}.error.udpate-jenkins-server-error`, + updateJenkinsServerStateError: `${server}.error.udpate-jenkins-server-state-error` +}; + +export const metricSuccessfulRequests = { + resetJenkinsRequest: `${server}.success.reset-jenkins-request`, + resetJenkinsServerInvocation: `${server}.error.reset-jenkins-server-invocation`, + deleteBuildsAndDeployments: `${server}.error.delete-builds-and-deployments`, + connectJenkinsServer: `${server}.success.connect-jenkins-server`, + disconnectJenkinsServer: `${server}.success.disconnect-jenkins-server`, + getAllJenkinsServer: `${server}.success.get-all-jenkins-server`, + getJenkinsServerWithSecret: `${server}.success.get-jenkins-server-with-secret`, + updateJenkinsServer: `${server}.error.udpate-jenkins-server` }; diff --git a/app/src/storage/connect-jenkins-server.test.ts b/app/src/storage/connect-jenkins-server.test.ts index bdde3043..34a0a044 100644 --- a/app/src/storage/connect-jenkins-server.test.ts +++ b/app/src/storage/connect-jenkins-server.test.ts @@ -1,11 +1,42 @@ import { JenkinsServer } from '../common/types'; import { connectJenkinsServer } from './connect-jenkins-server'; +jest.mock('@forge/api', () => { + return { + __getRuntime: jest.fn(), + storage: { + set: jest.fn(), + setSecret: jest.fn() + } + }; +}); + +jest.mock('@forge/metrics', () => { + const incr = jest.fn(); + const counter = jest.fn(() => ({ incr })); + + return { + __esModule: true, + default: { + internalMetrics: { + counter + } + }, + internalMetrics: { + counter + } + }; +}); + describe('Connect Jenkins Server Suite', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('Should store Jenkins server configuration to Forge Storage', async () => { const jenkinsServer: JenkinsServer = { - name: 'test-jenkins-sever', - uuid: 'unique-uid', + name: 'test-jenkins-server', + uuid: 'unique-uuid', secret: 'secret!!!', pipelines: [] }; diff --git a/app/src/storage/connect-jenkins-server.ts b/app/src/storage/connect-jenkins-server.ts index f899f577..b144f8fa 100644 --- a/app/src/storage/connect-jenkins-server.ts +++ b/app/src/storage/connect-jenkins-server.ts @@ -1,13 +1,18 @@ import { storage } from '@forge/api'; +import { internalMetrics } from '@forge/metrics'; import { JenkinsServer } from '../common/types'; import { SECRET_STORAGE_KEY_PREFIX, SERVER_STORAGE_KEY_PREFIX } from './constants'; import { JenkinsServerStorageError } from '../common/error'; import { Logger } from '../config/logger'; import { sendAnalytics } from '../analytics/analytics-client'; import { AnalyticsTrackEventsEnum } from '../analytics/analytics-events'; +import { metricFailedRequests, metricSuccessfulRequests } from '../common/metric-names'; -// eslint-disable-next-line max-len -const connectJenkinsServer = async (jenkinsServer: JenkinsServer, cloudId: string, accountId: string): Promise => { +const connectJenkinsServer = async ( + jenkinsServer: JenkinsServer, + cloudId: string, + accountId: string +): Promise => { const logger = Logger.getInstance('connectJenkinsServer'); try { @@ -18,10 +23,12 @@ const connectJenkinsServer = async (jenkinsServer: JenkinsServer, cloudId: strin await storage.setSecret(`${SECRET_STORAGE_KEY_PREFIX}${uuid}`, secret); logger.info('Jenkins server configuration saved successfully!', { uuid }); + internalMetrics.counter(metricSuccessfulRequests.connectJenkinsServer).incr(); await sendConnectAnalytics(cloudId, accountId); return true; } catch (error) { logger.error('Failed to store Jenkins server configuration', { error }); + internalMetrics.counter(metricFailedRequests.connectJenkinsServerError).incr(); throw new JenkinsServerStorageError('Failed to store jenkins server configuration'); } }; diff --git a/app/src/storage/disconnect-jenkins-server.test.ts b/app/src/storage/disconnect-jenkins-server.test.ts index 3612b1a7..9e21a56f 100644 --- a/app/src/storage/disconnect-jenkins-server.test.ts +++ b/app/src/storage/disconnect-jenkins-server.test.ts @@ -1,8 +1,39 @@ import { disconnectJenkinsServer } from './disconnect-jenkins-server'; +jest.mock('@forge/api', () => { + return { + __getRuntime: jest.fn(), + storage: { + delete: jest.fn(), + deleteSecret: jest.fn() + } + }; +}); + +jest.mock('@forge/metrics', () => { + const incr = jest.fn(); + const counter = jest.fn(() => ({ incr })); + + return { + __esModule: true, + default: { + internalMetrics: { + counter + } + }, + internalMetrics: { + counter + } + }; +}); + describe('Delete Jenkins Server Suite', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('Should delete Jenkins server configuration from Forge Storage', async () => { - const result = await disconnectJenkinsServer('test-uid', 'cloudId', 'accountId'); + const result = await disconnectJenkinsServer('test-uuid', 'cloudId', 'accountId'); expect(result).toBe(true); }); }); diff --git a/app/src/storage/disconnect-jenkins-server.ts b/app/src/storage/disconnect-jenkins-server.ts index 683470f5..609c6a06 100644 --- a/app/src/storage/disconnect-jenkins-server.ts +++ b/app/src/storage/disconnect-jenkins-server.ts @@ -1,9 +1,11 @@ import { storage } from '@forge/api'; +import { internalMetrics } from '@forge/metrics'; import { SECRET_STORAGE_KEY_PREFIX, SERVER_STORAGE_KEY_PREFIX } from './constants'; import { JenkinsServerStorageError } from '../common/error'; import { Logger } from '../config/logger'; import { sendAnalytics } from '../analytics/analytics-client'; import { AnalyticsTrackEventsEnum } from '../analytics/analytics-events'; +import { metricFailedRequests, metricSuccessfulRequests } from '../common/metric-names'; export const disconnectJenkinsServer = async (uuid: string, cloudId: string, accountId: string): Promise => { const logger = Logger.getInstance('disconnectJenkinsServer'); @@ -13,11 +15,12 @@ export const disconnectJenkinsServer = async (uuid: string, cloudId: string, acc const deleteSecretPromise = await storage.deleteSecret(`${SECRET_STORAGE_KEY_PREFIX}${uuid}`); await Promise.all([deleteJenkinsServerPromise, deleteSecretPromise]); logger.info('Jenkins server successfully disconnected!', { uuid }); + internalMetrics.counter(metricSuccessfulRequests.disconnectJenkinsServer).incr(); await sendDisconnectAnalytics(cloudId, accountId); - return true; } catch (error) { logger.error('Failed to delete jenkins server configuration', { error }); + internalMetrics.counter(metricFailedRequests.disconnectJenkinsServerError).incr(); throw new JenkinsServerStorageError('Failed to delete jenkins server configuration'); } }; diff --git a/app/src/storage/get-all-jenkins-servers.test.ts b/app/src/storage/get-all-jenkins-servers.test.ts index 08b0af54..650f135f 100644 --- a/app/src/storage/get-all-jenkins-servers.test.ts +++ b/app/src/storage/get-all-jenkins-servers.test.ts @@ -5,21 +5,30 @@ import { JenkinsServer } from '../common/types'; import { getAllJenkinsServers } from './get-all-jenkins-servers'; jest.mock('@forge/api', () => ({ + __getRuntime: jest.fn(), storage: { - get: jest.fn(), - set: jest.fn(), - setSecret: jest.fn(), - getSecret: jest.fn(), - delete: jest.fn(), - deleteSecret: jest.fn(), query: jest.fn(() => new MockQueryBuilder()) }, - webTrigger: { - getUrl: jest.fn() - }, startsWith: jest.fn() })); +jest.mock('@forge/metrics', () => { + const incr = jest.fn(); + const counter = jest.fn(() => ({ incr })); + + return { + __esModule: true, + default: { + internalMetrics: { + counter + } + }, + internalMetrics: { + counter + } + }; +}); + class MockQueryBuilder implements QueryBuilder { limit(): QueryBuilder { return this; @@ -67,6 +76,10 @@ const mockListResult: ListResult = { }; describe('Get All Jenkins Servers Suite', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('Should return all Jenkins servers sorted by last event timestamp', async () => { const allJenkinsServers: JenkinsServer[] = await getAllJenkinsServers(); diff --git a/app/src/storage/get-all-jenkins-servers.ts b/app/src/storage/get-all-jenkins-servers.ts index 469f05ba..9f35035a 100644 --- a/app/src/storage/get-all-jenkins-servers.ts +++ b/app/src/storage/get-all-jenkins-servers.ts @@ -1,9 +1,11 @@ import { startsWith, storage, ListResult, Result } from '@forge/api'; +import { internalMetrics } from '@forge/metrics'; import { JenkinsPipeline, JenkinsServer } from '../common/types'; import { SERVER_STORAGE_KEY_PREFIX } from './constants'; import { Logger } from '../config/logger'; +import { metricFailedRequests, metricSuccessfulRequests } from '../common/metric-names'; async function getAllJenkinsServers(): Promise { const logger = Logger.getInstance('getAllJenkinsServers'); @@ -20,9 +22,11 @@ async function getAllJenkinsServers(): Promise { } const jenkinsServers = transformToJenkinsServers(results); + internalMetrics.counter(metricSuccessfulRequests.getAllJenkinsServer).incr(); return jenkinsServers; } catch (error) { logger.error('Failed to fetch Jenkins server list', { error }); + internalMetrics.counter(metricFailedRequests.getAllJenkinsServerError).incr(); throw error; } } diff --git a/app/src/storage/get-jenkins-server-with-secret.ts b/app/src/storage/get-jenkins-server-with-secret.ts index b0985cac..4c123480 100644 --- a/app/src/storage/get-jenkins-server-with-secret.ts +++ b/app/src/storage/get-jenkins-server-with-secret.ts @@ -1,9 +1,11 @@ import { storage } from '@forge/api'; +import { internalMetrics } from '@forge/metrics'; import { getJenkinsServerSecret } from './get-jenkins-server-secret'; import { SERVER_STORAGE_KEY_PREFIX } from './constants'; import { JenkinsServer } from '../common/types'; import { NoJenkinsServerError } from '../common/error'; import { Logger } from '../config/logger'; +import { metricFailedRequests, metricSuccessfulRequests } from '../common/metric-names'; const getJenkinsServerWithSecret = async (jenkinsServerUuid: string): Promise => { const logger = Logger.getInstance('getJenkinsServerWithSecret'); @@ -17,6 +19,7 @@ const getJenkinsServerWithSecret = async (jenkinsServerUuid: string): Promise { + return { + __getRuntime: jest.fn(), + storage: { + set: jest.fn(), + get: jest.fn(), + query: jest.fn() + }, + startsWith: jest.fn() + }; +}); + +jest.mock('@forge/metrics', () => { + const incr = jest.fn(); + const counter = jest.fn(() => ({ incr })); + + return { + __esModule: true, + default: { + internalMetrics: { + counter + } + }, + internalMetrics: { + counter + } + }; +}); + describe('Update Jenkins Plugin Config State Suite', () => { const mockLogger = { - error: jest.fn(), + error: jest.fn() } as unknown as Logger; - beforeEach(() => { + afterEach(() => { jest.clearAllMocks(); }); it('Should update Jenkins plugin config state to Forge Storage', async () => { + const mockResolvedValue = jest.fn(); + mockResolvedValue.mockResolvedValue({ + key: 'unique-uuid', + pipelines: [] + }); + + storage.get = mockResolvedValue; + const jenkinsEvent = { ipAddress: '192.168.0.1', autoBuildEnabled: true, @@ -78,10 +115,10 @@ describe('Update Jenkins Plugin Config State Suite', () => { autoDeploymentsRegex: '' } as unknown as JenkinsPluginConfigEvent; - await updateJenkinsPluginConfigState('unique-uid', jenkinsEvent, 'cloudId', mockLogger); + await updateJenkinsPluginConfigState('unique-uuid', jenkinsEvent, 'cloudId', mockLogger); expect(storage.set).toBeCalledWith( - `jenkinsServer-unique-uid`, + `jenkinsServer-unique-uuid`, expect.objectContaining({ pluginConfig: { ipAddress: '192.168.0.1', @@ -96,6 +133,10 @@ describe('Update Jenkins Plugin Config State Suite', () => { }); it('Should throw an error if updating Jenkins plugin config fails', async () => { + const mockResolvedValue = jest.fn(); + mockResolvedValue.mockResolvedValue(undefined); + storage.get = mockResolvedValue; + const jenkinsEvent = { ipAddress: '192.168.0.1' } as unknown as JenkinsPluginConfigEvent; @@ -112,8 +153,20 @@ describe('Update Jenkins Plugin Config State Suite', () => { }); describe('Update Jenkins Server Suite', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('Should update Jenkins server state to Forge Storage', async () => { - await updateJenkinsServerState('unique-uid', { + const mockResolvedValue = jest.fn(); + mockResolvedValue.mockResolvedValue({ + key: 'unique-uuid', + pipelines: [] + }); + + storage.get = mockResolvedValue; + + await updateJenkinsServerState('unique-uuid', { name: 'PipelineA', lastEventType: EventType.BUILD, lastEventStatus: 'successful', @@ -123,8 +176,12 @@ describe('Update Jenkins Server Suite', () => { }); it('Should throw NoJenkinsServerError when invalid uid is passed', async () => { + const mockResolvedValue = jest.fn(); + mockResolvedValue.mockResolvedValue(undefined); + storage.get = mockResolvedValue; + expect(async () => { - await updateJenkinsServerState('error-uid', { + await updateJenkinsServerState('error-uuid', { name: 'PipelineA', lastEventType: EventType.BUILD, lastEventStatus: 'successful', @@ -134,6 +191,10 @@ describe('Update Jenkins Server Suite', () => { }); it('Should throw an error if the server does not exist', async () => { + const mockResolvedValue = jest.fn(); + mockResolvedValue.mockResolvedValue(undefined); + storage.get = mockResolvedValue; + try { await updateJenkinsServerState( mockSingleJenkinsPipeline.uuid, diff --git a/app/src/storage/update-jenkins-server-state.ts b/app/src/storage/update-jenkins-server-state.ts index 945caf83..63db47b9 100644 --- a/app/src/storage/update-jenkins-server-state.ts +++ b/app/src/storage/update-jenkins-server-state.ts @@ -1,4 +1,5 @@ import { storage } from '@forge/api'; +import { internalMetrics } from '@forge/metrics'; import { uniq } from 'lodash'; import { NoJenkinsServerError } from '../common/error'; import { JenkinsPipeline, JenkinsServer } from '../common/types'; @@ -7,6 +8,7 @@ import { Logger } from '../config/logger'; import { JenkinsPluginConfigEvent } from '../webtrigger/types'; import { sendAnalytics } from '../analytics/analytics-client'; import { AnalyticsTrackEventsEnum } from '../analytics/analytics-events'; +import { metricFailedRequests, metricSuccessfulRequests } from '../common/metric-names'; export const updateOrInsertPipeline = (jenkinsServer: JenkinsServer, incomingPipeline: JenkinsPipeline): void => { const pipelineExists = jenkinsServer.pipelines.some((pipeline) => pipeline.name === incomingPipeline.name); @@ -79,8 +81,10 @@ async function updateJenkinsServerState( `${SERVER_STORAGE_KEY_PREFIX}${jenkinsServer.uuid}`, jenkinsServer ); + internalMetrics.counter(metricSuccessfulRequests.updateJenkinsServer).incr(); } catch (error) { logger?.error(`Failed to update Jenkins server uuid ${uuid}`); + internalMetrics.counter(metricFailedRequests.updateJenkinsServerStateError).incr(); throw error; } } diff --git a/app/src/webtrigger/handle-jenkins-request.test.ts b/app/src/webtrigger/handle-jenkins-request.test.ts index 0beddf07..5cb5eac9 100644 --- a/app/src/webtrigger/handle-jenkins-request.test.ts +++ b/app/src/webtrigger/handle-jenkins-request.test.ts @@ -22,6 +22,34 @@ import { Errors } from '../common/error-messages'; jest.mock('../jira-client/send-event-to-jira'); jest.mock('../jira-client/get-gating-status-from-jira'); +jest.mock('@forge/api', () => { + return { + __getRuntime: jest.fn(), + storage: { + getSecret: jest.fn(), + get: jest.fn(), + set: jest.fn() + } + }; +}); + +jest.mock('@forge/metrics', () => { + const incr = jest.fn(); + const counter = jest.fn(() => ({ incr })); + + return { + __esModule: true, + default: { + internalMetrics: { + counter + } + }, + internalMetrics: { + counter + } + }; +}); + const CLOUD_ID = '97eaf652-4b6e-46cf-80c2-d99327a63bc1'; const JENKINS_SERVER_UUID = '1aaf4ea5-bca5-4ec9-86ed-c359e359eb97'; diff --git a/app/src/webtrigger/handle-reset-jenkins-request.test.ts b/app/src/webtrigger/handle-reset-jenkins-request.test.ts index ee5cd960..6a19ade0 100644 --- a/app/src/webtrigger/handle-reset-jenkins-request.test.ts +++ b/app/src/webtrigger/handle-reset-jenkins-request.test.ts @@ -28,7 +28,34 @@ jest.mock('atlassian-jwt', () => { }; }); +jest.mock('@forge/api', () => { + return { + __getRuntime: jest.fn() + }; +}); + +jest.mock('@forge/metrics', () => { + const incr = jest.fn(); + const counter = jest.fn(() => ({ incr })); + + return { + __esModule: true, + default: { + internalMetrics: { + counter + } + }, + internalMetrics: { + counter + } + }; +}); + describe('Reset Jenkins Server request suite', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + const now = Date.now() / 1000; // Convert milliseconds to seconds const iat = now - 2; // Subtract 2 seconds diff --git a/app/src/webtrigger/handle-reset-jenkins-request.ts b/app/src/webtrigger/handle-reset-jenkins-request.ts index 72c7e563..b0d38c2f 100644 --- a/app/src/webtrigger/handle-reset-jenkins-request.ts +++ b/app/src/webtrigger/handle-reset-jenkins-request.ts @@ -1,3 +1,4 @@ +import { internalMetrics } from '@forge/metrics'; import { deleteBuilds } from '../jira-client/delete-builds'; import { deleteDeployments } from '../jira-client/delete-deployments'; import { disconnectJenkinsServer } from '../storage/disconnect-jenkins-server'; @@ -11,6 +12,7 @@ import { createWebtriggerResponse, handleWebtriggerError } from './webtrigger-ut import { Errors } from '../common/error-messages'; import { Logger } from '../config/logger'; import { extractBodyFromSymmetricJwt, verifySymmetricJwt } from './jwt'; +import { metricFailedRequests, metricSuccessfulRequests } from '../common/metric-names'; async function handleResetJenkinsRequest( request: WebtriggerRequest, @@ -27,17 +29,21 @@ async function handleResetJenkinsRequest( if (jenkinsRequest.requestType === RequestType.RESET_JENKINS_SERVER) { await resetJenkinsServer(cloudId, logger, jenkinsRequest.data?.excludeUuid); + internalMetrics.counter(metricSuccessfulRequests.resetJenkinsRequest).incr(); return createWebtriggerResponse(200, '{"success": true}'); } if (jenkinsRequest.requestType === RequestType.DELETE_BUILDS_DEPLOYMENTS) { if (jenkinsRequest.data?.uuid) { await deleteBuildsAndDeployments(cloudId, jenkinsRequest.data.uuid, logger); + internalMetrics.counter(metricSuccessfulRequests.resetJenkinsRequest).incr(); return createWebtriggerResponse(200, '{"success": true}'); } + internalMetrics.counter(metricFailedRequests.resetJenkinsRequestNoUuidError).incr(); return createWebtriggerResponse(400, `{"error": ${Errors.MISSING_UUID}`); } + internalMetrics.counter(metricFailedRequests.unsupportedResetJenkinsRequestError).incr(); logger.error('handleResetJenkinsRequest error', { error: Errors.UNSUPPORTED_REQUEST_TYPE }); throw new UnsupportedRequestTypeError(Errors.UNSUPPORTED_REQUEST_TYPE); } catch (error) { @@ -61,12 +67,14 @@ async function resetJenkinsServer(cloudId: string, logger: Logger, excludeUuid?: deleteBuilds(cloudId, jenkinsServerUuid), deleteDeployments(cloudId, jenkinsServerUuid) ]); + internalMetrics.counter(metricSuccessfulRequests.resetJenkinsServerInvocation).incr(); disconnectJenkinsServerPromises.push(disconnectJenkinsServerPromise); }); return await Promise.all(disconnectJenkinsServerPromises); } catch (error) { logger.error('resetJenkinsServer error', { error: Errors.INVOCATION_ERROR }); + internalMetrics.counter(metricFailedRequests.resetJenkinsServerInvocationError).incr(); throw new InvocationError(Errors.INVOCATION_ERROR); } } @@ -75,8 +83,10 @@ async function deleteBuildsAndDeployments(cloudId: string, uuid: string, logger: try { await deleteBuilds(cloudId, uuid); await deleteDeployments(cloudId, uuid); + internalMetrics.counter(metricSuccessfulRequests.deleteBuildsAndDeployments).incr(); } catch (error) { logger.error('deleteBuildsAndDeployments error', { error: Errors.INVOCATION_ERROR }); + internalMetrics.counter(metricFailedRequests.deleteBuildsAndDeploymentsError).incr(); throw new InvocationError(Errors.INVOCATION_ERROR); } } diff --git a/app/src/webtrigger/webtrigger-utils.ts b/app/src/webtrigger/webtrigger-utils.ts index 5a0c8c8a..848bef6d 100644 --- a/app/src/webtrigger/webtrigger-utils.ts +++ b/app/src/webtrigger/webtrigger-utils.ts @@ -1,11 +1,15 @@ +import { internalMetrics } from '@forge/metrics'; import { JenkinsAppError } from '../common/error'; import { WebtriggerRequest, WebtriggerResponse } from './types'; import { Logger } from '../config/logger'; +import { metricFailedRequests } from '../common/metric-names'; + /** * Translates certain errors into an appropriate webtrigger response. */ function handleWebtriggerError(request: WebtriggerRequest, error: any, logger: Logger): WebtriggerResponse { if (error instanceof JenkinsAppError) { + internalMetrics.counter(metricFailedRequests.jenkinsAppError).incr(); return createWebtriggerResponse(400, error.message); } diff --git a/app/yarn.lock b/app/yarn.lock index 34bdfaa3..d5ff7659 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -35,7 +35,7 @@ resolved "https://packages.atlassian.com/api/npm/npm-remote/@babel/compat-data/-/compat-data-7.17.10.tgz" integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8": +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0": version "7.18.2" resolved "https://packages.atlassian.com/api/npm/npm-remote/@babel/core/-/core-7.18.2.tgz" integrity sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ== @@ -358,6 +358,18 @@ "@types/node-fetch" "^2.6.10" node-fetch "2.7.0" +"@forge/api@3.1.0": + version "3.1.0" + resolved "https://packages.atlassian.com/api/npm/npm-remote/@forge/api/-/api-3.1.0.tgz#c318082588d527f3740fbffed8f3e816617edaaf" + integrity sha512-FVjDEeZO8wWkVLa++KPm8NT7if+LIq0kepE3+PyAhRvfhXfNMS98ofZn9P1DHnvfvEr5Pyoekt1jLStCMivKdg== + dependencies: + "@forge/auth" "0.0.5" + "@forge/egress" "1.2.12" + "@forge/storage" "1.5.14" + "@forge/util" "1.4.0" + "@types/node-fetch" "^2.6.10" + node-fetch "2.7.0" + "@forge/auth@0.0.4": version "0.0.4" resolved "https://packages.atlassian.com/api/npm/npm-remote/@forge/auth/-/auth-0.0.4.tgz" @@ -386,13 +398,13 @@ dependencies: minimatch "^5.1.0" -"@forge/metrics@0.2.0": - version "0.2.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/@forge/metrics/-/metrics-0.2.0.tgz" - integrity sha512-QgTD5Y1uRRMSgZi4KQhAVYAMDgzKuV7lDgGeljo0MaJRqAOW5LGTipicXbDwPo6zruFDzFHJJ1bHWLrXvNoW7A== +"@forge/metrics@^0.2.2": + version "0.2.2" + resolved "https://packages.atlassian.com/api/npm/npm-remote/@forge/metrics/-/metrics-0.2.2.tgz#facf33b15797fb813e3499001b87c6ad7eaf36d6" + integrity sha512-tpOnQkXFIuvKt+hN/8F66ySEA8NezWHek6htfF15AhQp+0KDb35a5gVyOhQdq0IjHHsUMweEdVFlqfVgnDbqdA== dependencies: - "@forge/api" "3.0.0" - "@forge/runtime" "5.3.0" + "@forge/api" "3.1.0" + "@forge/runtime" "5.3.2" "@forge/resolver@1.5.14": version "1.5.14" @@ -401,10 +413,10 @@ dependencies: "@forge/api" "2.18.4" -"@forge/runtime@5.3.0": - version "5.3.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/@forge/runtime/-/runtime-5.3.0.tgz" - integrity sha512-e/bIl1fSK2EnTCZv3VLsJfn2xYU+iqTU/itrkleDhj8EHoN+RkR82jVeUtGzz0CD3BPZ4jTPDngHp7HAW1Bw3Q== +"@forge/runtime@5.3.2": + version "5.3.2" + resolved "https://packages.atlassian.com/api/npm/npm-remote/@forge/runtime/-/runtime-5.3.2.tgz#990dd5c15be6deef8068949bfc5c3f28c2241378" + integrity sha512-+IqTjC10sA5OpwvWJ+pGG+KbtDyyw86nRMg0K+cxZxMcnIOQZ4onVi561n2Eg4MiJ+dsKbP9H0nW1BXXqdE+Nw== dependencies: "@forge/util" "1.4.0" fp-ts "^2.16.2" @@ -715,7 +727,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://packages.atlassian.com/api/npm/npm-remote/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -730,7 +742,7 @@ "@scarf/scarf@^1.1.1": version "1.3.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/@scarf/scarf/-/scarf-1.3.0.tgz" + resolved "https://packages.atlassian.com/api/npm/npm-remote/@scarf/scarf/-/scarf-1.3.0.tgz#f8c75560d0dace4452dee1e31995e6396e61f3ee" integrity sha512-lHKK8M5CTcpFj2hZDB3wIjb0KAbEOgDmiJGDv1WBRfQgRm/a8/XMEkG/N1iM01xgbUDsPQwi42D+dFo1XPAKew== "@segment/analytics-core@1.4.1": @@ -868,7 +880,7 @@ dependencies: "@types/jest" "*" -"@types/jest@*", "@types/jest@^27.0.0", "@types/jest@27.5.2": +"@types/jest@*", "@types/jest@27.5.2": version "27.5.2" resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/jest/-/jest-27.5.2.tgz" integrity sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA== @@ -940,7 +952,7 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.13.0", "@typescript-eslint/eslint-plugin@5.61.0": +"@typescript-eslint/eslint-plugin@5.61.0": version "5.61.0" resolved "https://packages.atlassian.com/api/npm/npm-remote/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.61.0.tgz" integrity sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g== @@ -956,7 +968,7 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@5.61.0": +"@typescript-eslint/parser@5.61.0": version "5.61.0" resolved "https://packages.atlassian.com/api/npm/npm-remote/@typescript-eslint/parser/-/parser-5.61.0.tgz" integrity sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg== @@ -1024,7 +1036,7 @@ "@typescript-eslint/types" "5.61.0" eslint-visitor-keys "^3.3.0" -"@webassemblyjs/ast@^1.11.5", "@webassemblyjs/ast@1.11.6": +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": version "1.11.6" resolved "https://packages.atlassian.com/api/npm/npm-remote/@webassemblyjs/ast/-/ast-1.11.6.tgz" integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== @@ -1125,7 +1137,7 @@ "@webassemblyjs/wasm-gen" "1.11.6" "@webassemblyjs/wasm-parser" "1.11.6" -"@webassemblyjs/wasm-parser@^1.11.5", "@webassemblyjs/wasm-parser@1.11.6": +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": version "1.11.6" resolved "https://packages.atlassian.com/api/npm/npm-remote/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz" integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== @@ -1215,16 +1227,16 @@ acorn-walk@^7.1.1: resolved "https://packages.atlassian.com/api/npm/npm-remote/acorn-walk/-/acorn-walk-7.2.0.tgz" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8, acorn@^8.2.4, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: - version "8.9.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/acorn/-/acorn-8.9.0.tgz" - integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ== - acorn@^7.1.1: version "7.4.1" resolved "https://packages.atlassian.com/api/npm/npm-remote/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.2.4, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: + version "8.9.0" + resolved "https://packages.atlassian.com/api/npm/npm-remote/acorn/-/acorn-8.9.0.tgz" + integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ== + agent-base@6: version "6.0.2" resolved "https://packages.atlassian.com/api/npm/npm-remote/agent-base/-/agent-base-6.0.2.tgz" @@ -1237,7 +1249,7 @@ ajv-keywords@^3.5.2: resolved "https://packages.atlassian.com/api/npm/npm-remote/ajv-keywords/-/ajv-keywords-3.5.2.tgz" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.12.4, ajv@^6.12.5, ajv@^6.9.1: +ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://packages.atlassian.com/api/npm/npm-remote/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1360,7 +1372,7 @@ available-typed-arrays@^1.0.5: resolved "https://packages.atlassian.com/api/npm/npm-remote/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -babel-jest@^27.5.1, "babel-jest@>=27.0.0 <28": +babel-jest@^27.5.1: version "27.5.1" resolved "https://packages.atlassian.com/api/npm/npm-remote/babel-jest/-/babel-jest-27.5.1.tgz" integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== @@ -1524,16 +1536,7 @@ caniuse-lite@^1.0.30001332: resolved "https://packages.atlassian.com/api/npm/npm-remote/caniuse-lite/-/caniuse-lite-1.0.30001346.tgz" integrity sha512-q6ibZUO2t88QCIPayP/euuDREq+aMAxFE5S70PkrLh0iTDj/zEhgvJRKC2+CvXY6EWc6oQwUR48lL5vCW6jiXQ== -chalk@^2.0.0: - version "2.4.2" - resolved "https://packages.atlassian.com/api/npm/npm-remote/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://packages.atlassian.com/api/npm/npm-remote/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1612,16 +1615,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@~1.1.4: - version "1.1.4" - resolved "https://packages.atlassian.com/api/npm/npm-remote/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://packages.atlassian.com/api/npm/npm-remote/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@~1.1.4: + version "1.1.4" + resolved "https://packages.atlassian.com/api/npm/npm-remote/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + colorette@^2.0.14: version "2.0.20" resolved "https://packages.atlassian.com/api/npm/npm-remote/colorette/-/colorette-2.0.20.tgz" @@ -1717,6 +1720,13 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://packages.atlassian.com/api/npm/npm-remote/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.2.7: version "3.2.7" resolved "https://packages.atlassian.com/api/npm/npm-remote/debug/-/debug-3.2.7.tgz" @@ -1724,13 +1734,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4, debug@4: - version "4.3.4" - resolved "https://packages.atlassian.com/api/npm/npm-remote/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decimal.js@^10.2.1: version "10.3.1" resolved "https://packages.atlassian.com/api/npm/npm-remote/decimal.js/-/decimal.js-10.3.1.tgz" @@ -1944,7 +1947,7 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-airbnb-base@^15.0.0, eslint-config-airbnb-base@15.0.0: +eslint-config-airbnb-base@15.0.0, eslint-config-airbnb-base@^15.0.0: version "15.0.0" resolved "https://packages.atlassian.com/api/npm/npm-remote/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz" integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig== @@ -1977,7 +1980,7 @@ eslint-module-utils@^2.7.4: dependencies: debug "^3.2.7" -eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.25.3, eslint-plugin-import@2.27.5: +eslint-plugin-import@2.27.5: version "2.27.5" resolved "https://packages.atlassian.com/api/npm/npm-remote/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz" integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== @@ -1998,7 +2001,7 @@ eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.25.3, eslint-plugin-import semver "^6.3.0" tsconfig-paths "^3.14.1" -eslint-scope@^5.1.1, eslint-scope@5.1.1: +eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" resolved "https://packages.atlassian.com/api/npm/npm-remote/eslint-scope/-/eslint-scope-5.1.1.tgz" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -2019,7 +2022,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://packages.atlassian.com/api/npm/npm-remote/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.32.0 || ^8.2.0", eslint@8.50.0: +eslint@8.50.0: version "8.50.0" resolved "https://packages.atlassian.com/api/npm/npm-remote/eslint/-/eslint-8.50.0.tgz" integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg== @@ -2095,12 +2098,7 @@ estraverse@^4.1.1: resolved "https://packages.atlassian.com/api/npm/npm-remote/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0: - version "5.3.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/estraverse/-/estraverse-5.3.0.tgz" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -estraverse@^5.2.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://packages.atlassian.com/api/npm/npm-remote/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -2161,7 +2159,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@2.x: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://packages.atlassian.com/api/npm/npm-remote/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -2204,15 +2202,7 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-up@^4.0.0: - version "4.1.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/find-up/-/find-up-4.1.0.tgz" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^4.1.0: +find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://packages.atlassian.com/api/npm/npm-remote/find-up/-/find-up-4.1.0.tgz" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -2271,9 +2261,9 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -fp-ts@^2.10.5, fp-ts@^2.16.2, fp-ts@^2.5.0: +fp-ts@^2.16.2: version "2.16.2" - resolved "https://packages.atlassian.com/api/npm/npm-remote/fp-ts/-/fp-ts-2.16.2.tgz" + resolved "https://packages.atlassian.com/api/npm/npm-remote/fp-ts/-/fp-ts-2.16.2.tgz#7faa90f6fc2e8cf84c711d2c4e606afe2be9e342" integrity sha512-CkqAjnIKFqvo3sCyoBTqgJvF+bHrSik584S9nhTjtBESLx26cbtVMR/T9a6ApChOcSDAaM3JydDmWDUn4EEXng== fs.realpath@^1.0.0: @@ -2582,14 +2572,14 @@ interpret@^3.1.1: io-ts-reporters@^2.0.1: version "2.0.1" - resolved "https://packages.atlassian.com/api/npm/npm-remote/io-ts-reporters/-/io-ts-reporters-2.0.1.tgz" + resolved "https://packages.atlassian.com/api/npm/npm-remote/io-ts-reporters/-/io-ts-reporters-2.0.1.tgz#0154545aefd115f0f175a41743ed7327d19b1c34" integrity sha512-RVpLstYBsmTGgCW9wJ5KVyN/eRnRUDp87Flt4D1O3aJ7oAnd8csq8aXuu7ZeNK8qEDKmjUl9oUuzfwikaNAMKQ== dependencies: "@scarf/scarf" "^1.1.1" -io-ts@^2.2.16, io-ts@^2.2.21: +io-ts@^2.2.21: version "2.2.21" - resolved "https://packages.atlassian.com/api/npm/npm-remote/io-ts/-/io-ts-2.2.21.tgz" + resolved "https://packages.atlassian.com/api/npm/npm-remote/io-ts/-/io-ts-2.2.21.tgz#4ef754176f7082a1099d04c7d5c4ea53267c530a" integrity sha512-zz2Z69v9ZIC3mMLYWIeoUcwWD6f+O7yP92FMVVaXEOSZH1jnVBmET/urd/uoarD1WGBY4rCj8TAyMPzsGNzMFQ== is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: @@ -3048,7 +3038,7 @@ jest-resolve-dependencies@^27.5.1: jest-regex-util "^27.5.1" jest-snapshot "^27.5.1" -jest-resolve@*, jest-resolve@^27.5.1: +jest-resolve@^27.5.1: version "27.5.1" resolved "https://packages.atlassian.com/api/npm/npm-remote/jest-resolve/-/jest-resolve-27.5.1.tgz" integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== @@ -3206,7 +3196,7 @@ jest-worker@^27.4.5, jest-worker@^27.5.1: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^27.0.0, "jest@>= 25", jest@27.5.1: +jest@27.5.1: version "27.5.1" resolved "https://packages.atlassian.com/api/npm/npm-remote/jest/-/jest-27.5.1.tgz" integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== @@ -3293,6 +3283,11 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://packages.atlassian.com/api/npm/npm-remote/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json5@2.x, json5@^2.2.1: + version "2.2.1" + resolved "https://packages.atlassian.com/api/npm/npm-remote/json5/-/json5-2.2.1.tgz" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + json5@^1.0.2: version "1.0.2" resolved "https://packages.atlassian.com/api/npm/npm-remote/json5/-/json5-1.0.2.tgz" @@ -3300,11 +3295,6 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" -json5@^2.2.1, json5@2.x: - version "2.2.1" - resolved "https://packages.atlassian.com/api/npm/npm-remote/json5/-/json5-2.2.1.tgz" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== - jsuri@^1.3.1: version "1.3.1" resolved "https://packages.atlassian.com/api/npm/npm-remote/jsuri/-/jsuri-1.3.1.tgz" @@ -3456,28 +3446,7 @@ mimic-fn@^2.1.0: resolved "https://packages.atlassian.com/api/npm/npm-remote/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@^3.0.4: - version "3.1.2" - resolved "https://packages.atlassian.com/api/npm/npm-remote/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.5: - version "3.1.2" - resolved "https://packages.atlassian.com/api/npm/npm-remote/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.1.1: - version "3.1.2" - resolved "https://packages.atlassian.com/api/npm/npm-remote/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://packages.atlassian.com/api/npm/npm-remote/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -3503,7 +3472,7 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://packages.atlassian.com/api/npm/npm-remote/minimist/-/minimist-1.2.6.tgz" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -ms@^2.1.1, ms@2.1.2: +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://packages.atlassian.com/api/npm/npm-remote/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -3528,13 +3497,6 @@ nice-try@^1.0.4: resolved "https://packages.atlassian.com/api/npm/npm-remote/nice-try/-/nice-try-1.0.5.tgz" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-fetch@^2.6.7, node-fetch@2.7.0: - version "2.7.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/node-fetch/-/node-fetch-2.7.0.tgz" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - node-fetch@2.6.12: version "2.6.12" resolved "https://packages.atlassian.com/api/npm/npm-remote/node-fetch/-/node-fetch-2.6.12.tgz" @@ -3542,6 +3504,13 @@ node-fetch@2.6.12: dependencies: whatwg-url "^5.0.0" +node-fetch@2.7.0, node-fetch@^2.6.7: + version "2.7.0" + resolved "https://packages.atlassian.com/api/npm/npm-remote/node-fetch/-/node-fetch-2.7.0.tgz" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-int64@^0.4.0: version "0.4.0" resolved "https://packages.atlassian.com/api/npm/npm-remote/node-int64/-/node-int64-0.4.0.tgz" @@ -3978,32 +3947,22 @@ schema-utils@^3.1.1, schema-utils@^3.2.0: ajv "^6.12.5" ajv-keywords "^3.5.2" -semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.5.0: version "5.7.1" resolved "https://packages.atlassian.com/api/npm/npm-remote/semver/-/semver-5.7.1.tgz" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0: - version "6.3.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^6.3.0: - version "6.3.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.2, semver@^7.3.7, semver@7.x: +semver@7.x, semver@^7.3.2, semver@^7.3.7: version "7.3.7" resolved "https://packages.atlassian.com/api/npm/npm-remote/semver/-/semver-7.3.7.tgz" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" -"semver@2 || 3 || 4 || 5": - version "5.7.1" - resolved "https://packages.atlassian.com/api/npm/npm-remote/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://packages.atlassian.com/api/npm/npm-remote/semver/-/semver-6.3.0.tgz" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== serialize-javascript@^6.0.1: version "6.0.2" @@ -4429,7 +4388,7 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -"typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", "typescript@>=3.8 <5.0", typescript@4.9.5: +typescript@4.9.5: version "4.9.5" resolved "https://packages.atlassian.com/api/npm/npm-remote/typescript/-/typescript-4.9.5.tgz" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== @@ -4522,7 +4481,7 @@ webidl-conversions@^6.1.0: resolved "https://packages.atlassian.com/api/npm/npm-remote/webidl-conversions/-/webidl-conversions-6.1.0.tgz" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== -webpack-cli@^4.10.0, webpack-cli@4.x.x: +webpack-cli@^4.10.0: version "4.10.0" resolved "https://packages.atlassian.com/api/npm/npm-remote/webpack-cli/-/webpack-cli-4.10.0.tgz" integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== @@ -4540,7 +4499,7 @@ webpack-cli@^4.10.0, webpack-cli@4.x.x: rechoir "^0.7.0" webpack-merge "^5.7.3" -webpack-cli@^5.1.4, webpack-cli@5.x.x: +webpack-cli@^5.1.4: version "5.1.4" resolved "https://packages.atlassian.com/api/npm/npm-remote/webpack-cli/-/webpack-cli-5.1.4.tgz" integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== @@ -4573,10 +4532,10 @@ webpack-sources@^3.2.3: resolved "https://packages.atlassian.com/api/npm/npm-remote/webpack-sources/-/webpack-sources-3.2.3.tgz" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.1.0, webpack@5.89.0, webpack@5.x.x: - version "5.89.0" - resolved "https://packages.atlassian.com/api/npm/npm-remote/webpack/-/webpack-5.89.0.tgz" - integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw== +webpack@5.88.2: + version "5.88.2" + resolved "https://packages.atlassian.com/api/npm/npm-remote/webpack/-/webpack-5.88.2.tgz" + integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.0" @@ -4603,10 +4562,10 @@ webpack@^5.1.0, webpack@5.89.0, webpack@5.x.x: watchpack "^2.4.0" webpack-sources "^3.2.3" -"webpack@4.x.x || 5.x.x", webpack@5.88.2: - version "5.88.2" - resolved "https://packages.atlassian.com/api/npm/npm-remote/webpack/-/webpack-5.88.2.tgz" - integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== +webpack@5.89.0: + version "5.89.0" + resolved "https://packages.atlassian.com/api/npm/npm-remote/webpack/-/webpack-5.89.0.tgz" + integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.0" @@ -4760,10 +4719,10 @@ yallist@^4.0.0: yaml@^2.3.4: version "2.3.4" - resolved "https://packages.atlassian.com/api/npm/npm-remote/yaml/-/yaml-2.3.4.tgz" + resolved "https://packages.atlassian.com/api/npm/npm-remote/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== -yargs-parser@^20.2.2, yargs-parser@20.x: +yargs-parser@20.x, yargs-parser@^20.2.2: version "20.2.9" resolved "https://packages.atlassian.com/api/npm/npm-remote/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==