Files
2024-02-15 17:01:50 +00:00

240 lines
6.6 KiB
TypeScript

import * as Sentry from '@sentry/react';
import type {Field} from 'sentry/components/forms/types';
import ExternalLink from 'sentry/components/links/externalLink';
import {
AWS_REGIONS,
DEBUG_SOURCE_CASINGS,
DEBUG_SOURCE_LAYOUTS,
} from 'sentry/data/debugFileSources';
import {t, tct} from 'sentry/locale';
import {CustomRepoType} from 'sentry/types/debugFiles';
import {uniqueId} from 'sentry/utils/guid';
function objectToChoices(obj: Record<string, string>): [key: string, value: string][] {
return Object.entries(obj).map(([key, value]) => [key, value]);
}
type FieldMap = Record<string, Field>;
const commonFields: FieldMap = {
id: {
name: 'id',
type: 'hidden',
required: true,
defaultValue: uniqueId,
},
name: {
name: 'name',
type: 'string',
required: true,
label: t('Name'),
placeholder: t('New Repository'),
help: t('A display name for this repository'),
},
// filters are explicitly not exposed to the UI
layoutType: {
name: 'layout.type',
type: 'select',
label: t('Directory Layout'),
help: t('The layout of the folder structure.'),
defaultValue: 'native',
choices: objectToChoices(DEBUG_SOURCE_LAYOUTS),
},
layoutCasing: {
name: 'layout.casing',
type: 'select',
label: t('Path Casing'),
help: t('The case of files and folders.'),
defaultValue: 'default',
choices: objectToChoices(DEBUG_SOURCE_CASINGS),
},
prefix: {
name: 'prefix',
type: 'string',
label: 'Root Path',
placeholder: '/',
help: t('The path at which files are located within this repository.'),
},
separator: {
name: '',
type: 'separator',
},
};
export function getFormFieldsAndInitialData(
type: CustomRepoType,
sourceConfig?: Record<string, any>
) {
if (type === CustomRepoType.HTTP || type === CustomRepoType.APP_STORE_CONNECT) {
return {};
}
const {secret_key, layout, private_key, ...config} = sourceConfig ?? {};
const initialData = layout
? {...config, 'layout.casing': layout.casing, 'layout.type': layout.type}
: config;
switch (type) {
case 's3':
return {
fields: [
commonFields.id,
commonFields.name,
commonFields.separator,
{
name: 'bucket',
type: 'string',
required: true,
label: t('Bucket'),
placeholder: 's3-bucket-name',
help: t(
'Name of the S3 bucket. Read permissions are required to download symbols.'
),
},
{
name: 'region',
type: 'select',
required: true,
label: t('Region'),
help: t('The AWS region and availability zone of the bucket.'),
choices: AWS_REGIONS.map(([k, v]) => [
k,
<span key={k}>
<code>{k}</code> {v}
</span>,
]),
},
{
name: 'access_key',
type: 'string',
required: true,
label: t('Access Key ID'),
placeholder: 'AKIAIOSFODNN7EXAMPLE',
help: tct(
'Access key to the AWS account. Credentials can be managed in the [link].',
{
link: (
<ExternalLink href="https://console.aws.amazon.com/iam/">
IAM console
</ExternalLink>
),
}
),
},
{
name: 'secret_key',
type: 'string',
required: true,
label: t('Secret Access Key'),
placeholder:
typeof secret_key === 'object'
? t('(Secret Access Key unchanged)')
: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
},
commonFields.separator,
commonFields.prefix,
commonFields.layoutType,
commonFields.layoutCasing,
],
initialData: !initialData
? undefined
: {
...initialData,
secret_key: undefined,
},
};
case 'gcs':
return {
fields: [
commonFields.id,
commonFields.name,
commonFields.separator,
{
name: 'bucket',
type: 'string',
required: true,
label: t('Bucket'),
placeholder: 'gcs-bucket-name',
help: t(
'Name of the GCS bucket. Read permissions are required to download symbols.'
),
},
{
name: 'client_email',
type: 'email',
required: true,
label: t('Client Email'),
placeholder: '[email protected]',
help: t('Email address of the GCS service account.'),
},
{
name: 'private_key',
type: 'string',
required: true,
multiline: true,
autosize: true,
maxRows: 5,
rows: 3,
label: t('Private Key'),
placeholder:
typeof private_key === 'object'
? t('(Private Key unchanged)')
: '-----BEGIN PRIVATE KEY-----\n[PRIVATE-KEY]\n-----END PRIVATE KEY-----',
help: tct(
'The service account key. Credentials can be managed on the [link].',
{
link: (
<ExternalLink href="https://console.cloud.google.com/project/_/iam-admin">
IAM &amp; Admin Page
</ExternalLink>
),
}
),
},
commonFields.separator,
commonFields.prefix,
commonFields.layoutType,
commonFields.layoutCasing,
],
initialData: !initialData
? undefined
: {
...initialData,
private_key: undefined,
},
};
default: {
Sentry.captureException(new Error('Unknown custom repository type'));
return {}; // this shall never happen
}
}
}
export function getFinalData(type: CustomRepoType, data: Record<string, any>) {
if (type === CustomRepoType.HTTP || type === CustomRepoType.APP_STORE_CONNECT) {
return data;
}
switch (type) {
case 's3':
return {
...data,
secret_key: data.secret_key ?? {
'hidden-secret': true,
},
};
case 'gcs':
return {
...data,
private_key: data.private_key ?? {
'hidden-secret': true,
},
};
default: {
Sentry.captureException(new Error('Unknown custom repository type'));
return {}; // this shall never happen
}
}
}