diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 257fde3c24..c382abc3a8 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -17,6 +17,11 @@ import { Router as GitHubActionsRouter, isPluginApplicableToEntity as isGitHubActionsAvailable, } from '@backstage/plugin-github-actions'; +import { + Router as JenkinsRouter, + isPluginApplicableToEntity as isJenkinsAvailable, + LatestRunCard as JenkinsLatestRunCard, +} from '@backstage/plugin-jenkins'; import { Router as CircleCIRouter, isPluginApplicableToEntity as isCircleCIAvailable, @@ -38,6 +43,8 @@ const CICDSwitcher = ({ entity }: { entity: Entity }) => { // This component is just an example of how you can implement your company's logic in entity page. // You can for example enforce that all components of type 'service' should use GitHubActions switch (true) { + case isJenkinsAvailable(entity): + return ; case isGitHubActionsAvailable(entity): return ; case isCircleCIAvailable(entity): @@ -57,6 +64,11 @@ const OverviewContent = ({ entity }: { entity: Entity }) => ( + {isJenkinsAvailable(entity) && ( + + + + )} ); diff --git a/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx b/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx index 7f19728780..ee0f03f04a 100644 --- a/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx +++ b/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx @@ -21,10 +21,6 @@ import { LatestWorkflowRunCard, GITHUB_ACTIONS_ANNOTATION, } from '@backstage/plugin-github-actions'; -import { - JenkinsBuildsWidget, - JenkinsLastBuildWidget, -} from '@backstage/plugin-jenkins'; import { Grid } from '@material-ui/core'; import React, { FC } from 'react'; import { AboutCard } from '../AboutCard'; @@ -36,16 +32,6 @@ export const EntityPageOverview: FC<{ entity: Entity }> = ({ entity }) => { - {entity.metadata?.annotations?.['jenkins.io/github-folder'] && ( - - - - )} - {entity.metadata?.annotations?.['jenkins.io/github-folder'] && ( - - - - )} {entity.metadata?.annotations?.[GITHUB_ACTIONS_ANNOTATION] && ( diff --git a/plugins/jenkins/README.md b/plugins/jenkins/README.md index 3e721c5e7a..8f0d43cba7 100644 --- a/plugins/jenkins/README.md +++ b/plugins/jenkins/README.md @@ -14,17 +14,7 @@ Website: [https://jenkins.io/](https://jenkins.io/) yarn add @backstage/plugin-jenkins ``` -2. Add plugin API to your Backstage instance: - -```js -// packages/app/src/api.ts -import { JenkinsApi, jenkinsApiRef } from '@backstage/plugin-jenkins'; - -const builder = ApiRegistry.builder(); -builder.add(jenkinsApiRef, new JenkinsApi(`${backendUrl}/proxy/jenkins/api`)); -``` - -2. Add plugin itself: +2. Add plugin: ```js // packages/app/src/plugins.ts diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index 0d532f8c45..c62df08db2 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -23,6 +23,7 @@ "dependencies": { "@backstage/catalog-model": "^0.1.1-alpha.21", "@backstage/core": "^0.1.1-alpha.21", + "@backstage/plugin-catalog": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", diff --git a/plugins/jenkins/src/api/index.ts b/plugins/jenkins/src/api/index.ts index 545a1da9cc..2b95fe97d9 100644 --- a/plugins/jenkins/src/api/index.ts +++ b/plugins/jenkins/src/api/index.ts @@ -15,7 +15,7 @@ */ import { createApiRef } from '@backstage/core'; -import { CITableBuildInfo } from '../pages/BuildsPage/lib/CITable'; +import { CITableBuildInfo } from '../components/BuildsPage/lib/CITable'; const jenkins = require('jenkins'); @@ -65,6 +65,21 @@ export class JenkinsApi { }) .pop(); + const author = jobDetails.actions + .filter( + (action: any) => + action._class === + 'jenkins.scm.api.metadata.ContributorMetadataAction', + ) + .map((action: any) => { + return action.contributorDisplayName; + }) + .pop(); + + if (author) { + scmInfo.author = author; + } + return scmInfo; } @@ -154,12 +169,15 @@ export class JenkinsApi { if (jobScmInfo) { source.url = jobScmInfo?.url; source.displayName = jobScmInfo?.displayName; + source.author = jobScmInfo?.author; } const path = new URL(jenkinsResult.url).pathname; return { id: path, + buildNumber: jenkinsResult.number, + buildUrl: jenkinsResult.url, buildName: jenkinsResult.fullDisplayName, status: jenkinsResult.building ? 'running' : jenkinsResult.result, onRestartClick: () => { diff --git a/plugins/jenkins/src/assets/build-details.png b/plugins/jenkins/src/assets/build-details.png index 396af428af..ee463fea43 100644 Binary files a/plugins/jenkins/src/assets/build-details.png and b/plugins/jenkins/src/assets/build-details.png differ diff --git a/plugins/jenkins/src/assets/folder-results.png b/plugins/jenkins/src/assets/folder-results.png index 2e14f3551f..c01e4cf437 100644 Binary files a/plugins/jenkins/src/assets/folder-results.png and b/plugins/jenkins/src/assets/folder-results.png differ diff --git a/plugins/jenkins/src/components/BuildWithStepsPage/BuildWithStepsPage.tsx b/plugins/jenkins/src/components/BuildWithStepsPage/BuildWithStepsPage.tsx new file mode 100644 index 0000000000..637cd40d6d --- /dev/null +++ b/plugins/jenkins/src/components/BuildWithStepsPage/BuildWithStepsPage.tsx @@ -0,0 +1,134 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { useParams } from 'react-router-dom'; +import { Content, Link } from '@backstage/core'; +import { + Typography, + Breadcrumbs, + Paper, + TableContainer, + Table, + TableRow, + TableCell, + TableBody, + Link as MaterialLink, +} from '@material-ui/core'; +import { makeStyles } from '@material-ui/core/styles'; +import { useBuildWithSteps } from '../useBuildWithSteps'; +import { useProjectSlugFromEntity } from '../useProjectSlugFromEntity'; +import { JenkinsRunStatus } from '../BuildsPage/lib/Status'; +import ExternalLinkIcon from '@material-ui/icons/Launch'; + +const useStyles = makeStyles(theme => ({ + root: { + maxWidth: 720, + margin: theme.spacing(2), + }, + table: { + padding: theme.spacing(1), + }, + externalLinkIcon: { + fontSize: 'inherit', + verticalAlign: 'bottom', + }, +})); + +const Page = () => ( + + + +); + +const BuildWithStepsView = () => { + const { owner, repo } = useProjectSlugFromEntity(); + const { branch, buildNumber } = useParams(); + const classes = useStyles(); + const buildPath = `${owner}/${repo}/${branch}/${buildNumber}`; + const [{ value }] = useBuildWithSteps(buildPath); + + return ( +
+ + Jobs + Run + + + + + + + Branch + + {value?.source?.branchName} + + + + Message + + {value?.source?.displayName} + + + + Commit ID + + {value?.source?.commit?.hash} + + + + Status + + + + + + + + Author + + {value?.source?.author} + + + + Jenkins + + + + View on Jenkins{' '} + + + + + + + GitHub + + + + View on GitHub{' '} + + + + + +
+
+
+ ); +}; + +export default Page; +export { BuildWithStepsView as BuildWithSteps }; diff --git a/plugins/jenkins/src/pages/BuildWithStepsPage/index.ts b/plugins/jenkins/src/components/BuildWithStepsPage/index.ts similarity index 100% rename from plugins/jenkins/src/pages/BuildWithStepsPage/index.ts rename to plugins/jenkins/src/components/BuildWithStepsPage/index.ts diff --git a/plugins/jenkins/src/pages/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx b/plugins/jenkins/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx similarity index 100% rename from plugins/jenkins/src/pages/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx rename to plugins/jenkins/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx diff --git a/plugins/jenkins/src/pages/BuildWithStepsPage/lib/ActionOutput/index.ts b/plugins/jenkins/src/components/BuildWithStepsPage/lib/ActionOutput/index.ts similarity index 100% rename from plugins/jenkins/src/pages/BuildWithStepsPage/lib/ActionOutput/index.ts rename to plugins/jenkins/src/components/BuildWithStepsPage/lib/ActionOutput/index.ts diff --git a/plugins/jenkins/src/pages/BuildsPage/lib/CITable/CITable.tsx b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx similarity index 81% rename from plugins/jenkins/src/pages/BuildsPage/lib/CITable/CITable.tsx rename to plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx index 7f17107374..282cbc59b5 100644 --- a/plugins/jenkins/src/pages/BuildsPage/lib/CITable/CITable.tsx +++ b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx @@ -14,21 +14,26 @@ * limitations under the License. */ import React, { FC } from 'react'; -import { Link, Typography, Box, IconButton } from '@material-ui/core'; +import { Box, IconButton, Link, Typography } from '@material-ui/core'; import RetryIcon from '@material-ui/icons/Replay'; import GitHubIcon from '@material-ui/icons/GitHub'; -import { Link as RouterLink } from 'react-router-dom'; +import { generatePath, Link as RouterLink } from 'react-router-dom'; import { Table, TableColumn } from '@backstage/core'; import { JenkinsRunStatus } from '../Status'; +import { useBuilds } from '../../../useBuilds'; +import { useProjectSlugFromEntity } from '../../../useProjectSlugFromEntity'; +import { buildRouteRef } from '../../../../plugin'; export type CITableBuildInfo = { id: string; buildName: string; - buildUrl?: string; + buildNumber: number; + buildUrl: string; source: { branchName: string; url: string; displayName: string; + author?: string; commit: { hash: string; }; @@ -105,7 +110,13 @@ const generatedColumns: TableColumn[] = [ field: 'buildName', highlight: true, render: (row: Partial) => ( - + {row.buildName} ), @@ -177,7 +188,8 @@ type Props = { pageSize: number; onChangePageSize: (pageSize: number) => void; }; -export const CITable: FC = ({ + +export const CITableView: FC = ({ projectName, loading, pageSize, @@ -191,7 +203,7 @@ export const CITable: FC = ({ return ( = ({ onClick: () => retry(), }, ]} - data={builds} + data={builds ?? []} onChangePage={onChangePage} onChangeRowsPerPage={onChangePageSize} title={ @@ -216,3 +228,18 @@ export const CITable: FC = ({ /> ); }; + +export const CITable = () => { + const { owner, repo } = useProjectSlugFromEntity(); + + const [tableProps, { setPage, retry, setPageSize }] = useBuilds(owner, repo); + + return ( + + ); +}; diff --git a/plugins/jenkins/src/pages/BuildsPage/lib/CITable/index.ts b/plugins/jenkins/src/components/BuildsPage/lib/CITable/index.ts similarity index 100% rename from plugins/jenkins/src/pages/BuildsPage/lib/CITable/index.ts rename to plugins/jenkins/src/components/BuildsPage/lib/CITable/index.ts diff --git a/plugins/jenkins/src/pages/BuildsPage/lib/Status/JenkinsRunStatus.tsx b/plugins/jenkins/src/components/BuildsPage/lib/Status/JenkinsRunStatus.tsx similarity index 100% rename from plugins/jenkins/src/pages/BuildsPage/lib/Status/JenkinsRunStatus.tsx rename to plugins/jenkins/src/components/BuildsPage/lib/Status/JenkinsRunStatus.tsx diff --git a/plugins/jenkins/src/pages/BuildsPage/lib/Status/index.ts b/plugins/jenkins/src/components/BuildsPage/lib/Status/index.ts similarity index 100% rename from plugins/jenkins/src/pages/BuildsPage/lib/Status/index.ts rename to plugins/jenkins/src/components/BuildsPage/lib/Status/index.ts diff --git a/plugins/jenkins/src/components/JenkinsPluginWidget/JenkinsLastBuildWidget.tsx b/plugins/jenkins/src/components/Cards/Cards.tsx similarity index 78% rename from plugins/jenkins/src/components/JenkinsPluginWidget/JenkinsLastBuildWidget.tsx rename to plugins/jenkins/src/components/Cards/Cards.tsx index 6731808d8e..5034effdcf 100644 --- a/plugins/jenkins/src/components/JenkinsPluginWidget/JenkinsLastBuildWidget.tsx +++ b/plugins/jenkins/src/components/Cards/Cards.tsx @@ -14,12 +14,12 @@ * limitations under the License. */ import React from 'react'; -import { Entity } from '@backstage/catalog-model'; import { Link, Theme, makeStyles, LinearProgress } from '@material-ui/core'; import { InfoCard, StructuredMetadataTable } from '@backstage/core'; import ExternalLinkIcon from '@material-ui/icons/Launch'; -import { useBuilds } from '../../state'; -import { JenkinsRunStatus } from '../../pages/BuildsPage/lib/Status'; +import { useBuilds } from '../useBuilds'; +import { JenkinsRunStatus } from '../BuildsPage/lib/Status'; +import { useProjectSlugFromEntity } from '../useProjectSlugFromEntity'; const useStyles = makeStyles({ externalLinkIcon: { @@ -38,6 +38,7 @@ const WidgetContent = ({ }) => { const classes = useStyles(); if (loading || !lastRun) return ; + return ( { - const [owner, repo] = ( - entity?.metadata.annotations?.['jenkins.io/github-folder'] ?? '/' - ).split('/'); - const [{ loading, value }] = useBuilds(owner, repo, branch); - - const lastRun = value ?? {}; - +export const LatestRunCard = ({ branch = 'master' }: { branch: string }) => { + const { owner, repo } = useProjectSlugFromEntity(); + const [{ builds, loading }] = useBuilds(owner, repo, branch); + const lastRun = builds ?? {}; return ( diff --git a/plugins/jenkins/src/components/PluginHeader/index.ts b/plugins/jenkins/src/components/Cards/index.ts similarity index 93% rename from plugins/jenkins/src/components/PluginHeader/index.ts rename to plugins/jenkins/src/components/Cards/index.ts index 4de972f6f2..dace09e1a9 100644 --- a/plugins/jenkins/src/components/PluginHeader/index.ts +++ b/plugins/jenkins/src/components/Cards/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './PluginHeader'; +export { LatestRunCard } from './Cards'; diff --git a/plugins/jenkins/src/components/Layout/Layout.tsx b/plugins/jenkins/src/components/Layout/Layout.tsx deleted file mode 100644 index c6000437a3..0000000000 --- a/plugins/jenkins/src/components/Layout/Layout.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { Header, Page, pageTheme, HeaderLabel } from '@backstage/core'; - -export const Layout: React.FC = ({ children }) => { - return ( - -
- - -
- {children} -
- ); -}; diff --git a/plugins/jenkins/src/components/Layout/index.ts b/plugins/jenkins/src/components/Layout/index.ts deleted file mode 100644 index 236fc98851..0000000000 --- a/plugins/jenkins/src/components/Layout/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export * from './Layout'; diff --git a/plugins/jenkins/src/components/PluginHeader/PluginHeader.tsx b/plugins/jenkins/src/components/PluginHeader/PluginHeader.tsx deleted file mode 100644 index 501649e49a..0000000000 --- a/plugins/jenkins/src/components/PluginHeader/PluginHeader.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { ContentHeader, SupportButton } from '@backstage/core'; -import { Box, Typography } from '@material-ui/core'; - -export type Props = { title?: string }; -export const PluginHeader = ({ title = 'Jenkins' }) => { - return ( - ( - - {title} - - )} - > - - This plugin allows you to view and interact with your builds in Jenkins. - - - ); -}; diff --git a/plugins/jenkins/src/components/Router.tsx b/plugins/jenkins/src/components/Router.tsx new file mode 100644 index 0000000000..56df5456bc --- /dev/null +++ b/plugins/jenkins/src/components/Router.tsx @@ -0,0 +1,41 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Route, Routes } from 'react-router'; +import { buildRouteRef, rootRouteRef } from '../plugin'; +import { DetailedViewPage } from './BuildWithStepsPage/'; +import { JENKINS_ANNOTATION } from '../constants'; +import { Entity } from '@backstage/catalog-model'; +import { WarningPanel } from '@backstage/core'; +import { CITable } from './BuildsPage/lib/CITable'; + +export const isPluginApplicableToEntity = (entity: Entity) => + Boolean(entity.metadata.annotations?.[JENKINS_ANNOTATION]) && + entity.metadata.annotations?.[JENKINS_ANNOTATION] !== ''; + +export const Router = ({ entity }: { entity: Entity }) => { + return !isPluginApplicableToEntity(entity) ? ( + +
entity.metadata.annotations['{JENKINS_ANNOTATION}']
+ key is missing on the entity. +
+ ) : ( + + } /> + } /> + + ); +}; diff --git a/plugins/jenkins/src/state/useAsyncPolling.ts b/plugins/jenkins/src/components/useAsyncPolling.ts similarity index 100% rename from plugins/jenkins/src/state/useAsyncPolling.ts rename to plugins/jenkins/src/components/useAsyncPolling.ts diff --git a/plugins/jenkins/src/state/useBuildWithSteps.ts b/plugins/jenkins/src/components/useBuildWithSteps.ts similarity index 97% rename from plugins/jenkins/src/state/useBuildWithSteps.ts rename to plugins/jenkins/src/components/useBuildWithSteps.ts index 617b2b1f4f..86d8162612 100644 --- a/plugins/jenkins/src/state/useBuildWithSteps.ts +++ b/plugins/jenkins/src/components/useBuildWithSteps.ts @@ -16,7 +16,7 @@ import { errorApiRef, useApi } from '@backstage/core'; import { useCallback } from 'react'; import { useAsyncRetry } from 'react-use'; -import { jenkinsApiRef } from '../api/index'; +import { jenkinsApiRef } from '../api'; import { useAsyncPolling } from './useAsyncPolling'; const INTERVAL_AMOUNT = 1500; diff --git a/plugins/jenkins/src/state/useBuilds.ts b/plugins/jenkins/src/components/useBuilds.ts similarity index 92% rename from plugins/jenkins/src/state/useBuilds.ts rename to plugins/jenkins/src/components/useBuilds.ts index deb3125637..62e3719dbd 100644 --- a/plugins/jenkins/src/state/useBuilds.ts +++ b/plugins/jenkins/src/components/useBuilds.ts @@ -56,8 +56,9 @@ export function useBuilds(owner: string, repo: string, branch?: string) { }); }, [repo, getBuilds]); - const { loading, value, retry } = useAsyncRetry( - () => getBuilds().then(builds => builds ?? [], restartBuild), + const { loading, value: builds, retry } = useAsyncRetry( + () => + getBuilds().then(retrievedBuilds => retrievedBuilds ?? [], restartBuild), [page, pageSize, getBuilds], ); @@ -67,12 +68,12 @@ export function useBuilds(owner: string, repo: string, branch?: string) { page, pageSize, loading, - value, + builds, projectName, total, }, { - getBuilds, + builds, setPage, setPageSize, restartBuild, diff --git a/plugins/jenkins/src/components/JenkinsPluginWidget/JenkinsBuildsWidget.tsx b/plugins/jenkins/src/components/useProjectSlugFromEntity.ts similarity index 66% rename from plugins/jenkins/src/components/JenkinsPluginWidget/JenkinsBuildsWidget.tsx rename to plugins/jenkins/src/components/useProjectSlugFromEntity.ts index 12eaf5653b..1dca918990 100644 --- a/plugins/jenkins/src/components/JenkinsPluginWidget/JenkinsBuildsWidget.tsx +++ b/plugins/jenkins/src/components/useProjectSlugFromEntity.ts @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { useEntity } from '@backstage/plugin-catalog'; +import { JENKINS_ANNOTATION } from '../constants'; -import React from 'react'; -import { Builds } from '../../pages/BuildsPage/lib/Builds'; -import { Entity } from '@backstage/catalog-model'; +export const useProjectSlugFromEntity = () => { + const { entity } = useEntity(); -export const JenkinsBuildsWidget = ({ entity }: { entity: Entity }) => { const [owner, repo] = ( - entity?.metadata.annotations?.['jenkins.io/github-folder'] ?? '/' + entity.metadata.annotations?.[JENKINS_ANNOTATION] ?? '' ).split('/'); - - return ; + return { owner, repo }; }; diff --git a/plugins/jenkins/src/pages/BuildsPage/lib/Builds/index.ts b/plugins/jenkins/src/constants.ts similarity index 90% rename from plugins/jenkins/src/pages/BuildsPage/lib/Builds/index.ts rename to plugins/jenkins/src/constants.ts index e91a9496b7..fe8980de73 100644 --- a/plugins/jenkins/src/pages/BuildsPage/lib/Builds/index.ts +++ b/plugins/jenkins/src/constants.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { Builds } from './Builds'; +export const JENKINS_ANNOTATION = 'jenkins.io/github-folder'; diff --git a/plugins/jenkins/src/index.ts b/plugins/jenkins/src/index.ts index c7f2d8dc28..30fa0c70a5 100644 --- a/plugins/jenkins/src/index.ts +++ b/plugins/jenkins/src/index.ts @@ -14,5 +14,8 @@ * limitations under the License. */ -export { plugin, JenkinsBuildsWidget, JenkinsLastBuildWidget } from './plugin'; +export { plugin } from './plugin'; +export { LatestRunCard } from './components/Cards'; +export { Router, isPluginApplicableToEntity } from './components/Router'; +export { JENKINS_ANNOTATION } from './constants'; export * from './api'; diff --git a/plugins/jenkins/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx b/plugins/jenkins/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx deleted file mode 100644 index ab4fc3f34f..0000000000 --- a/plugins/jenkins/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React, { FC, useEffect } from 'react'; -import { useSearchParams } from 'react-router-dom'; -import { Content, InfoCard, Progress } from '@backstage/core'; -import { Grid, Box, Link, IconButton } from '@material-ui/core'; -import { makeStyles } from '@material-ui/core/styles'; -import { PluginHeader } from '../../components/PluginHeader'; -import { ActionOutput } from './lib/ActionOutput/ActionOutput'; -import { Layout } from '../../components/Layout'; -import LaunchIcon from '@material-ui/icons/Launch'; -import GitHubIcon from '@material-ui/icons/GitHub'; -import { useBuildWithSteps } from '../../state/useBuildWithSteps'; - -const IconLink = IconButton as typeof Link; -const BuildName: FC<{ build?: any }> = ({ build }) => ( - - {build?.buildName} - - {/* TODO use Jenkins logo*/} - - - - - -); -const useStyles = makeStyles(theme => ({ - neutral: {}, - failed: { - position: 'relative', - '&:after': { - pointerEvents: 'none', - content: '""', - position: 'absolute', - top: 0, - right: 0, - left: 0, - bottom: 0, - boxShadow: `inset 4px 0px 0px ${theme.palette.error.main}`, - }, - }, - running: { - position: 'relative', - '&:after': { - pointerEvents: 'none', - content: '""', - position: 'absolute', - top: 0, - right: 0, - left: 0, - bottom: 0, - boxShadow: `inset 4px 0px 0px ${theme.palette.info.main}`, - }, - }, - cardContent: { - backgroundColor: theme.palette.background.default, - }, - success: { - position: 'relative', - '&:after': { - pointerEvents: 'none', - content: '""', - position: 'absolute', - top: 0, - right: 0, - left: 0, - bottom: 0, - boxShadow: `inset 4px 0px 0px ${theme.palette.success.main}`, - }, - }, -})); - -const pickClassName = ( - classes: ReturnType, - build: any = {}, -) => { - if (build.result === 'UNSTABLE') return classes.failed; - if (build.result === 'FAILURE') return classes.failed; - if (build.building) return classes.running; - if (build.status === 'SUCCESS') return classes.success; - - return classes.neutral; -}; - -const Page = () => ( - - - - - -); - -const BuildWithStepsView = () => { - const [searchParams] = useSearchParams(); - const buildPath = searchParams.get('url') || ''; - const classes = useStyles(); - const [{ loading, value }, { startPolling, stopPolling }] = useBuildWithSteps( - buildPath, - ); - - useEffect(() => { - startPolling(); - return () => stopPolling(); - }, [buildPath, startPolling, stopPolling]); - return ( - <> - - - - - } - cardClassName={classes.cardContent} - > - {loading ? : } - - - - - ); -}; - -const BuildsList: FC<{ build?: any }> = ({ build }) => ( - - {build && - build.steps && - build.steps.map(({ name, actions }: { name: string; actions: any[] }) => ( - - ))} - -); - -const ActionsList: FC<{ actions: any[]; name: string }> = ({ actions }) => { - const classes = useStyles(); - return ( - <> - {actions.map((action: any) => ( - - ))} - - ); -}; - -export default Page; -export { BuildWithStepsView as BuildWithSteps }; diff --git a/plugins/jenkins/src/pages/BuildsPage/lib/Builds/Builds.tsx b/plugins/jenkins/src/pages/BuildsPage/lib/Builds/Builds.tsx deleted file mode 100644 index 79f081c82d..0000000000 --- a/plugins/jenkins/src/pages/BuildsPage/lib/Builds/Builds.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { CITable } from '../CITable'; -import { useBuilds } from '../../../../state'; - -export const Builds = ({ owner, repo }: { owner: string; repo: string }) => { - const [ - { total, loading, value, projectName, page, pageSize }, - { setPage, retry, setPageSize }, - ] = useBuilds(owner, repo); - return ( - - ); -}; diff --git a/plugins/jenkins/src/plugin.ts b/plugins/jenkins/src/plugin.ts index 4d1af322c4..8282f6b7f9 100644 --- a/plugins/jenkins/src/plugin.ts +++ b/plugins/jenkins/src/plugin.ts @@ -20,11 +20,15 @@ import { createApiFactory, configApiRef, } from '@backstage/core'; -import { DetailedViewPage } from './pages/BuildWithStepsPage'; import { jenkinsApiRef, JenkinsApi } from './api'; +export const rootRouteRef = createRouteRef({ + path: '', + title: 'Jenkins', +}); + export const buildRouteRef = createRouteRef({ - path: '/jenkins/job', + path: 'run/:branch/:buildNumber', title: 'Jenkins run', }); @@ -40,10 +44,4 @@ export const plugin = createPlugin({ ), }), ], - register({ router }) { - router.addRoute(buildRouteRef, DetailedViewPage); - }, }); - -export { JenkinsBuildsWidget } from './components/JenkinsPluginWidget/JenkinsBuildsWidget'; -export { JenkinsLastBuildWidget } from './components/JenkinsPluginWidget/JenkinsLastBuildWidget'; diff --git a/plugins/jenkins/src/state/index.ts b/plugins/jenkins/src/state/index.ts deleted file mode 100644 index d21a380c2a..0000000000 --- a/plugins/jenkins/src/state/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export * from './useBuilds'; -export * from './useBuildWithSteps';