import {RouteComponentProps} from 'react-router'; import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator'; import {Alert} from 'sentry/components/alert'; import AutoSelectText from 'sentry/components/autoSelectText'; import {Button} from 'sentry/components/button'; import Confirm from 'sentry/components/confirm'; import FieldGroup from 'sentry/components/forms/fieldGroup'; import ExternalLink from 'sentry/components/links/externalLink'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import {Panel, PanelBody, PanelHeader} from 'sentry/components/panels'; import PluginList from 'sentry/components/pluginList'; import TextCopyInput from 'sentry/components/textCopyInput'; import {t, tct} from 'sentry/locale'; import {Organization, Plugin, Project} from 'sentry/types'; import getDynamicText from 'sentry/utils/getDynamicText'; import routeTitleGen from 'sentry/utils/routeTitle'; import withPlugins from 'sentry/utils/withPlugins'; import AsyncView from 'sentry/views/asyncView'; import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader'; const TOKEN_PLACEHOLDER = 'YOUR_TOKEN'; const WEBHOOK_PLACEHOLDER = 'YOUR_WEBHOOK_URL'; type Props = { organization: Organization; plugins: {loading: boolean; plugins: Plugin[]}; project: Project; } & RouteComponentProps<{projectId: string}, {}>; type State = { data: { token: string; webhookUrl: string; } | null; } & AsyncView['state']; const placeholderData = { token: TOKEN_PLACEHOLDER, webhookUrl: WEBHOOK_PLACEHOLDER, }; class ProjectReleaseTracking extends AsyncView { getTitle() { const {projectId} = this.props.params; return routeTitleGen(t('Releases'), projectId, false); } getEndpoints(): ReturnType { const {organization} = this.props; const {projectId} = this.props.params; // Allow 403s return [ [ 'data', `/projects/${organization.slug}/${projectId}/releases/token/`, {}, {allowError: err => err && err.status === 403}, ], ]; } handleRegenerateToken = () => { const {organization} = this.props; const {projectId} = this.props.params; this.api.request(`/projects/${organization.slug}/${projectId}/releases/token/`, { method: 'POST', data: {project: projectId}, success: data => { this.setState({ data: { token: data.token, webhookUrl: data.webhookUrl, }, }); addSuccessMessage( t( 'Your deploy token has been regenerated. You will need to update any existing deploy hooks.' ) ); }, error: () => { addErrorMessage(t('Unable to regenerate deploy token, please try again')); }, }); }; getReleaseWebhookIntructions() { const {webhookUrl} = this.state.data || placeholderData; return ( 'curl ' + webhookUrl + ' \\' + '\n ' + '-X POST \\' + '\n ' + "-H 'Content-Type: application/json' \\" + '\n ' + '-d \'{"version": "abcdefg"}\'' ); } renderBody() { const {organization, project, plugins} = this.props; const hasWrite = organization.access.includes('project:write'); if (plugins.loading) { return ; } const pluginList = plugins.plugins.filter( (p: Plugin) => p.type === 'release-tracking' && p.hasConfiguration ); let {token, webhookUrl} = this.state.data || placeholderData; token = getDynamicText({value: token, fixed: '__TOKEN__'}); webhookUrl = getDynamicText({value: webhookUrl, fixed: '__WEBHOOK_URL__'}); return (
{!hasWrite && ( {t( 'You do not have sufficient permissions to access Release tokens, placeholders are displayed below.' )} )}

{t( 'Configure release tracking for this project to automatically record new releases of your application.' )}

{t('Client Configuration')}

{tct( 'Start by binding the [release] attribute in your application, take a look at [link] to see how to configure this for the SDK you are using.', { link: ( our docs ), release: release, } )}

{t( "This will annotate each event with the version of your application, as well as automatically create a release entity in the system the first time it's seen." )}

{t( 'In addition you may configure a release hook (or use our API) to push a release and include additional metadata with it.' )}

{t('Deploy Token')} {token}
{t('Webhook')}

{t( 'If you simply want to integrate with an existing system, sometimes its easiest just to use a webhook.' )}

{webhookUrl}

{t( 'The release webhook accepts the same parameters as the "Create a new Release" API endpoint.' )}

{getDynamicText({ value: (
{this.getReleaseWebhookIntructions()}
), fixed: (
                  {`curl __WEBHOOK_URL__ \\
  -X POST \\
  -H 'Content-Type: application/json' \\
  -d \'{"version": "abcdefg"}\'`}
                
), })}
{t('API')}

{t( 'You can notify Sentry when you release new versions of your application via our HTTP API.' )}

{tct('See the [link:releases documentation] for more information.', { link: , })}

); } } export default withPlugins(ProjectReleaseTracking); // Export for tests export {ProjectReleaseTracking};