From a566cba67171d37ffa6a626616c94692d9bc132b Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Thu, 10 Sep 2020 16:18:24 +0200 Subject: [PATCH 01/25] wip: big commit to add sidebar settings dialog --- .../core/src/layout/Sidebar/PinButton.tsx | 75 ---------------- .../src/layout/Sidebar/Settings/PinButton.tsx | 64 ++++++++++++++ .../Sidebar/Settings/ProviderSettingsItem.tsx | 52 +++++++---- .../Sidebar/Settings/SettingsDialog.tsx | 70 +++++++++++++++ .../layout/Sidebar/Settings/SignInAvatar.tsx | 63 ++++++++++++++ .../layout/Sidebar/Settings/ThemeToggle.tsx | 87 +++++++++++++++++++ .../layout/Sidebar/Settings/UserProfile.tsx | 61 ------------- .../layout/Sidebar/Settings/UserSettings.tsx | 78 +++++++++++++++++ .../Sidebar/Settings/UserSettingsMenu.tsx | 55 ++++++++++++ .../core/src/layout/Sidebar/Settings/index.ts | 3 +- .../Sidebar/Settings/useUserProfileInfo.ts | 26 ++++++ .../src/layout/Sidebar/SidebarThemeToggle.tsx | 58 ------------- .../core/src/layout/Sidebar/UserSettings.tsx | 53 ----------- packages/core/src/layout/Sidebar/index.ts | 7 +- 14 files changed, 486 insertions(+), 266 deletions(-) delete mode 100644 packages/core/src/layout/Sidebar/PinButton.tsx create mode 100644 packages/core/src/layout/Sidebar/Settings/PinButton.tsx create mode 100644 packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx create mode 100644 packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx create mode 100644 packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx delete mode 100644 packages/core/src/layout/Sidebar/Settings/UserProfile.tsx create mode 100644 packages/core/src/layout/Sidebar/Settings/UserSettings.tsx create mode 100644 packages/core/src/layout/Sidebar/Settings/UserSettingsMenu.tsx create mode 100644 packages/core/src/layout/Sidebar/Settings/useUserProfileInfo.ts delete mode 100644 packages/core/src/layout/Sidebar/SidebarThemeToggle.tsx delete mode 100644 packages/core/src/layout/Sidebar/UserSettings.tsx diff --git a/packages/core/src/layout/Sidebar/PinButton.tsx b/packages/core/src/layout/Sidebar/PinButton.tsx deleted file mode 100644 index 8c52eeb24d..0000000000 --- a/packages/core/src/layout/Sidebar/PinButton.tsx +++ /dev/null @@ -1,75 +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, useContext } from 'react'; -import { makeStyles } from '@material-ui/core'; -import DoubleArrowIcon from '@material-ui/icons/DoubleArrow'; -import { SidebarContext } from './config'; -import { BackstageTheme } from '@backstage/theme'; -import { SidebarPinStateContext } from './Page'; - -const ARROW_BUTTON_SIZE = 20; -const useStyles = makeStyles(theme => { - return { - root: { - position: 'relative', - alignSelf: 'stretch', - }, - arrowButtonWrapper: { - position: 'absolute', - right: 0, - width: ARROW_BUTTON_SIZE, - height: ARROW_BUTTON_SIZE, - top: -(theme.spacing(6) + ARROW_BUTTON_SIZE) / 2, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - borderRadius: '2px 0px 0px 2px', - background: theme.palette.pinSidebarButton.background, - color: theme.palette.pinSidebarButton.icon, - border: 'none', - outline: 'none', - cursor: 'pointer', - }, - arrowButtonIcon: { - transform: ({ isPinned }) => (isPinned ? 'rotate(180deg)' : 'none'), - }, - }; -}); - -export const SidebarPinButton: FC<{}> = () => { - const { isOpen } = useContext(SidebarContext); - const { isPinned, toggleSidebarPinState } = useContext( - SidebarPinStateContext, - ); - const classes = useStyles({ isPinned }); - - return ( -
- {isOpen && ( - - )} -
- ); -}; diff --git a/packages/core/src/layout/Sidebar/Settings/PinButton.tsx b/packages/core/src/layout/Sidebar/Settings/PinButton.tsx new file mode 100644 index 0000000000..dcd0818ad6 --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/PinButton.tsx @@ -0,0 +1,64 @@ +/* + * 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, { useContext } from 'react'; +import { + ListItem, + ListItemSecondaryAction, + ListItemText, + Tooltip, +} from '@material-ui/core'; +import LockIcon from '@material-ui/icons/Lock'; +import LockOpenIcon from '@material-ui/icons/LockOpen'; +import { ToggleButton } from '@material-ui/lab'; +import { SidebarPinStateContext } from '../Page'; + +export const SidebarPinButton = () => { + const { isPinned, toggleSidebarPinState } = useContext( + SidebarPinStateContext, + ); + + const PinIcon = () => ( + + {isPinned ? : } + + ); + + return ( + + + + { + toggleSidebarPinState(); + }} + > + + + + + ); +}; diff --git a/packages/core/src/layout/Sidebar/Settings/ProviderSettingsItem.tsx b/packages/core/src/layout/Sidebar/Settings/ProviderSettingsItem.tsx index 3d3d7439e1..653c64575b 100644 --- a/packages/core/src/layout/Sidebar/Settings/ProviderSettingsItem.tsx +++ b/packages/core/src/layout/Sidebar/Settings/ProviderSettingsItem.tsx @@ -14,31 +14,53 @@ * limitations under the License. */ -import React, { FC } from 'react'; -import { OAuthApi, OpenIdConnectApi, IconComponent } from '@backstage/core-api'; -import { SidebarItem } from '../Items'; -import { IconButton, Tooltip } from '@material-ui/core'; -import StarBorder from '@material-ui/icons/StarBorder'; +import React from 'react'; +import { IconComponent, OAuthApi, OpenIdConnectApi } from '@backstage/core-api'; +import { + ListItem, + ListItemIcon, + ListItemSecondaryAction, + ListItemText, + Tooltip, +} from '@material-ui/core'; import PowerButton from '@material-ui/icons/PowerSettingsNew'; +import { ToggleButton } from '@material-ui/lab'; -export const ProviderSettingsItem: FC<{ +type Props = { title: string; icon: IconComponent; signedIn: boolean; api: OAuthApi | OpenIdConnectApi; signInHandler: Function; -}> = ({ title, icon, signedIn, api, signInHandler }) => { - return ( - - (signedIn ? api.logout() : signInHandler())}> +}; + +export const ProviderSettingsItem = ({ + title, + icon: Icon, + signedIn, + api, + signInHandler, +}: Props) => ( + + + + + + + (signedIn ? api.logout() : signInHandler())} + > - + - - - ); -}; + + + +); diff --git a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx new file mode 100644 index 0000000000..b37053763b --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx @@ -0,0 +1,70 @@ +/* + * 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 { + Card, + CardContent, + CardHeader, + Divider, + makeStyles, +} from '@material-ui/core'; +import List from '@material-ui/core/List'; +import ListSubheader from '@material-ui/core/ListSubheader'; +import { SidebarPinButton } from './PinButton'; +import { SignInAvatar } from './SignInAvatar'; +import { SidebarThemeToggle } from './ThemeToggle'; +import { UserSettingsMenu } from './UserSettingsMenu'; +import { useUserProfile } from './useUserProfileInfo'; + +const useStyles = makeStyles({ + root: { + minWidth: 400, + }, +}); + +export const SettingsDialog = ({ + providerSettings, +}: { + providerSettings?: React.ReactNode; +}) => { + const classes = useStyles(); + const { profile, displayName } = useUserProfile(); + + return ( + + } + action={} + title={displayName} + subheader={profile.email} + /> + + + App Settings}> + + + + + Available Auth Providers} + > + {providerSettings} + + + + ); +}; diff --git a/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx b/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx new file mode 100644 index 0000000000..c6eed74a18 --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx @@ -0,0 +1,63 @@ +/* + * 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 { BackstageTheme } from '@backstage/theme'; +import { makeStyles, Avatar } from '@material-ui/core'; +import { useUserProfile } from './useUserProfileInfo'; + +// const useStyles = makeStyles({ +// avatar: { +// width: ({ size }) => size, +// height: ({ size }) => size, +// }, +// }); + +// export const SignInAvatar = ({ size = 24 }: { size?: number }) => { +// const classes = useStyles({ size }); +// const { profile, displayName } = useUserProfile(); + +// return ( +// +// {displayName[0]} +// +// ); +// }; + +// const useStyles = makeStyles({ +// avatar: { +// width: 24, +// height: 24, +// }, +// }); + +const useStyles = makeStyles({ + avatar: { + width: 24, + height: 24, + }, +}); + +export const SignInAvatar = () => { + const classes = useStyles(); + const { profile, displayName } = useUserProfile(); + + return ( + + {displayName[0]} + + ); +}; diff --git a/packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx b/packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx new file mode 100644 index 0000000000..29cfb24885 --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx @@ -0,0 +1,87 @@ +/* + * 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 { useObservable } from 'react-use'; +import LightIcon from '@material-ui/icons/WbSunny'; +import DarkIcon from '@material-ui/icons/Brightness2'; +import AutoIcon from '@material-ui/icons/BrightnessAuto'; +import { appThemeApiRef, useApi } from '@backstage/core-api'; +import ToggleButton from '@material-ui/lab/ToggleButton'; +import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup'; +import { + ListItem, + ListItemText, + ListItemSecondaryAction, + Tooltip, +} from '@material-ui/core'; + +export const SidebarThemeToggle = () => { + const appThemeApi = useApi(appThemeApiRef); + const themeId = useObservable( + appThemeApi.activeThemeId$(), + appThemeApi.getActiveThemeId(), + ); + + const themeIds = appThemeApi.getInstalledThemes(); + // TODO: can these be put on the theme itself? + const themeIcons = { + dark: , + light: , + }; + + const handleSetTheme = ( + _event: React.MouseEvent, + newThemeId: string | undefined, + ) => { + if (themeIds.some(t => t.id === newThemeId)) { + appThemeApi.setActiveThemeId(newThemeId); + } else { + appThemeApi.setActiveThemeId(undefined); + } + }; + + return ( + + + + + {themeIds.map(theme => ( + + + {themeIcons[theme.variant]} + + + ))} + + + + + + + + + ); +}; diff --git a/packages/core/src/layout/Sidebar/Settings/UserProfile.tsx b/packages/core/src/layout/Sidebar/Settings/UserProfile.tsx deleted file mode 100644 index 3b854801c9..0000000000 --- a/packages/core/src/layout/Sidebar/Settings/UserProfile.tsx +++ /dev/null @@ -1,61 +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, useRef } from 'react'; -import { makeStyles, Avatar, Divider } from '@material-ui/core'; -import { useApi, identityApiRef } from '@backstage/core-api'; -import { SidebarItem } from '../Items'; -import ExpandLess from '@material-ui/icons/ExpandLess'; -import ExpandMore from '@material-ui/icons/ExpandMore'; - -const useStyles = makeStyles({ - avatar: { - width: 24, - height: 24, - }, -}); - -export const UserProfile: FC<{ open: boolean; setOpen: Function }> = ({ - open, - setOpen, -}) => { - const ref = useRef(); // for scrolling down when collapse item opens - const classes = useStyles(); - const identityApi = useApi(identityApiRef); - - const handleClick = () => { - setOpen(!open); - setTimeout(() => ref.current?.scrollIntoView({ behavior: 'smooth' }), 300); - }; - - const userId = identityApi.getUserId(); - const profile = identityApi.getProfile(); - const displayName = profile.displayName ?? userId; - const SignInAvatar = () => ( - - {displayName[0]} - - ); - - return ( - <> - - - {open ? : } - - - ); -}; diff --git a/packages/core/src/layout/Sidebar/Settings/UserSettings.tsx b/packages/core/src/layout/Sidebar/Settings/UserSettings.tsx new file mode 100644 index 0000000000..8f541364ff --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/UserSettings.tsx @@ -0,0 +1,78 @@ +/* + * 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, { useEffect, useContext } from 'react'; +import { Popover } from '@material-ui/core'; +import { SignInAvatar } from './SignInAvatar'; +import { SettingsDialog } from './SettingsDialog'; +import { SidebarItem } from '../Items'; +import { useUserProfile } from './useUserProfileInfo'; +import { SidebarContext } from '../config'; + +export const SidebarUserSettings = ({ + providerSettings, +}: { + providerSettings?: React.ReactNode; +}) => { + const { isOpen: sidebarOpen } = useContext(SidebarContext); + const { displayName } = useUserProfile(); + const [open, setOpen] = React.useState(false); + const [anchorEl, setAnchorEl] = React.useState( + undefined, + ); + + const handleOpen = (event?: React.MouseEvent) => { + setAnchorEl(event?.currentTarget ?? undefined); + setOpen(true); + }; + + const handleClose = () => { + setAnchorEl(undefined); + setOpen(false); + }; + + // Close the provider list when sidebar collapse + useEffect(() => { + if (!sidebarOpen && open) setOpen(false); + }, [open, sidebarOpen]); + + const SidebarAvatar = () => ; + + return ( + <> + + + + + + ); +}; diff --git a/packages/core/src/layout/Sidebar/Settings/UserSettingsMenu.tsx b/packages/core/src/layout/Sidebar/Settings/UserSettingsMenu.tsx new file mode 100644 index 0000000000..9ac287c57e --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/UserSettingsMenu.tsx @@ -0,0 +1,55 @@ +/* + * 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 { identityApiRef, useApi } from '@backstage/core-api'; +import { IconButton, ListItemIcon, Menu, MenuItem } from '@material-ui/core'; +import SignOutIcon from '@material-ui/icons/MeetingRoom'; +import MoreVertIcon from '@material-ui/icons/MoreVert'; + +export const UserSettingsMenu = () => { + const identityApi = useApi(identityApiRef); + const [open, setOpen] = React.useState(false); + const [anchorEl, setAnchorEl] = React.useState( + undefined, + ); + + const handleOpen = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + setOpen(true); + }; + + const handleClose = () => { + setAnchorEl(undefined); + setOpen(false); + }; + + return ( + <> + + + + + identityApi.logout()}> + + + + Sign Out + + + + ); +}; diff --git a/packages/core/src/layout/Sidebar/Settings/index.ts b/packages/core/src/layout/Sidebar/Settings/index.ts index 6557ace53a..5479236a3b 100644 --- a/packages/core/src/layout/Sidebar/Settings/index.ts +++ b/packages/core/src/layout/Sidebar/Settings/index.ts @@ -17,4 +17,5 @@ export { ProviderSettingsItem } from './ProviderSettingsItem'; export { OAuthProviderSettings } from './OAuthProviderSettings'; export { OIDCProviderSettings } from './OIDCProviderSettings'; -export { UserProfile } from './UserProfile'; +// export { UserProfile } from './UserProfile'; +export { SidebarUserSettings } from './UserSettings'; diff --git a/packages/core/src/layout/Sidebar/Settings/useUserProfileInfo.ts b/packages/core/src/layout/Sidebar/Settings/useUserProfileInfo.ts new file mode 100644 index 0000000000..60dae294a5 --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/useUserProfileInfo.ts @@ -0,0 +1,26 @@ +/* + * 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 { useApi, identityApiRef } from '@backstage/core-api'; + +export const useUserProfile = () => { + const identityApi = useApi(identityApiRef); + const userId = identityApi.getUserId(); + const profile = identityApi.getProfile(); + const displayName = profile.displayName ?? userId; + + return { profile, displayName }; +}; diff --git a/packages/core/src/layout/Sidebar/SidebarThemeToggle.tsx b/packages/core/src/layout/Sidebar/SidebarThemeToggle.tsx deleted file mode 100644 index 32bc9d9632..0000000000 --- a/packages/core/src/layout/Sidebar/SidebarThemeToggle.tsx +++ /dev/null @@ -1,58 +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 } from 'react'; -import { useObservable } from 'react-use'; -import LightIcon from '@material-ui/icons/WbSunny'; -import DarkIcon from '@material-ui/icons/Brightness2'; -import AutoIcon from '@material-ui/icons/BrightnessAuto'; -import { appThemeApiRef, useApi } from '@backstage/core-api'; -import { SidebarItem } from './Items'; - -export const SidebarThemeToggle: FC<{}> = () => { - const appThemeApi = useApi(appThemeApiRef); - const themeId = useObservable( - appThemeApi.activeThemeId$(), - appThemeApi.getActiveThemeId(), - ); - - let text = 'Auto'; - let icon = AutoIcon; - switch (themeId) { - case 'dark': - text = 'Dark mode'; - icon = DarkIcon; - break; - case 'light': - text = 'Light mode'; - icon = LightIcon; - break; - default: - break; - } - - const handleToggle = () => { - if (!themeId) { - appThemeApi.setActiveThemeId('light'); - } else if (themeId === 'light') { - appThemeApi.setActiveThemeId('dark'); - } else { - appThemeApi.setActiveThemeId(undefined); - } - }; - - return ; -}; diff --git a/packages/core/src/layout/Sidebar/UserSettings.tsx b/packages/core/src/layout/Sidebar/UserSettings.tsx deleted file mode 100644 index f586f6d077..0000000000 --- a/packages/core/src/layout/Sidebar/UserSettings.tsx +++ /dev/null @@ -1,53 +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 { identityApiRef, useApi } from '@backstage/core-api'; -import Collapse from '@material-ui/core/Collapse'; -import SignOutIcon from '@material-ui/icons/MeetingRoom'; -import React, { useContext, useEffect } from 'react'; -import { SidebarContext } from './config'; -import { SidebarItem } from './Items'; -import { UserProfile as SidebarUserProfile } from './Settings'; - -type SidebarUserSettingsProps = { providerSettings?: React.ReactNode }; - -export function SidebarUserSettings({ - providerSettings, -}: SidebarUserSettingsProps) { - const { isOpen: sidebarOpen } = useContext(SidebarContext); - const [open, setOpen] = React.useState(false); - const identityApi = useApi(identityApiRef); - - // Close the provider list when sidebar collapse - useEffect(() => { - if (!sidebarOpen && open) setOpen(false); - }, [open, sidebarOpen]); - - return ( - <> - - - {providerSettings} - - identityApi.logout()} - /> - - - ); -} diff --git a/packages/core/src/layout/Sidebar/index.ts b/packages/core/src/layout/Sidebar/index.ts index fdca7e4eea..fb9a457dea 100644 --- a/packages/core/src/layout/Sidebar/index.ts +++ b/packages/core/src/layout/Sidebar/index.ts @@ -25,14 +25,15 @@ export { SidebarSpacer, } from './Items'; export { IntroCard, SidebarIntro } from './Intro'; -export { SidebarPinButton } from './PinButton'; +// export { SidebarPinButton } from './PinButton'; export { SIDEBAR_INTRO_LOCAL_STORAGE, SidebarContext, sidebarConfig, } from './config'; export type { SidebarContextType } from './config'; -export { SidebarThemeToggle } from './SidebarThemeToggle'; -export { SidebarUserSettings } from './UserSettings'; +// export { SidebarThemeToggle } from './SidebarThemeToggle'; +// export { SidebarUserSettings } from './UserSettings'; export { DefaultProviderSettings } from './DefaultProviderSettings'; export * from './Settings'; +// export { SidebarUserSettings } from './UserSettings'; From 5e9acd5947b02bde74ebc77a787051db0812454a Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Thu, 10 Sep 2020 17:59:40 +0200 Subject: [PATCH 02/25] Option to change size of SignInAvatar --- .../Sidebar/Settings/SettingsDialog.tsx | 2 +- .../layout/Sidebar/Settings/SignInAvatar.tsx | 37 ++++--------------- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx index b37053763b..9077654b5c 100644 --- a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx +++ b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx @@ -47,7 +47,7 @@ export const SettingsDialog = ({ return ( } + avatar={} action={} title={displayName} subheader={profile.email} diff --git a/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx b/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx index c6eed74a18..519d467436 100644 --- a/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx +++ b/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx @@ -18,41 +18,18 @@ import React from 'react'; import { BackstageTheme } from '@backstage/theme'; import { makeStyles, Avatar } from '@material-ui/core'; import { useUserProfile } from './useUserProfileInfo'; +import { sidebarConfig } from '../config'; -// const useStyles = makeStyles({ -// avatar: { -// width: ({ size }) => size, -// height: ({ size }) => size, -// }, -// }); - -// export const SignInAvatar = ({ size = 24 }: { size?: number }) => { -// const classes = useStyles({ size }); -// const { profile, displayName } = useUserProfile(); - -// return ( -// -// {displayName[0]} -// -// ); -// }; - -// const useStyles = makeStyles({ -// avatar: { -// width: 24, -// height: 24, -// }, -// }); - -const useStyles = makeStyles({ +const useStyles = makeStyles({ avatar: { - width: 24, - height: 24, + width: ({ size }) => size, + height: ({ size }) => size, }, }); -export const SignInAvatar = () => { - const classes = useStyles(); +export const SignInAvatar = ({ size }: { size?: number }) => { + const { iconSize } = sidebarConfig; + const classes = useStyles(size ? { size } : { size: iconSize }); const { profile, displayName } = useUserProfile(); return ( From cd66f03f9d2ec31bc543bb1374ae754e6c6d9c74 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Fri, 11 Sep 2020 09:58:45 +0200 Subject: [PATCH 03/25] Cleanup and breaking out into more components --- .../Sidebar/Settings/AppSettingsList.tsx | 26 +++++++++++++++++ .../Sidebar/Settings/AuthProviderList.tsx | 29 +++++++++++++++++++ .../src/layout/Sidebar/Settings/PinButton.tsx | 2 +- .../Sidebar/Settings/SettingsDialog.tsx | 28 +++++++----------- .../layout/Sidebar/Settings/SignInAvatar.tsx | 4 ++- .../layout/Sidebar/Settings/ThemeToggle.tsx | 2 +- .../layout/Sidebar/Settings/UserSettings.tsx | 9 +++--- 7 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 packages/core/src/layout/Sidebar/Settings/AppSettingsList.tsx create mode 100644 packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx diff --git a/packages/core/src/layout/Sidebar/Settings/AppSettingsList.tsx b/packages/core/src/layout/Sidebar/Settings/AppSettingsList.tsx new file mode 100644 index 0000000000..5dad178ccd --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/AppSettingsList.tsx @@ -0,0 +1,26 @@ +/* + * 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 { List, ListSubheader } from '@material-ui/core'; +import { SidebarThemeToggle } from './ThemeToggle'; +import { SidebarPinButton } from './PinButton'; + +export const AppSettingsList = () => ( + App Settings}> + + + +); diff --git a/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx b/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx new file mode 100644 index 0000000000..5d13d61148 --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx @@ -0,0 +1,29 @@ +/* + * 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 List from '@material-ui/core/List'; +import ListSubheader from '@material-ui/core/ListSubheader'; + +type Props = { + providerSettings?: React.ReactNode; +}; + +export const AuthProvidersList = ({ providerSettings }: Props) => ( + Available Auth Providers}> + {providerSettings} + +); diff --git a/packages/core/src/layout/Sidebar/Settings/PinButton.tsx b/packages/core/src/layout/Sidebar/Settings/PinButton.tsx index dcd0818ad6..2727313ede 100644 --- a/packages/core/src/layout/Sidebar/Settings/PinButton.tsx +++ b/packages/core/src/layout/Sidebar/Settings/PinButton.tsx @@ -50,7 +50,7 @@ export const SidebarPinButton = () => { { toggleSidebarPinState(); diff --git a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx index 9077654b5c..ee2f0bdfb4 100644 --- a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx +++ b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx @@ -22,11 +22,10 @@ import { Divider, makeStyles, } from '@material-ui/core'; -import List from '@material-ui/core/List'; -import ListSubheader from '@material-ui/core/ListSubheader'; -import { SidebarPinButton } from './PinButton'; +import { AppSettingsList } from './AppSettingsList'; +import { AuthProvidersList } from './AuthProviderList'; +import { FeatureFlagsList } from './FeatureFlagsList'; import { SignInAvatar } from './SignInAvatar'; -import { SidebarThemeToggle } from './ThemeToggle'; import { UserSettingsMenu } from './UserSettingsMenu'; import { useUserProfile } from './useUserProfileInfo'; @@ -36,11 +35,11 @@ const useStyles = makeStyles({ }, }); -export const SettingsDialog = ({ - providerSettings, -}: { +type Props = { providerSettings?: React.ReactNode; -}) => { +}; + +export const SettingsDialog = ({ providerSettings }: Props) => { const classes = useStyles(); const { profile, displayName } = useUserProfile(); @@ -54,16 +53,11 @@ export const SettingsDialog = ({ /> - App Settings}> - - - + - Available Auth Providers} - > - {providerSettings} - + + + ); diff --git a/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx b/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx index 519d467436..f0430edfcf 100644 --- a/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx +++ b/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx @@ -27,7 +27,9 @@ const useStyles = makeStyles({ }, }); -export const SignInAvatar = ({ size }: { size?: number }) => { +type Props = { size?: number }; + +export const SignInAvatar = ({ size }: Props) => { const { iconSize } = sidebarConfig; const classes = useStyles(size ? { size } : { size: iconSize }); const { profile, displayName } = useUserProfile(); diff --git a/packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx b/packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx index 29cfb24885..a5e703089c 100644 --- a/packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx +++ b/packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx @@ -37,7 +37,7 @@ export const SidebarThemeToggle = () => { ); const themeIds = appThemeApi.getInstalledThemes(); - // TODO: can these be put on the theme itself? + // TODO(marcuseide): can these be put on the theme itself? const themeIcons = { dark: , light: , diff --git a/packages/core/src/layout/Sidebar/Settings/UserSettings.tsx b/packages/core/src/layout/Sidebar/Settings/UserSettings.tsx index 8f541364ff..85dbefff9b 100644 --- a/packages/core/src/layout/Sidebar/Settings/UserSettings.tsx +++ b/packages/core/src/layout/Sidebar/Settings/UserSettings.tsx @@ -22,11 +22,11 @@ import { SidebarItem } from '../Items'; import { useUserProfile } from './useUserProfileInfo'; import { SidebarContext } from '../config'; -export const SidebarUserSettings = ({ - providerSettings, -}: { +type Props = { providerSettings?: React.ReactNode; -}) => { +}; + +export const SidebarUserSettings = ({ providerSettings }: Props) => { const { isOpen: sidebarOpen } = useContext(SidebarContext); const { displayName } = useUserProfile(); const [open, setOpen] = React.useState(false); @@ -44,7 +44,6 @@ export const SidebarUserSettings = ({ setOpen(false); }; - // Close the provider list when sidebar collapse useEffect(() => { if (!sidebarOpen && open) setOpen(false); }, [open, sidebarOpen]); From 12e2d169f8b547d86a0890e4dbe7720ffc52ded9 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Fri, 11 Sep 2020 09:59:53 +0200 Subject: [PATCH 04/25] Add featureflags components and toggle method on api --- packages/core-api/src/app/FeatureFlags.tsx | 7 ++ .../Sidebar/Settings/FeatureFlagsItem.tsx | 67 +++++++++++++++++++ .../Sidebar/Settings/FeatureFlagsList.tsx | 38 +++++++++++ 3 files changed, 112 insertions(+) create mode 100644 packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx create mode 100644 packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx diff --git a/packages/core-api/src/app/FeatureFlags.tsx b/packages/core-api/src/app/FeatureFlags.tsx index 11c084d3ed..79c3e5d6af 100644 --- a/packages/core-api/src/app/FeatureFlags.tsx +++ b/packages/core-api/src/app/FeatureFlags.tsx @@ -80,6 +80,13 @@ export class UserFlags extends Map { return output; } + toggle(name: FeatureFlagName): FeatureFlagState { + Boolean(super.get(name)) + ? super.set(name, FeatureFlagState.Off) + : super.set(name, FeatureFlagState.On); + return super.get(name) || FeatureFlagState.Off; + } + delete(name: FeatureFlagName): boolean { const output = super.delete(name); this.save(); diff --git a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx new file mode 100644 index 0000000000..d7da3afbe6 --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx @@ -0,0 +1,67 @@ +/* + * 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 { FeatureFlagName, FeatureFlagsApi } from '@backstage/core-api'; +import { + ListItem, + ListItemSecondaryAction, + ListItemText, + Tooltip, +} from '@material-ui/core'; +import CheckIcon from '@material-ui/icons/CheckCircle'; +import { ToggleButton } from '@material-ui/lab'; + +type Props = { + featureFlag: { name: FeatureFlagName; pluginId: string }; + api: FeatureFlagsApi; +}; + +export const FlagItem = ({ featureFlag, api }: Props) => { + const [enabled, setEnabled] = React.useState( + Boolean(api.getFlags().get(featureFlag.name)), + ); + + const toggleFlag = () => { + const newState = api.getFlags().toggle(featureFlag.name); + setEnabled(Boolean(newState)); + }; + + return ( + + + + + + + + + + + ); +}; diff --git a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx new file mode 100644 index 0000000000..13e3a28c35 --- /dev/null +++ b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx @@ -0,0 +1,38 @@ +/* + * 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 List from '@material-ui/core/List'; +import ListSubheader from '@material-ui/core/ListSubheader'; +import { useApi, featureFlagsApiRef } from '@backstage/core-api'; +import { FlagItem } from './FeatureFlagsItem'; + +export const FeatureFlagsList = () => { + const featureFlagsApi = useApi(featureFlagsApiRef); + const featureFlags = featureFlagsApi.getRegisteredFlags(); + + return ( + Feature Flags}> + {featureFlags.map(featureFlag => ( + + ))} + + ); +}; From f01596d8c45ae54ad35a5afe5aba48353b619a95 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Fri, 11 Sep 2020 10:07:48 +0200 Subject: [PATCH 05/25] Update sidepar --- packages/app/src/components/Root/Root.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index e91504d619..03e24cf4ae 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -35,8 +35,6 @@ import { SidebarSearchField, SidebarSpace, SidebarUserSettings, - SidebarThemeToggle, - SidebarPinButton, DefaultProviderSettings, } from '@backstage/core'; import { NavLink } from 'react-router-dom'; @@ -103,9 +101,7 @@ const Root: FC<{}> = ({ children }) => ( /> - } /> - {children} From c8292fa05c4f6932dcf8a2d3269e9ef8f8bb56e2 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Fri, 11 Sep 2020 10:46:47 +0200 Subject: [PATCH 06/25] Change logic of FeatureFlags.toggle() --- packages/core-api/src/app/FeatureFlags.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/core-api/src/app/FeatureFlags.tsx b/packages/core-api/src/app/FeatureFlags.tsx index 79c3e5d6af..3db2a18a02 100644 --- a/packages/core-api/src/app/FeatureFlags.tsx +++ b/packages/core-api/src/app/FeatureFlags.tsx @@ -81,9 +81,11 @@ export class UserFlags extends Map { } toggle(name: FeatureFlagName): FeatureFlagState { - Boolean(super.get(name)) - ? super.set(name, FeatureFlagState.Off) - : super.set(name, FeatureFlagState.On); + if (super.get(name) === FeatureFlagState.On) { + super.set(name, FeatureFlagState.Off); + } else { + super.set(name, FeatureFlagState.On); + } return super.get(name) || FeatureFlagState.Off; } From 88fa72f91f7c8e9da2b92e5e04caeb6f775c6c95 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Fri, 11 Sep 2020 10:58:37 +0200 Subject: [PATCH 07/25] Handle empty sections --- .../Sidebar/Settings/AuthProviderList.tsx | 20 ++++++++++---- .../Sidebar/Settings/FeatureFlagsList.tsx | 26 ++++++++++++------- .../Sidebar/Settings/SettingsDialog.tsx | 11 +------- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx b/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx index 5d13d61148..50832da681 100644 --- a/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx +++ b/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx @@ -17,13 +17,23 @@ import React from 'react'; import List from '@material-ui/core/List'; import ListSubheader from '@material-ui/core/ListSubheader'; +import { Divider } from '@material-ui/core'; type Props = { providerSettings?: React.ReactNode; }; -export const AuthProvidersList = ({ providerSettings }: Props) => ( - Available Auth Providers}> - {providerSettings} - -); +export const AuthProvidersList = ({ providerSettings }: Props) => { + if (!providerSettings) { + return null; + } + + return ( + <> + + Available Auth Providers}> + {providerSettings} + + + ); +}; diff --git a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx index 13e3a28c35..d74a501c13 100644 --- a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx +++ b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx @@ -19,20 +19,28 @@ import List from '@material-ui/core/List'; import ListSubheader from '@material-ui/core/ListSubheader'; import { useApi, featureFlagsApiRef } from '@backstage/core-api'; import { FlagItem } from './FeatureFlagsItem'; +import { Divider } from '@material-ui/core'; export const FeatureFlagsList = () => { const featureFlagsApi = useApi(featureFlagsApiRef); const featureFlags = featureFlagsApi.getRegisteredFlags(); + if (featureFlags.length === 0) { + return null; + } + return ( - Feature Flags}> - {featureFlags.map(featureFlag => ( - - ))} - + <> + + Feature Flags}> + {featureFlags.map(featureFlag => ( + + ))} + + ); }; diff --git a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx index ee2f0bdfb4..9c452982e3 100644 --- a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx +++ b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx @@ -15,13 +15,7 @@ */ import React from 'react'; -import { - Card, - CardContent, - CardHeader, - Divider, - makeStyles, -} from '@material-ui/core'; +import { Card, CardContent, CardHeader, makeStyles } from '@material-ui/core'; import { AppSettingsList } from './AppSettingsList'; import { AuthProvidersList } from './AuthProviderList'; import { FeatureFlagsList } from './FeatureFlagsList'; @@ -52,11 +46,8 @@ export const SettingsDialog = ({ providerSettings }: Props) => { subheader={profile.email} /> - - - From e9c59b773e901804d623654e083d01709e84c6a2 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Fri, 11 Sep 2020 11:00:35 +0200 Subject: [PATCH 08/25] Update default-app template --- .../templates/default-app/packages/app/src/sidebar.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx index 96d18965ec..9dd9ea64c3 100644 --- a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx @@ -18,8 +18,6 @@ import { SidebarContext, SidebarSpace, SidebarUserSettings, - SidebarThemeToggle, - SidebarPinButton, DefaultProviderSettings, } from '@backstage/core'; @@ -39,9 +37,7 @@ export const AppSidebar = () => ( - } /> - ); From fd83d501db3530039ab5c494f92797cca8fe7a18 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Thu, 17 Sep 2020 13:36:12 +0200 Subject: [PATCH 09/25] Remove unnecessary boolean conversion --- .../core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx index d7da3afbe6..21074a5153 100644 --- a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx +++ b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx @@ -53,11 +53,7 @@ export const FlagItem = ({ featureFlag, api }: Props) => { selected={enabled} onChange={toggleFlag} > - + From b67b2b6c0a4e543956ae75213ee9953145b34634 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Thu, 17 Sep 2020 13:37:29 +0200 Subject: [PATCH 10/25] Remove commented out code --- packages/core/src/layout/Sidebar/Settings/index.ts | 1 - packages/core/src/layout/Sidebar/index.ts | 4 ---- 2 files changed, 5 deletions(-) diff --git a/packages/core/src/layout/Sidebar/Settings/index.ts b/packages/core/src/layout/Sidebar/Settings/index.ts index 5479236a3b..7abf061620 100644 --- a/packages/core/src/layout/Sidebar/Settings/index.ts +++ b/packages/core/src/layout/Sidebar/Settings/index.ts @@ -17,5 +17,4 @@ export { ProviderSettingsItem } from './ProviderSettingsItem'; export { OAuthProviderSettings } from './OAuthProviderSettings'; export { OIDCProviderSettings } from './OIDCProviderSettings'; -// export { UserProfile } from './UserProfile'; export { SidebarUserSettings } from './UserSettings'; diff --git a/packages/core/src/layout/Sidebar/index.ts b/packages/core/src/layout/Sidebar/index.ts index fb9a457dea..a644c06e14 100644 --- a/packages/core/src/layout/Sidebar/index.ts +++ b/packages/core/src/layout/Sidebar/index.ts @@ -25,15 +25,11 @@ export { SidebarSpacer, } from './Items'; export { IntroCard, SidebarIntro } from './Intro'; -// export { SidebarPinButton } from './PinButton'; export { SIDEBAR_INTRO_LOCAL_STORAGE, SidebarContext, sidebarConfig, } from './config'; export type { SidebarContextType } from './config'; -// export { SidebarThemeToggle } from './SidebarThemeToggle'; -// export { SidebarUserSettings } from './UserSettings'; export { DefaultProviderSettings } from './DefaultProviderSettings'; export * from './Settings'; -// export { SidebarUserSettings } from './UserSettings'; From 3664ef13c2752ca8c11cf388da633bb8fbd42e3f Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Thu, 17 Sep 2020 13:53:57 +0200 Subject: [PATCH 11/25] Pass props to lists and control rendering from outside wrapper --- .../Sidebar/Settings/AuthProviderList.tsx | 22 ++++-------- .../Sidebar/Settings/FeatureFlagsItem.tsx | 20 ++++++++--- .../Sidebar/Settings/FeatureFlagsList.tsx | 36 ++++++------------- .../Sidebar/Settings/SettingsDialog.tsx | 25 +++++++++++-- 4 files changed, 54 insertions(+), 49 deletions(-) diff --git a/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx b/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx index 50832da681..34cf6fb837 100644 --- a/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx +++ b/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx @@ -17,23 +17,13 @@ import React from 'react'; import List from '@material-ui/core/List'; import ListSubheader from '@material-ui/core/ListSubheader'; -import { Divider } from '@material-ui/core'; type Props = { - providerSettings?: React.ReactNode; + providerSettings: React.ReactNode; }; -export const AuthProvidersList = ({ providerSettings }: Props) => { - if (!providerSettings) { - return null; - } - - return ( - <> - - Available Auth Providers}> - {providerSettings} - - - ); -}; +export const AuthProvidersList = ({ providerSettings }: Props) => ( + Available Auth Providers}> + {providerSettings} + +); diff --git a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx index 21074a5153..3e40ce69cc 100644 --- a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx +++ b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx @@ -15,7 +15,11 @@ */ import React from 'react'; -import { FeatureFlagName, FeatureFlagsApi } from '@backstage/core-api'; +import { + FeatureFlagName, + useApi, + featureFlagsApiRef, +} from '@backstage/core-api'; import { ListItem, ListItemSecondaryAction, @@ -25,12 +29,18 @@ import { import CheckIcon from '@material-ui/icons/CheckCircle'; import { ToggleButton } from '@material-ui/lab'; -type Props = { - featureFlag: { name: FeatureFlagName; pluginId: string }; - api: FeatureFlagsApi; +export type Item = { + name: FeatureFlagName; + pluginId: string; }; -export const FlagItem = ({ featureFlag, api }: Props) => { +type Props = { + featureFlag: Item; +}; + +export const FlagItem = ({ featureFlag }: Props) => { + const api = useApi(featureFlagsApiRef); + const [enabled, setEnabled] = React.useState( Boolean(api.getFlags().get(featureFlag.name)), ); diff --git a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx index d74a501c13..5687446511 100644 --- a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx +++ b/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx @@ -17,30 +17,16 @@ import React from 'react'; import List from '@material-ui/core/List'; import ListSubheader from '@material-ui/core/ListSubheader'; -import { useApi, featureFlagsApiRef } from '@backstage/core-api'; -import { FlagItem } from './FeatureFlagsItem'; -import { Divider } from '@material-ui/core'; +import { FlagItem, Item } from './FeatureFlagsItem'; -export const FeatureFlagsList = () => { - const featureFlagsApi = useApi(featureFlagsApiRef); - const featureFlags = featureFlagsApi.getRegisteredFlags(); - - if (featureFlags.length === 0) { - return null; - } - - return ( - <> - - Feature Flags}> - {featureFlags.map(featureFlag => ( - - ))} - - - ); +type Props = { + featureFlags: Item[]; }; + +export const FeatureFlagsList = ({ featureFlags }: Props) => ( + Feature Flags}> + {featureFlags.map(featureFlag => ( + + ))} + +); diff --git a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx index 9c452982e3..71c4899862 100644 --- a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx +++ b/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx @@ -15,13 +15,20 @@ */ import React from 'react'; -import { Card, CardContent, CardHeader, makeStyles } from '@material-ui/core'; +import { + Card, + CardContent, + CardHeader, + makeStyles, + Divider, +} from '@material-ui/core'; import { AppSettingsList } from './AppSettingsList'; import { AuthProvidersList } from './AuthProviderList'; import { FeatureFlagsList } from './FeatureFlagsList'; import { SignInAvatar } from './SignInAvatar'; import { UserSettingsMenu } from './UserSettingsMenu'; import { useUserProfile } from './useUserProfileInfo'; +import { useApi, featureFlagsApiRef } from '@backstage/core-api'; const useStyles = makeStyles({ root: { @@ -36,6 +43,8 @@ type Props = { export const SettingsDialog = ({ providerSettings }: Props) => { const classes = useStyles(); const { profile, displayName } = useUserProfile(); + const featureFlagsApi = useApi(featureFlagsApiRef); + const featureFlags = featureFlagsApi.getRegisteredFlags(); return ( @@ -47,8 +56,18 @@ export const SettingsDialog = ({ providerSettings }: Props) => { /> - - + {providerSettings && ( + <> + + + + )} + {featureFlags.length > 0 && ( + <> + + + + )} ); From d8d074c1b4b8ce927529259f0e612186d3bea22f Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Thu, 17 Sep 2020 13:48:47 +0100 Subject: [PATCH 12/25] scaffolder: Fix backend fails to start --- packages/backend/src/plugins/scaffolder.ts | 71 +++++++++++++++------- 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index c4b7e22142..2793a38459 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -55,31 +55,60 @@ export default async function createPlugin({ const publishers = new Publishers(); - const githubToken = config.getString('scaffolder.github.token'); - const repoVisibility = config.getString( - 'scaffolder.github.visibility', - ) as RepoVisilityOptions; + const githubConfig = config.getOptionalConfig('scaffolder.github'); - const githubClient = new Octokit({ auth: githubToken }); - const githubPublisher = new GithubPublisher({ - client: githubClient, - token: githubToken, - repoVisibility, - }); - publishers.register('file', githubPublisher); - publishers.register('github', githubPublisher); + if (githubConfig) { + try { + const repoVisibility = githubConfig.getString( + 'visibility', + ) as RepoVisilityOptions; + + const githubToken = githubConfig.getString('token'); + const githubClient = new Octokit({ auth: githubToken }); + const githubPublisher = new GithubPublisher({ + client: githubClient, + token: githubToken, + repoVisibility, + }); + publishers.register('file', githubPublisher); + publishers.register('github', githubPublisher); + } catch (e) { + const providerName = 'github'; + if (process.env.NODE_ENV !== 'development') { + throw new Error( + `Failed to initialize ${providerName} scaffolding provider, ${e.message}`, + ); + } + + logger.warn( + `Skipping ${providerName} scaffolding provider, ${e.message}`, + ); + } + } const gitLabConfig = config.getOptionalConfig('scaffolder.gitlab.api'); - if (gitLabConfig) { - const gitLabToken = gitLabConfig.getString('token'); - const gitLabClient = new Gitlab({ - host: gitLabConfig.getOptionalString('baseUrl'), - token: gitLabToken, - }); - const gitLabPublisher = new GitlabPublisher(gitLabClient, gitLabToken); - publishers.register('gitlab', gitLabPublisher); - publishers.register('gitlab/api', gitLabPublisher); + try { + const gitLabToken = gitLabConfig.getString('token'); + const gitLabClient = new Gitlab({ + host: gitLabConfig.getOptionalString('baseUrl'), + token: gitLabToken, + }); + const gitLabPublisher = new GitlabPublisher(gitLabClient, gitLabToken); + publishers.register('gitlab', gitLabPublisher); + publishers.register('gitlab/api', gitLabPublisher); + } catch (e) { + const providerName = 'gitlab'; + if (process.env.NODE_ENV !== 'development') { + throw new Error( + `Failed to initialize ${providerName} scaffolding provider, ${e.message}`, + ); + } + + logger.warn( + `Skipping ${providerName} scaffolding provider, ${e.message}`, + ); + } } const dockerClient = new Docker(); From a4e563ed2d5fc1f121f1a27050bf58f31c5adc25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 17 Sep 2020 15:32:40 +0200 Subject: [PATCH 13/25] fix(catalog-backend): unify github and github/api, and use git-url-parse --- app-config.yaml | 12 +- .../templates/default-app/app-config.yaml.hbs | 4 - plugins/catalog-backend/package.json | 2 + .../src/ingestion/LocationReaders.ts | 4 +- .../processors/GithubApiReaderProcessor.ts | 192 ------------- ....test.ts => GithubReaderProcessor.test.ts} | 132 +++++++-- .../processors/GithubReaderProcessor.ts | 264 ++++++++++++++---- plugins/scaffolder-backend/package.json | 2 +- plugins/techdocs-backend/package.json | 2 +- yarn.lock | 9 +- 10 files changed, 338 insertions(+), 285 deletions(-) delete mode 100644 plugins/catalog-backend/src/ingestion/processors/GithubApiReaderProcessor.ts rename plugins/catalog-backend/src/ingestion/processors/{GithubApiReaderProcessor.test.ts => GithubReaderProcessor.test.ts} (54%) diff --git a/app-config.yaml b/app-config.yaml index 3349a6585f..bbc14e09f6 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -58,21 +58,23 @@ catalog: - allow: [Component, API, Group, Template, Location] processors: github: - privateToken: - $secret: - env: GITHUB_PRIVATE_TOKEN - githubApi: providers: - target: https://github.com token: $secret: env: GITHUB_PRIVATE_TOKEN - # Example for how to add your GitHub Enterprise instance: + #### Example for how to add your GitHub Enterprise instance using the API: # - target: https://ghe.example.net # apiBaseUrl: https://ghe.example.net/api/v3 # token: # $secret: # env: GHE_PRIVATE_TOKEN + #### Example for how to add your GitHub Enterprise instance using raw HTTP fetches (token is optional): + # - target: https://ghe.example.net + # rawBaseUrl: https://ghe.example.net/raw + # token: + # $secret: + # env: GHE_PRIVATE_TOKEN bitbucketApi: username: $secret: diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index ecac0613d9..d63176bb92 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -65,10 +65,6 @@ catalog: - allow: [Component, API, Group, Template, Location] processors: github: - privateToken: - $secret: - env: GITHUB_PRIVATE_TOKEN - githubApi: providers: - target: https://github.com token: diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index d1711cf3d5..bb62efdebb 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -27,6 +27,7 @@ "express": "^4.17.1", "express-promise-router": "^3.0.3", "fs-extra": "^9.0.0", + "git-url-parse": "^11.2.0", "knex": "^0.21.1", "lodash": "^4.17.15", "morgan": "^1.10.0", @@ -40,6 +41,7 @@ }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.21", + "@types/git-url-parse": "^9.0.0", "@types/lodash": "^4.14.151", "@types/node-fetch": "^2.5.7", "@types/supertest": "^2.0.8", diff --git a/plugins/catalog-backend/src/ingestion/LocationReaders.ts b/plugins/catalog-backend/src/ingestion/LocationReaders.ts index 6f3a27f00d..a564e9725c 100644 --- a/plugins/catalog-backend/src/ingestion/LocationReaders.ts +++ b/plugins/catalog-backend/src/ingestion/LocationReaders.ts @@ -27,7 +27,6 @@ import { AnnotateLocationEntityProcessor } from './processors/AnnotateLocationEn import { EntityPolicyProcessor } from './processors/EntityPolicyProcessor'; import { FileReaderProcessor } from './processors/FileReaderProcessor'; import { GithubReaderProcessor } from './processors/GithubReaderProcessor'; -import { GithubApiReaderProcessor } from './processors/GithubApiReaderProcessor'; import { GitlabApiReaderProcessor } from './processors/GitlabApiReaderProcessor'; import { GitlabReaderProcessor } from './processors/GitlabReaderProcessor'; import { BitbucketApiReaderProcessor } from './processors/BitbucketApiReaderProcessor'; @@ -77,8 +76,7 @@ export class LocationReaders implements LocationReader { return [ StaticLocationProcessor.fromConfig(config), new FileReaderProcessor(), - new GithubReaderProcessor(config), - GithubApiReaderProcessor.fromConfig(config), + GithubReaderProcessor.fromConfig(config), new GitlabApiReaderProcessor(config), new GitlabReaderProcessor(), new BitbucketApiReaderProcessor(config), diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubApiReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubApiReaderProcessor.ts deleted file mode 100644 index 812bf6f488..0000000000 --- a/plugins/catalog-backend/src/ingestion/processors/GithubApiReaderProcessor.ts +++ /dev/null @@ -1,192 +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 { LocationSpec } from '@backstage/catalog-model'; -import { Config } from '@backstage/config'; -import fetch, { HeadersInit, RequestInit } from 'node-fetch'; -import * as result from './results'; -import { LocationProcessor, LocationProcessorEmit } from './types'; - -/** - * The configuration parameters for a single GitHub API provider. - */ -export type ProviderConfig = { - /** - * The prefix of the target that this matches on, e.g. "https://github.com", - * with no trailing slash. - */ - target: string; - - /** - * The base URL of the API of this provider, e.g. "https://api.github.com", - * with no trailing slash. - */ - apiBaseUrl: string; - - /** - * The authorization token to use for requests to this provider. - * - * If no token is specified, anonymous API access is used. - */ - token?: string; -}; - -export function getRequestOptions(provider: ProviderConfig): RequestInit { - const headers: HeadersInit = { - Accept: 'application/vnd.github.v3.raw', - }; - - if (provider.token) { - headers.Authorization = `token ${provider.token}`; - } - - return { - headers, - }; -} - -// Converts for example -// from: https://github.com/a/b/blob/branchname/path/to/c.yaml -// to: https://api.github.com/repos/a/b/contents/path/to/c.yaml?ref=branchname -export function getRawUrl(target: string, provider: ProviderConfig): URL { - try { - const oldPath = new URL(target).pathname.split('/'); - const [, userOrOrg, repoName, blobOrRaw, ref, ...restOfPath] = oldPath; - - if ( - !userOrOrg || - !repoName || - (blobOrRaw !== 'blob' && blobOrRaw !== 'raw') || - !restOfPath.join('/').match(/\.ya?ml$/) - ) { - throw new Error('Wrong URL or Invalid file path'); - } - - // Transform to API path - const newPath = [ - 'repos', - userOrOrg, - repoName, - 'contents', - ...restOfPath, - ].join('/'); - return new URL(`${provider.apiBaseUrl}/${newPath}?ref=${ref}`); - } catch (e) { - throw new Error(`Incorrect URL: ${target}, ${e}`); - } -} - -export function readConfig(configRoot: Config): ProviderConfig[] { - const providers: ProviderConfig[] = []; - - // In a previous version of the configuration, we only supported github, - // and the "privateToken" key held the token to use for it. The new - // configuration method is to use the "providers" key instead. - const config = configRoot.getOptionalConfig('catalog.processors.githubApi'); - const providerConfigs = config?.getOptionalConfigArray('providers') ?? []; - const legacyToken = config?.getOptionalString('privateToken'); - - // First read all the explicit providers - for (const providerConfig of providerConfigs) { - const target = providerConfig.getString('target').replace(/\/+$/, ''); - let apiBaseUrl = providerConfig.getOptionalString('apiBaseUrl'); - const token = providerConfig.getOptionalString('token'); - - if (apiBaseUrl) { - apiBaseUrl = apiBaseUrl.replace(/\/+$/, ''); - } else if (target === 'https://github.com') { - apiBaseUrl = 'https://api.github.com'; - } else { - throw new Error( - `Provider at ${target} must configure an explicit apiBaseUrl`, - ); - } - - providers.push({ target, apiBaseUrl, token }); - } - - // If no explicit github.com provider was added, put one in the list as - // a convenience - if (!providers.some(p => p.target === 'https://github.com')) { - providers.push({ - target: 'https://github.com', - apiBaseUrl: 'https://api.github.com', - token: legacyToken, - }); - } - - return providers; -} - -/** - * A processor that adds the ability to read files from GitHub v3 APIs, such as - * the one exposed by GitHub itself. - */ -export class GithubApiReaderProcessor implements LocationProcessor { - private providers: ProviderConfig[]; - - static fromConfig(config: Config) { - return new GithubApiReaderProcessor(readConfig(config)); - } - - constructor(providers: ProviderConfig[]) { - this.providers = providers; - } - - async readLocation( - location: LocationSpec, - optional: boolean, - emit: LocationProcessorEmit, - ): Promise { - if (location.type !== 'github/api') { - return false; - } - - const provider = this.providers.find(p => - location.target.startsWith(`${p.target}/`), - ); - if (!provider) { - throw new Error( - `There is no GitHub provider that matches ${location.target}. Please add a configuration entry for it under catalog.github.processors.githubApi.`, - ); - } - - try { - const url = getRawUrl(location.target, provider); - const options = getRequestOptions(provider); - const response = await fetch(url.toString(), options); - - if (response.ok) { - const data = await response.buffer(); - emit(result.data(location, data)); - } else { - const message = `${location.target} could not be read as ${url}, ${response.status} ${response.statusText}`; - if (response.status === 404) { - if (!optional) { - emit(result.notFoundError(location, message)); - } - } else { - emit(result.generalError(location, message)); - } - } - } catch (e) { - const message = `Unable to read ${location.type} ${location.target}, ${e}`; - emit(result.generalError(location, message)); - } - - return true; - } -} diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubApiReaderProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.test.ts similarity index 54% rename from plugins/catalog-backend/src/ingestion/processors/GithubApiReaderProcessor.test.ts rename to plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.test.ts index 48f38f0e97..e3c7611e80 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubApiReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.test.ts @@ -17,18 +17,20 @@ import { LocationSpec } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import { + getApiUrl, + getApiRequestOptions, getRawUrl, - getRequestOptions, - GithubApiReaderProcessor, + getRawRequestOptions, + GithubReaderProcessor, ProviderConfig, readConfig, -} from './GithubApiReaderProcessor'; +} from './GithubReaderProcessor'; -describe('GithubApiReaderProcessor', () => { - describe('getRequestOptions', () => { +describe('GithubReaderProcessor', () => { + describe('getApiRequestOptions', () => { it('sets the correct API version', () => { const config: ProviderConfig = { target: '', apiBaseUrl: '' }; - expect((getRequestOptions(config).headers as any).Accept).toEqual( + expect((getApiRequestOptions(config).headers as any).Accept).toEqual( 'application/vnd.github.v3.raw', ); }); @@ -44,24 +46,95 @@ describe('GithubApiReaderProcessor', () => { apiBaseUrl: '', }; expect( - (getRequestOptions(withToken).headers as any).Authorization, + (getApiRequestOptions(withToken).headers as any).Authorization, ).toEqual('token A'); expect( - (getRequestOptions(withoutToken).headers as any).Authorization, + (getApiRequestOptions(withoutToken).headers as any).Authorization, ).toBeUndefined(); }); }); + describe('getRawRequestOptions', () => { + it('inserts a token when needed', () => { + const withToken: ProviderConfig = { + target: '', + rawBaseUrl: '', + token: 'A', + }; + const withoutToken: ProviderConfig = { + target: '', + rawBaseUrl: '', + }; + expect( + (getRawRequestOptions(withToken).headers as any).Authorization, + ).toEqual('token A'); + expect( + (getRawRequestOptions(withoutToken).headers as any).Authorization, + ).toBeUndefined(); + }); + }); + + describe('getApiUrl', () => { + it('rejects targets that do not look like URLs', () => { + const config: ProviderConfig = { target: '', apiBaseUrl: '' }; + expect(() => getApiUrl('a/b', config)).toThrow(/Incorrect URL: a\/b/); + }); + + it('happy path for github', () => { + const config: ProviderConfig = { + target: 'https://github.com', + apiBaseUrl: 'https://api.github.com', + }; + expect( + getApiUrl( + 'https://github.com/a/b/blob/branchname/path/to/c.yaml', + config, + ), + ).toEqual( + new URL( + 'https://api.github.com/repos/a/b/contents/path/to/c.yaml?ref=branchname', + ), + ); + expect( + getApiUrl( + 'https://ghe.mycompany.net/a/b/blob/branchname/path/to/c.yaml', + config, + ), + ).toEqual( + new URL( + 'https://api.github.com/repos/a/b/contents/path/to/c.yaml?ref=branchname', + ), + ); + }); + + it('happy path for ghe', () => { + const config: ProviderConfig = { + target: 'https://ghe.mycompany.net', + apiBaseUrl: 'https://ghe.mycompany.net/api/v3', + }; + expect( + getApiUrl( + 'https://ghe.mycompany.net/a/b/blob/branchname/path/to/c.yaml', + config, + ), + ).toEqual( + new URL( + 'https://ghe.mycompany.net/api/v3/repos/a/b/contents/path/to/c.yaml?ref=branchname', + ), + ); + }); + }); + describe('getRawUrl', () => { it('rejects targets that do not look like URLs', () => { const config: ProviderConfig = { target: '', apiBaseUrl: '' }; expect(() => getRawUrl('a/b', config)).toThrow(/Incorrect URL: a\/b/); }); - it('passes through the happy path', () => { + it('happy path for github', () => { const config: ProviderConfig = { target: 'https://github.com', - apiBaseUrl: 'https://api.github.com', + rawBaseUrl: 'https://raw.githubusercontent.com', }; expect( getRawUrl( @@ -70,10 +143,25 @@ describe('GithubApiReaderProcessor', () => { ), ).toEqual( new URL( - 'https://api.github.com/repos/a/b/contents/path/to/c.yaml?ref=branchname', + 'https://raw.githubusercontent.com/a/b/branchname/path/to/c.yaml', ), ); }); + + it('happy path for ghe', () => { + const config: ProviderConfig = { + target: 'https://ghe.mycompany.net', + rawBaseUrl: 'https://ghe.mycompany.net/raw', + }; + expect( + getRawUrl( + 'https://ghe.mycompany.net/a/b/blob/branchname/path/to/c.yaml', + config, + ), + ).toEqual( + new URL('https://ghe.mycompany.net/raw/a/b/branchname/path/to/c.yaml'), + ); + }); }); describe('readConfig', () => { @@ -84,7 +172,7 @@ describe('GithubApiReaderProcessor', () => { { context: '', data: { - catalog: { processors: { githubApi: { providers } } }, + catalog: { processors: { github: { providers } } }, }, }, ]); @@ -93,22 +181,30 @@ describe('GithubApiReaderProcessor', () => { it('adds a default GitHub entry when missing', () => { const output = readConfig(config([])); expect(output).toEqual([ - { target: 'https://github.com', apiBaseUrl: 'https://api.github.com' }, + { + target: 'https://github.com', + apiBaseUrl: 'https://api.github.com', + rawBaseUrl: 'https://raw.githubusercontent.com', + }, ]); }); it('injects the correct GitHub API base URL when missing', () => { const output = readConfig(config([{ target: 'https://github.com' }])); expect(output).toEqual([ - { target: 'https://github.com', apiBaseUrl: 'https://api.github.com' }, + { + target: 'https://github.com', + apiBaseUrl: 'https://api.github.com', + rawBaseUrl: 'https://raw.githubusercontent.com', + }, ]); }); - it('rejects custom targets with no API base URL', () => { + it('rejects custom targets with no base URLs', () => { expect(() => readConfig(config([{ target: 'https://ghe.company.com' }])), ).toThrow( - 'Provider at https://ghe.company.com must configure an explicit apiBaseUrl', + 'Provider at https://ghe.company.com must configure an explicit apiBaseUrl or rawBaseUrl', ); }); @@ -132,7 +228,7 @@ describe('GithubApiReaderProcessor', () => { describe('implementation', () => { it('rejects unknown types', async () => { - const processor = new GithubApiReaderProcessor([ + const processor = new GithubReaderProcessor([ { target: 'https://github.com', apiBaseUrl: 'https://api.github.com' }, ]); const location: LocationSpec = { @@ -145,7 +241,7 @@ describe('GithubApiReaderProcessor', () => { }); it('rejects unknown targets', async () => { - const processor = new GithubApiReaderProcessor([ + const processor = new GithubReaderProcessor([ { target: 'https://github.com', apiBaseUrl: 'https://api.github.com' }, ]); const location: LocationSpec = { diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts index 9f38d782fe..f83469bd16 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts @@ -15,33 +15,199 @@ */ import { LocationSpec } from '@backstage/catalog-model'; -import fetch, { RequestInit, HeadersInit } from 'node-fetch'; +import { Config } from '@backstage/config'; +import parseGitUri from 'git-url-parse'; +import fetch, { HeadersInit, RequestInit } from 'node-fetch'; import * as result from './results'; import { LocationProcessor, LocationProcessorEmit } from './types'; -import { Config } from '@backstage/config'; -export class GithubReaderProcessor implements LocationProcessor { - private privateToken: string; +/** + * The configuration parameters for a single GitHub API provider. + */ +export type ProviderConfig = { + /** + * The prefix of the target that this matches on, e.g. "https://github.com", + * with no trailing slash. + */ + target: string; - constructor(config?: Config) { - this.privateToken = - config?.getOptionalString('catalog.processors.github.privateToken') ?? ''; + /** + * The base URL of the API of this provider, e.g. "https://api.github.com", + * with no trailing slash. + * + * May be omitted specifically for GitHub; then it will be deduced. + * + * The API will always be preferred if both its base URL and a token are + * present. + */ + apiBaseUrl?: string; + + /** + * The base URL of the raw fetch endpoint of this provider, e.g. + * "https://raw.githubusercontent.com", with no trailing slash. + * + * May be omitted specifically for GitHub; then it will be deduced. + * + * The API will always be preferred if both its base URL and a token are + * present. + */ + rawBaseUrl?: string; + + /** + * The authorization token to use for requests to this provider. + * + * If no token is specified, anonymous access is used. + */ + token?: string; +}; + +export function getApiRequestOptions(provider: ProviderConfig): RequestInit { + const headers: HeadersInit = { + Accept: 'application/vnd.github.v3.raw', + }; + + if (provider.token) { + headers.Authorization = `token ${provider.token}`; } - getRequestOptions(): RequestInit { - const headers: HeadersInit = { - Accept: 'application/vnd.github.v3.raw', - }; + return { + headers, + }; +} - if (this.privateToken !== '') { - headers.Authorization = `token ${this.privateToken}`; +export function getRawRequestOptions(provider: ProviderConfig): RequestInit { + const headers: HeadersInit = {}; + + if (provider.token) { + headers.Authorization = `token ${provider.token}`; + } + + return { + headers, + }; +} + +// Converts for example +// from: https://github.com/a/b/blob/branchname/path/to/c.yaml +// to: https://api.github.com/repos/a/b/contents/path/to/c.yaml?ref=branchname +export function getApiUrl(target: string, provider: ProviderConfig): URL { + try { + const { owner, name, ref, filepathtype, filepath } = parseGitUri(target); + + if ( + !owner || + !name || + !ref || + (filepathtype !== 'blob' && filepathtype !== 'raw') || + !filepath?.match(/\.ya?ml$/) + ) { + throw new Error('Wrong URL or invalid file path'); } - const requestOptions: RequestInit = { - headers, - }; + const pathWithoutSlash = filepath.replace(/^\//, ''); + return new URL( + `${provider.apiBaseUrl}/repos/${owner}/${name}/contents/${pathWithoutSlash}?ref=${ref}`, + ); + } catch (e) { + throw new Error(`Incorrect URL: ${target}, ${e}`); + } +} - return requestOptions; +// Converts for example +// from: https://github.com/a/b/blob/branchname/c.yaml +// to: https://raw.githubusercontent.com/a/b/branchname/c.yaml +export function getRawUrl(target: string, provider: ProviderConfig): URL { + try { + const { owner, name, ref, filepathtype, filepath } = parseGitUri(target); + + if ( + !owner || + !name || + !ref || + (filepathtype !== 'blob' && filepathtype !== 'raw') || + !filepath?.match(/\.ya?ml$/) + ) { + throw new Error('Wrong URL or invalid file path'); + } + + const pathWithoutSlash = filepath.replace(/^\//, ''); + return new URL( + `${provider.rawBaseUrl}/${owner}/${name}/${ref}/${pathWithoutSlash}`, + ); + } catch (e) { + throw new Error(`Incorrect URL: ${target}, ${e}`); + } +} + +export function readConfig(config: Config): ProviderConfig[] { + const providers: ProviderConfig[] = []; + + // In a previous version of the configuration, we only supported github, + // and the "privateToken" key held the token to use for it. The new + // configuration method is to use the "providers" key instead. + const providerConfigs = + config.getOptionalConfigArray('catalog.processors.github.providers') ?? + config.getOptionalConfigArray('catalog.processors.githubApi.providers') ?? + []; + const legacyToken = + config.getOptionalString('catalog.processors.github.privateToken') ?? + config.getOptionalString('catalog.processors.githubApi.privateToken'); + + // First read all the explicit providers + for (const providerConfig of providerConfigs) { + const target = providerConfig.getString('target').replace(/\/+$/, ''); + let apiBaseUrl = providerConfig.getOptionalString('apiBaseUrl'); + let rawBaseUrl = providerConfig.getOptionalString('rawBaseUrl'); + const token = providerConfig.getOptionalString('token'); + + if (apiBaseUrl) { + apiBaseUrl = apiBaseUrl.replace(/\/+$/, ''); + } else if (target === 'https://github.com') { + apiBaseUrl = 'https://api.github.com'; + } + + if (rawBaseUrl) { + rawBaseUrl = rawBaseUrl.replace(/\/+$/, ''); + } else if (target === 'https://github.com') { + rawBaseUrl = 'https://raw.githubusercontent.com'; + } + + if (!apiBaseUrl && !rawBaseUrl) { + throw new Error( + `Provider at ${target} must configure an explicit apiBaseUrl or rawBaseUrl`, + ); + } + + providers.push({ target, apiBaseUrl, rawBaseUrl, token }); + } + + // If no explicit github.com provider was added, put one in the list as + // a convenience + if (!providers.some(p => p.target === 'https://github.com')) { + providers.push({ + target: 'https://github.com', + apiBaseUrl: 'https://api.github.com', + rawBaseUrl: 'https://raw.githubusercontent.com', + token: legacyToken, + }); + } + + return providers; +} + +/** + * A processor that adds the ability to read files from GitHub v3 APIs, such as + * the one exposed by GitHub itself. + */ +export class GithubReaderProcessor implements LocationProcessor { + private providers: ProviderConfig[]; + + static fromConfig(config: Config) { + return new GithubReaderProcessor(readConfig(config)); + } + + constructor(providers: ProviderConfig[]) { + this.providers = providers; } async readLocation( @@ -49,16 +215,31 @@ export class GithubReaderProcessor implements LocationProcessor { optional: boolean, emit: LocationProcessorEmit, ): Promise { - if (location.type !== 'github') { + // The github/api type is for backward compatibility + if (location.type !== 'github' && location.type !== 'github/api') { return false; } - try { - const url = this.buildRawUrl(location.target); + const provider = this.providers.find(p => + location.target.startsWith(`${p.target}/`), + ); + if (!provider) { + throw new Error( + `There is no GitHub provider that matches ${location.target}. Please add a configuration entry for it under catalog.processors.github.providers.`, + ); + } - // TODO(freben): Should "hard" errors thrown by this line be treated as - // notFound instead of fatal? - const response = await fetch(url.toString(), this.getRequestOptions()); + try { + const useApi = + provider.apiBaseUrl && (provider.token || !provider.rawBaseUrl); + const url = useApi + ? getApiUrl(location.target, provider) + : getRawUrl(location.target, provider); + const options = useApi + ? getApiRequestOptions(provider) + : getRawRequestOptions(provider); + console.log(url.toString()); + const response = await fetch(url.toString(), options); if (response.ok) { const data = await response.buffer(); @@ -80,41 +261,4 @@ export class GithubReaderProcessor implements LocationProcessor { return true; } - - // Converts - // from: https://github.com/a/b/blob/master/c.yaml - // to: https://raw.githubusercontent.com/a/b/master/c.yaml - private buildRawUrl(target: string): URL { - try { - const url = new URL(target); - - const [ - empty, - userOrOrg, - repoName, - blobKeyword, - ...restOfPath - ] = url.pathname.split('/'); - - if ( - url.hostname !== 'github.com' || - empty !== '' || - userOrOrg === '' || - repoName === '' || - blobKeyword !== 'blob' || - !restOfPath.join('/').match(/\.yaml$/) - ) { - throw new Error('Wrong GitHub URL'); - } - - // Removing the "blob" part - url.pathname = [empty, userOrOrg, repoName, ...restOfPath].join('/'); - url.hostname = 'raw.githubusercontent.com'; - url.protocol = 'https'; - - return url; - } catch (e) { - throw new Error(`Incorrect url: ${target}, ${e}`); - } - } } diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index dd758eaef0..c28e0631ab 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -33,7 +33,7 @@ "express": "^4.17.1", "express-promise-router": "^3.0.3", "fs-extra": "^9.0.0", - "git-url-parse": "^11.1.2", + "git-url-parse": "^11.2.0", "globby": "^11.0.0", "helmet": "^4.0.0", "jsonschema": "^1.2.6", diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 47b2ebc8aa..476b321e1e 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -30,7 +30,7 @@ "express": "^4.17.1", "express-promise-router": "^3.0.3", "fs-extra": "^9.0.1", - "git-url-parse": "^11.1.3", + "git-url-parse": "^11.2.0", "knex": "^0.21.1", "node-fetch": "^2.6.0", "nodegit": "^0.27.0", diff --git a/yarn.lock b/yarn.lock index e60ed587a1..9cc45f94fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10695,13 +10695,20 @@ git-up@^4.0.0: is-ssh "^1.3.0" parse-url "^5.0.0" -git-url-parse@^11.1.2, git-url-parse@^11.1.3: +git-url-parse@^11.1.2: version "11.1.3" resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.1.3.tgz#03625b6fc09905e9ad1da7bb2b84be1bf9123143" integrity sha512-GPsfwticcu52WQ+eHp0IYkAyaOASgYdtsQDIt4rUp6GbiNt1P9ddrh3O0kQB0eD4UJZszVqNT3+9Zwcg40fywA== dependencies: git-up "^4.0.0" +git-url-parse@^11.2.0: + version "11.2.0" + resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.2.0.tgz#2955fd51befd6d96ea1389bbe2ef57e8e6042b04" + integrity sha512-KPoHZg8v+plarZvto4ruIzzJLFQoRx+sUs5DQSr07By9IBKguVd+e6jwrFR6/TP6xrCJlNV1tPqLO1aREc7O2g== + dependencies: + git-up "^4.0.0" + gitconfiglocal@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" From 51a9b70e3aadd66f68c05598ca596480d801a702 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 17 Sep 2020 19:17:31 +0200 Subject: [PATCH 14/25] e2e-test: ignore unhandled errors from jsdom --- packages/e2e-test/src/e2e-test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/e2e-test/src/e2e-test.ts b/packages/e2e-test/src/e2e-test.ts index 83f92ea360..146a3ec644 100644 --- a/packages/e2e-test/src/e2e-test.ts +++ b/packages/e2e-test/src/e2e-test.ts @@ -403,5 +403,15 @@ async function testBackendStart(appDir: string, isPostgres: boolean) { } } -process.on('unhandledRejection', handleError); +process.on('unhandledRejection', (error: Error) => { + // Try to avoid exiting if the unhandled error is coming from jsdom, i.e. zombie. + // Those are typically errors on the page that should be benign, at least in the + // context of this test. We have other ways of asserting that the page is being + // rendered correctly. + if (error?.stack?.includes('node_modules/jsdom/lib')) { + console.log(`Ignored error inside jsdom, ${error}`); + } else { + handleError(error); + } +}); main().catch(handleError); From 975b97daf21fc1ad5cc0af8ab4c4c75366afbcc8 Mon Sep 17 00:00:00 2001 From: Jesse Alan Johnson Date: Thu, 17 Sep 2020 14:41:13 -0400 Subject: [PATCH 15/25] new tutorials (#2435) * new tutorial * prettier formatting * Update quickstart.md * prettier write * refined quickstart tutorial * Create QuickStart-app-plugin * Rename QuickStart-app-plugin to quickStart-app-plugin * Update and rename quickStart-app-plugin to quickstart-app-plugin * Adding second tutorial with prettier * removing rogue file * updating where to go link * adding sidebars entry for new tutorials --- docs/tutorials/quickstart-app-auth.md | 199 ++++++++++ docs/tutorials/quickstart-app-plugin.md | 487 ++++++++++++++++++++++++ microsite/sidebars.json | 6 +- 3 files changed, 691 insertions(+), 1 deletion(-) create mode 100644 docs/tutorials/quickstart-app-auth.md create mode 100644 docs/tutorials/quickstart-app-plugin.md diff --git a/docs/tutorials/quickstart-app-auth.md b/docs/tutorials/quickstart-app-auth.md new file mode 100644 index 0000000000..fea1d7085a --- /dev/null +++ b/docs/tutorials/quickstart-app-auth.md @@ -0,0 +1,199 @@ +--- +id: quickstart-app-auth +title: Monorepo App Setup With Authentication +--- + +###### September 15th 2020 - @backstage/create-app - v0.1.1-alpha.21 + +
+ +> This document takes you through setting up a backstage app that runs in your +> own environment. It starts with a skeleton install and verifying of the +> monorepo's functionality. Next, GitHub authentication is added and tested. +> +> This document assumes you have NodeJS 12 active along with Yarn. Please note, +> that at the time of this writing, the current version is 0.1.1-alpha.21. This +> guide can still be used with future versions, just, verify as you go. If you +> run into issues, you can compare your setup with mine here > +> [simple-backstage-app](https://github.com/johnson-jesse/simple-backstage-app). + +# The Skeleton Application + +From the terminal: + +1. Create a (monorepo) application: `npx @backstage/create-app` +1. Enter an `id` for your new app like `mybiz-backstage` I went with + `simple-backstage-app` +1. Choose `SQLite` as your database. This is the quickest way to get started as + PostgreSQL requires additional setup not covered here. +1. Start your backend: `yarn --cwd packages/backend start` + +```zsh +# You should see positive verbiage in your terminal output +2020-09-11T22:20:26.712Z backstage info Listening on :7000 +``` + +5. Finally, start the frontend. Open a new terminal window and from the root of + your project, run: `yarn start` + +```zsh +# You should see positive verbiage in your terminal output +ℹ 「wds」: Project is running at http://localhost:3000/ +``` + +Once the app compiles, a browser window should have popped with your stand alone +application loaded at `localhost:3000`. This could take a couple minutes. + +```zsh +# You should see positive verbiage in your terminal output +ℹℹ 「wdm」: Compiled successfully. +``` + +Since there is no auth currently configured, you are automatically entered as a +guest. Let's fix that now and add auth. + +# The Auth Configuration + +1. Open `app-config.yaml` and change it as follows + +_from:_ + +```yaml +auth: + providers: {} +``` + +_to:_ + +```yaml +auth: + providers: + github: + development: + clientId: + $secret: + env: AUTH_GITHUB_CLIENT_ID + clientSecret: + $secret: + env: AUTH_GITHUB_CLIENT_SECRET + ## uncomment the following three lines if using enterprise + # enterpriseInstanceUrl: + # $secret: + # env: AUTH_GITHUB_ENTERPRISE_INSTANCE_URL +``` + +2. Set environment variables in whatever fashion is easiest for you. I chose to + add mine to my `.zshrc` profile. + +```zsh +# For macOS Catalina & Z Shell +# ------ simple-backstage-app GitHub +export AUTH_GITHUB_CLIENT_ID=xxx +export AUTH_GITHUB_CLIENT_SECRET=xxx +# export AUTH_GITHUB_ENTERPRISE_INSTANCE_URL=https://github.{MY_BIZ}.com +``` + +3. And of course I need to source that file. + +```zsh +# Loading the new variables +% source ~/.zshrc + +# Any other currently opened terminals need to be restarted to pick up the new values +# verify your setup by running env +% env +# should output something like +> ... +> AUTH_GITHUB_CLIENT_ID=xxx +> AUTH_GITHUB_CLIENT_SECRET=xxx +> ... +``` + +4. The values to replace `xxx` above come from your oauth app setup. + +``` +> Log into http://github.com +> Navigate to (Settings > Developer Settings > OAuth Apps > New OAuth App)[https://github.com/settings/applications/new] +> Set Homepage URL = http://localhost:3000 +> Set Callback URL = http://localhost:7000/auth/github +> Click [Register application] +> On the next page, copy and paste your new Client ID and Client Secret to the environment variables above, `AUTH_GITHUB_CLIENT_ID` & `AUTH_GITHUB_CLIENT_SECRET` +> Don't forget to `source` that profile file again if necessary. +``` + +5. Open and change _root > packages > app > src >_`App.tsx` as follows + +```tsx +// Add the following imports to the existing list from core +import { githubAuthApiRef, SignInPage } from '@backstage/core'; +``` + +6. In the same file, change the createApp function as follows + +```tsx +const app = createApp({ + apis, + plugins: Object.values(plugins), + components: { + SignInPage: props => { + return ( + + ); + }, + }, +}); +``` + +6. Open and change _root > packages > app > src >_ `apis.ts` as follows + +```ts +// Add the following imports to the existing list from core +import { githubAuthApiRef, GithubAuth } from '@backstage/core'; +``` + +7. In the same file, change the builder block for oauthRequestApiRef as follows + +_from:_ + +```ts +builder.add(oauthRequestApiRef, new OAuthRequestManager()); +``` + +_to:_ + +```ts +const oauthRequestApi = builder.add( + oauthRequestApiRef, + new OAuthRequestManager(), +); + +builder.add( + githubAuthApiRef, + GithubAuth.create({ + discoveryApi, + oauthRequestApi, + }), +); +``` + +> Start the backend and frontend as before. When the browser loads, you should +> be presented with a login page for GitHub. Login as usual with your GitHub +> account. If this is your first time, you will be asked to authorize and then +> are redirected to the catalog page if all is well. + +# Where to go from here + +> You're probably eager to write your first custom plugin. Follow this next +> tutorial for an in-depth look at a custom GitHub repository browser plugin. +> [Adding Custom Plugin to Existing Monorepo App](quickstart-app-plugin.md). diff --git a/docs/tutorials/quickstart-app-plugin.md b/docs/tutorials/quickstart-app-plugin.md new file mode 100644 index 0000000000..28efb2a007 --- /dev/null +++ b/docs/tutorials/quickstart-app-plugin.md @@ -0,0 +1,487 @@ +--- +id: quickstart-app-plugin +title: Adding Custom Plugin to Existing Monorepo App +--- + +###### September 15th 2020 - v0.1.1-alpha.21 + +
+ +> This document takes you through setting up a new plugin for your existing +> monorepo with a _GitHub provider already setup_. If you don't have either of +> those, you can clone +> [simple-backstage-app](https://github.com/johnson-jesse/simple-backstage-app) +> which this document builds on. +> +> This document does not cover authoring a plugin for sharing with the Backstage +> community. That will have to be a later discussion. +> +> We start with a skeleton plugin install. And after verifying its +> functionality, extend the Sidebar to make our life easy. Finally, we add +> custom code to display GitHub repository information. +> +> This document assumes you have NodeJS 12 active along with Yarn. Please note, +> that at the time of this writing, the current version is 0.1.1-alpha.21. This +> guide can still be used with future versions, just, verify as you go. If you +> run into issues, you can compare your setup with mine here > +> [simple-backstage-app-plugin](https://github.com/johnson-jesse/simple-backstage-app-plugin). + +# The Skeleton Plugin + +1. Start by using the built in creator. From the terminal and root of your + project run: `yarn create-plugin` +1. Enter a plugin ID. I used `github-playground` +1. When the process finishes, let's start the backend: + `yarn --cwd packages/backend start` +1. If you see errors starting, refer to + [Auth Configuration](https://github.com/johnson-jesse/simple-backstage-app/blob/master/README.md#the-auth-configuration) + for more information on environment variables. +1. And now the frontend, from a new terminal window and the root of your + project: `yarn start` +1. As usual, a browser window should popup loading the App. +1. Now manually navigate to our plugin page from your browser: + `http://localhost:3000/github-playground` +1. You should see successful verbiage for this endpoint, + `Welcome to github-playground!` + +# The Shortcut + +Let's add a shortcut. + +1. Open and modify `root: packages > app > src > sidebar.tsx` with the + following: + +```tsx +import GitHubIcon from '@material-ui/icons/GitHub'; +... + +``` + +Simple! The App will reload with your changes automatically. You should now see +a github icon displayed in the sidebar. Clicking that will link to our new +plugin. And now, the API fun begins. + +# The Identity + +Our first modification will be to extract information from the Identity API. + +1. Start by opening + `root: plugins > github-playground > src > components > ExampleComponent > ExampleComponent.tsx` +1. Add two new imports + +```tsx +// Add identityApiRef to the list of imported from core +import { identityApiRef } from '@backstage/core'; +import { useApi } from '@backstage/core-api'; +``` + +3. Adjust the ExampleComponent from inline to block + +_from inline:_ + +```tsx +const ExampleComponent: FC<{}> = () => ( ... ) +``` + +_to block:_ + +```tsx +const ExampleComponent: FC<{}> = () => { + + return ( + ... + ) +} +``` + +4. Now add our hook and const data before the return statement + +```tsx +// our API hook +const identityApi = useApi(identityApiRef); + +// data to use +const userId = identityApi.getUserId(); +const profile = identityApi.getProfile(); +``` + +5. Finally, update the InfoCard's jsx to use our new data + +```tsx + + + {`${profile.displayName} | ${profile.email}`} + + +``` + +If everything is saved, you should see your name, id, and email on the +github-playground page. Our data accessed is synchronous. So we just grab and +go. + +6. Here is the entire file for reference +
Complete ExampleComponent.tsx +

+ +```tsx +import React, { FC } from 'react'; +import { Typography, Grid } from '@material-ui/core'; +import { + InfoCard, + Header, + Page, + pageTheme, + Content, + ContentHeader, + HeaderLabel, + SupportButton, + identityApiRef, +} from '@backstage/core'; +import { useApi } from '@backstage/core-api'; +import ExampleFetchComponent from '../ExampleFetchComponent'; + +const ExampleComponent: FC<{}> = () => { + const identityApi = useApi(identityApiRef); + const userId = identityApi.getUserId(); + const profile = identityApi.getProfile(); + + return ( + +

+ + +
+ + + A description of your plugin goes here. + + + + + + {`${profile.displayName} | ${profile.email}`} + + + + + + + + + + ); +}; + +export default ExampleComponent; +``` + +

+
+ +# The Wipe + +The last file we will touch is ExampleFetchComponent. Because of the number of +changes, let's start by wiping this component clean. + +1. Start by opening + `root: plugins > github-playground > src > components > ExampleFetchComponent > ExampleFetchComponent.tsx` +1. Replace everyting in the file with the following: + +```tsx +import React, { FC } from 'react'; +import { useAsync } from 'react-use'; +import Alert from '@material-ui/lab/Alert'; +import { + Table, + TableColumn, + Progress, + githubAuthApiRef, +} from '@backstage/core'; +import { useApi } from '@backstage/core-api'; +import { graphql } from '@octokit/graphql'; + +const ExampleFetchComponent: FC<{}> = () => { + return
Nothing to see yet
; +}; + +export default ExampleFetchComponent; +``` + +3. Save that and ensure you see no errors. Comment out the unused imports if + your linter gets in the way. + +###### We will add a lot to this file for the sake of ease. Please don't do this in productional code! + +# The Graph Model + +GitHub has a graphql API available for interacting. Let's start by adding our +basic repository query + +1. Add the query const statement outside ExampleFetchComponent + +```tsx +const query = `{ + viewer { + repositories(first: 100) { + totalCount + nodes { + name + createdAt + description + diskUsage + isFork + } + pageInfo { + endCursor + hasNextPage + } + } + } +}`; +``` + +2. Using this structure as a guide, we will break our query into type parts +3. Add the following outside of ExampleFetchComponent + +```tsx +type Node = { + name: string; + createdAt: string; + description: string; + diskUsage: number; + isFork: boolean; +}; + +type Viewer = { + repositories: { + totalCount: number; + nodes: Node[]; + pageInfo: { + endCursor: string; + hasNextPage: boolean; + }; + }; +}; +``` + +# The Tabel Model + +Using Backstage's own component library, let's define a custom table. This +component will get used if we have data to display. + +1. Add the following outside of ExampleFetchComponent + +```tsx +type DenseTableProps = { + viewer: Viewer; +}; + +export const DenseTable: FC = ({ viewer }) => { + const columns: TableColumn[] = [ + { title: 'Name', field: 'name' }, + { title: 'Created', field: 'createdAt' }, + { title: 'Description', field: 'description' }, + { title: 'Disk Usage', field: 'diskUsage' }, + { title: 'Fork', field: 'isFork' }, + ]; + + return ( + + ); +}; +``` + +# The Fetch + +We're ready to flush out our fetch component + +1. Add our api hook inside ExampleFetchComponent + +```tsx +const auth = useApi(githubAuthApiRef); +``` + +2. The access token we need to make our GitHub request and the request itself is + obtained in an asynchronous manner. +3. Add the useAsync block inside the ExampleFetchComponent + +```tsx +const { value, loading, error } = useAsync(async (): Promise => { + const token = await auth.getAccessToken(); + + const gqlEndpoint = graphql.defaults({ + // Uncomment baseUrl if using enterprise + // baseUrl: 'https://github.MY-BIZ.com/api', + headers: { + authorization: `token ${token}`, + }, + }); + const { viewer } = await gqlEndpoint(query); + return viewer; +}, []); +``` + +4. The resolved data is conventiently destructured with value containing our + Viewer type. loading as a boolean, self explainatory. And error which is + present only if necessary. So let's use those as the first 3 of 4 multi + return statements. +5. Add the _if return_ blocks below our async block + +```tsx +if (loading) return ; +if (error) return {error.message}; +if (value && value.repositories) return ; +``` + +6. The third line here utilizes our custom table accepting our Viewer type. +7. Finally, we add our _else return_ block to catch any other scenarios. + +```tsx +return ( +
+); +``` + +8. After saving that, and given we don't have any errors, you should see a table + with basic information on your repositories. +9. Here is the entire file for reference +
Complete ExampleFetchComponent.tsx +

+ +```tsx +import React, { FC } from 'react'; +import { useAsync } from 'react-use'; +import Alert from '@material-ui/lab/Alert'; +import { + Table, + TableColumn, + Progress, + githubAuthApiRef, +} from '@backstage/core'; +import { useApi } from '@backstage/core-api'; +import { graphql } from '@octokit/graphql'; + +const query = `{ +viewer { + repositories(first: 100) { + totalCount + nodes { + name + createdAt + description + diskUsage + isFork + } + pageInfo { + endCursor + hasNextPage + } + } +} +}`; + +type Node = { + name: string; + createdAt: string; + description: string; + diskUsage: number; + isFork: boolean; +}; + +type Viewer = { + repositories: { + totalCount: number; + nodes: Node[]; + pageInfo: { + endCursor: string; + hasNextPage: boolean; + }; + }; +}; + +type DenseTableProps = { + viewer: Viewer; +}; + +export const DenseTable: FC = ({ viewer }) => { + const columns: TableColumn[] = [ + { title: 'Name', field: 'name' }, + { title: 'Created', field: 'createdAt' }, + { title: 'Description', field: 'description' }, + { title: 'Disk Usage', field: 'diskUsage' }, + { title: 'Fork', field: 'isFork' }, + ]; + + return ( +

+ ); +}; + +const ExampleFetchComponent: FC<{}> = () => { + const auth = useApi(githubAuthApiRef); + + const { value, loading, error } = useAsync(async (): Promise => { + const token = await auth.getAccessToken(); + + const gqlEndpoint = graphql.defaults({ + // Uncomment baseUrl if using enterprise + // baseUrl: 'https://github.MY-BIZ.com/api', + headers: { + authorization: `token ${token}`, + }, + }); + const { viewer } = await gqlEndpoint(query); + return viewer; + }, []); + + if (loading) return ; + if (error) return {error.message}; + if (value && value.repositories) return ; + + return ( +
+ ); +}; + +export default ExampleFetchComponent; +``` + +

+ + +10. We finished! If there are no errors, you should see your own GitHub + repoistory information displayed in a basic table. If you run into issues, + you can compare the repo that backs this documdnt, + [simple-backstage-app-plugin](https://github.com/johnson-jesse/simple-backstage-app-plugin) + +# Where to go from here + +> Break apart ExampleFetchComponent into smaller logical parts contained in +> their own files. Rename your components to something other than ExampleXxx. +> +> You might be real proud of a plugin you develop. Follow this next tutorial for +> an in-depth look at publishing and including that for the entire Backstage +> community. [TODO](#). diff --git a/microsite/sidebars.json b/microsite/sidebars.json index f7aa0630ef..aac524c538 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -143,7 +143,11 @@ "ids": ["api/backend"] } ], - "Tutorials": ["tutorials/journey"], + "Tutorials": [ + "tutorials/journey", + "tutorials/quickstart-app-auth", + "tutorials/quickstart-app-plugin" + ], "Architecture Decision Records (ADRs)": [ "architecture-decisions/adrs-overview", "architecture-decisions/adrs-adr001", From 94b8e88ebae96219615b507efa80cb250c350332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 18 Sep 2020 09:49:21 +0200 Subject: [PATCH 16/25] fix(catalog-backend): address comments and add docs --- CHANGELOG.md | 4 ++ .../software-catalog/configuration.md | 61 +++++++++++++++++++ microsite/sidebars.json | 1 + mkdocs.yml | 3 +- .../src/ingestion/LocationReaders.ts | 6 +- .../processors/GithubReaderProcessor.test.ts | 35 +++++++---- .../processors/GithubReaderProcessor.ts | 15 +++-- 7 files changed, 106 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 294c57815e..814716b60c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re - Change root `tsc` output dir to `dist-types`, in order to allow for standalone plugin repos. [#2278](https://github.com/spotify/backstage/pull/2278) +### @backstage/catalog-backend + +- We have simplified the way that GitHub ingestion works. The `catalog.processors.githubApi` key is deprecated, in favor of `catalog.processors.github`. At the same time, the location type `github/api` is likewise deprecated, in favor of `github`. This location type now serves both raw HTTP reads and APIv3 reads, depending on how you configure it. It also supports having several providers at once - for example, both public GitHub and an internal GitHub Enterprise, with different keys. If you still use the `catalog.processors.githubApi` config key, things will work but you will get a deprecation warning at startup. In a later release, support for the old key will go away entirely. See the [configuration section in the docs](https://backstage.io/docs/features/software-catalog/configuration) for more details. + ## v0.1.1-alpha.21 - Added many more frontend plugins to the template along with the sidebar. [#1942](https://github.com/spotify/backstage/pull/1942), [#2084](https://github.com/spotify/backstage/pull/2084) diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 0bcfaabe0a..c98bd73ca3 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -4,6 +4,67 @@ title: Catalog Configuration description: Documentation on Software Catalog Configuration --- +## Processors + +The catalog makes use of so called processors to perform all kinds of ingestion +tasks, such as reading raw entity data from a remote source, parsing it, +transforming it, and validating it. These processors are configured under the +`catalog.processors` key. + +### Processor: github + +The `github` processor is responsible for fetching entity data from files on +GitHub or GitHub Enterprise. The configuration for this processor lives under +`catalog.processors.github`. Example: + +```yaml +catalog: + processors: + github: + providers: + - target: https://github.com + token: + $secret: + env: GITHUB_PRIVATE_TOKEN + - target: https://ghe.example.net + apiBaseUrl: https://ghe.example.net/api/v3 + rawBaseUrl: https://ghe.example.net/raw + token: + $secret: + env: GHE_PRIVATE_TOKEN +``` + +The main subkey is `providers`, where you can list the various GitHub compatible +providers you want to be able to fetch data from. Each entry is a structure with +up to four elements: + +- `target` (required): The string prefix of the location target that you want to + match on, with no trailing slash. For GitHub, it should be exactly + `https://github.com`. +- `token` (optional): An authentication token as expected by GitHub. If + supplied, it will be passed along with all calls to this provider, both API + and raw. If it is not supplied, anonymous access will be used. +- `apiBaseUrl` (optional): If you want to communicate using the APIv3 method + with this provider, specify the base URL for its endpoint here, with no + trailing slash. Specifically when the target is github, you can leave it out + to be inferred automatically. For a GitHub Enterprise installation, it is + commonly at `https://api.` or `https:///api/v3`. +- `rawBaseUrl` (optional): If you want to communicate using the raw HTTP method + with this provider, specify the base URL for its endpoint here, with no + trailing slash. Specifically when the target is public GitHub, you can leave + it out to be inferred automatically. For a GitHub Enterprise installation, it + is commonly at `https://api.` or `https:///api/v3`. + +You need to supply either `apiBaseUrl` or `rawBaseUrl` or both (except for +public GitHub, for which we can infer them). The `apiBaseUrl` will always be +preferred over the other if a `token` is given, otherwise `rawBaseUrl` will be +preferred. + +If you do not supply a public GitHub provider, one will be added automatically, +silently at startup for convenience. So you only have to list it if you want to +supply a token for it - and if you do, you can also leave out the `apiBaseUrl` +and `rawBaseUrl` fields. + ## Static Location Configuration To enable declarative catalog setups, it is possible to add locations to the diff --git a/microsite/sidebars.json b/microsite/sidebars.json index f7aa0630ef..f3c2cf7e76 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -40,6 +40,7 @@ "ids": [ "features/software-catalog/software-catalog-overview", "features/software-catalog/installation", + "features/software-catalog/configuration", "features/software-catalog/system-model", "features/software-catalog/descriptor-format", "features/software-catalog/well-known-annotations", diff --git a/mkdocs.yml b/mkdocs.yml index a74ef5737f..ba607f8a6e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -28,10 +28,11 @@ nav: - Features: - Software Catalog: - Overview: 'features/software-catalog/index.md' + - Installation: 'features/software-catalog/installation.md' + - Configuration: 'features/software-catalog/configuration.md' - System model: 'features/software-catalog/system-model.md' - YAML File Format: 'features/software-catalog/descriptor-format.md' - Well-known Annotations: 'features/software-catalog/well-known-annotations.md' - - Configuration: 'features/software-catalog/configuration.md' - Extending the model: 'features/software-catalog/extending-the-model.md' - External integrations: 'features/software-catalog/external-integrations.md' - API: 'features/software-catalog/api.md' diff --git a/plugins/catalog-backend/src/ingestion/LocationReaders.ts b/plugins/catalog-backend/src/ingestion/LocationReaders.ts index a564e9725c..8da6e20ab3 100644 --- a/plugins/catalog-backend/src/ingestion/LocationReaders.ts +++ b/plugins/catalog-backend/src/ingestion/LocationReaders.ts @@ -66,17 +66,19 @@ export class LocationReaders implements LocationReader { private readonly rulesEnforcer: CatalogRulesEnforcer; static defaultProcessors(options: { + logger: Logger; config?: Config; entityPolicy?: EntityPolicy; }): LocationProcessor[] { const { + logger, config = new ConfigReader({}, 'missing-config'), entityPolicy = new EntityPolicies(), } = options; return [ StaticLocationProcessor.fromConfig(config), new FileReaderProcessor(), - GithubReaderProcessor.fromConfig(config), + GithubReaderProcessor.fromConfig(config, logger), new GitlabApiReaderProcessor(config), new GitlabReaderProcessor(), new BitbucketApiReaderProcessor(config), @@ -92,7 +94,7 @@ export class LocationReaders implements LocationReader { constructor({ logger = getVoidLogger(), config, - processors = LocationReaders.defaultProcessors({ config }), + processors = LocationReaders.defaultProcessors({ logger, config }), }: Options) { this.logger = logger; this.processors = processors; diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.test.ts index e3c7611e80..3ab24541e7 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.test.ts @@ -14,13 +14,14 @@ * limitations under the License. */ +import { getVoidLogger } from '@backstage/backend-common'; import { LocationSpec } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import { - getApiUrl, getApiRequestOptions, - getRawUrl, + getApiUrl, getRawRequestOptions, + getRawUrl, GithubReaderProcessor, ProviderConfig, readConfig, @@ -179,7 +180,7 @@ describe('GithubReaderProcessor', () => { } it('adds a default GitHub entry when missing', () => { - const output = readConfig(config([])); + const output = readConfig(config([]), getVoidLogger()); expect(output).toEqual([ { target: 'https://github.com', @@ -190,7 +191,10 @@ describe('GithubReaderProcessor', () => { }); it('injects the correct GitHub API base URL when missing', () => { - const output = readConfig(config([{ target: 'https://github.com' }])); + const output = readConfig( + config([{ target: 'https://github.com' }]), + getVoidLogger(), + ); expect(output).toEqual([ { target: 'https://github.com', @@ -202,26 +206,33 @@ describe('GithubReaderProcessor', () => { it('rejects custom targets with no base URLs', () => { expect(() => - readConfig(config([{ target: 'https://ghe.company.com' }])), + readConfig( + config([{ target: 'https://ghe.company.com' }]), + getVoidLogger(), + ), ).toThrow( 'Provider at https://ghe.company.com must configure an explicit apiBaseUrl or rawBaseUrl', ); }); it('rejects funky configs', () => { - expect(() => readConfig(config([{ target: 7 } as any]))).toThrow( - /target/, - ); - expect(() => readConfig(config([{ noTarget: '7' } as any]))).toThrow( - /target/, - ); + expect(() => + readConfig(config([{ target: 7 } as any]), getVoidLogger()), + ).toThrow(/target/); + expect(() => + readConfig(config([{ noTarget: '7' } as any]), getVoidLogger()), + ).toThrow(/target/); expect(() => readConfig( config([{ target: 'https://github.com', apiBaseUrl: 7 } as any]), + getVoidLogger(), ), ).toThrow(/apiBaseUrl/); expect(() => - readConfig(config([{ target: 'https://github.com', token: 7 } as any])), + readConfig( + config([{ target: 'https://github.com', token: 7 } as any]), + getVoidLogger(), + ), ).toThrow(/token/); }); }); diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts index f83469bd16..4f0c66148f 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts @@ -18,6 +18,7 @@ import { LocationSpec } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import parseGitUri from 'git-url-parse'; import fetch, { HeadersInit, RequestInit } from 'node-fetch'; +import { Logger } from 'winston'; import * as result from './results'; import { LocationProcessor, LocationProcessorEmit } from './types'; @@ -139,9 +140,16 @@ export function getRawUrl(target: string, provider: ProviderConfig): URL { } } -export function readConfig(config: Config): ProviderConfig[] { +export function readConfig(config: Config, logger: Logger): ProviderConfig[] { const providers: ProviderConfig[] = []; + // TODO(freben): Deprecate the old config root entirely in a later release + if (config.has('catalog.processors.githubApi')) { + logger.warn( + 'The catalog.processors.githubApi configuration key has been deprecated, please use catalog.processors.github instead', + ); + } + // In a previous version of the configuration, we only supported github, // and the "privateToken" key held the token to use for it. The new // configuration method is to use the "providers" key instead. @@ -202,8 +210,8 @@ export function readConfig(config: Config): ProviderConfig[] { export class GithubReaderProcessor implements LocationProcessor { private providers: ProviderConfig[]; - static fromConfig(config: Config) { - return new GithubReaderProcessor(readConfig(config)); + static fromConfig(config: Config, logger: Logger) { + return new GithubReaderProcessor(readConfig(config, logger)); } constructor(providers: ProviderConfig[]) { @@ -238,7 +246,6 @@ export class GithubReaderProcessor implements LocationProcessor { const options = useApi ? getApiRequestOptions(provider) : getRawRequestOptions(provider); - console.log(url.toString()); const response = await fetch(url.toString(), options); if (response.ok) { From 53d1f1f9a58976e0e6b28c89e0f12f7b2fef1d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 18 Sep 2020 11:04:03 +0200 Subject: [PATCH 17/25] chore(contrib): form the basic contrib hierarchy --- contrib/README.md | 9 +++++++++ .../basic_kubernetes_example_with_helm/README.md | 1 + .../basic_kubernetes_example_with_helm}/app.yaml | 0 .../basic_kubernetes_example_with_helm}/backend.yaml | 0 .../backstage/.helmignore | 0 .../backstage/Chart.yaml | 0 .../backstage/README.md | 0 .../backstage/templates/_helpers.tpl | 0 .../backstage/templates/deployment.yaml | 0 .../backstage/templates/ingress.yaml | 0 .../backstage/templates/service.yaml | 0 .../backstage/values.yaml | 0 .../basic_kubernetes_example_with_helm}/ingress.yaml | 0 .../basic_kubernetes_example_with_helm}/service.yaml | 0 14 files changed, 10 insertions(+) create mode 100644 contrib/README.md create mode 100644 contrib/kubernetes/basic_kubernetes_example_with_helm/README.md rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/app.yaml (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/backend.yaml (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/backstage/.helmignore (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/backstage/Chart.yaml (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/backstage/README.md (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/backstage/templates/_helpers.tpl (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/backstage/templates/deployment.yaml (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/backstage/templates/ingress.yaml (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/backstage/templates/service.yaml (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/backstage/values.yaml (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/ingress.yaml (100%) rename {install/kubernetes => contrib/kubernetes/basic_kubernetes_example_with_helm}/service.yaml (100%) diff --git a/contrib/README.md b/contrib/README.md new file mode 100644 index 0000000000..2bf33c063b --- /dev/null +++ b/contrib/README.md @@ -0,0 +1,9 @@ +# Backstage Contrib + +This directory contains various community contributions related to Backstage. + +Unless otherwise specified, all content in this hierarchy fall under the same +[licensing terms](../LICENSE) as in the rest of the repository, and come with +no guarantees of functionality or fitness of purpose. That being said, we +really appreciate contributions in here and encourage them being kept up to +date. diff --git a/contrib/kubernetes/basic_kubernetes_example_with_helm/README.md b/contrib/kubernetes/basic_kubernetes_example_with_helm/README.md new file mode 100644 index 0000000000..2dc875f671 --- /dev/null +++ b/contrib/kubernetes/basic_kubernetes_example_with_helm/README.md @@ -0,0 +1 @@ +# Basic Kubernetes example with Helm diff --git a/install/kubernetes/app.yaml b/contrib/kubernetes/basic_kubernetes_example_with_helm/app.yaml similarity index 100% rename from install/kubernetes/app.yaml rename to contrib/kubernetes/basic_kubernetes_example_with_helm/app.yaml diff --git a/install/kubernetes/backend.yaml b/contrib/kubernetes/basic_kubernetes_example_with_helm/backend.yaml similarity index 100% rename from install/kubernetes/backend.yaml rename to contrib/kubernetes/basic_kubernetes_example_with_helm/backend.yaml diff --git a/install/kubernetes/backstage/.helmignore b/contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/.helmignore similarity index 100% rename from install/kubernetes/backstage/.helmignore rename to contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/.helmignore diff --git a/install/kubernetes/backstage/Chart.yaml b/contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/Chart.yaml similarity index 100% rename from install/kubernetes/backstage/Chart.yaml rename to contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/Chart.yaml diff --git a/install/kubernetes/backstage/README.md b/contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/README.md similarity index 100% rename from install/kubernetes/backstage/README.md rename to contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/README.md diff --git a/install/kubernetes/backstage/templates/_helpers.tpl b/contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/templates/_helpers.tpl similarity index 100% rename from install/kubernetes/backstage/templates/_helpers.tpl rename to contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/templates/_helpers.tpl diff --git a/install/kubernetes/backstage/templates/deployment.yaml b/contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/templates/deployment.yaml similarity index 100% rename from install/kubernetes/backstage/templates/deployment.yaml rename to contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/templates/deployment.yaml diff --git a/install/kubernetes/backstage/templates/ingress.yaml b/contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/templates/ingress.yaml similarity index 100% rename from install/kubernetes/backstage/templates/ingress.yaml rename to contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/templates/ingress.yaml diff --git a/install/kubernetes/backstage/templates/service.yaml b/contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/templates/service.yaml similarity index 100% rename from install/kubernetes/backstage/templates/service.yaml rename to contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/templates/service.yaml diff --git a/install/kubernetes/backstage/values.yaml b/contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/values.yaml similarity index 100% rename from install/kubernetes/backstage/values.yaml rename to contrib/kubernetes/basic_kubernetes_example_with_helm/backstage/values.yaml diff --git a/install/kubernetes/ingress.yaml b/contrib/kubernetes/basic_kubernetes_example_with_helm/ingress.yaml similarity index 100% rename from install/kubernetes/ingress.yaml rename to contrib/kubernetes/basic_kubernetes_example_with_helm/ingress.yaml diff --git a/install/kubernetes/service.yaml b/contrib/kubernetes/basic_kubernetes_example_with_helm/service.yaml similarity index 100% rename from install/kubernetes/service.yaml rename to contrib/kubernetes/basic_kubernetes_example_with_helm/service.yaml From c44af2deac17302aedca0a308f0fad9d536fcaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 18 Sep 2020 11:15:49 +0200 Subject: [PATCH 18/25] fix(workflows): do not run e2e when contrib or docs change --- .github/workflows/e2e.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index d53ca1b607..69bd8393c8 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -3,6 +3,8 @@ name: E2E Test Linux on: pull_request: paths-ignore: + - 'contrib/**' + - 'docs/**' - 'microsite/**' jobs: From 20353279d785d32cbfc1fb6df362541479dce0d3 Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Thu, 17 Sep 2020 15:54:33 +0200 Subject: [PATCH 19/25] feat: use title for API type in table Now that the API definition types are available via an API, we can resolve the remaining TODO comment here. --- .../ApiExplorerPage/ApiExplorerPage.test.tsx | 8 +++++ .../ApiExplorerTable.test.tsx | 35 +++++++++++++------ .../ApiExplorerTable/ApiExplorerTable.tsx | 20 ++++++++--- 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx index 639f1e3d9c..e386f281e8 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx @@ -20,6 +20,7 @@ import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog'; import { MockStorageApi, wrapInTestApp } from '@backstage/test-utils'; import { render } from '@testing-library/react'; import React from 'react'; +import { apiDocsConfigRef } from '../../config'; import { ApiExplorerPage } from './ApiExplorerPage'; describe('ApiCatalogPage', () => { @@ -32,6 +33,7 @@ describe('ApiCatalogPage', () => { metadata: { name: 'Entity1', }, + spec: { type: 'openapi' }, }, { apiVersion: 'backstage.io/v1alpha1', @@ -39,12 +41,17 @@ describe('ApiCatalogPage', () => { metadata: { name: 'Entity2', }, + spec: { type: 'openapi' }, }, ] as Entity[]), getLocationByEntity: () => Promise.resolve({ id: 'id', type: 'github', target: 'url' }), }; + const apiDocsConfig = { + getApiDefinitionWidget: () => undefined, + }; + const renderWrapped = (children: React.ReactNode) => render( wrapInTestApp( @@ -52,6 +59,7 @@ describe('ApiCatalogPage', () => { apis={ApiRegistry.from([ [catalogApiRef, catalogApi], [storageApiRef, MockStorageApi.create()], + [apiDocsConfigRef, apiDocsConfig], ])} > {children} diff --git a/plugins/api-docs/src/components/ApiExplorerTable/ApiExplorerTable.test.tsx b/plugins/api-docs/src/components/ApiExplorerTable/ApiExplorerTable.test.tsx index 9cd7b01945..c679c2201f 100644 --- a/plugins/api-docs/src/components/ApiExplorerTable/ApiExplorerTable.test.tsx +++ b/plugins/api-docs/src/components/ApiExplorerTable/ApiExplorerTable.test.tsx @@ -15,9 +15,11 @@ */ import { Entity } from '@backstage/catalog-model'; +import { ApiProvider, ApiRegistry } from '@backstage/core'; import { wrapInTestApp } from '@backstage/test-utils'; import { render } from '@testing-library/react'; import * as React from 'react'; +import { apiDocsConfigRef } from '../../config'; import { ApiExplorerTable } from './ApiExplorerTable'; const entites: Entity[] = [ @@ -25,29 +27,38 @@ const entites: Entity[] = [ apiVersion: 'backstage.io/v1alpha1', kind: 'API', metadata: { name: 'api1' }, + spec: { type: 'openapi' }, }, { apiVersion: 'backstage.io/v1alpha1', kind: 'API', metadata: { name: 'api2' }, + spec: { type: 'openapi' }, }, { apiVersion: 'backstage.io/v1alpha1', kind: 'API', metadata: { name: 'api3' }, + spec: { type: 'grpc' }, }, ]; +const apiRegistry = ApiRegistry.with(apiDocsConfigRef, { + getApiDefinitionWidget: () => undefined, +}); + describe('ApiCatalogTable component', () => { it('should render error message when error is passed in props', async () => { const rendered = render( wrapInTestApp( - , + + + , ), ); const errorMessage = await rendered.findByText( @@ -59,11 +70,13 @@ describe('ApiCatalogTable component', () => { it('should display entity names when loading has finished and no error occurred', async () => { const rendered = render( wrapInTestApp( - , + + + , ), ); expect(rendered.getByText(/APIs \(3\)/)).toBeInTheDocument(); diff --git a/plugins/api-docs/src/components/ApiExplorerTable/ApiExplorerTable.tsx b/plugins/api-docs/src/components/ApiExplorerTable/ApiExplorerTable.tsx index fd1e9c3518..485fcc216d 100644 --- a/plugins/api-docs/src/components/ApiExplorerTable/ApiExplorerTable.tsx +++ b/plugins/api-docs/src/components/ApiExplorerTable/ApiExplorerTable.tsx @@ -14,14 +14,23 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; -import { Table, TableColumn } from '@backstage/core'; -import { Link, Chip } from '@material-ui/core'; +import { ApiEntityV1alpha1, Entity } from '@backstage/catalog-model'; +import { Table, TableColumn, useApi } from '@backstage/core'; +import { Chip, Link } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; import React from 'react'; import { generatePath, Link as RouterLink } from 'react-router-dom'; +import { apiDocsConfigRef } from '../../config'; import { entityRoute } from '../../routes'; +const ApiTypeTitle = ({ apiEntity }: { apiEntity: ApiEntityV1alpha1 }) => { + const config = useApi(apiDocsConfigRef); + const definition = config.getApiDefinitionWidget(apiEntity); + const type = definition ? definition.title : apiEntity.spec.type; + + return {type}; +}; + const columns: TableColumn[] = [ { title: 'Name', @@ -54,8 +63,11 @@ const columns: TableColumn[] = [ field: 'spec.lifecycle', }, { - title: 'Type', // TODO: Resolve the type display name using the API from https://github.com/spotify/backstage/pull/2451 + title: 'Type', field: 'spec.type', + render: (entity: Entity) => ( + + ), }, { title: 'Description', From 6341af5b31467a564778fb217b967208872f0f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20=C3=85lund?= Date: Fri, 18 Sep 2020 11:24:51 +0200 Subject: [PATCH 20/25] [microsite] Add CNCF logo (#2511) --- microsite/pages/en/index.js | 13 +++++++++++++ microsite/static/css/custom.css | 11 +++++++++++ microsite/static/img/cncf-color.svg | 1 + microsite/static/img/cncf-white.svg | 1 + 4 files changed, 26 insertions(+) create mode 100644 microsite/static/img/cncf-color.svg create mode 100644 microsite/static/img/cncf-white.svg diff --git a/microsite/pages/en/index.js b/microsite/pages/en/index.js index f595032bd0..37298ae8e2 100644 --- a/microsite/pages/en/index.js +++ b/microsite/pages/en/index.js @@ -462,6 +462,19 @@ class Index extends React.Component { Contribute + + + + + Backstage is a{' '} + + Cloud Native Computing Foundation + {' '} + sandbox project + +
+ + ); } diff --git a/microsite/static/css/custom.css b/microsite/static/css/custom.css index 111065a5d5..00a102ba00 100644 --- a/microsite/static/css/custom.css +++ b/microsite/static/css/custom.css @@ -1070,3 +1070,14 @@ code { margin: auto; } } + +.cncf-block { + text-align: center; +} + +.cncf-logo { + background: center no-repeat url(../img/cncf-white.svg); + width: 100%; + height: 100px; + margin-bottom: 40px; +} diff --git a/microsite/static/img/cncf-color.svg b/microsite/static/img/cncf-color.svg new file mode 100644 index 0000000000..12f7d3e48a --- /dev/null +++ b/microsite/static/img/cncf-color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/microsite/static/img/cncf-white.svg b/microsite/static/img/cncf-white.svg new file mode 100644 index 0000000000..d94aaf3249 --- /dev/null +++ b/microsite/static/img/cncf-white.svg @@ -0,0 +1 @@ + \ No newline at end of file From 082d8b0bfddb5571208ab27ecdb85716bb512c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 18 Sep 2020 13:57:43 +0200 Subject: [PATCH 21/25] feat(catalog-backend): delete log entries older than a cutoff --- plugins/catalog-backend/src/database/CommonDatabase.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-backend/src/database/CommonDatabase.ts b/plugins/catalog-backend/src/database/CommonDatabase.ts index 0c56ca4370..4ad5362fb6 100644 --- a/plugins/catalog-backend/src/database/CommonDatabase.ts +++ b/plugins/catalog-backend/src/database/CommonDatabase.ts @@ -343,7 +343,14 @@ export class CommonDatabase implements Database { entityName?: string, message?: string, ): Promise { - return this.database( + // Remove log entries older than a day + const cutoff = new Date(); + cutoff.setDate(cutoff.getDate() - 1); + await this.database('location_update_log') + .where('created_at', '<', cutoff.toISOString()) + .del(); + + await this.database( 'location_update_log', ).insert({ status, From f097c32b59116e0399a46b9470e20e849afd9000 Mon Sep 17 00:00:00 2001 From: Sebastian Qvarfordt Date: Fri, 18 Sep 2020 14:02:35 +0200 Subject: [PATCH 22/25] TechDocs: Use a flag to determine if we should use a local mkdocs or techdocs-container (#2503) * Use a flag to determine wether to use techdocs-container or local install of mkdocs * Updated techdocs generator to look at app-config string instead of argument to decide how to run the generator * Removed console log... * Reverted scaffolder file that was accidentally committed. * Fixed lint issues * Added config to create-app template --- app-config.yaml | 2 + docs/features/techdocs/getting-started.md | 24 ++++++ packages/backend/src/plugins/techdocs.ts | 2 +- .../templates/default-app/app-config.yaml.hbs | 2 + .../packages/backend/src/plugins/techdocs.ts | 2 +- .../src/service/standaloneServer.ts | 5 +- .../stages/generate/generators.test.ts | 6 +- .../src/techdocs/stages/generate/techdocs.ts | 84 +++++++++++++------ 8 files changed, 97 insertions(+), 30 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index e018eef87e..5ca76ce789 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -35,6 +35,8 @@ organization: techdocs: storageUrl: http://localhost:7000/techdocs/static/docs requestUrl: http://localhost:7000/techdocs/docs + generators: + techdocs: 'docker' sentry: organization: spotify diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index d8c836c970..b9d215fd8a 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -71,6 +71,30 @@ building and publishing of your documentation, you want to change the `requestUrl` to point to your storage. In this case `storageUrl` is not required. +### Disable Docker in Docker situation (Optional) + +The TechDocs backend plugin runs a docker container with mkdocs to generate the +frontend of the docs from source files (Markdown). If you are deploying +Backstage using Docker, this will mean that your Backstage Docker container will +try to run another Docker container for TechDocs backend. + +To avoid this problem, we have a configuration available. You can set a value in +your `app-config.yaml` that tells the techdocs generator if it should run the +`local` mkdocs or run it from `docker`. This defaults to running as `docker` if +no config is provided. + +```yaml +techdocs: + generators: + techdocs: local +``` + +Setting `generators.techdocs` to `local` means you will have to make sure your +environment is compatible with techdocs. You will have to install the +`mkdocs-techdocs-container` and 'mkdocs' package from pip, as well as graphviz +and plantuml from your package manager. This has only been tested with python +3.7 and python 3.8. + ## Run Backstage locally Change folder to `/packages/backend` and run the diff --git a/packages/backend/src/plugins/techdocs.ts b/packages/backend/src/plugins/techdocs.ts index 7364cc4d83..58dca83b43 100644 --- a/packages/backend/src/plugins/techdocs.ts +++ b/packages/backend/src/plugins/techdocs.ts @@ -31,7 +31,7 @@ export default async function createPlugin({ config, }: PluginEnvironment) { const generators = new Generators(); - const techdocsGenerator = new TechdocsGenerator(logger); + const techdocsGenerator = new TechdocsGenerator(logger, config); generators.register('techdocs', techdocsGenerator); const preparers = new Preparers(); diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index ecac0613d9..d8d5adae37 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -46,6 +46,8 @@ proxy: techdocs: storageUrl: http://localhost:7000/techdocs/static/docs requestUrl: http://localhost:7000/techdocs/docs + generators: + techdocs: 'docker' lighthouse: baseUrl: http://localhost:3003 diff --git a/packages/create-app/templates/default-app/packages/backend/src/plugins/techdocs.ts b/packages/create-app/templates/default-app/packages/backend/src/plugins/techdocs.ts index dfd9eb5e33..9c7de3512b 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/plugins/techdocs.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/plugins/techdocs.ts @@ -15,7 +15,7 @@ export default async function createPlugin({ config, }: PluginEnvironment) { const generators = new Generators(); - const techdocsGenerator = new TechdocsGenerator(logger); + const techdocsGenerator = new TechdocsGenerator(logger, config); generators.register('techdocs', techdocsGenerator); diff --git a/plugins/techdocs-backend/src/service/standaloneServer.ts b/plugins/techdocs-backend/src/service/standaloneServer.ts index 93233af4c0..7a39742b80 100644 --- a/plugins/techdocs-backend/src/service/standaloneServer.ts +++ b/plugins/techdocs-backend/src/service/standaloneServer.ts @@ -38,6 +38,7 @@ export async function startStandaloneServer( options: ServerOptions, ): Promise { const logger = options.logger.child({ service: 'techdocs-backend' }); + const config = ConfigReader.fromConfigs([]); logger.debug('Creating application...'); const preparers = new Preparers(); @@ -45,7 +46,7 @@ export async function startStandaloneServer( preparers.register('dir', directoryPreparer); const generators = new Generators(); - const techdocsGenerator = new TechdocsGenerator(logger); + const techdocsGenerator = new TechdocsGenerator(logger, config); generators.register('techdocs', techdocsGenerator); const publisher = new LocalPublish(logger); @@ -59,7 +60,7 @@ export async function startStandaloneServer( logger, publisher, dockerClient, - config: ConfigReader.fromConfigs([]), + config, }); const service = createServiceBuilder(module) .enableCors({ origin: 'http://localhost:3000' }) diff --git a/plugins/techdocs-backend/src/techdocs/stages/generate/generators.test.ts b/plugins/techdocs-backend/src/techdocs/stages/generate/generators.test.ts index b339aef9f8..a9303c3794 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/generate/generators.test.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/generate/generators.test.ts @@ -16,6 +16,7 @@ import { Generators, TechdocsGenerator } from './'; import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; const logger = getVoidLogger(); @@ -38,7 +39,10 @@ describe('generators', () => { it('should return correct registered generator', async () => { const generators = new Generators(); - const techdocs = new TechdocsGenerator(logger); + const techdocs = new TechdocsGenerator( + logger, + ConfigReader.fromConfigs([]), + ); generators.register('techdocs', techdocs); diff --git a/plugins/techdocs-backend/src/techdocs/stages/generate/techdocs.ts b/plugins/techdocs-backend/src/techdocs/stages/generate/techdocs.ts index cb89b42e38..ac73963f9a 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/generate/techdocs.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/generate/techdocs.ts @@ -18,6 +18,8 @@ import fs from 'fs-extra'; import path from 'path'; import os from 'os'; import { Logger } from 'winston'; +import { PassThrough } from 'stream'; +import { Config } from '@backstage/config'; import { GeneratorBase, @@ -26,18 +28,39 @@ import { } from './types'; import { runDockerContainer, runCommand } from './helpers'; -const commandExists = require('command-exists-promise'); +type TechdocsGeneratorOptions = { + // This option enables users to configure if they want to use TechDocs container + // or generate without the container. + // This is used to avoid running into Docker in Docker environment. + runGeneratorIn: string; +}; + +const createStream = (): [string[], PassThrough] => { + const log = [] as Array; + + const stream = new PassThrough(); + stream.on('data', chunk => { + const textValue = chunk.toString().trim(); + if (textValue?.length > 1) log.push(textValue); + }); + + return [log, stream]; +}; export class TechdocsGenerator implements GeneratorBase { private readonly logger: Logger; + private readonly options: TechdocsGeneratorOptions; - constructor(logger: Logger) { + constructor(logger: Logger, config: Config) { this.logger = logger; + this.options = { + runGeneratorIn: + config.getOptionalString('techdocs.generators.techdocs') ?? 'docker', + }; } public async run({ directory, - logStream, dockerClient, }: GeneratorRunOptions): Promise { const tmpdirPath = os.tmpdir(); @@ -46,35 +69,46 @@ export class TechdocsGenerator implements GeneratorBase { const resultDir = fs.mkdtempSync( path.join(tmpdirResolvedPath, 'techdocs-tmp-'), ); + const [log, logStream] = createStream(); try { - const mkdocsInstalled = await commandExists('mkdocs'); - if (mkdocsInstalled) { - await runCommand({ - command: 'mkdocs', - args: ['build', '-d', resultDir, '-v'], - options: { - cwd: directory, - }, - logStream, - }); - } else { - await runDockerContainer({ - imageName: 'spotify/techdocs', - args: ['build', '-d', '/result'], - logStream, - docsDir: directory, - resultDir, - dockerClient, - }); - this.logger.info( - `[TechDocs]: Successfully generated docs from ${directory} into ${resultDir}`, - ); + switch (this.options.runGeneratorIn) { + case 'local': + await runCommand({ + command: 'mkdocs', + args: ['build', '-d', resultDir, '-v'], + options: { + cwd: directory, + }, + logStream, + }); + this.logger.info( + `[TechDocs]: Successfully generated docs from ${directory} into ${resultDir} using local mkdocs`, + ); + break; + case 'docker': + await runDockerContainer({ + imageName: 'spotify/techdocs', + args: ['build', '-d', '/result'], + logStream, + docsDir: directory, + resultDir, + dockerClient, + }); + this.logger.info( + `[TechDocs]: Successfully generated docs from ${directory} into ${resultDir} using techdocs-container`, + ); + break; + default: + throw new Error( + `Invalid config value "${this.options.runGeneratorIn}" provided in 'techdocs.generators.techdocs'.`, + ); } } catch (error) { this.logger.debug( `[TechDocs]: Failed to generate docs from ${directory} into ${resultDir}`, ); + this.logger.debug(`[TechDocs]: Build failed with error: ${log}`); throw new Error( `Failed to generate docs from ${directory} into ${resultDir} with error ${error.message}`, ); From 259205727e16092a72566276dde246214541bc67 Mon Sep 17 00:00:00 2001 From: Raghunandan Date: Fri, 18 Sep 2020 10:08:54 +0200 Subject: [PATCH 23/25] v0.1.1-alpha.21 --- lerna.json | 2 +- packages/app/package.json | 2 +- packages/backend-common/package.json | 4 ++-- plugins/catalog/package.json | 4 ++-- plugins/circleci/package.json | 2 +- plugins/explore/package.json | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lerna.json b/lerna.json index 63e4701ce3..8239c1fdf2 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "packages": ["packages/*", "plugins/*"], "npmClient": "yarn", "useWorkspaces": true, - "version": "0.1.1-alpha.20" + "version": "0.1.1-alpha.21" } diff --git a/packages/app/package.json b/packages/app/package.json index bf0f340a40..6f95904b32 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -4,8 +4,8 @@ "private": true, "bundled": true, "dependencies": { - "@backstage/cli": "^0.1.1-alpha.21", "@backstage/catalog-model": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.21", "@backstage/core": "^0.1.1-alpha.21", "@backstage/plugin-api-docs": "^0.1.1-alpha.21", "@backstage/plugin-catalog": "^0.1.1-alpha.21", diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index c9103375eb..334a5f4bc0 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -42,12 +42,12 @@ "helmet": "^4.0.0", "knex": "^0.21.1", "lodash": "^4.17.15", + "logform": "^2.1.1", "morgan": "^1.10.0", "prom-client": "^12.0.0", "selfsigned": "^1.10.7", "stoppable": "^1.1.0", - "winston": "^3.2.1", - "logform": "^2.1.1" + "winston": "^3.2.1" }, "peerDependencies": { "pg-connection-string": "^2.3.0" diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index e1b52795d3..d6a5442ca5 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -29,6 +29,7 @@ "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", + "@types/react": "^16.9", "classnames": "^2.2.6", "moment": "^2.26.0", "react": "^16.13.1", @@ -37,8 +38,7 @@ "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^15.3.3", - "swr": "^0.3.0", - "@types/react": "^16.9" + "swr": "^0.3.0" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.21", diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 7c8f36d370..01408c7048 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -21,8 +21,8 @@ "postpack": "backstage-cli postpack" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.21", "@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", diff --git a/plugins/explore/package.json b/plugins/explore/package.json index f302f4080c..05e86ebf1f 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -29,8 +29,8 @@ "classnames": "^2.2.6", "react": "^16.13.1", "react-dom": "^16.13.1", - "react-use": "^15.3.3", - "react-router": "6.0.0-beta.0" + "react-router": "6.0.0-beta.0", + "react-use": "^15.3.3" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.21", From 72235dd51ef3a29cbd7ebce30b73edc54d9f1511 Mon Sep 17 00:00:00 2001 From: Raghunandan Date: Fri, 18 Sep 2020 10:09:32 +0200 Subject: [PATCH 24/25] v0.1.1-alpha.22 --- lerna.json | 2 +- packages/app/package.json | 48 ++++++++++++------------- packages/backend-common/package.json | 10 +++--- packages/backend/package.json | 32 ++++++++--------- packages/catalog-model/package.json | 6 ++-- packages/cli-common/package.json | 2 +- packages/cli/package.json | 8 ++--- packages/config-loader/package.json | 4 +-- packages/config/package.json | 2 +- packages/core-api/package.json | 10 +++--- packages/core/package.json | 12 +++---- packages/create-app/package.json | 4 +-- packages/dev-utils/package.json | 10 +++--- packages/docgen/package.json | 2 +- packages/e2e-test/package.json | 4 +-- packages/storybook/package.json | 4 +-- packages/techdocs-cli/package.json | 4 +-- packages/test-utils-core/package.json | 2 +- packages/test-utils/package.json | 10 +++--- packages/theme/package.json | 4 +-- plugins/api-docs/package.json | 16 ++++----- plugins/app-backend/package.json | 8 ++--- plugins/auth-backend/package.json | 8 ++--- plugins/catalog-backend/package.json | 10 +++--- plugins/catalog/package.json | 18 +++++----- plugins/circleci/package.json | 14 ++++---- plugins/explore/package.json | 12 +++---- plugins/gcp-projects/package.json | 10 +++--- plugins/github-actions/package.json | 16 ++++----- plugins/gitops-profiles/package.json | 10 +++--- plugins/graphiql/package.json | 12 +++---- plugins/graphql/package.json | 6 ++-- plugins/identity-backend/package.json | 6 ++-- plugins/jenkins/package.json | 14 ++++---- plugins/lighthouse/package.json | 14 ++++---- plugins/newrelic/package.json | 10 +++--- plugins/proxy-backend/package.json | 8 ++--- plugins/register-component/package.json | 14 ++++---- plugins/rollbar-backend/package.json | 8 ++--- plugins/rollbar/package.json | 16 ++++----- plugins/scaffolder-backend/package.json | 10 +++--- plugins/scaffolder/package.json | 16 ++++----- plugins/sentry-backend/package.json | 6 ++-- plugins/sentry/package.json | 12 +++---- plugins/tech-radar/package.json | 12 +++---- plugins/techdocs-backend/package.json | 10 +++--- plugins/techdocs/package.json | 18 +++++----- plugins/welcome/package.json | 10 +++--- 48 files changed, 252 insertions(+), 252 deletions(-) diff --git a/lerna.json b/lerna.json index 8239c1fdf2..a018b1a289 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "packages": ["packages/*", "plugins/*"], "npmClient": "yarn", "useWorkspaces": true, - "version": "0.1.1-alpha.21" + "version": "0.1.1-alpha.22" } diff --git a/packages/app/package.json b/packages/app/package.json index 6f95904b32..cb61e1ed8c 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,32 +1,32 @@ { "name": "example-app", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": true, "bundled": true, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.21", - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/plugin-api-docs": "^0.1.1-alpha.21", - "@backstage/plugin-catalog": "^0.1.1-alpha.21", - "@backstage/plugin-circleci": "^0.1.1-alpha.21", - "@backstage/plugin-explore": "^0.1.1-alpha.21", - "@backstage/plugin-gcp-projects": "^0.1.1-alpha.21", - "@backstage/plugin-github-actions": "^0.1.1-alpha.21", - "@backstage/plugin-gitops-profiles": "^0.1.1-alpha.21", - "@backstage/plugin-graphiql": "^0.1.1-alpha.21", - "@backstage/plugin-jenkins": "^0.1.1-alpha.21", - "@backstage/plugin-lighthouse": "^0.1.1-alpha.21", - "@backstage/plugin-newrelic": "^0.1.1-alpha.21", - "@backstage/plugin-register-component": "^0.1.1-alpha.21", - "@backstage/plugin-rollbar": "^0.1.1-alpha.21", - "@backstage/plugin-scaffolder": "^0.1.1-alpha.21", - "@backstage/plugin-sentry": "^0.1.1-alpha.21", - "@backstage/plugin-tech-radar": "^0.1.1-alpha.21", - "@backstage/plugin-techdocs": "^0.1.1-alpha.21", - "@backstage/plugin-welcome": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/plugin-api-docs": "^0.1.1-alpha.22", + "@backstage/plugin-catalog": "^0.1.1-alpha.22", + "@backstage/plugin-circleci": "^0.1.1-alpha.22", + "@backstage/plugin-explore": "^0.1.1-alpha.22", + "@backstage/plugin-gcp-projects": "^0.1.1-alpha.22", + "@backstage/plugin-github-actions": "^0.1.1-alpha.22", + "@backstage/plugin-gitops-profiles": "^0.1.1-alpha.22", + "@backstage/plugin-graphiql": "^0.1.1-alpha.22", + "@backstage/plugin-jenkins": "^0.1.1-alpha.22", + "@backstage/plugin-lighthouse": "^0.1.1-alpha.22", + "@backstage/plugin-newrelic": "^0.1.1-alpha.22", + "@backstage/plugin-register-component": "^0.1.1-alpha.22", + "@backstage/plugin-rollbar": "^0.1.1-alpha.22", + "@backstage/plugin-scaffolder": "^0.1.1-alpha.22", + "@backstage/plugin-sentry": "^0.1.1-alpha.22", + "@backstage/plugin-tech-radar": "^0.1.1-alpha.22", + "@backstage/plugin-techdocs": "^0.1.1-alpha.22", + "@backstage/plugin-welcome": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@octokit/rest": "^18.0.0", diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 334a5f4bc0..9d8a7061e0 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/cli-common": "^0.1.1-alpha.21", - "@backstage/config": "^0.1.1-alpha.21", - "@backstage/config-loader": "^0.1.1-alpha.21", + "@backstage/cli-common": "^0.1.1-alpha.22", + "@backstage/config": "^0.1.1-alpha.22", + "@backstage/config-loader": "^0.1.1-alpha.22", "@types/cors": "^2.8.6", "@types/express": "^4.17.6", "compression": "^1.7.4", @@ -58,7 +58,7 @@ } }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/compression": "^1.7.0", "@types/http-errors": "^1.6.3", "@types/morgan": "^1.9.0", diff --git a/packages/backend/package.json b/packages/backend/package.json index c255f65015..aa6f0ad0bf 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "dist/index.cjs.js", "types": "src/index.ts", "private": true, @@ -18,23 +18,23 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", - "@backstage/catalog-model": "^0.1.1-alpha.21", - "@backstage/config": "^0.1.1-alpha.21", - "@backstage/plugin-app-backend": "^0.1.1-alpha.21", - "@backstage/plugin-auth-backend": "^0.1.1-alpha.21", - "@backstage/plugin-catalog-backend": "^0.1.1-alpha.21", - "@backstage/plugin-graphql-backend": "^0.1.1-alpha.21", - "@backstage/plugin-identity-backend": "^0.1.1-alpha.21", - "@backstage/plugin-proxy-backend": "^0.1.1-alpha.21", - "@backstage/plugin-rollbar-backend": "^0.1.1-alpha.21", - "@backstage/plugin-scaffolder-backend": "^0.1.1-alpha.21", - "@backstage/plugin-sentry-backend": "^0.1.1-alpha.21", - "@backstage/plugin-techdocs-backend": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/config": "^0.1.1-alpha.22", + "@backstage/plugin-app-backend": "^0.1.1-alpha.22", + "@backstage/plugin-auth-backend": "^0.1.1-alpha.22", + "@backstage/plugin-catalog-backend": "^0.1.1-alpha.22", + "@backstage/plugin-graphql-backend": "^0.1.1-alpha.22", + "@backstage/plugin-identity-backend": "^0.1.1-alpha.22", + "@backstage/plugin-proxy-backend": "^0.1.1-alpha.22", + "@backstage/plugin-rollbar-backend": "^0.1.1-alpha.22", + "@backstage/plugin-scaffolder-backend": "^0.1.1-alpha.22", + "@backstage/plugin-sentry-backend": "^0.1.1-alpha.22", + "@backstage/plugin-techdocs-backend": "^0.1.1-alpha.22", "@gitbeaker/node": "^23.5.0", "@octokit/rest": "^18.0.0", "dockerode": "^3.2.0", - "example-app": "^0.1.1-alpha.21", + "example-app": "^0.1.1-alpha.22", "express": "^4.17.1", "knex": "^0.21.1", "pg": "^8.3.0", @@ -43,7 +43,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/dockerode": "^2.5.32", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 0d18125d43..d683eec68d 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-model", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.21", + "@backstage/config": "^0.1.1-alpha.22", "@types/json-schema": "^7.0.5", "@types/yup": "^0.28.2", "json-schema": "^0.2.5", @@ -29,7 +29,7 @@ "yup": "^0.29.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/express": "^4.17.6", "@types/jest": "^26.0.7", "@types/lodash": "^4.14.151", diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index 4132907e70..1340b46ae3 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli-common", "description": "Common functionality used by cli, backend, and create-app", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "main": "src/index.ts", "types": "src/index.ts", diff --git a/packages/cli/package.json b/packages/cli/package.json index 492cd3b958..e1f51be5b7 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public" @@ -28,9 +28,9 @@ "backstage-cli": "bin/backstage-cli" }, "dependencies": { - "@backstage/cli-common": "^0.1.1-alpha.21", - "@backstage/config": "^0.1.1-alpha.21", - "@backstage/config-loader": "^0.1.1-alpha.21", + "@backstage/cli-common": "^0.1.1-alpha.22", + "@backstage/config": "^0.1.1-alpha.22", + "@backstage/config-loader": "^0.1.1-alpha.22", "@hot-loader/react-dom": "^16.13.0", "@lerna/package-graph": "^3.18.5", "@lerna/project": "^3.18.0", diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 592b8eefb3..5960b553f7 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public", @@ -30,7 +30,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.21", + "@backstage/config": "^0.1.1-alpha.22", "fs-extra": "^9.0.0", "yaml": "^1.9.2", "yup": "^0.29.1" diff --git a/packages/config/package.json b/packages/config/package.json index 236964f2bd..0b61e50ac6 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config", "description": "Config API used by Backstage core, backend, and CLI", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public", diff --git a/packages/core-api/package.json b/packages/core-api/package.json index 191394e536..72d0748183 100644 --- a/packages/core-api/package.json +++ b/packages/core-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-api", "description": "Internal Core API used by Backstage plugins and apps", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public", @@ -29,8 +29,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/config": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@types/react": "^16.9", @@ -41,8 +41,8 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/test-utils-core": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/test-utils-core": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/packages/core/package.json b/packages/core/package.json index 7e9932bdc1..3ed730e0f3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core", "description": "Core API used by Backstage plugins and apps", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public", @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.21", - "@backstage/core-api": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/config": "^0.1.1-alpha.22", + "@backstage/core-api": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -54,8 +54,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/packages/create-app/package.json b/packages/create-app/package.json index af7b78eb74..b303c2423b 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "Create app package for Backstage", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public" @@ -27,7 +27,7 @@ "start": "nodemon --" }, "dependencies": { - "@backstage/cli-common": "^0.1.1-alpha.21", + "@backstage/cli-common": "^0.1.1-alpha.22", "chalk": "^4.0.0", "commander": "^6.1.0", "fs-extra": "^9.0.0", diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index fe7272bf04..0b6e04f322 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public", @@ -29,10 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@testing-library/jest-dom": "^5.10.1", diff --git a/packages/docgen/package.json b/packages/docgen/package.json index c75ea53faf..3836af6542 100644 --- a/packages/docgen/package.json +++ b/packages/docgen/package.json @@ -1,7 +1,7 @@ { "name": "docgen", "description": "Tool for generating API Documentation for itself", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": true, "homepage": "https://backstage.io", "repository": { diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 0af233ec8e..e518d4f710 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,7 +1,7 @@ { "name": "e2e-test", "description": "E2E test for verifying Backstage packages", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": true, "homepage": "https://backstage.io", "repository": { @@ -21,7 +21,7 @@ "test:e2e": "yarn start" }, "devDependencies": { - "@backstage/cli-common": "^0.1.1-alpha.21", + "@backstage/cli-common": "^0.1.1-alpha.22", "@types/fs-extra": "^9.0.1", "@types/node": "^13.7.2", "fs-extra": "^9.0.0", diff --git a/packages/storybook/package.json b/packages/storybook/package.json index 8f12a2891c..a1decf279a 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -1,6 +1,6 @@ { "name": "storybook", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "description": "Storybook build for core package", "private": true, "scripts": { @@ -14,7 +14,7 @@ ] }, "dependencies": { - "@backstage/theme": "^0.1.1-alpha.21" + "@backstage/theme": "^0.1.1-alpha.22" }, "devDependencies": { "@storybook/addon-actions": "^6.0.21", diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 222620f976..340d9e2aff 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "CLI for running TechDocs locally.", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public" @@ -44,7 +44,7 @@ "ext": "ts" }, "dependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "commander": "^6.1.0", "fs-extra": "^9.0.1", "http-proxy": "^1.18.1", diff --git a/packages/test-utils-core/package.json b/packages/test-utils-core/package.json index 8439bee779..d79acf80a8 100644 --- a/packages/test-utils-core/package.json +++ b/packages/test-utils-core/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils-core", "description": "Utilities to test Backstage core", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 8567af8c14..cb115fe633 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public", @@ -29,10 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/core-api": "^0.1.1-alpha.21", - "@backstage/test-utils-core": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/core-api": "^0.1.1-alpha.22", + "@backstage/test-utils-core": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/packages/theme/package.json b/packages/theme/package.json index 436455633b..a1a3d6d111 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/theme", "description": "material-ui theme for use with Backstage.", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public", @@ -31,7 +31,7 @@ "@material-ui/core": "^4.11.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21" + "@backstage/cli": "^0.1.1-alpha.22" }, "files": [ "dist" diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 25e5c6b900..378ceb2d08 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,10 +20,10 @@ "clean": "backstage-cli clean" }, "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", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/plugin-catalog": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@kyma-project/asyncapi-react": "^0.11.0", "@material-icons/font": "^1.0.2", "@material-ui/core": "^4.11.0", @@ -39,9 +39,9 @@ "swagger-ui-react": "^3.31.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index f4080abc42..c4738c7105 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", - "@backstage/config-loader": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", + "@backstage/config-loader": "^0.1.1-alpha.22", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^3.0.3", @@ -30,7 +30,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/supertest": "^2.0.8", "msw": "^0.19.5", "supertest": "^4.0.2" diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 2336adb860..91fe08c0fa 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", - "@backstage/config": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", + "@backstage/config": "^0.1.1-alpha.22", "@types/express": "^4.17.6", "compression": "^1.7.4", "cookie-parser": "^1.4.5", @@ -49,7 +49,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/jwt-decode": "2.2.1", diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index bb62efdebb..f443ff362f 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", - "@backstage/catalog-model": "^0.1.1-alpha.21", - "@backstage/config": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/config": "^0.1.1-alpha.22", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^3.0.3", @@ -40,7 +40,7 @@ "yup": "^0.29.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/git-url-parse": "^9.0.0", "@types/lodash": "^4.14.151", "@types/node-fetch": "^2.5.7", diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index d6a5442ca5..f5520f39f9 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,11 +21,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.21", - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/plugin-scaffolder": "^0.1.1-alpha.21", - "@backstage/plugin-techdocs": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/plugin-scaffolder": "^0.1.1-alpha.22", + "@backstage/plugin-techdocs": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -41,9 +41,9 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/react-hooks": "^3.3.0", diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 01408c7048..10278fc065 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-circleci", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "postpack": "backstage-cli postpack" }, "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", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/plugin-catalog": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -38,8 +38,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 05e86ebf1f..c889f96153 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-explore", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -33,9 +33,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index cdc4bb507d..b71cebf6e4 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcp-projects", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -32,8 +32,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 49862dea80..9d1538ce99 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-actions", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,11 +21,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.21", - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/core-api": "^0.1.1-alpha.21", - "@backstage/plugin-catalog": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/core-api": "^0.1.1-alpha.22", + "@backstage/plugin-catalog": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -40,8 +40,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 62dacb5e91..cb25167ba6 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gitops-profiles", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -32,8 +32,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index b4d0b685da..e6122eb38b 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "private": false, "publishConfig": { "access": "public", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -43,9 +43,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/graphql/package.json b/plugins/graphql/package.json index 706592c430..754cadc9f4 100644 --- a/plugins/graphql/package.json +++ b/plugins/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-graphql-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -19,7 +19,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", "@types/express": "^4.17.6", "apollo-server": "^2.16.0", "apollo-server-express": "^2.16.0", @@ -31,7 +31,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/supertest": "^2.0.8", "eslint-plugin-graphql": "^4.0.0", "msw": "^0.20.5", diff --git a/plugins/identity-backend/package.json b/plugins/identity-backend/package.json index 18db7c9220..a34049fb91 100644 --- a/plugins/identity-backend/package.json +++ b/plugins/identity-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-identity-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", "@types/express": "^4.17.6", "compression": "^1.7.4", "cors": "^2.8.5", @@ -33,7 +33,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "jest-fetch-mock": "^3.0.3" }, "files": [ diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index c62df08db2..398161f270 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "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", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/plugin-catalog": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -36,8 +36,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 24a106e53d..c5522ae67a 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-lighthouse", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.21", - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/config": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -34,9 +34,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 38a47bc0fc..0cadf440f7 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -31,8 +31,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index efda451fd5..fb1b82f3ea 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -19,8 +19,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", - "@backstage/config": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", + "@backstage/config": "^0.1.1-alpha.22", "@types/express": "^4.17.6", "@types/http-proxy-middleware": "^0.19.3", "express": "^4.17.1", @@ -35,7 +35,7 @@ "yup": "^0.29.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/node-fetch": "^2.5.7", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/plugins/register-component/package.json b/plugins/register-component/package.json index 3dda51c3d5..8ccaae9914 100644 --- a/plugins/register-component/package.json +++ b/plugins/register-component/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-register-component", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "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", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/plugin-catalog": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -36,8 +36,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 96a968ee46..969d3c79b9 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-rollbar-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", - "@backstage/config": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", + "@backstage/config": "^0.1.1-alpha.22", "@types/express": "^4.17.6", "axios": "^0.20.0", "camelcase-keys": "^6.2.2", @@ -37,7 +37,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/supertest": "^2.0.8", "jest-fetch-mock": "^3.0.3", "supertest": "^4.0.2" diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index ae9d0c5bc5..cb37c6187a 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-rollbar", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "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", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/plugin-catalog": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -37,9 +37,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/react-hooks": "^3.3.0", diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index e0a9ae5129..0eaa33e1f8 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", - "@backstage/catalog-model": "^0.1.1-alpha.21", - "@backstage/config": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/config": "^0.1.1-alpha.22", "@gitbeaker/core": "^23.5.0", "@gitbeaker/node": "^23.5.0", "@octokit/rest": "^18.0.0", @@ -46,7 +46,7 @@ "yaml": "^1.10.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@octokit/types": "^5.4.1", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 2efc2c270a..ab95e83201 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "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", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/plugin-catalog": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -41,9 +41,9 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/sentry-backend/package.json b/plugins/sentry-backend/package.json index ffdcc18f7e..dbc7b48a1b 100644 --- a/plugins/sentry-backend/package.json +++ b/plugins/sentry-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sentry-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", "@types/express": "^4.17.6", "axios": "^0.20.0", "compression": "^1.7.4", @@ -34,7 +34,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "jest-fetch-mock": "^3.0.3" }, "files": [ diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index e3b900ca8d..6e7daea15c 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sentry", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.21", - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -36,8 +36,8 @@ "timeago.js": "^4.0.2" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index fc29d9c836..f25ec752e1 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-radar", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -35,8 +35,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index b9c2953d28..1ca8b3ee44 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.21", - "@backstage/catalog-model": "^0.1.1-alpha.21", - "@backstage/config": "^0.1.1-alpha.21", + "@backstage/backend-common": "^0.1.1-alpha.22", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/config": "^0.1.1-alpha.22", "@types/dockerode": "^2.5.34", "@types/express": "^4.17.6", "command-exists-promise": "^2.0.2", @@ -38,7 +38,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", "@types/node-fetch": "^2.5.7", "supertest": "^4.0.2" }, diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index a3471c8142..d2f99cb824 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,12 +22,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.21", - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/core-api": "^0.1.1-alpha.21", - "@backstage/plugin-catalog": "^0.1.1-alpha.21", - "@backstage/test-utils": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/catalog-model": "^0.1.1-alpha.22", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/core-api": "^0.1.1-alpha.22", + "@backstage/plugin-catalog": "^0.1.1-alpha.22", + "@backstage/test-utils": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -40,8 +40,8 @@ "sanitize-html": "^1.27.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/welcome/package.json b/plugins/welcome/package.json index a0dae6859d..741a680cd9 100644 --- a/plugins/welcome/package.json +++ b/plugins/welcome/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-welcome", - "version": "0.1.1-alpha.21", + "version": "0.1.1-alpha.22", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -21,8 +21,8 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.21", - "@backstage/theme": "^0.1.1-alpha.21", + "@backstage/core": "^0.1.1-alpha.22", + "@backstage/theme": "^0.1.1-alpha.22", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -32,8 +32,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.21", - "@backstage/dev-utils": "^0.1.1-alpha.21", + "@backstage/cli": "^0.1.1-alpha.22", + "@backstage/dev-utils": "^0.1.1-alpha.22", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", From 3c1aec3c532c35ebb3740c9d40941d163a67a86d Mon Sep 17 00:00:00 2001 From: Raghunandan Date: Fri, 18 Sep 2020 11:06:33 +0200 Subject: [PATCH 25/25] Update changelog --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 814716b60c..cf68fad6bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,15 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re ## Next Release +> Collect changes for the next release below + +## v0.1.1-alpha.22 + ### @backstage/core - Introduced initial version of an inverted app/plugin relationship, where plugins export components for apps to use, instead registering themselves directly into the app. This enables more fine-grained control of plugin features, and also composition of plugins such as catalog pages with additional cards and tabs. This breaks the use of `RouteRef`s, and there will be more changes related to this in the future, but this change lays the initial foundation. See `packages/app` and followup PRs for how to update plugins for this change. [#2076](https://github.com/spotify/backstage/pull/2076) - Switch to an automatic dependency injection mechanism for all Utility APIs, allowing plugins to ship default implementations of their APIs. See [https://backstage.io/docs/api/utility-apis](https://backstage.io/docs/api/utility-apis). [#2285](https://github.com/spotify/backstage/pull/2285) -> Collect changes for the next release below - ### @backstage/cli - Change `backstage-cli backend:build-image` to forward all args to `docker image build`, instead of just tag. Also add `--build` flag for building all dependent packages before packaging the workspace for the docker build. [#2299](https://github.com/spotify/backstage/pull/2299)