Further RNPM integration
Summary: This commit removes `rnpm` folder that we left during initial merge to keep the diff cleaner. The `core`, `link` and `install` have now the same directory structure as any other command to make development more natural for all of us. From most notable differences: 1) the `src` folder is now gone. The new structure should make it easier for people to work with the stuff and also move us closer to 100% rnpm integration, 2) There's also no `package.json` present in any of the `rnpm` packages, since they are no longer standalone modules, 3) There's no `bugs.url` in link.js since main package.json of React doesn't specify it. Decided to hardcode it to facebook/react-native since it's really unlikely to change. If one would prefer to use pkg.bugs.url as before, a separate PR modifying package.json should be sent. Closes https://github.com/facebook/react-native/pull/9509 Differential Revision: D3751115 fbshipit-source-id: 74ae8330f7634df0887ad676808f47eee4b8de85
This commit is contained in:
parent
25f2a26ce9
commit
0af640bfae
|
@ -11,7 +11,7 @@
|
|||
'use strict';
|
||||
|
||||
const Config = require('./util/Config');
|
||||
const getUserCommands = require('./rnpm/core/src/getCommands');
|
||||
const getUserCommands = require('./core/getCommands');
|
||||
|
||||
export type Command = {
|
||||
name: string,
|
||||
|
@ -37,10 +37,10 @@ const documentedCommands = [
|
|||
require('./library/library'),
|
||||
require('./bundle/bundle'),
|
||||
require('./bundle/unbundle'),
|
||||
require('./rnpm/link/link'),
|
||||
require('./rnpm/link/unlink'),
|
||||
require('./rnpm/install/install'),
|
||||
require('./rnpm/install/uninstall'),
|
||||
require('./link/link'),
|
||||
require('./link/unlink'),
|
||||
require('./install/install'),
|
||||
require('./install/uninstall'),
|
||||
require('./upgrade/upgrade'),
|
||||
require('./logAndroid/logAndroid'),
|
||||
require('./logIOS/logIOS'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const findAndroidAppFolder = require('../../src/config/android/findAndroidAppFolder');
|
||||
const findAndroidAppFolder = require('../../config/android/findAndroidAppFolder');
|
||||
const mockFs = require('mock-fs');
|
||||
const mocks = require('../../__fixtures__/android');
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const findManifest = require('../../src/config/android/findManifest');
|
||||
const findManifest = require('../../config/android/findManifest');
|
||||
const mockFs = require('mock-fs');
|
||||
const mocks = require('../../__fixtures__/android');
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const findPackageClassName = require('../../src/config/android/findPackageClassName');
|
||||
const findPackageClassName = require('../../config/android/findPackageClassName');
|
||||
const mockFs = require('mock-fs');
|
||||
const mocks = require('../../__fixtures__/android');
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const getDependencyConfig = require('../../src/config/android').dependencyConfig;
|
||||
const getDependencyConfig = require('../../config/android').dependencyConfig;
|
||||
const mockFs = require('mock-fs');
|
||||
const mocks = require('../../__fixtures__/android');
|
||||
const userConfig = {};
|
|
@ -1,6 +1,6 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const getProjectConfig = require('../../src/config/android').projectConfig;
|
||||
const getProjectConfig = require('../../config/android').projectConfig;
|
||||
const mockFs = require('mock-fs');
|
||||
const mocks = require('../../__fixtures__/android');
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const findManifest = require('../../src/config/android/findManifest');
|
||||
const readManifest = require('../../src/config/android/readManifest');
|
||||
const findManifest = require('../../config/android/findManifest');
|
||||
const readManifest = require('../../config/android/readManifest');
|
||||
const mockFs = require('mock-fs');
|
||||
const mocks = require('../../__fixtures__/android');
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const findAssets = require('../src/config/findAssets');
|
||||
const findAssets = require('../config/findAssets');
|
||||
const mockFs = require('mock-fs');
|
||||
const dependencies = require('../__fixtures__/dependencies');
|
||||
const isArray = (arg) =>
|
|
@ -1,7 +1,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const path = require('path');
|
||||
const findPlugins = require('../src/findPlugins');
|
||||
const findPlugins = require('../findPlugins');
|
||||
|
||||
const pjsonPath = path.join(process.cwd(), 'package.json');
|
||||
const isArray = (arg) =>
|
|
@ -1,6 +1,6 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const findProject = require('../../src/config/ios/findProject');
|
||||
const findProject = require('../../config/ios/findProject');
|
||||
const mockFs = require('mock-fs');
|
||||
const projects = require('../../__fixtures__/projects');
|
||||
const ios = require('../../__fixtures__/ios');
|
|
@ -1,6 +1,6 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const getProjectConfig = require('../../src/config/ios').projectConfig;
|
||||
const getProjectConfig = require('../../config/ios').projectConfig;
|
||||
const mockFs = require('mock-fs');
|
||||
const projects = require('../../__fixtures__/projects');
|
||||
|
|
@ -5,9 +5,9 @@ jest.setMock('child_process', {
|
|||
on: (ev, cb) => cb(spawnError),
|
||||
}),
|
||||
});
|
||||
jest.dontMock('../src/makeCommand');
|
||||
jest.dontMock('../makeCommand');
|
||||
|
||||
const makeCommand = require('../src/makeCommand');
|
||||
const makeCommand = require('../makeCommand');
|
||||
|
||||
describe('makeCommand', () => {
|
||||
const command = makeCommand('echo');
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
var blacklist = require('../packager/blacklist');
|
||||
var path = require('path');
|
||||
var rnpmConfig = require('./rnpm/core/src/config');
|
||||
var rnpmConfig = require('./core/config');
|
||||
|
||||
/**
|
||||
* Default configuration for the CLI.
|
||||
|
|
|
@ -7,7 +7,7 @@ const spawnOpts = {
|
|||
|
||||
log.heading = 'rnpm-install';
|
||||
|
||||
module.exports = function install(args, config) {
|
||||
function install(args, config) {
|
||||
const name = args[0];
|
||||
|
||||
var res = spawnSync('npm', ['install', name, '--save'], spawnOpts);
|
||||
|
@ -24,3 +24,9 @@ module.exports = function install(args, config) {
|
|||
|
||||
log.info(`Module ${name} has been successfully installed & linked`);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
func: install,
|
||||
description: 'install and link native dependencies',
|
||||
name: 'install <packageName>',
|
||||
};
|
|
@ -7,7 +7,7 @@ const spawnOpts = {
|
|||
|
||||
log.heading = 'rnpm-install';
|
||||
|
||||
module.exports = function install(args, config) {
|
||||
function uninstall(args, config) {
|
||||
const name = args[0];
|
||||
|
||||
var res = spawnSync('rnpm', ['unlink', name], spawnOpts);
|
||||
|
@ -24,3 +24,9 @@ module.exports = function install(args, config) {
|
|||
|
||||
log.info(`Module ${name} has been successfully uninstalled & unlinked`);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
func: uninstall,
|
||||
description: 'uninstall and unlink native dependencies',
|
||||
name: 'uninstall <packageName>',
|
||||
};
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
jest.autoMockOff();
|
||||
|
||||
const applyParams = require('../../src/android/patches/applyParams');
|
||||
const applyParams = require('../../android/patches/applyParams');
|
||||
|
||||
describe('applyParams', () => {
|
||||
it('apply params to the string', () => {
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const path = require('path');
|
||||
const isInstalled = require('../../src/android/isInstalled');
|
||||
const isInstalled = require('../../android/isInstalled');
|
||||
|
||||
const projectConfig = {
|
||||
buildGradlePath: path.join(__dirname, '../../__fixtures__/android/patchedBuild.gradle'),
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
jest.autoMockOff();
|
||||
|
||||
const makeBuildPatch = require('../../src/android/patches/makeBuildPatch');
|
||||
const makeBuildPatch = require('../../android/patches/makeBuildPatch');
|
||||
const name = 'test';
|
||||
|
||||
describe('makeBuildPatch', () => {
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
jest.autoMockOff();
|
||||
|
||||
const makeImportPatch = require('../../src/android/patches/makeImportPatch');
|
||||
const makeImportPatch = require('../../android/patches/makeImportPatch');
|
||||
|
||||
const packageImportPath = 'import some.example.project';
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
jest.autoMockOff();
|
||||
|
||||
const makePackagePatch = require('../../src/android/patches/makePackagePatch');
|
||||
const applyParams = require('../../src/android/patches/applyParams');
|
||||
const makePackagePatch = require('../../android/patches/makePackagePatch');
|
||||
const applyParams = require('../../android/patches/applyParams');
|
||||
|
||||
const packageInstance = 'new SomeLibrary(${foo}, ${bar}, \'something\')';
|
||||
const name = 'some-library';
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const path = require('path');
|
||||
const makeSettingsPatch = require('../../src/android/patches/makeSettingsPatch');
|
||||
const makeSettingsPatch = require('../../android/patches/makeSettingsPatch');
|
||||
|
||||
const name = 'test';
|
||||
const projectConfig = {
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
jest.autoMockOff();
|
||||
|
||||
const getDependencyConfig = require('../src/getDependencyConfig');
|
||||
const getDependencyConfig = require('../getDependencyConfig');
|
||||
const sinon = require('sinon');
|
||||
|
||||
describe('getDependencyConfig', () => {
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
jest.autoMockOff();
|
||||
|
||||
const getProjectDependencies = require('../src/getProjectDependencies');
|
||||
const getProjectDependencies = require('../getProjectDependencies');
|
||||
const path = require('path');
|
||||
|
||||
describe('getProjectDependencies', () => {
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
jest.autoMockOff();
|
||||
|
||||
const groupFilesByType = require('../src/groupFilesByType');
|
||||
const groupFilesByType = require('../groupFilesByType');
|
||||
|
||||
describe('groupFilesByType', () => {
|
||||
|
|
@ -4,7 +4,7 @@ jest.autoMockOff();
|
|||
|
||||
const xcode = require('xcode');
|
||||
const path = require('path');
|
||||
const addFileToProject = require('../../src/ios/addFileToProject');
|
||||
const addFileToProject = require('../../ios/addFileToProject');
|
||||
const _ = require('lodash');
|
||||
|
||||
const project = xcode.project(
|
|
@ -5,7 +5,7 @@ jest.autoMockOff();
|
|||
const xcode = require('xcode');
|
||||
const path = require('path');
|
||||
const PbxFile = require('xcode/lib/pbxFile');
|
||||
const addProjectToLibraries = require('../../src/ios/addProjectToLibraries');
|
||||
const addProjectToLibraries = require('../../ios/addProjectToLibraries');
|
||||
const last = require('lodash').last;
|
||||
|
||||
const project = xcode.project(
|
|
@ -4,8 +4,8 @@ jest.autoMockOff();
|
|||
|
||||
const xcode = require('xcode');
|
||||
const path = require('path');
|
||||
const addSharedLibraries = require('../../src/ios/addSharedLibraries');
|
||||
const getGroup = require('../../src/ios/getGroup');
|
||||
const addSharedLibraries = require('../../ios/addSharedLibraries');
|
||||
const getGroup = require('../../ios/getGroup');
|
||||
|
||||
const project = xcode.project(
|
||||
path.join(__dirname, '../../__fixtures__/project.pbxproj')
|
|
@ -4,8 +4,8 @@ jest.autoMockOff();
|
|||
|
||||
const xcode = require('xcode');
|
||||
const path = require('path');
|
||||
const createGroup = require('../../src/ios/createGroup');
|
||||
const getGroup = require('../../src/ios/getGroup');
|
||||
const createGroup = require('../../ios/createGroup');
|
||||
const getGroup = require('../../ios/getGroup');
|
||||
const last = require('lodash').last;
|
||||
|
||||
const project = xcode.project(
|
|
@ -4,7 +4,7 @@ jest.autoMockOff();
|
|||
|
||||
const xcode = require('xcode');
|
||||
const path = require('path');
|
||||
const getBuildProperty = require('../../src/ios/getBuildProperty');
|
||||
const getBuildProperty = require('../../ios/getBuildProperty');
|
||||
|
||||
const project = xcode.project(
|
||||
path.join(__dirname, '../../__fixtures__/project.pbxproj')
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const xcode = require('xcode');
|
||||
const getGroup = require('../../src/ios/getGroup');
|
||||
const getGroup = require('../../ios/getGroup');
|
||||
const path = require('path');
|
||||
|
||||
const project = xcode.project(
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
jest.autoMockOff();
|
||||
|
||||
const getHeaderSearchPath = require('../../src/ios/getHeaderSearchPath');
|
||||
const getHeaderSearchPath = require('../../ios/getHeaderSearchPath');
|
||||
const path = require('path');
|
||||
|
||||
const SRC_DIR = path.join('react-native-project', 'ios');
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
jest.autoMockOff();
|
||||
|
||||
const getHeadersInFolder = require('../../src/ios/getHeadersInFolder');
|
||||
const getHeadersInFolder = require('../../ios/getHeadersInFolder');
|
||||
|
||||
describe('ios::getHeadersInFolder', () => {
|
||||
xit('should return an array of all headers in given folder', () => {
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const xcode = require('xcode');
|
||||
const getPlist = require('../../src/ios/getPlist');
|
||||
const getPlist = require('../../ios/getPlist');
|
||||
const path = require('path');
|
||||
|
||||
const project = xcode.project(
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const xcode = require('xcode');
|
||||
const getPlistPath = require('../../src/ios/getPlistPath');
|
||||
const getPlistPath = require('../../ios/getPlistPath');
|
||||
const path = require('path');
|
||||
|
||||
const project = xcode.project(
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const xcode = require('xcode');
|
||||
const getProducts = require('../../src/ios/getProducts');
|
||||
const getProducts = require('../../ios/getProducts');
|
||||
const path = require('path');
|
||||
|
||||
const project = xcode.project(
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const xcode = require('xcode');
|
||||
const hasLibraryImported = require('../../src/ios/hasLibraryImported');
|
||||
const hasLibraryImported = require('../../ios/hasLibraryImported');
|
||||
const path = require('path');
|
||||
|
||||
const project = xcode.project(
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const path = require('path');
|
||||
const isInstalled = require('../../src/ios/isInstalled');
|
||||
const isInstalled = require('../../ios/isInstalled');
|
||||
|
||||
const baseProjectConfig = {
|
||||
pbxprojPath: path.join(__dirname, '../../__fixtures__/project.pbxproj'),
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const xcode = require('xcode');
|
||||
const mapHeaderSearchPaths = require('../../src/ios/mapHeaderSearchPaths');
|
||||
const mapHeaderSearchPaths = require('../../ios/mapHeaderSearchPaths');
|
||||
const path = require('path');
|
||||
|
||||
const project = xcode.project(
|
|
@ -4,8 +4,8 @@ jest.autoMockOff();
|
|||
|
||||
const xcode = require('xcode');
|
||||
const PbxFile = require('xcode/lib/pbxFile');
|
||||
const addProjectToLibraries = require('../../src/ios/addProjectToLibraries');
|
||||
const removeProjectFromLibraries = require('../../src/ios/removeProjectFromLibraries');
|
||||
const addProjectToLibraries = require('../../ios/addProjectToLibraries');
|
||||
const removeProjectFromLibraries = require('../../ios/removeProjectFromLibraries');
|
||||
const last = require('lodash').last;
|
||||
const path = require('path');
|
||||
|
|
@ -4,8 +4,8 @@ jest.autoMockOff();
|
|||
|
||||
const xcode = require('xcode');
|
||||
const pbxFile = require('xcode/lib/pbxFile');
|
||||
const addFileToProject = require('../../src/ios/addFileToProject');
|
||||
const removeProjectFromProject = require('../../src/ios/removeProjectFromProject');
|
||||
const addFileToProject = require('../../ios/addFileToProject');
|
||||
const removeProjectFromProject = require('../../ios/removeProjectFromProject');
|
||||
const path = require('path');
|
||||
|
||||
const project = xcode.project(
|
|
@ -4,9 +4,9 @@ jest.autoMockOff();
|
|||
|
||||
const xcode = require('xcode');
|
||||
const path = require('path');
|
||||
const addSharedLibraries = require('../../src/ios/addSharedLibraries');
|
||||
const removeSharedLibraries = require('../../src/ios/removeSharedLibraries');
|
||||
const getGroup = require('../../src/ios/getGroup');
|
||||
const addSharedLibraries = require('../../ios/addSharedLibraries');
|
||||
const removeSharedLibraries = require('../../ios/removeSharedLibraries');
|
||||
const getGroup = require('../../ios/getGroup');
|
||||
|
||||
const project = xcode.project(
|
||||
path.join(__dirname, '../../__fixtures__/project.pbxproj')
|
|
@ -8,7 +8,7 @@ const path = require('path');
|
|||
|
||||
describe('link', () => {
|
||||
beforeEach(() => {
|
||||
delete require.cache[require.resolve('../src/link')];
|
||||
delete require.cache[require.resolve('../link')];
|
||||
log.level = 'silent';
|
||||
});
|
||||
|
||||
|
@ -19,7 +19,7 @@ describe('link', () => {
|
|||
},
|
||||
};
|
||||
|
||||
const link = require('../src/link');
|
||||
const link = require('../link').func;
|
||||
link([], config).catch(() => done());
|
||||
});
|
||||
|
||||
|
@ -29,7 +29,7 @@ describe('link', () => {
|
|||
getDependencyConfig: sinon.stub().returns({ assets: [], commands: {} }),
|
||||
};
|
||||
|
||||
const link = require('../src/link');
|
||||
const link = require('../link').func;
|
||||
link(['react-native-gradient'], config).then(() => {
|
||||
expect(
|
||||
config.getDependencyConfig.calledWith('react-native-gradient')
|
||||
|
@ -53,7 +53,7 @@ describe('link', () => {
|
|||
}
|
||||
);
|
||||
|
||||
const link = require('../src/link');
|
||||
const link = require('../link').func;
|
||||
link([], config).then(() => {
|
||||
expect(
|
||||
config.getDependencyConfig.calledWith('react-native-test')
|
||||
|
@ -71,26 +71,26 @@ describe('link', () => {
|
|||
};
|
||||
|
||||
jest.setMock(
|
||||
'../src/android/isInstalled.js',
|
||||
'../android/isInstalled.js',
|
||||
sinon.stub().returns(false)
|
||||
);
|
||||
|
||||
jest.setMock(
|
||||
'../src/android/registerNativeModule.js',
|
||||
'../android/registerNativeModule.js',
|
||||
registerNativeModule
|
||||
);
|
||||
|
||||
jest.setMock(
|
||||
'../src/ios/isInstalled.js',
|
||||
'../ios/isInstalled.js',
|
||||
sinon.stub().returns(false)
|
||||
);
|
||||
|
||||
jest.setMock(
|
||||
'../src/ios/registerNativeModule.js',
|
||||
'../ios/registerNativeModule.js',
|
||||
registerNativeModule
|
||||
);
|
||||
|
||||
const link = require('../src/link');
|
||||
const link = require('../link').func;
|
||||
|
||||
link(['react-native-blur'], config).then(() => {
|
||||
expect(registerNativeModule.calledTwice).toBeTruthy();
|
||||
|
@ -107,26 +107,26 @@ describe('link', () => {
|
|||
};
|
||||
|
||||
jest.setMock(
|
||||
'../src/ios/isInstalled.js',
|
||||
'../ios/isInstalled.js',
|
||||
sinon.stub().returns(true)
|
||||
);
|
||||
|
||||
jest.setMock(
|
||||
'../src/android/isInstalled.js',
|
||||
'../android/isInstalled.js',
|
||||
sinon.stub().returns(true)
|
||||
);
|
||||
|
||||
jest.setMock(
|
||||
'../src/ios/registerNativeModule.js',
|
||||
'../ios/registerNativeModule.js',
|
||||
registerNativeModule
|
||||
);
|
||||
|
||||
jest.setMock(
|
||||
'../src/android/registerNativeModule.js',
|
||||
'../android/registerNativeModule.js',
|
||||
registerNativeModule
|
||||
);
|
||||
|
||||
const link = require('../src/link');
|
||||
const link = require('../link').func;
|
||||
|
||||
link(['react-native-blur'], config).then(() => {
|
||||
expect(registerNativeModule.callCount).toEqual(0);
|
||||
|
@ -140,12 +140,12 @@ describe('link', () => {
|
|||
const postlink = sinon.stub().yieldsAsync();
|
||||
|
||||
jest.setMock(
|
||||
'../src/ios/registerNativeModule.js',
|
||||
'../ios/registerNativeModule.js',
|
||||
registerNativeModule
|
||||
);
|
||||
|
||||
jest.setMock(
|
||||
'../src/ios/isInstalled.js',
|
||||
'../ios/isInstalled.js',
|
||||
sinon.stub().returns(false)
|
||||
);
|
||||
|
||||
|
@ -156,7 +156,7 @@ describe('link', () => {
|
|||
}),
|
||||
};
|
||||
|
||||
const link = require('../src/link');
|
||||
const link = require('../link').func;
|
||||
|
||||
link(['react-native-blur'], config).then(() => {
|
||||
expect(prelink.calledBefore(registerNativeModule)).toBeTruthy();
|
||||
|
@ -172,7 +172,7 @@ describe('link', () => {
|
|||
const copyAssets = sinon.stub();
|
||||
|
||||
jest.setMock(
|
||||
'../src/ios/copyAssets.js',
|
||||
'../ios/copyAssets.js',
|
||||
copyAssets
|
||||
);
|
||||
|
||||
|
@ -181,7 +181,7 @@ describe('link', () => {
|
|||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||
};
|
||||
|
||||
const link = require('../src/link');
|
||||
const link = require('../link').func;
|
||||
|
||||
link(['react-native-blur'], config).then(() => {
|
||||
expect(copyAssets.calledOnce).toBeTruthy();
|
|
@ -3,7 +3,7 @@
|
|||
jest.autoMockOff();
|
||||
|
||||
const sinon = require('sinon');
|
||||
const promiseWaterfall = require('../src/promiseWaterfall');
|
||||
const promiseWaterfall = require('../promiseWaterfall');
|
||||
|
||||
describe('promiseWaterfall', () => {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue