import {Component} from 'react'; import type {RouteComponentProps} from 'react-router'; import * as Sentry from '@sentry/react'; import {addErrorMessage} from 'sentry/actionCreators/indicator'; import type {Client} from 'sentry/api'; import {LinkButton} from 'sentry/components/button'; import EmptyMessage from 'sentry/components/emptyMessage'; import {Body, Main} from 'sentry/components/layouts/thirds'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import Panel from 'sentry/components/panels/panel'; import {IconCommit} from 'sentry/icons'; import {t} from 'sentry/locale'; import type {Repository} from 'sentry/types/integrations'; import type {Organization} from 'sentry/types/organization'; import getDisplayName from 'sentry/utils/getDisplayName'; import withApi from 'sentry/utils/withApi'; import withOrganization from 'sentry/utils/withOrganization'; import withRepositories from 'sentry/utils/withRepositories'; import {ReleaseContext} from '..'; // These props are required when using this HoC type DependentProps = RouteComponentProps<{release: string}, {}>; type HoCsProps = { api: Client; organization: Organization; repositories?: Repository[]; repositoriesError?: Error; repositoriesLoading?: boolean; }; type State = { isLoading: boolean; releaseRepos: Repository[]; activeReleaseRepo?: Repository; }; function withReleaseRepos

( WrappedComponent: React.ComponentType

) { class WithReleaseRepos extends Component

{ static displayName = `withReleaseRepos(${getDisplayName(WrappedComponent)})`; state: State = { releaseRepos: [], isLoading: true, }; componentDidMount() { this.fetchReleaseRepos(); } componentDidUpdate(prevProps: P & HoCsProps, prevState: State) { if ( this.props.params.release !== prevProps.params.release || (!!prevProps.repositoriesLoading && !this.props.repositoriesLoading) ) { this.fetchReleaseRepos(); return; } if ( prevState.releaseRepos.length !== this.state.releaseRepos.length || prevProps.location.query?.activeRepo !== this.props.location.query?.activeRepo ) { this.setActiveReleaseRepo(this.props); } } declare context: React.ContextType; static contextType = ReleaseContext; setActiveReleaseRepo(props: P & HoCsProps) { const {releaseRepos, activeReleaseRepo} = this.state; if (!releaseRepos.length) { return; } const activeCommitRepo = props.location.query?.activeRepo; if (!activeCommitRepo) { this.setState({ activeReleaseRepo: releaseRepos[0] ?? null, }); return; } if (activeCommitRepo === activeReleaseRepo?.name) { return; } const matchedRepository = releaseRepos.find( commitRepo => commitRepo.name === activeCommitRepo ); if (matchedRepository) { this.setState({ activeReleaseRepo: matchedRepository, }); return; } addErrorMessage(t('The repository you were looking for was not found.')); } async fetchReleaseRepos() { const {params, api, organization, repositories, repositoriesLoading} = this.props; if (repositoriesLoading === undefined || repositoriesLoading === true) { return; } if (!repositories?.length) { this.setState({isLoading: false}); return; } const {release} = params; const {project} = this.context; this.setState({isLoading: true}); try { const releasePath = encodeURIComponent(release); const releaseRepos = await api.requestPromise( `/projects/${organization.slug}/${project.slug}/releases/${releasePath}/repositories/` ); this.setState({releaseRepos, isLoading: false}); this.setActiveReleaseRepo(this.props); } catch (error) { Sentry.captureException(error); addErrorMessage( t( 'An error occurred while trying to fetch the repositories of the release: %s', release ) ); } } render() { const {isLoading, activeReleaseRepo, releaseRepos} = this.state; const {repositoriesLoading, repositories, params, router, location, organization} = this.props; if (isLoading || repositoriesLoading) { return ; } const noRepositoryOrgRelatedFound = !repositories?.length; if (noRepositoryOrgRelatedFound) { return (

} title={t('Releases are better with commit data!')} description={t( 'Connect a repository to see commit info, files changed, and authors involved in future releases.' )} action={ {t('Connect a repository')} } />
); } const noReleaseReposFound = !releaseRepos.length; if (noReleaseReposFound) { return (
} title={t('Releases are better with commit data!')} description={t( 'No commits associated with this release have been found.' )} />
); } if (activeReleaseRepo === undefined) { return ; } const {release} = params; const orgSlug = organization.slug; return ( ); } } return withApi(withOrganization(withRepositories(WithReleaseRepos))); } export default withReleaseRepos;