Merge remote-tracking branch 'origin/master' into entity-ref-link
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-user-settings': patch
|
||||
---
|
||||
|
||||
Prevent `.set()` to execute a request to the StorageClient if the user is `guest`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Initializes a git repository when creating an app using @packages/create-app
|
||||
+1
-1
@@ -9,7 +9,7 @@ search:
|
||||
- plugins/search/**/*
|
||||
- plugins/search-*/**/*
|
||||
- packages/search-*/**/*
|
||||
docs-like-code:
|
||||
techdocs:
|
||||
- plugins/techdocs/**/*
|
||||
- plugins/techdocs-*/**/*
|
||||
- packages/techdocs-*/**/*
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
@@ -41,6 +41,11 @@ 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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -3637,11 +3637,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
|
||||
@@ -11140,8 +11142,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
|
||||
@@ -11153,7 +11155,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
|
||||
|
||||
@@ -13797,11 +13799,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
|
||||
|
||||
@@ -15319,12 +15321,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
|
||||
|
||||
@@ -18753,9 +18755,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
|
||||
|
||||
@@ -23710,8 +23712,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
|
||||
@@ -23722,7 +23724,7 @@ __metadata:
|
||||
gtoken: ^6.1.0
|
||||
jws: ^4.0.0
|
||||
lru-cache: ^6.0.0
|
||||
checksum: 0d80d7e136e672055e44fdb44f9e13843a554cc531a01deb1b0da6b78427778785faa7377ed85d840208bb61878cd7d69902172886476bd49ea67e645729570a
|
||||
checksum: 5ab2904f5da3c119a7c241a1d5a11640468a7da58dfcec8a9cad181cc2723e6662b3c65997906069852d9fa066ba3e4b7f14e11cbb80d541e320b66ead6777dc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -27722,8 +27724,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
|
||||
@@ -27733,7 +27735,7 @@ __metadata:
|
||||
once: ^1.4.0
|
||||
vasync: ^2.2.0
|
||||
verror: ^1.8.1
|
||||
checksum: 4eb7b18839d8fe1d8acc0ba5d2aa71aefcb25ecb6f4f9582299d73faf546984326590c44366f8b148d3a4276707006b1aaffffdc548b3c4ca753e720403da4a5
|
||||
checksum: 791cf22812805db3888dfc8aa8e4db8337e67387b318522c9965d40e678ecdb64950a6ea5930083590ec3377038620a3e63f90e985173ae6aca40e7f485290e0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user