Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,9 @@
"dependencies": {
"debug": "^3.0.0",
"git-diff-apply": "^0.4.0",
"rfc6902-ordered": "^1.0.0",
"semver": "^5.4.1",
"three-way-merger": "^0.3.0",
"yargs": "^8.0.2"
},
"devDependencies": {
Expand Down
82 changes: 82 additions & 0 deletions src/auto-merge-package-json.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
'use strict';

const EOL = require('os').EOL;
const ThreeWayMerger = require('three-way-merger');
const rfc6902 = require('rfc6902-ordered');

const dependencyKeys = [
'dependencies',
'devDependencies',
'peerDependencies',
'bundledDependencies',
'optionalDependencies'
];

function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}

function sortObjectKeys(obj) {
return Object.keys(obj).sort().reduce((sorted, key) => {
sorted[key] = obj[key];
return sorted;
}, {});
}

function applyDependencyOperations(operations, deps) {
operations.add.forEach(dep => deps[dep.name] = dep.version);
operations.remove.forEach(dep => delete deps[dep.name]);
operations.change.forEach(dep => deps[dep.name] = dep.version);
}

function mergeDependencyChanges(source, ours, theirs) {
let mergeOperations = ThreeWayMerger.merge({ source, ours, theirs });

// get a fresh copy so we don't mutate the passed in arg
let result = clone(ours);

dependencyKeys.forEach(dependencyKey => {
// we could be missing the key and need to add to it
if (!result[dependencyKey]) {
result[dependencyKey] = {};
}

applyDependencyOperations(mergeOperations[dependencyKey], result[dependencyKey]);

if (!Object.keys(result[dependencyKey]).length) {
delete result[dependencyKey];
} else {
result[dependencyKey] = sortObjectKeys(result[dependencyKey]);
}
});

return result;
}

function mergeNonDependencyChanges(source, ours, theirs) {
let fromSourceToTheirs = rfc6902.createPatch(source, theirs);

rfc6902.applyPatch(ours, fromSourceToTheirs, theirs);

return ours;
}

function stringify(value) {
return JSON.stringify(value, null, 2).replace(/\n/g, EOL) + EOL;
}

module.exports = function autoMergePackageJson(_currentPackageJson, _fromPackageJson, _toPackageJson) {
let currentPackageJson = JSON.parse(_currentPackageJson);
let fromPackageJson = JSON.parse(_fromPackageJson);
let toPackageJson = JSON.parse(_toPackageJson);

let mergedDependenciesPackageJson = mergeDependencyChanges(fromPackageJson, currentPackageJson, toPackageJson);
let mergedOtherPackageJson = mergeNonDependencyChanges(fromPackageJson, currentPackageJson, toPackageJson);

let finalMergedPackageJson = clone(mergedOtherPackageJson);
dependencyKeys.forEach(dependencyKey => {
finalMergedPackageJson[dependencyKey] = mergedDependenciesPackageJson[dependencyKey];
});

return stringify(finalMergedPackageJson);
};
19 changes: 18 additions & 1 deletion src/index.js
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
'use strict';

const fs = require('fs');
const getPackageVersion = require('./get-package-version');
const getProjectVersion = require('./get-project-version');
const getTagVersion = require('./get-tag-version');
const getProjectType = require('./get-project-type');
const autoMergePackageJson = require('./auto-merge-package-json');
const gitDiffApply = require('git-diff-apply');
const run = require('./run');

Expand DownExpand Up@@ -40,6 +42,21 @@ module.exports = function emberCliUpdate(options) {
remoteUrl,
startTag,
endTag,
ignoreConflicts
ignoreConflicts,
ignoredFiles: ['package.json']
}).then(results => {
let myPackageJson = fs.readFileSync('package.json', 'utf8');
let fromPackageJson = results.from['package.json'];
let toPackageJson = results.to['package.json'];

let newPackageJson = autoMergePackageJson(myPackageJson, fromPackageJson, toPackageJson);

fs.writeFileSync('package.json', newPackageJson);

run('git add package.json');
}).catch(err => {
require('debug')('ember-cli-update')(err);

throw err;
});
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"a": "2"
}
}
5 changes: 5 additions & 0 deletions test/fixtures/package.json/adds-dependencies/to/package.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"a": "2"
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"version": "1.0.0",
"name": "bar",
"baz": false
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"version": "1.0.0",
"name": "bar",
"baz": false
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
{
"foo": true,
"version": "1.0.0",
"name": "bar",
"baz": false
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
{
"foo": true,
"version": "1.0.0",
"name": "bar",
"baz": false
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"a": "1"
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"a": "1"
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"a": "1"
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"a": "1"
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"a": "2"
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"a": "2"
}
}
42 changes: 42 additions & 0 deletions test/unit/auto-merge-package-json-test.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
'use strict';

const expect = require('chai').expect;
const fs = require('fs');
const path = require('path');
const autoMergePackageJson = require('../../src/auto-merge-package-json');

const fixturesPath = 'test/fixtures/package.json';

function getFixtures(fixturesDir) {
let fixtures = path.join(fixturesPath, fixturesDir);
return fs.readdirSync(fixtures).reduce((result, name) => {
result[name] = fs.readFileSync(path.join(fixtures, name, 'package.json'), 'utf8');
return result;
}, {});
}

describe('Unit - autoMergePackageJson', function() {
function forEachDir(callback) {
fs.readdirSync(fixturesPath).forEach(fixtureDir => {
let it = global.it;
if (fixtureDir.indexOf('_') === 0) {
it = it.only;
}
callback(it, fixtureDir);
});
}

forEachDir((it, fixturesDir) => {
it(fixturesDir, function() {
let fixtures = getFixtures(fixturesDir);
let from = fixtures.from;
let my = fixtures.my;
let result = fixtures.result;
let to = fixtures.to;

let actual = autoMergePackageJson(my, from, to);

expect(actual).to.equal(result);
});
});
});