Merge branch 'backstage:master' into plugin-azure-functions

This commit is contained in:
Wesley
2022-09-29 16:59:36 +02:00
committed by GitHub
32 changed files with 437 additions and 75 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-user-settings': patch
---
Prevent `.set()` to execute a request to the StorageClient if the user is `guest`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-gcalendar': patch
---
Fixed loader showing when user not signed in
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-api-docs': patch
---
Updated dependency `@asyncapi/react-component` to `1.0.0-next.43`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Initializes a git repository when creating an app using @packages/create-app
+1 -1
View File
@@ -9,7 +9,7 @@ search:
- plugins/search/**/*
- plugins/search-*/**/*
- packages/search-*/**/*
docs-like-code:
techdocs:
- plugins/techdocs/**/*
- plugins/techdocs-*/**/*
- packages/techdocs-*/**/*
+3 -3
View File
@@ -33,7 +33,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -63,7 +63,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -178,7 +178,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -8,7 +8,7 @@ jobs:
cron:
runs-on: ubuntu-latest
steps:
- uses: backstage/actions/cron@v0.5.5
- uses: backstage/actions/cron@v0.5.6
with:
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+2 -2
View File
@@ -67,7 +67,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -145,7 +145,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -10,4 +10,4 @@ jobs:
if: github.repository == 'backstage/backstage'
steps:
- name: Issue sync
uses: backstage/actions/issue-sync@v0.5.5
uses: backstage/actions/issue-sync@v0.5.6
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
const prNumber = artifact.name.slice('pr_number-'.length)
console.log(`::set-output name=pr-number::${prNumber}`);
- uses: backstage/actions/re-review@v0.5.5
- uses: backstage/actions/re-review@v0.5.6
with:
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request )
steps:
- name: PR sync
uses: backstage/actions/pr-sync@v0.5.5
uses: backstage/actions/pr-sync@v0.5.6
with:
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -22,7 +22,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+6 -1
View File
@@ -41,13 +41,18 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Configure Git
run: |
git config --global user.email noreply@backstage.io
git config --global user.name 'GitHub e2e user'
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -39,7 +39,7 @@ jobs:
run: yarn build
- name: Install mkdocs & techdocs-core
run: python -m pip install mkdocs-techdocs-core
run: python -m pip install mkdocs-techdocs-core==1.1.6 mkdocs==1.3.1
- name: techdocs-cli e2e test
working-directory: packages/techdocs-cli
+5
View File
@@ -39,6 +39,11 @@ jobs:
- uses: actions/checkout@v3
- name: Configure Git
run: |
git config --global user.email noreply@backstage.io
git config --global user.name 'GitHub e2e user'
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.5
uses: backstage/actions/yarn-install@v0.5.6
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
- name: storybook yarn install
@@ -0,0 +1,30 @@
# Upgrade Backstage App
## Overview
The script upgrades the version of Backstage created via the create-app plugin. It lets you resolve conflicts iteratively with your own merge [tool](https://www.git-scm.com/docs/git-mergetool).
## Requirements
You will need to have the following tools in your shell environment:
- git
- curl
- jq
## Usage
Here's how to use the script:
1. download the script
2. copy it in the root of your app
3. bootstrap a git repository (you may already have done so):
```bash
git init
git add .
git commit -m "initial commit"
```
4. run `sh upgrade-backstage-app.sh [optional-backstage-version]`
5. resolve any conflicts iteratively
@@ -0,0 +1,15 @@
#!/bin/sh
CURRENT_VERSION="v$(cat backstage.json | jq -r '.version')"
TARGET_VERSION=${1:-"$(curl -s https://api.github.com/repos/backstage/backstage/releases/latest | jq -r '.tag_name')"}
CREATE_APP_CURRENT_VERSION=$(curl -s https://raw.githubusercontent.com/backstage/backstage/$CURRENT_VERSION/packages/create-app/package.json | jq -r '.version')
CREATE_APP_TARGET_VERSION=$(curl -s https://raw.githubusercontent.com/backstage/backstage/$TARGET_VERSION/packages/create-app/package.json | jq -r '.version')
if [ "$CURRENT_VERSION" == "$TARGET_VERSION" ]; then
echo "Already up to date"
else
echo "Attempting upgrade from Backstage $CURRENT_VERSION (create-app $CREATE_APP_CURRENT_VERSION) to $TARGET_VERSION ($CREATE_APP_TARGET_VERSION)"
rm -rf .upgrade && mkdir .upgrade
curl -s https://raw.githubusercontent.com/backstage/upgrade-helper-diff/master/diffs/$CREATE_APP_CURRENT_VERSION..$CREATE_APP_TARGET_VERSION.diff > .upgrade/upgrade.diff
git apply -3 .upgrade/upgrade.diff
git mergetool
fi
+2
View File
@@ -34,6 +34,7 @@
"dependencies": {
"@backstage/cli-common": "workspace:^",
"chalk": "^4.0.0",
"command-exists": "^1.2.9",
"commander": "^9.1.0",
"fs-extra": "10.1.0",
"handlebars": "^4.7.3",
@@ -43,6 +44,7 @@
},
"devDependencies": {
"@backstage/cli": "workspace:^",
"@types/command-exists": "^1.2.0",
"@types/fs-extra": "^9.0.1",
"@types/inquirer": "^8.1.3",
"@types/node": "^16.11.26",
+17 -1
View File
@@ -32,6 +32,8 @@ const promptMock = jest.spyOn(inquirer, 'prompt');
const checkPathExistsMock = jest.spyOn(tasks, 'checkPathExistsTask');
const templatingMock = jest.spyOn(tasks, 'templatingTask');
const checkAppExistsMock = jest.spyOn(tasks, 'checkAppExistsTask');
const initGitRepositoryMock = jest.spyOn(tasks, 'initGitRepository');
const readGitConfig = jest.spyOn(tasks, 'readGitConfig');
const createTemporaryAppFolderMock = jest.spyOn(
tasks,
'createTemporaryAppFolderTask',
@@ -47,7 +49,7 @@ describe('command entrypoint', () => {
});
});
afterAll(() => {
afterEach(() => {
mockFs.restore();
});
@@ -56,6 +58,11 @@ describe('command entrypoint', () => {
name: 'MyApp',
dbType: 'PostgreSQL',
});
readGitConfig.mockResolvedValue({
name: 'git-user',
email: 'git-email',
defaultBranch: 'git-default-branch',
});
});
afterEach(() => {
@@ -67,6 +74,7 @@ describe('command entrypoint', () => {
await createApp(cmd);
expect(checkAppExistsMock).toHaveBeenCalled();
expect(createTemporaryAppFolderMock).toHaveBeenCalled();
expect(initGitRepositoryMock).toHaveBeenCalled();
expect(templatingMock).toHaveBeenCalled();
expect(moveAppMock).toHaveBeenCalled();
expect(buildAppMock).toHaveBeenCalled();
@@ -76,6 +84,7 @@ describe('command entrypoint', () => {
const cmd = { path: 'myDirectory' } as unknown as Command;
await createApp(cmd);
expect(checkPathExistsMock).toHaveBeenCalled();
expect(initGitRepositoryMock).toHaveBeenCalled();
expect(templatingMock).toHaveBeenCalled();
expect(buildAppMock).toHaveBeenCalled();
});
@@ -85,4 +94,11 @@ describe('command entrypoint', () => {
await createApp(cmd);
expect(buildAppMock).not.toHaveBeenCalled();
});
it('should not call `initGitRepository` when `gitConfig` is undefined', async () => {
const cmd = {} as unknown as Command;
readGitConfig.mockResolvedValue({});
await createApp(cmd);
expect(initGitRepositoryMock).not.toHaveBeenCalled();
});
});
+19 -2
View File
@@ -28,8 +28,12 @@ import {
createTemporaryAppFolderTask,
moveAppTask,
templatingTask,
initGitRepository,
readGitConfig,
} from './lib/tasks';
const DEFAULT_BRANCH = 'master';
export default async (opts: OptionValues): Promise<void> => {
/* eslint-disable-next-line no-restricted-syntax */
const paths = findPaths(__dirname);
@@ -73,6 +77,8 @@ export default async (opts: OptionValues): Promise<void> => {
Task.log('Creating the app...');
try {
const gitConfig = await readGitConfig();
if (opts.path) {
// Template directly to specified path
@@ -80,7 +86,10 @@ export default async (opts: OptionValues): Promise<void> => {
await checkPathExistsTask(appDir);
Task.section('Preparing files');
await templatingTask(templateDir, opts.path, answers);
await templatingTask(templateDir, opts.path, {
...answers,
defaultBranch: gitConfig?.defaultBranch ?? DEFAULT_BRANCH,
});
} else {
// Template to temporary location, and then move files
@@ -91,12 +100,20 @@ export default async (opts: OptionValues): Promise<void> => {
await createTemporaryAppFolderTask(tempDir);
Task.section('Preparing files');
await templatingTask(templateDir, tempDir, answers);
await templatingTask(templateDir, tempDir, {
...answers,
defaultBranch: gitConfig?.defaultBranch ?? DEFAULT_BRANCH,
});
Task.section('Moving to final location');
await moveAppTask(tempDir, appDir, answers.name);
}
if (gitConfig?.name && gitConfig?.email) {
Task.section('Initializing git repository');
await initGitRepository(appDir);
}
if (!opts.skipInstall) {
Task.section('Building the app');
await buildAppTask(appDir);
+116 -7
View File
@@ -17,7 +17,8 @@
import fs from 'fs-extra';
import mockFs from 'mock-fs';
import child_process from 'child_process';
import path from 'path';
import path, { resolve as resolvePath } from 'path';
import os from 'os';
import {
Task,
buildAppTask,
@@ -26,8 +27,12 @@ import {
createTemporaryAppFolderTask,
moveAppTask,
templatingTask,
initGitRepository,
readGitConfig,
} from './tasks';
const commandExists = jest.fn();
jest.spyOn(Task, 'log').mockReturnValue(undefined);
jest.spyOn(Task, 'error').mockReturnValue(undefined);
jest.spyOn(Task, 'section').mockReturnValue(undefined);
@@ -36,6 +41,12 @@ jest
.mockImplementation((_a, _b, taskFunc) => taskFunc());
jest.mock('child_process');
jest.mock(
'command-exists',
() =>
(...args: any[]) =>
commandExists(...args),
);
// By mocking this the filesystem mocks won't mess with reading all of the package.jsons
jest.mock('./versions', () => ({
@@ -87,6 +98,14 @@ jest.mock('./versions', () => ({
}));
describe('tasks', () => {
const mockExec = child_process.exec as unknown as jest.MockedFunction<
(
command: string,
options: any,
callback: (error: null, stdout: any, stderr: any) => void,
) => void
>;
beforeEach(() => {
mockFs({
'projects/my-module.ts': '',
@@ -100,6 +119,7 @@ describe('tasks', () => {
});
afterEach(() => {
mockExec.mockRestore();
mockFs.restore();
});
@@ -174,12 +194,6 @@ describe('tasks', () => {
describe('buildAppTask', () => {
it('should change to `appDir` and run `yarn install` and `yarn tsc`', async () => {
const mockChdir = jest.spyOn(process, 'chdir');
const mockExec = child_process.exec as unknown as jest.MockedFunction<
(
command: string,
callback: (error: null, stdout: string, stderr: string) => void,
) => void
>;
// requires callback implementation to support `promisify` wrapper
// https://stackoverflow.com/a/60579617/10044859
@@ -273,4 +287,99 @@ describe('tasks', () => {
).toContain('sqlite3"');
});
});
describe('readGitConfig', () => {
const tmpDir = resolvePath(os.tmpdir(), 'git-temp-dir');
it('should return git config if git package is installed and git credentials are set', async () => {
mockExec.mockImplementation((_command, _options, callback) => {
callback(null, { stdout: 'main' }, 'standard error');
});
commandExists.mockResolvedValue(true);
const gitConfig = await readGitConfig();
expect(gitConfig).toBeTruthy();
expect(gitConfig).toEqual({
name: 'main',
email: 'main',
defaultBranch: 'main',
});
expect(mockExec).toHaveBeenCalledWith(
'git config user.name',
{ cwd: tmpDir },
expect.any(Function),
);
expect(mockExec).toHaveBeenCalledWith(
'git config user.email',
{ cwd: tmpDir },
expect.any(Function),
);
expect(mockExec).toHaveBeenCalledWith(
'git init',
{ cwd: tmpDir },
expect.any(Function),
);
expect(mockExec).toHaveBeenCalledWith(
'git commit --allow-empty -m "Initial commit"',
{ cwd: tmpDir },
expect.any(Function),
);
});
it('should return false if git package is not installed', async () => {
commandExists.mockResolvedValue(false);
const gitConfig = await readGitConfig();
expect(gitConfig).toEqual({});
});
it('should return false if git package is installed but git credentials are not set', async () => {
mockExec.mockImplementation((_command, _options, callback) => {
callback(null, { stdout: null }, 'standard error');
});
commandExists.mockResolvedValue(true);
const gitConfig = await readGitConfig();
expect(gitConfig).toEqual({});
expect(mockExec).toHaveBeenCalledWith(
'git config user.name',
{ cwd: tmpDir },
expect.any(Function),
);
expect(mockExec).toHaveBeenCalledWith(
'git config user.email',
{ cwd: tmpDir },
expect.any(Function),
);
});
});
describe('initGitRepository', () => {
it('should initialize a git repository at the given path', async () => {
const destinationDir = 'tmp/mockApp/';
mockExec.mockImplementation((_command, callback) => {
callback(null, { stdout: 'main' }, 'standard error');
});
await initGitRepository(destinationDir);
expect(mockExec).toHaveBeenCalledTimes(2);
expect(mockExec).toHaveBeenNthCalledWith(
1,
'git init',
expect.any(Function),
);
expect(mockExec).toHaveBeenNthCalledWith(
2,
'git commit --allow-empty -m "Initial commit"',
expect.any(Function),
);
});
});
});
+82
View File
@@ -28,10 +28,18 @@ import {
import { exec as execCb } from 'child_process';
import { packageVersions } from './versions';
import { promisify } from 'util';
import commandExists from 'command-exists';
import os from 'os';
const TASK_NAME_MAX_LENGTH = 14;
const exec = promisify(execCb);
export type GitConfig = {
name?: string;
email?: string;
defaultBranch?: string;
};
export class Task {
static log(name: string = '') {
process.stdout.write(`${chalk.green(name)}\n`);
@@ -236,3 +244,77 @@ export async function moveAppTask(
});
});
}
/**
* Read git configs by creating a temp folder and initializing a repo
*
* @throws if `exec` fails
*/
export async function readGitConfig(): Promise<GitConfig> {
const tempDir = resolvePath(os.tmpdir(), 'git-temp-dir');
const runCmd = (cmd: string) =>
exec(cmd, { cwd: tempDir }).catch(error => {
process.stdout.write(error.stderr);
process.stdout.write(error.stdout);
throw new Error(`Could not execute command ${chalk.cyan(cmd)}`);
});
const isGitAvailable = await commandExists('git').catch(() => false);
if (!isGitAvailable) return {};
try {
await fs.mkdir(tempDir);
const [gitUsername, gitEmail] = await Promise.all([
runCmd('git config user.name'),
runCmd('git config user.email'),
]);
const gitCredentials = Boolean(
gitUsername.stdout?.trim() && gitEmail.stdout?.trim(),
);
if (!gitCredentials) return {};
await runCmd('git init');
await runCmd('git commit --allow-empty -m "Initial commit"');
const gitDefaultBranch = await runCmd(
'git branch --format="%(refname:short)"',
);
return {
name: gitUsername.stdout?.trim(),
email: gitEmail.stdout?.trim(),
defaultBranch: gitDefaultBranch.stdout?.trim(),
};
} catch (error) {
throw new Error(`Failed to read git config, ${error}`);
} finally {
await fs.rm(tempDir, { recursive: true });
}
}
/**
* Initializes a git repository in the destination folder
*
* @param dir - source path to initialize git repository in
* @throws if `exec` fails
*/
export async function initGitRepository(dir: string) {
const runCmd = (cmd: string) =>
exec(cmd).catch(error => {
process.stdout.write(error.stderr);
process.stdout.write(error.stdout);
throw new Error(`Could not execute command ${chalk.cyan(cmd)}`);
});
await Task.forItem('init', 'git repository', async () => {
process.chdir(dir);
await runCmd('git init');
await runCmd('git commit --allow-empty -m "Initial commit"');
});
}
@@ -16,7 +16,7 @@
"clean": "backstage-cli repo clean",
"test": "backstage-cli repo test",
"test:all": "backstage-cli repo test --coverage",
"lint": "backstage-cli repo lint --since origin/master",
"lint": "backstage-cli repo lint --since origin/{{defaultBranch}}",
"lint:all": "backstage-cli repo lint",
"prettier:check": "prettier --check .",
"create-plugin": "backstage-cli create-plugin --scope internal",
+1 -1
View File
@@ -32,7 +32,7 @@
"clean": "backstage-cli package clean"
},
"dependencies": {
"@asyncapi/react-component": "1.0.0-next.42",
"@asyncapi/react-component": "1.0.0-next.43",
"@backstage/catalog-model": "workspace:^",
"@backstage/core-components": "workspace:^",
"@backstage/core-plugin-api": "workspace:^",
@@ -50,10 +50,13 @@ export const CalendarCard = () => {
useAsync(async () => signIn(true), [signIn]);
const { isLoading: isCalendarLoading, data: calendars = [] } =
useCalendarsQuery({
enabled: isSignedIn,
});
const {
isLoading: isCalendarLoading,
isFetching: isCalendarFetching,
data: calendars = [],
} = useCalendarsQuery({
enabled: isSignedIn,
});
const primaryCalendarId = calendars.find(c => c.primary === true)?.id;
const defaultSelectedCalendars = primaryCalendarId ? [primaryCalendarId] : [];
const [storedCalendars, setStoredCalendars] = useStoredCalendars(
@@ -69,6 +72,11 @@ export const CalendarCard = () => {
timeZone: date.zoneName,
});
const showLoader =
(isCalendarLoading && isCalendarFetching) ||
isEventLoading ||
!isInitialized;
return (
<InfoCard
noPadding
@@ -100,7 +108,9 @@ export const CalendarCard = () => {
calendars={calendars}
selectedCalendars={storedCalendars}
setSelectedCalendars={setStoredCalendars}
disabled={isCalendarLoading || !isSignedIn}
disabled={
(isCalendarFetching && isCalendarLoading) || !isSignedIn
}
/>
</>
) : (
@@ -114,8 +124,8 @@ export const CalendarCard = () => {
}}
>
<Box>
{(isCalendarLoading || isEventLoading || !isInitialized) && (
<Box pt={2} pb={2}>
{showLoader && (
<Box py={2}>
<Progress variant="query" />
</Box>
)}
@@ -38,6 +38,10 @@ describe('Persistent Storage API', () => {
const mockIdentityApi: Partial<IdentityApi> = {
getCredentials: async () => ({ token: 'a-token' }),
};
const mockIdentityApiFallback: Partial<IdentityApi> = {
// This API recreates the guest mode, where the WebStorage is used as fallback
getCredentials: async () => ({}),
};
const createPersistentStorage = (
args?: Partial<{
@@ -56,6 +60,23 @@ describe('Persistent Storage API', () => {
});
};
const createPersistentStorageFallback = (
args?: Partial<{
fetchApi: FetchApi;
discoveryApi: DiscoveryApi;
errorApi: ErrorApi;
namespace?: string;
}>,
): StorageApi => {
return UserSettingsStorage.create({
errorApi: mockErrorApi,
fetchApi: new MockFetchApi(),
discoveryApi: mockDiscoveryApi,
identityApi: mockIdentityApiFallback as IdentityApi,
...args,
});
};
afterEach(() => {
jest.resetAllMocks();
});
@@ -124,6 +145,33 @@ describe('Persistent Storage API', () => {
await storage.set('my-key', dummyValue);
});
it('should fallback set when user not logged in', async () => {
const storage = createPersistentStorageFallback();
const selectedKeyNextHandler = jest.fn();
const dummyValue = 'my-value';
await new Promise<void>(resolve => {
storage.observe$<typeof dummyValue>('my-key').subscribe({
next: snapshot => {
selectedKeyNextHandler(snapshot);
if (snapshot.presence === 'present') {
resolve();
}
},
});
storage.set('my-key', dummyValue);
});
expect(selectedKeyNextHandler).toHaveBeenCalledTimes(1);
expect(selectedKeyNextHandler).toHaveBeenCalledWith({
key: 'my-key',
value: dummyValue,
presence: 'present',
});
});
it('should subscribe to key changes when setting a new value', async () => {
const storage = createPersistentStorage();
@@ -118,6 +118,7 @@ export class UserSettingsStorage implements StorageApi {
if (!(await this.isSignedIn())) {
await this.fallback.set(key, data);
this.notifyChanges({ key, presence: 'present', value: data });
return;
}
const fetchUrl = await this.getFetchUrl(key);
+41 -39
View File
@@ -286,12 +286,12 @@ __metadata:
languageName: node
linkType: hard
"@asyncapi/parser@npm:^1.15.0":
version: 1.15.0
resolution: "@asyncapi/parser@npm:1.15.0"
"@asyncapi/parser@npm:^1.17.0":
version: 1.17.0
resolution: "@asyncapi/parser@npm:1.17.0"
dependencies:
"@apidevtools/json-schema-ref-parser": ^9.0.6
"@asyncapi/specs": ^2.14.0
"@asyncapi/specs": ^3.2.0
"@fmvilas/pseudo-yaml-ast": ^0.3.1
ajv: ^6.10.1
js-yaml: ^3.13.1
@@ -299,17 +299,17 @@ __metadata:
lodash.clonedeep: ^4.5.0
node-fetch: ^2.6.0
tiny-merge-patch: ^0.1.2
checksum: e9435265b4671f6a4c2451e054751ea637dd466b1f6b6848622781fbf6fa9fc93c292ed8791bf38816f63cd9c352f09727ab2d34f76d62f8f21c084b0125445b
checksum: 6ac0bd3c9c90abf331cfdfb054dab047cf0324ee803633c2abc6dad96b12c64d033e4fb94907906adfb521ba16e9b23083b2a6acc7719ccd22154a7867046a95
languageName: node
linkType: hard
"@asyncapi/react-component@npm:1.0.0-next.42":
version: 1.0.0-next.42
resolution: "@asyncapi/react-component@npm:1.0.0-next.42"
"@asyncapi/react-component@npm:1.0.0-next.43":
version: 1.0.0-next.43
resolution: "@asyncapi/react-component@npm:1.0.0-next.43"
dependencies:
"@asyncapi/avro-schema-parser": ^0.3.0
"@asyncapi/openapi-schema-parser": ^2.0.0
"@asyncapi/parser": ^1.15.0
"@asyncapi/parser": ^1.17.0
highlight.js: ^10.7.2
isomorphic-dompurify: ^0.13.0
marked: ^4.0.14
@@ -319,14 +319,14 @@ __metadata:
peerDependencies:
react: ">=16.8.0"
react-dom: ">=16.8.0"
checksum: eba4aaf344aabc1889085df7f94d14d51e2449db06cabc70c60b9d5b0b2fb9ccec6aa89cbedf9d45c28deca99e1e4ab2d4399b0a2756e9969d4691f304088a77
checksum: d19adc2b6e674633457da28d38636df4cf9891f4038827b52f2737699d064bcf0d3be707e9f3284852d1bb507f3f36df9ec3bb02fd6f901cfda7a1f49ea9c5da
languageName: node
linkType: hard
"@asyncapi/specs@npm:^2.14.0":
version: 2.14.0
resolution: "@asyncapi/specs@npm:2.14.0"
checksum: 066c23c493df54c44c319433bdcf8482a3acd584e32c0073e6a9f5b167d61bde23a252621be2b28bbaf1466636f6cafaab570795de403f0c671358784d4b12ed
"@asyncapi/specs@npm:^3.2.0":
version: 3.2.0
resolution: "@asyncapi/specs@npm:3.2.0"
checksum: 09971262aefc8844ab3e7c0c3652711862ac562dd5d614f23b496185690430a81df8e50eddba657f4141e0fd9548ef622fe6c20f4e3dec8054be23f774798335
languageName: node
linkType: hard
@@ -3687,11 +3687,13 @@ __metadata:
dependencies:
"@backstage/cli": "workspace:^"
"@backstage/cli-common": "workspace:^"
"@types/command-exists": ^1.2.0
"@types/fs-extra": ^9.0.1
"@types/inquirer": ^8.1.3
"@types/node": ^16.11.26
"@types/recursive-readdir": ^2.2.0
chalk: ^4.0.0
command-exists: ^1.2.9
commander: ^9.1.0
fs-extra: 10.1.0
handlebars: ^4.7.3
@@ -4066,7 +4068,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@backstage/plugin-api-docs@workspace:plugins/api-docs"
dependencies:
"@asyncapi/react-component": 1.0.0-next.42
"@asyncapi/react-component": 1.0.0-next.43
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/core-app-api": "workspace:^"
@@ -8554,8 +8556,8 @@ __metadata:
linkType: hard
"@google-cloud/storage@npm:^6.0.0":
version: 6.5.1
resolution: "@google-cloud/storage@npm:6.5.1"
version: 6.5.2
resolution: "@google-cloud/storage@npm:6.5.2"
dependencies:
"@google-cloud/paginator": ^3.0.7
"@google-cloud/projectify": ^3.0.0
@@ -8575,7 +8577,7 @@ __metadata:
retry-request: ^5.0.0
teeny-request: ^8.0.0
uuid: ^8.0.0
checksum: 5ae81ae5e00afeb73ae07a00772af5d5fa8f2ceacc4723d4e6e24f05ca9bc7cd22885acee3cb75c15068fe85f20b81719c1634b2c2ac0d05552172a229b34ea5
checksum: 31e8abea01e5160434a23c11c7219c83469c97a0c3bed9dc29d5ff1441ba1f42aa75a99df6e0b95db1501cf4b7f4c896c79b13bb597a35ddd2924408b584f802
languageName: node
linkType: hard
@@ -11249,8 +11251,8 @@ __metadata:
linkType: hard
"@octokit/auth-app@npm:^4.0.0":
version: 4.0.5
resolution: "@octokit/auth-app@npm:4.0.5"
version: 4.0.6
resolution: "@octokit/auth-app@npm:4.0.6"
dependencies:
"@octokit/auth-oauth-app": ^5.0.0
"@octokit/auth-oauth-user": ^2.0.0
@@ -11262,7 +11264,7 @@ __metadata:
lru-cache: ^6.0.0
universal-github-app-jwt: ^1.0.1
universal-user-agent: ^6.0.0
checksum: 26da7c1b279be68be17572897652091257a5ef7666fa5ac4c79dd42f2717aed560b117089c44ad766b4f90a87348572356ac3571c417fef385fdf31794281023
checksum: 342fece6db4470ee489e710af8aa14ffd3a89e666815a15fadbabe3a382932a714d5bece24375f0ca39f3310f9d10bd28bc348210282cbc6701d27dd9b2ff7ed
languageName: node
linkType: hard
@@ -13710,11 +13712,11 @@ __metadata:
linkType: hard
"@types/inquirer@npm:^8.1.3":
version: 8.2.3
resolution: "@types/inquirer@npm:8.2.3"
version: 8.2.4
resolution: "@types/inquirer@npm:8.2.4"
dependencies:
"@types/through": "*"
checksum: 2978e749fbda061b85a56331a267f6c7f40380c17bce1b0f8b0bd1d86c88820e3bd7df4985c633647652b571f7ffd6b97b929cabe8b7d61259d354229e4c6c5b
checksum: 3a46231faac1e5df4863a2d501617b3f25e9481ea8a966a9b866bafef01fcc151606d9f25cb66f90492dd0d1d7af7c675a2314f50db85a7f2aeed265d93eb412
languageName: node
linkType: hard
@@ -13906,11 +13908,11 @@ __metadata:
linkType: hard
"@types/ldapjs@npm:^2.2.0":
version: 2.2.2
resolution: "@types/ldapjs@npm:2.2.2"
version: 2.2.4
resolution: "@types/ldapjs@npm:2.2.4"
dependencies:
"@types/node": "*"
checksum: e5da993f06240251dad1e095564c722124ed08d915781fb3046f7933cde94b5d2681030ab9f48d4aa5d72b655b501bfd6f2ad4ea41d557d0e1a08d574ed058bf
checksum: 3f240809927e1292380e5977579d7edffb6e5e41b35510c7091b51da19e7387d4ebff0f254c0b145f3cf5d5485b6bb39c77335d857d092e6f4e9ce5a6682a872
languageName: node
linkType: hard
@@ -15428,12 +15430,12 @@ __metadata:
linkType: hard
"@yarnpkg/parsers@npm:^3.0.0-rc.4":
version: 3.0.0-rc.20
resolution: "@yarnpkg/parsers@npm:3.0.0-rc.20"
version: 3.0.0-rc.21
resolution: "@yarnpkg/parsers@npm:3.0.0-rc.21"
dependencies:
js-yaml: ^3.10.0
tslib: ^2.4.0
checksum: a0dfc2d4d824322ae779363870ad7705b42161ad5e90c992404bf5dc0454a046a6f04144303c9bb047239e480b882b4105272127f2ba080b865180276c46deda
checksum: c0741ef01089a7d452dfb75b8c24a82ddcc3e218dac22b794a06f2e50c7070378c460f63f63fb7ed0f62f634114e448e3d85a75ccd4db84e1526242ae9b4a7d5
languageName: node
linkType: hard
@@ -18862,9 +18864,9 @@ __metadata:
linkType: hard
"core-js@npm:^3.6.5":
version: 3.25.2
resolution: "core-js@npm:3.25.2"
checksum: e93c6c645d44d98973efb07750975552ad405f080f5a563a99972ff6b2c5c6ee25705f55accd363f5dccd51e9e5f56be25e2be6c14a7294da65763e0e5659c02
version: 3.25.3
resolution: "core-js@npm:3.25.3"
checksum: 26ca0a5e575e6da03dc30099f48bc00db50a1c0a3f81299165f111cb163869ae453de5e345f2cb7bc8be85a9adcee11fca94f0fbdbdf6d483c68e1c55a9efc5a
languageName: node
linkType: hard
@@ -23821,8 +23823,8 @@ __metadata:
linkType: hard
"google-auth-library@npm:^8.0.0":
version: 8.5.1
resolution: "google-auth-library@npm:8.5.1"
version: 8.5.2
resolution: "google-auth-library@npm:8.5.2"
dependencies:
arrify: ^2.0.0
base64-js: ^1.3.0
@@ -23833,7 +23835,7 @@ __metadata:
gtoken: ^6.1.0
jws: ^4.0.0
lru-cache: ^6.0.0
checksum: 0d80d7e136e672055e44fdb44f9e13843a554cc531a01deb1b0da6b78427778785faa7377ed85d840208bb61878cd7d69902172886476bd49ea67e645729570a
checksum: 5ab2904f5da3c119a7c241a1d5a11640468a7da58dfcec8a9cad181cc2723e6662b3c65997906069852d9fa066ba3e4b7f14e11cbb80d541e320b66ead6777dc
languageName: node
linkType: hard
@@ -27840,8 +27842,8 @@ __metadata:
linkType: hard
"ldapjs@npm:^2.2.0":
version: 2.3.2
resolution: "ldapjs@npm:2.3.2"
version: 2.3.3
resolution: "ldapjs@npm:2.3.3"
dependencies:
abstract-logging: ^2.0.0
asn1: ^0.2.4
@@ -27851,7 +27853,7 @@ __metadata:
once: ^1.4.0
vasync: ^2.2.0
verror: ^1.8.1
checksum: 4eb7b18839d8fe1d8acc0ba5d2aa71aefcb25ecb6f4f9582299d73faf546984326590c44366f8b148d3a4276707006b1aaffffdc548b3c4ca753e720403da4a5
checksum: 791cf22812805db3888dfc8aa8e4db8337e67387b318522c9965d40e678ecdb64950a6ea5930083590ec3377038620a3e63f90e985173ae6aca40e7f485290e0
languageName: node
linkType: hard