Merge pull request #1986 from spotify/rugvip/bapp

Add app-backend plugin for serving app content
This commit is contained in:
Patrik Oldsberg
2020-08-31 13:51:18 +02:00
committed by GitHub
24 changed files with 623 additions and 26 deletions
+2
View File
@@ -18,9 +18,11 @@
"migrate:create": "knex migrate:make -x ts"
},
"dependencies": {
"example-app": "^0.1.1-alpha.20",
"@backstage/backend-common": "^0.1.1-alpha.20",
"@backstage/catalog-model": "^0.1.1-alpha.20",
"@backstage/config": "^0.1.1-alpha.20",
"@backstage/plugin-app-backend": "^0.1.1-alpha.20",
"@backstage/plugin-auth-backend": "^0.1.1-alpha.20",
"@backstage/plugin-catalog-backend": "^0.1.1-alpha.20",
"@backstage/plugin-graphql-backend": "^0.1.1-alpha.20",
+4 -1
View File
@@ -40,6 +40,7 @@ import sentry from './plugins/sentry';
import proxy from './plugins/proxy';
import techdocs from './plugins/techdocs';
import graphql from './plugins/graphql';
import app from './plugins/app';
import { PluginEnvironment } from './types';
function makeCreateEnv(loadedConfigs: AppConfig[]) {
@@ -71,6 +72,7 @@ async function main() {
const sentryEnv = useHotMemoize(module, () => createEnv('sentry'));
const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs'));
const graphqlEnv = useHotMemoize(module, () => createEnv('graphql'));
const appEnv = useHotMemoize(module, () => createEnv('app'));
const service = createServiceBuilder(module)
.loadConfig(configReader)
@@ -83,7 +85,8 @@ async function main() {
.addRouter('/identity', await identity(identityEnv))
.addRouter('/techdocs', await techdocs(techdocsEnv))
.addRouter('/proxy', await proxy(proxyEnv, '/proxy'))
.addRouter('/graphql', await graphql(graphqlEnv));
.addRouter('/graphql', await graphql(graphqlEnv))
.addRouter('', await app(appEnv));
await service.start().catch(err => {
console.log(err);
+25
View File
@@ -0,0 +1,25 @@
/*
* 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 { createRouter } from '@backstage/plugin-app-backend';
import { PluginEnvironment } from '../types';
export default async function createPlugin({ logger }: PluginEnvironment) {
return await createRouter({
logger,
appPackageName: 'example-app',
});
}
+3
View File
@@ -28,6 +28,9 @@ module.exports = {
env: {
jest: true,
},
globals: {
__non_webpack_require__: 'readonly',
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
+1
View File
@@ -14,5 +14,6 @@
* limitations under the License.
*/
export { readEnvConfig } from './lib';
export { loadConfig } from './loader';
export type { LoadConfigOptions } from './loader';
+21 -21
View File
@@ -14,16 +14,16 @@
* limitations under the License.
*/
import { readEnv } from './env';
import { readEnvConfig } from './env';
describe('readEnv', () => {
describe('readEnvConfig', () => {
it('should return empty config for empty env', () => {
expect(readEnv({})).toEqual([]);
expect(readEnvConfig({})).toEqual([]);
});
it('should return empty config for no matching keys', () => {
expect(
readEnv({
readEnvConfig({
NODE_ENV: 'production',
NOPE_ENV: 'development',
APP_CONFIG: 'foo',
@@ -34,7 +34,7 @@ describe('readEnv', () => {
it('should create config from env', () => {
expect(
readEnv({
readEnvConfig({
NODE_ENV: 'production',
APP_CONFIG_foo: '"bar"',
APP_CONFIG_numbers_a: '1',
@@ -57,22 +57,22 @@ describe('readEnv', () => {
});
it('should accept string values', () => {
expect(readEnv({ APP_CONFIG_foo: '"abc"', APP_CONFIG_bar: 'xyz' })).toEqual(
[
{
data: {
foo: 'abc',
bar: 'xyz',
},
context: 'env',
expect(
readEnvConfig({ APP_CONFIG_foo: '"abc"', APP_CONFIG_bar: 'xyz' }),
).toEqual([
{
data: {
foo: 'abc',
bar: 'xyz',
},
],
);
context: 'env',
},
]);
});
it('should accept complex objects', () => {
expect(
readEnv({
readEnvConfig({
APP_CONFIG_foo: '{ "a": 123, "b": "123", "c": [] }',
APP_CONFIG_bar: '[123, "abc", {}]',
}),
@@ -95,7 +95,7 @@ describe('readEnv', () => {
['APP_CONFIG_fo o'],
['APP_CONFIG_foo_(foo)_foo'],
])('should reject invalid key %p', key => {
expect(() => readEnv({ [key]: '0' })).toThrow(
expect(() => readEnvConfig({ [key]: '0' })).toThrow(
`Invalid env config key '${key.replace('APP_CONFIG_', '')}'`,
);
});
@@ -103,7 +103,7 @@ describe('readEnv', () => {
it.each([['hello'], ['"hello'], ['{'], ['}']])(
'should fallback to string when invalid json value %p',
value => {
expect(readEnv({ APP_CONFIG_foo: value })).toEqual([
expect(readEnvConfig({ APP_CONFIG_foo: value })).toEqual([
{
data: {
foo: value,
@@ -116,7 +116,7 @@ describe('readEnv', () => {
it('should not allow null as a value', () => {
expect(() =>
readEnv({
readEnvConfig({
APP_CONFIG_foo: 'null',
}),
).toThrow(
@@ -126,7 +126,7 @@ describe('readEnv', () => {
it('should not allow duplicate values', () => {
expect(() =>
readEnv({
readEnvConfig({
APP_CONFIG_foo_bar: '1',
APP_CONFIG_foo_bar_baz: '2',
}),
@@ -137,7 +137,7 @@ describe('readEnv', () => {
it('should not allow mixing of objects and other values', () => {
expect(() =>
readEnv({
readEnvConfig({
APP_CONFIG_nested_foo: '1',
APP_CONFIG_nested: '2',
}),
+1 -1
View File
@@ -39,7 +39,7 @@ const CONFIG_KEY_PART_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z][a-z0-9]*)*$/i;
*
* APP_CONFIG_app_title='"My Title"'
*/
export function readEnv(env: {
export function readEnvConfig(env: {
[name: string]: string | undefined;
}): AppConfig[] {
let data: JsonObject | undefined = undefined;
+1 -1
View File
@@ -16,5 +16,5 @@
export { resolveStaticConfig } from './resolver';
export { readConfigFile } from './reader';
export { readEnv } from './env';
export { readEnvConfig } from './env';
export { readSecret } from './secrets';
+2 -2
View File
@@ -20,7 +20,7 @@ import { AppConfig, JsonObject } from '@backstage/config';
import {
resolveStaticConfig,
readConfigFile,
readEnv,
readEnvConfig,
readSecret,
} from './lib';
@@ -102,7 +102,7 @@ export async function loadConfig(
);
}
configs.push(...readEnv(process.env));
configs.push(...readEnvConfig(process.env));
return configs;
}