From 0b7936c88e901b731c4fbf7f01604fce8a02f854 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 14 Dec 2018 08:24:19 -0500 Subject: [PATCH 1/7] Pin codecov package to the lastest master --- package-lock.json | 79 ++++++++++++++++++++++++++++++++++++++++++++--- package.json | 2 +- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index eef33d95bb..31ec405425 100644 --- a/package-lock.json +++ b/package-lock.json @@ -244,6 +244,15 @@ "acorn": "^5.0.3" } }, + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, "ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", @@ -2016,15 +2025,14 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "codecov": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.1.0.tgz", - "integrity": "sha512-aWQc/rtHbcWEQLka6WmBAOpV58J2TwyXqlpAQGhQaSiEUoigTTUk6lLd2vB3kXkhnDyzyH74RXfmV4dq2txmdA==", + "version": "github:codecov/codecov-node#e427d900309adb50746a39a50aa7d80071a5ddd0", + "from": "github:codecov/codecov-node#e427d90", "dev": true, "requires": { "argv": "^0.0.2", "ignore-walk": "^3.0.1", "js-yaml": "^3.12.0", - "request": "^2.87.0", + "teeny-request": "^3.7.0", "urlgrey": "^0.4.4" }, "dependencies": { @@ -2854,6 +2862,21 @@ "is-symbol": "^1.0.1" } }, + "es6-promise": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", + "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -4024,6 +4047,33 @@ "sshpk": "^1.7.0" } }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, "iconv-lite": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", @@ -5082,7 +5132,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -7693,6 +7743,25 @@ "xtend": "^4.0.0" } }, + "teeny-request": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", + "integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1", + "node-fetch": "^2.2.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, "temp": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", diff --git a/package.json b/package.json index 33e7651c5e..5b0603a104 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "babel-plugin-istanbul": "4.1.6", "chai": "4.1.2", "chai-as-promised": "7.1.1", - "codecov": "3.1.0", + "codecov": "codecov/codecov-node#e427d90", "cross-env": "5.2.0", "cross-unzip": "0.2.1", "dedent-js": "1.0.1", From 902c1a70b823dbe3999f368b06bb12bc6cafa6c0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 14 Dec 2018 09:07:57 -0500 Subject: [PATCH 2/7] :fire: an autobind call --- lib/atom/atom-text-editor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index abf5164906..32d410bfdc 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -5,7 +5,7 @@ import {CompositeDisposable} from 'event-kit'; import RefHolder from '../models/ref-holder'; import {RefHolderPropType} from '../prop-types'; -import {autobind, extractProps} from '../helpers'; +import {extractProps} from '../helpers'; const editorUpdateProps = { mini: PropTypes.bool, @@ -28,7 +28,7 @@ export default class AtomTextEditor extends React.Component { static propTypes = { ...editorCreationProps, - workspace: PropTypes.object.isRequired, // FIXME make more specific + workspace: PropTypes.object.isRequired, didChangeCursorPosition: PropTypes.func, didAddSelection: PropTypes.func, @@ -98,7 +98,7 @@ export default class AtomTextEditor extends React.Component { this.subs.dispose(); } - observeSelections(selection) { + observeSelections = selection => { const selectionSubs = new CompositeDisposable( selection.onDidChangeRange(this.props.didChangeSelectionRange), selection.onDidDestroy(() => { From 2647651c4b4f8c3326fdfeaf9b2962e35e6d9a26 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 14 Dec 2018 10:22:18 -0500 Subject: [PATCH 3/7] Cover some of the Present state --- lib/models/repository-states/present.js | 3 + test/models/repository.test.js | 134 +++++++++++++++++++++++- 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index c591d25c7e..830c18280e 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -43,6 +43,7 @@ export default class Present extends State { this.commitMessageTemplate = null; this.fetchInitialMessage(); + /* istanbul ignore else */ if (history) { this.discardHistory.updateHistory(history); } @@ -165,6 +166,7 @@ export default class Present extends State { keys.add(Keys.statusBundle); } + /* istanbul ignore else */ if (keys.size > 0) { this.cache.invalidate(Array.from(keys)); this.didUpdate(); @@ -557,6 +559,7 @@ export default class Present extends State { destructiveAction, partialDiscardFilePath, ); + /* istanbul ignore else */ if (snapshots) { await this.saveDiscardHistory(); } diff --git a/test/models/repository.test.js b/test/models/repository.test.js index 77e3aa2a7c..cfbf9df9b0 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -6,6 +6,7 @@ import compareSets from 'compare-sets'; import isEqualWith from 'lodash.isequalwith'; import Repository from '../../lib/models/repository'; +import CompositeGitStrategy from '../../lib/composite-git-strategy'; import {nullCommit} from '../../lib/models/commit'; import {nullOperationStates} from '../../lib/models/operation-states'; import Author from '../../lib/models/author'; @@ -136,6 +137,25 @@ describe('Repository', function() { }); }); + it('accesses an OperationStates model', async function() { + const repository = new Repository(await cloneRepository()); + await repository.getLoadPromise(); + + const os = repository.getOperationStates(); + assert.isFalse(os.isPushInProgress()); + assert.isFalse(os.isPullInProgress()); + assert.isFalse(os.isFetchInProgress()); + assert.isFalse(os.isCommitInProgress()); + assert.isFalse(os.isCheckoutInProgress()); + }); + + it('shows status bar tiles once present', async function() { + const repository = new Repository(await cloneRepository()); + assert.isFalse(repository.showStatusBarTiles()); + await repository.getLoadPromise(); + assert.isTrue(repository.showStatusBarTiles()); + }); + describe('getGitDirectoryPath', function() { it('returns the correct git directory path', async function() { const workingDirPath = await cloneRepository('three-files'); @@ -173,6 +193,14 @@ describe('Repository', function() { assert.isTrue(repo.isPresent()); assert.equal(repo.getWorkingDirectoryPath(), soonToBeRepositoryPath); }); + + it('fails with an error when a repository is already present', async function() { + const workdir = await cloneRepository(); + const repository = new Repository(workdir); + await repository.getLoadPromise(); + + await assert.isRejected(repository.init()); + }); }); describe('clone', function() { @@ -198,6 +226,16 @@ describe('Repository', function() { assert.isTrue(repo.isPresent()); assert.equal(repo.getWorkingDirectoryPath(), destDir); }); + + it('fails with an error when a repository is already present', async function() { + const upstream = await cloneRepository(); + + const workdir = await cloneRepository(); + const repository = new Repository(workdir); + await repository.getLoadPromise(); + + await assert.isRejected(repository.clone(upstream)); + }); }); describe('staging and unstaging files', function() { @@ -1328,6 +1366,20 @@ describe('Repository', function() { }); }); + it('checks out one side or another', async function() { + const workingDirPath = await cloneRepository('merge-conflict'); + const repo = new Repository(workingDirPath); + await repo.getLoadPromise(); + await assert.isRejected(repo.git.merge('origin/branch')); + + repo.refresh(); + assert.isTrue(await repo.pathHasMergeMarkers('modified-on-both-ours.txt')); + + await repo.checkoutSide('ours', ['modified-on-both-ours.txt']); + + assert.isFalse(await repo.pathHasMergeMarkers('modified-on-both-ours.txt')); + }); + describe('abortMerge()', function() { describe('when the working directory is clean', function() { it('resets the index and the working directory to match HEAD', async function() { @@ -2174,13 +2226,68 @@ describe('Repository', function() { }); }); - describe('updating commit message', function() { + describe('commit message', function() { let sub; afterEach(function() { sub && sub.dispose(); }); + describe('initial state', function() { + let workdir; + + beforeEach(async function() { + workdir = await cloneRepository(); + }); + + it('is initialized to the merge message if one is present', async function() { + await fs.writeFile(path.join(workdir, '.git/MERGE_MSG'), 'sup', {encoding: 'utf8'}); + + const repository = new Repository(workdir); + await repository.getLoadPromise(); + + await assert.async.strictEqual(repository.getCommitMessage(), 'sup'); + }); + + it('is initialized to the commit message template if one is present', async function() { + await fs.writeFile(path.join(workdir, 'template'), 'hai', {encoding: 'utf8'}); + await CompositeGitStrategy.create(workdir).setConfig('commit.template', path.join(workdir, 'template')); + + const repository = new Repository(workdir); + await repository.getLoadPromise(); + await new Promise(resolve => { + sub = repository.onDidUpdate(() => { + sub.dispose(); + resolve(); + }); + }); + + await assert.async.strictEqual(repository.getCommitMessage(), 'hai'); + }); + }); + + describe('update broadcast', function() { + it('broadcasts an update when set', async function() { + const repository = new Repository(await cloneRepository()); + await repository.getLoadPromise(); + const didUpdate = sinon.spy(); + sub = repository.onDidUpdate(didUpdate); + + repository.setCommitMessage('new message'); + assert.isTrue(didUpdate.called); + }); + + it('may suppress the update when set', async function() { + const repository = new Repository(await cloneRepository()); + await repository.getLoadPromise(); + const didUpdate = sinon.spy(); + sub = repository.onDidUpdate(didUpdate); + + repository.setCommitMessage('quietly now', {suppressUpdate: true}); + assert.isFalse(didUpdate.called); + }); + }); + describe('updateCommitMessageAfterFileSystemChange', function() { it('handles events with no `path` property', async function() { const {repository} = await wireUpObserver(); @@ -2213,6 +2320,31 @@ describe('Repository', function() { ); await assert.async.strictEqual(repository.getCommitMessage(), fs.readFileSync(templatePath, 'utf8')); }); + + it('leaves the commit message alone if the template content did not change', async function() { + const {repository, observer, subscriptions} = await wireUpObserver(); + sub = subscriptions; + await observer.start(); + + const templateOnePath = path.join(repository.getWorkingDirectoryPath(), 'the-template-0.txt'); + const templateTwoPath = path.join(repository.getWorkingDirectoryPath(), 'the-template-1.txt'); + const templateContent = 'the same'; + + await Promise.all( + [templateOnePath, templateTwoPath].map(p => fs.writeFile(p, templateContent, {encoding: 'utf8'})), + ); + + await repository.git.setConfig('commit.template', templateOnePath); + await expectEvents(repository, path.join('.git', 'config')); + await assert.async.strictEqual(repository.getCommitMessage(), 'the same'); + + repository.setCommitMessage('different'); + + await repository.git.setConfig('commit.template', templateTwoPath); + await expectEvents(repository, path.join('.git', 'config')); + assert.strictEqual(repository.getCommitMessage(), 'different'); + }); + it('updates commit message to empty string if commit.template is unset', async function() { const {repository, observer, subscriptions} = await wireUpObserver(); sub = subscriptions; From d56d1d8c8d17d1de194e38b440ca3a520a09197e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 14 Dec 2018 10:27:07 -0500 Subject: [PATCH 4/7] Actually remove autobind call --- lib/atom/atom-text-editor.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index 32d410bfdc..8d180480ac 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -50,7 +50,6 @@ export default class AtomTextEditor extends React.Component { constructor(props) { super(props); - autobind(this, 'observeSelections'); this.subs = new CompositeDisposable(); From c623c64b44799c9c1e8bed963bee28a332631141 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 14 Dec 2018 10:55:50 -0500 Subject: [PATCH 5/7] Cover that last line in AtomTextEditor --- test/atom/atom-text-editor.test.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/atom/atom-text-editor.test.js b/test/atom/atom-text-editor.test.js index 23f764074a..a2d8cb7e78 100644 --- a/test/atom/atom-text-editor.test.js +++ b/test/atom/atom-text-editor.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import {mount} from 'enzyme'; +import {mount, shallow} from 'enzyme'; import {TextBuffer} from 'atom'; import RefHolder from '../../lib/models/ref-holder'; @@ -35,6 +35,12 @@ describe('AtomTextEditor', function() { assert.isTrue(workspace.isTextEditor(app.instance().refModel.get())); }); + it('returns undefined if the current model is unavailable', function() { + const emptyHolder = new RefHolder(); + const app = shallow(); + assert.isUndefined(app.instance().getModel()); + }); + it('configures the created text editor with props', function() { mount( Date: Fri, 14 Dec 2018 11:00:02 -0500 Subject: [PATCH 6/7] Remove autobind in Decoration --- lib/atom/decoration.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/atom/decoration.js b/lib/atom/decoration.js index 9e3049f1a2..cd3cbead27 100644 --- a/lib/atom/decoration.js +++ b/lib/atom/decoration.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import {Disposable} from 'event-kit'; import cx from 'classnames'; -import {createItem, autobind, extractProps} from '../helpers'; +import {createItem, extractProps} from '../helpers'; import {RefHolderPropType} from '../prop-types'; import {TextEditorContext} from './atom-text-editor'; import {DecorableContext} from './marker'; @@ -40,8 +40,6 @@ class BareDecoration extends React.Component { constructor(props, context) { super(props, context); - autobind(this, 'observeParents'); - this.decorationHolder = new RefHolder(); this.editorSub = new Disposable(); this.decorableSub = new Disposable(); @@ -93,7 +91,7 @@ class BareDecoration extends React.Component { } } - observeParents() { + observeParents = () => { this.decorationHolder.map(decoration => decoration.destroy()); const editorValid = this.props.editorHolder.map(editor => !editor.isDestroyed()).getOr(false); From e5b50b319f9a5bb331ec906a0581e5bf7a4c2e40 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 14 Dec 2018 12:48:35 -0500 Subject: [PATCH 7/7] Enable builds for all branches and PRs --- azure-pipelines.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ed16668ac6..bbc2bc05c3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,14 +1,3 @@ -trigger: - branches: - include: - - master - - releases/* - -pr: - branches: - include: - - "*" - jobs: - job: Linux pool: