Merge branch 'master' into mobile-sidebar

Signed-off-by: Philipp Hugenroth <philipph@spotify.com>
This commit is contained in:
Philipp Hugenroth
2021-12-07 11:10:41 +01:00
993 changed files with 33405 additions and 5140 deletions
+116
View File
@@ -1,5 +1,121 @@
# @backstage/create-app
## 0.4.6
### Patch Changes
- 24d2ce03f3: Search Modal now relies on the Search Context to access state and state setter. If you use the SidebarSearchModal as described in the [getting started documentation](https://backstage.io/docs/features/search/getting-started#using-the-search-modal), make sure to update your code with the SearchContextProvider.
```diff
export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarPage>
<Sidebar>
<SidebarLogo />
- <SidebarSearchModal />
+ <SearchContextProvider>
+ <SidebarSearchModal />
+ </SearchContextProvider>
<SidebarDivider />
...
```
- 905dd952ac: Incorporate usage of the tokenManager into the backend created using `create-app`.
In existing backends, update the `PluginEnvironment` to include a `tokenManager`:
```diff
// packages/backend/src/types.ts
...
import {
...
+ TokenManager,
} from '@backstage/backend-common';
export type PluginEnvironment = {
...
+ tokenManager: TokenManager;
};
```
Then, create a `ServerTokenManager`. This can either be a `noop` that requires no secret and validates all requests by default, or one that uses a secret from your `app-config.yaml` to generate and validate tokens.
```diff
// packages/backend/src/index.ts
...
import {
...
+ ServerTokenManager,
} from '@backstage/backend-common';
...
function makeCreateEnv(config: Config) {
...
// CHOOSE ONE
// TokenManager not requiring a secret
+ const tokenManager = ServerTokenManager.noop();
// OR TokenManager requiring a secret
+ const tokenManager = ServerTokenManager.fromConfig(config);
...
return (plugin: string): PluginEnvironment => {
...
- return { logger, cache, database, config, reader, discovery };
+ return { logger, cache, database, config, reader, discovery, tokenManager };
};
}
```
## 0.4.5
### Patch Changes
- dcaeaac174: Cleaned out the `peerDependencies` in the published version of the package, making it much quicker to run `npx @backstage/create-app` as it no longer needs to install a long list of unnecessary.
- a5a5d7e1f1: DefaultTechDocsCollator is now included in the search backend, and the Search Page updated with the SearchType component that includes the techdocs type
- bab752e2b3: Change default port of backend from 7000 to 7007.
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
You can change the port back to 7000 or any other value by providing an `app-config.yaml` with the following values:
```
backend:
listen: 0.0.0.0:7123
baseUrl: http://localhost:7123
```
More information can be found here: https://backstage.io/docs/conf/writing
- 42ebbc18c0: Bump gitbeaker to the latest version
## 0.4.4
### Patch Changes
- 4ebc9fd277: Create backstage.json file
`@backstage/create-app` will create a new `backstage.json` file. At this point, the file will contain a `version` property, representing the version of `@backstage/create-app` used for creating the application. If the backstage's application has been bootstrapped using an older version of `@backstage/create-app`, the `backstage.json` file can be created and kept in sync, together with all the changes of the latest version of backstage, by running the following script:
```bash
yarn backstage-cli versions:bump
```
- e21e3c6102: Bumping minimum requirements for `dockerode` and `testcontainers`
- 014cbf8cb9: Migrated the app template use the new `@backstage/app-defaults` for the `createApp` import, since the `createApp` exported by `@backstage/app-core-api` will be removed in the future.
To migrate an existing application, add the latest version of `@backstage/app-defaults` as a dependency in `packages/app/package.json`, and make the following change to `packages/app/src/App.tsx`:
```diff
-import { createApp, FlatRoutes } from '@backstage/core-app-api';
+import { createApp } from '@backstage/app-defaults';
+import { FlatRoutes } from '@backstage/core-app-api';
```
- 2163e83fa2: Refactor and add regression tests for create-app tasks
- Updated dependencies
- @backstage/cli-common@0.1.6
## 0.4.3
### Patch Changes
+5 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/create-app",
"description": "A CLI that helps you create your own Backstage app",
"version": "0.4.3",
"version": "0.4.6",
"private": false,
"publishConfig": {
"access": "public"
@@ -25,10 +25,12 @@
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"clean": "backstage-cli clean",
"prepack": "node scripts/prepack.js",
"postpack": "node scripts/postpack.js",
"start": "nodemon --"
},
"dependencies": {
"@backstage/cli-common": "^0.1.5",
"@backstage/cli-common": "^0.1.6",
"chalk": "^4.0.0",
"commander": "^6.1.0",
"fs-extra": "9.1.0",
@@ -40,6 +42,7 @@
"devDependencies": {
"@types/fs-extra": "^9.0.1",
"@types/inquirer": "^7.3.1",
"@types/node": "^14.14.32",
"@types/recursive-readdir": "^2.2.0",
"mock-fs": "^5.1.1",
"ts-node": "^10.0.0"
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env node
/*
* Copyright 2021 The Backstage Authors
*
* 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.
*/
/* eslint-disable no-restricted-syntax */
const fs = require('fs-extra');
const path = require('path');
async function main() {
const pkgPath = path.resolve(__dirname, '../package.json');
const pkgBackupPath = path.resolve(__dirname, '../package.json-prepack');
try {
await fs.move(pkgBackupPath, pkgPath, { overwrite: true });
} catch (err) {
console.error(`Failed to restore package.json during postpack, ${err}`);
}
}
main().catch(err => {
console.error(err.stack);
process.exit(1);
});
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env node
/*
* Copyright 2021 The Backstage Authors
*
* 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.
*/
/* eslint-disable no-restricted-syntax */
const fs = require('fs-extra');
const path = require('path');
async function main() {
const pkgPath = path.resolve(__dirname, '../package.json');
const pkgBackupPath = path.resolve(__dirname, '../package.json-prepack');
const pkg = await fs.readJson(pkgPath);
await fs.writeJson(pkgBackupPath, pkg, { encoding: 'utf8', spaces: 2 });
delete pkg.peerDependencies;
await fs.writeJson(pkgPath, pkg, { encoding: 'utf8', spaces: 2 });
}
main().catch(err => {
console.error(err.stack);
process.exit(1);
});
+3 -3
View File
@@ -59,7 +59,7 @@ describe('command entrypoint', () => {
test('should call expected tasks with no path option', async () => {
const cmd = {} as unknown as Command;
await createApp(cmd);
await createApp(cmd, '1.0.0');
expect(checkAppExistsMock).toHaveBeenCalled();
expect(createTemporaryAppFolderMock).toHaveBeenCalled();
expect(templatingMock).toHaveBeenCalled();
@@ -69,7 +69,7 @@ describe('command entrypoint', () => {
it('should call expected tasks with path option', async () => {
const cmd = { path: 'myDirectory' } as unknown as Command;
await createApp(cmd);
await createApp(cmd, '1.0.0');
expect(checkPathExistsMock).toHaveBeenCalled();
expect(templatingMock).toHaveBeenCalled();
expect(buildAppMock).toHaveBeenCalled();
@@ -77,7 +77,7 @@ describe('command entrypoint', () => {
it('should not call `buildAppTask` when `skipInstall` is supplied', async () => {
const cmd = { skipInstall: true } as unknown as Command;
await createApp(cmd);
await createApp(cmd, '1.0.0');
expect(buildAppMock).not.toHaveBeenCalled();
});
});
+3 -3
View File
@@ -30,7 +30,7 @@ import {
templatingTask,
} from './lib/tasks';
export default async (cmd: Command): Promise<void> => {
export default async (cmd: Command, version: string): Promise<void> => {
/* eslint-disable-next-line no-restricted-syntax */
const paths = findPaths(__dirname);
@@ -82,7 +82,7 @@ export default async (cmd: Command): Promise<void> => {
await checkPathExistsTask(appDir);
Task.section('Preparing files');
await templatingTask(templateDir, cmd.path, answers);
await templatingTask(templateDir, cmd.path, answers, version);
} else {
// Template to temporary location, and then move files
@@ -93,7 +93,7 @@ export default async (cmd: Command): Promise<void> => {
await createTemporaryAppFolderTask(tempDir);
Task.section('Preparing files');
await templatingTask(templateDir, tempDir, answers);
await templatingTask(templateDir, tempDir, answers, version);
Task.section('Moving to final location');
await moveAppTask(tempDir, appDir, answers.name);
+1 -1
View File
@@ -38,7 +38,7 @@ const main = (argv: string[]) => {
'--skip-install',
'Skip the install and builds steps after creating the app',
)
.action(createApp);
.action(cmd => createApp(cmd, version));
program.parse(argv);
};
+4 -1
View File
@@ -195,9 +195,12 @@ describe('templatingTask', () => {
name: 'SuperCoolBackstageInstance',
dbTypeSqlite: true,
};
await templatingTask(templateDir, destinationDir, context);
await templatingTask(templateDir, destinationDir, context, '1.0.0');
expect(fs.existsSync('templatedApp/package.json')).toBe(true);
expect(fs.existsSync('templatedApp/.dockerignore')).toBe(true);
await expect(fs.readJson('templatedApp/backstage.json')).resolves.toEqual({
version: '1.0.0',
});
// catalog was populated with `context.name`
expect(
fs.readFileSync('templatedApp/catalog-info.yaml', 'utf-8'),
+9
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { BACKSTAGE_JSON } from '@backstage/cli-common';
import chalk from 'chalk';
import fs from 'fs-extra';
import handlebars from 'handlebars';
@@ -22,6 +23,7 @@ import recursive from 'recursive-readdir';
import {
basename,
dirname,
join,
resolve as resolvePath,
relative as relativePath,
} from 'path';
@@ -84,6 +86,7 @@ export async function templatingTask(
templateDir: string,
destinationDir: string,
context: any,
version: string,
) {
const files = await recursive(templateDir).catch(error => {
throw new Error(`Failed to read template directory: ${error.message}`);
@@ -133,6 +136,12 @@ export async function templatingTask(
});
}
}
await Task.forItem('creating', BACKSTAGE_JSON, () =>
fs.writeFile(
join(destinationDir, BACKSTAGE_JSON),
`{\n "version": ${JSON.stringify(version)}\n}\n`,
),
);
}
/**
@@ -1,8 +1,8 @@
app:
# Should be the same as backend.baseUrl when using the `app-backend` plugin
baseUrl: http://localhost:7000
baseUrl: http://localhost:7007
backend:
baseUrl: http://localhost:7000
baseUrl: http://localhost:7007
listen:
port: 7000
port: 7007
@@ -6,9 +6,14 @@ organization:
name: My Company
backend:
baseUrl: http://localhost:7000
# Used for enabling authentication, secret is shared by all backend plugins
# See backend-to-backend-auth.md in the docs for information on the format
# auth:
# keys:
# - secret: ${BACKEND_SECRET}
baseUrl: http://localhost:7007
listen:
port: 7000
port: 7007
csp:
connect-src: ["'self'", 'http:', 'https:']
# Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference
@@ -32,7 +37,9 @@ backend:
user: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
# https://node-postgres.com/features/ssl
# ssl: require # see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
# you can set the sslmode configuration option via the `PGSSLMODE` environment variable
# see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
# ssl:
# ca: # if you have a CA file and want to verify it you can uncomment this section
# $file: <file-path>/ca/server.crt
{{/if}}
@@ -10,9 +10,9 @@ describe('App', () => {
{
data: {
app: { title: 'Test' },
backend: { baseUrl: 'http://localhost:7000' },
backend: { baseUrl: 'http://localhost:7007' },
techdocs: {
storageUrl: 'http://localhost:7000/api/techdocs/static/docs',
storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
},
},
context: 'test',
@@ -14,6 +14,24 @@
* limitations under the License.
*/
import React, { useContext, PropsWithChildren } from 'react';
import { Link, makeStyles } from '@material-ui/core';
import HomeIcon from '@material-ui/icons/Home';
import ExtensionIcon from '@material-ui/icons/Extension';
import MapIcon from '@material-ui/icons/MyLocation';
import LibraryBooks from '@material-ui/icons/LibraryBooks';
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
import LogoFull from './LogoFull';
import LogoIcon from './LogoIcon';
import { NavLink } from 'react-router-dom';
import {
Settings as SidebarSettings,
UserSettingsSignInAvatar,
} from '@backstage/plugin-user-settings';
import {
SidebarSearchModal,
SearchContextProvider,
} from '@backstage/plugin-search';
import {
Sidebar,
sidebarConfig,
@@ -25,23 +43,8 @@ import {
SidebarScrollWrapper,
SidebarSpace,
} from '@backstage/core-components';
import { SidebarSearchModal } from '@backstage/plugin-search';
import {
Settings as SidebarSettings,
UserSettingsSignInAvatar,
} from '@backstage/plugin-user-settings';
import { Link, makeStyles } from '@material-ui/core';
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
import ExtensionIcon from '@material-ui/icons/Extension';
import HomeIcon from '@material-ui/icons/Home';
import LibraryBooks from '@material-ui/icons/LibraryBooks';
import MenuIcon from '@material-ui/icons/Menu';
import MapIcon from '@material-ui/icons/MyLocation';
import SearchIcon from '@material-ui/icons/Search';
import React, { PropsWithChildren, useContext } from 'react';
import { NavLink } from 'react-router-dom';
import LogoFull from './LogoFull';
import LogoIcon from './LogoIcon';
const useSidebarLogoStyles = makeStyles({
root: {
@@ -81,7 +84,9 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
<Sidebar>
<SidebarLogo />
<SidebarGroup label="Search" icon={<SearchIcon />} to="/search">
<SidebarSearchModal />
<SearchContextProvider>
<SidebarSearchModal />
</SearchContextProvider>{' '}
</SidebarGroup>
<SidebarDivider />
<SidebarGroup label="Menu" icon={<MenuIcon />}>
@@ -2,10 +2,13 @@ import React from 'react';
import { makeStyles, Theme, Grid, List, Paper } from '@material-ui/core';
import { CatalogResultListItem } from '@backstage/plugin-catalog';
import { DocsResultListItem } from '@backstage/plugin-techdocs';
import {
SearchBar,
SearchFilter,
SearchResult,
SearchType,
DefaultResultListItem,
} from '@backstage/plugin-search';
import { Content, Header, Page } from '@backstage/core-components';
@@ -39,6 +42,11 @@ const SearchPage = () => {
</Grid>
<Grid item xs={3}>
<Paper className={classes.filters}>
<SearchType
values={['techdocs', 'software-catalog']}
name="type"
defaultValue="software-catalog"
/>
<SearchFilter.Select
className={classes.filter}
name="kind"
@@ -64,6 +72,13 @@ const SearchPage = () => {
result={document}
/>
);
case 'techdocs':
return (
<DocsResultListItem
key={document.location}
result={document}
/>
);
default:
return (
<DefaultResultListItem
@@ -36,7 +36,7 @@ yarn start
Substitute `x` for actual values, or leave them as dummy values just to try out
the backend without using the auth or sentry features.
The backend starts up on port 7000 per default.
The backend starts up on port 7007 per default.
## Populating The Catalog
@@ -27,9 +27,9 @@
"@backstage/plugin-search-backend": "^{{version '@backstage/plugin-search-backend'}}",
"@backstage/plugin-search-backend-node": "^{{version '@backstage/plugin-search-backend-node'}}",
"@backstage/plugin-techdocs-backend": "^{{version '@backstage/plugin-techdocs-backend'}}",
"@gitbeaker/node": "^30.2.0",
"@gitbeaker/node": "^34.6.0",
"@octokit/rest": "^18.5.3",
"dockerode": "^3.2.1",
"dockerode": "^3.3.1",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"knex": "^0.21.6",
@@ -43,7 +43,7 @@
},
"devDependencies": {
"@backstage/cli": "^{{version '@backstage/cli'}}",
"@types/dockerode": "^3.2.1",
"@types/dockerode": "^3.3.0",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5"
},
@@ -17,6 +17,7 @@ import {
DatabaseManager,
SingleHostDiscovery,
UrlReaders,
ServerTokenManager,
} from '@backstage/backend-common';
import { Config } from '@backstage/config';
import app from './plugins/app';
@@ -37,12 +38,13 @@ function makeCreateEnv(config: Config) {
const cacheManager = CacheManager.fromConfig(config);
const databaseManager = DatabaseManager.fromConfig(config);
const tokenManager = ServerTokenManager.noop();
return (plugin: string): PluginEnvironment => {
const logger = root.child({ type: 'plugin', plugin });
const database = databaseManager.forPlugin(plugin);
const cache = cacheManager.forPlugin(plugin);
return { logger, database, cache, config, reader, discovery };
return { logger, database, cache, config, reader, discovery, tokenManager };
};
}
@@ -6,21 +6,36 @@ import {
} from '@backstage/plugin-search-backend-node';
import { PluginEnvironment } from '../types';
import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
import { DefaultTechDocsCollator } from '@backstage/plugin-techdocs-backend';
export default async function createPlugin({
logger,
discovery,
config,
tokenManager,
}: PluginEnvironment) {
// Initialize a connection to a search engine.
const searchEngine = new LunrSearchEngine({ logger });
const indexBuilder = new IndexBuilder({ logger, searchEngine });
// Collators are responsible for gathering documents known to plugins. This
// particular collator gathers entities from the software catalog.
// collator gathers entities from the software catalog.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: DefaultCatalogCollator.fromConfig(config, { discovery }),
collator: DefaultCatalogCollator.fromConfig(config, {
discovery,
tokenManager,
}),
});
// collator gathers entities from techdocs.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: DefaultTechDocsCollator.fromConfig(config, {
discovery,
logger,
tokenManager,
}),
});
// The scheduler controls when documents are gathered from collators and sent
@@ -4,6 +4,7 @@ import {
PluginCacheManager,
PluginDatabaseManager,
PluginEndpointDiscovery,
TokenManager,
UrlReader,
} from '@backstage/backend-common';
@@ -14,4 +15,5 @@ export type PluginEnvironment = {
config: Config;
reader: UrlReader;
discovery: PluginEndpointDiscovery;
tokenManager: TokenManager;
};