Repository: ember-cli/ember-try (js)

Issue:
`ember try:reset` with workspaces
I've tried running `ember try:reset` within a monorepo with yarn workspaces and I'm seeing the following error

```
TypeError: Cannot read property 'map' of undefined
/node_modules/ember-try/lib/dependency-manager-adapters/workspace.js:90:43
/node_modules/ember-try/lib/utils/scenario-manager.js:40:25
...
```

It looks like `this._packageAdapters` is `undefined`?

https://github.com/ember-cli/ember-try/blob/aa4e3fff85b538f3b1aa77b00af0add6bc7d6f94/lib/dependency-manager-adapters/workspace.js#L88-L90

It looks like the package adapters are initialised in `setup()`

https://github.com/ember-cli/ember-try/blob/aa4e3fff85b538f3b1aa77b00af0add6bc7d6f94/lib/dependency-manager-adapters/workspace.js#L52-L60

In the tests `setup()` is run before `cleanup()`, so either the tests are assuming `setup()` is run first and it isn't, or the package adapters should be initialised in both `setup()` and `cleanup()`?

https://github.com/ember-cli/ember-try/blob/aa4e3fff85b538f3b1aa77b00af0add6bc7d6f94/test/dependency-manager-adapters/workspace-adapter-test.js#L210-L219

I can put together a PR, but I'm still figuring out what order things run in..

Pull request description:
Ensure Yarn Workspace adapter supports `ember try:reset`.
Fundamentally, `Adapter.prototype.cleanup` **cannot** require `Adatper.prototype.setup` to have been called. _Most_ of the time `.setup` is called before `.cleanup` (this happens with `ember try:each` and `ember try:one`), but when `--skip-cleanup` is specified (e.g.  `ember try:one scenario-name --skip-cleanup`) and you subsequently run `ember try:reset` the `.setup` happened in a completely different process.

The issue here is a misunderstanding when we added the `WorkspaceAdapter` initially. Basically, the assumtion was that `.setup` was for setting up both local instance state (e.g. the `this._packageAdapters` array) **and** for actually preparing for a `ember try:...` run (doing backups / etc).

The fix is to move the internal state setup code directly into `init`/`constructor, and ensure that `.setup` is only used to create the backups themselves.

Fixes #466

Patch:
diff --git a/lib/dependency-manager-adapters/workspace.js b/lib/dependency-manager-adapters/workspace.js
index d251b94..88d299c 100644
--- a/lib/dependency-manager-adapters/workspace.js
+++ b/lib/dependency-manager-adapters/workspace.js
@@ -18,15 +18,6 @@ module.exports = CoreObject.extend({
     if (!this.useYarnCommand) {
       throw new Error('workspaces are currently only supported by Yarn, you must set `useYarn` to true');
     }
-  },
-
-  packageJSON: 'package.json',
-
-  setup(options) {
-    if (!options) {
-      options = {};
-    }
-
     let packageJSON = JSON.parse(fs.readFileSync(this.packageJSON));
     let workspaceGlobs;
 
@@ -59,6 +50,15 @@ module.exports = CoreObject.extend({
       });
     });
 
+  },
+
+  packageJSON: 'package.json',
+
+  setup(options) {
+    if (!options) {
+      options = {};
+    }
+
     return RSVP.all(this._packageAdapters.map(adapter => adapter.setup(options)));
   },
 


Test patch:
diff --git a/test/dependency-manager-adapters/workspace-adapter-test.js b/test/dependency-manager-adapters/workspace-adapter-test.js
index 5422b63..2c794f5 100644
--- a/test/dependency-manager-adapters/workspace-adapter-test.js
+++ b/test/dependency-manager-adapters/workspace-adapter-test.js
@@ -195,6 +195,29 @@ describe('workspaceAdapter', () => {
   });
 
   describe('#cleanup', () => {
+    it('works without having called #setup first', () => {
+      fs.ensureDirSync('packages/test/node_modules');
+
+      writeJSONFile('packages/test/package.json', { originalPackageJSON: false });
+      writeJSONFile('packages/test/node_modules/prove-it.json', { originalNodeModules: false });
+
+      let workspaceAdapter = new WorkspaceAdapter({
+        cwd: tmpdir,
+        useYarnCommand: true,
+        run: () => Promise.resolve(),
+      });
+
+      fs.ensureDirSync('packages/test/.node_modules.ember-try');
+
+      writeJSONFile('packages/test/package.json.ember-try', { originalPackageJSON: true });
+      writeJSONFile('packages/test/.node_modules.ember-try/prove-it.json', { originalNodeModules: true });
+
+      return workspaceAdapter.cleanup().then(() => {
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/package.json'), { originalPackageJSON: true });
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/node_modules/prove-it.json'), { originalNodeModules: true });
+      });
+    });
+
     it('replaces the package.json with the backed up version', () => {
       fs.ensureDirSync('packages/test/node_modules');
 
diff --git a/test/utils/dependency-manager-adapter-factory-test.js b/test/utils/dependency-manager-adapter-factory-test.js
index 851e1b3..90383fe 100644
--- a/test/utils/dependency-manager-adapter-factory-test.js
+++ b/test/utils/dependency-manager-adapter-factory-test.js
@@ -1,10 +1,30 @@
 'use strict';
 
+const path = require('path');
+const fs = require('fs-extra');
+const tmp = require('tmp-sync');
 const expect = require('chai').expect;
 const DependencyManagerAdapterFactory = require('../../lib/utils/dependency-manager-adapter-factory');
 const WorkspaceAdapter = require('../../lib/dependency-manager-adapters/workspace');
+let writeJSONFile = require('../helpers/write-json-file');
+
+const ROOT = process.cwd();
+let tmproot = path.join(ROOT, 'tmp');
 
 describe('DependencyManagerAdapterFactory', () => {
+  let tmpdir;
+
+  beforeEach(() => {
+    tmpdir = tmp.in(tmproot);
+    process.chdir(tmpdir);
+  });
+
+  afterEach(() => {
+    process.chdir(ROOT);
+
+    return fs.remove(tmproot);
+  });
+
   describe('generateFromConfig', () => {
     it('creates both adapters, in order, when there is only an npm key', () => {
       let adapters = DependencyManagerAdapterFactory.generateFromConfig({ scenarios: [{ npm: {} }] }, 'here');
@@ -42,11 +62,19 @@ describe('DependencyManagerAdapterFactory', () => {
     });
 
     it('creates only a workspace adapter when useWorkspaces is set to true', () => {
-      let adapters = DependencyManagerAdapterFactory.generateFromConfig({
-        useYarn: true,
-        useWorkspaces: true,
-        scenarios: [{ npm: {} }]
-      });
+      writeJSONFile('package.json', { workspaces: ['packages/test'] });
+
+      fs.ensureDirSync('packages/test');
+      writeJSONFile('packages/test/package.json', {});
+
+      let adapters = DependencyManagerAdapterFactory.generateFromConfig(
+        {
+          useYarn: true,
+          useWorkspaces: true,
+          scenarios: [{ npm: {} }]
+        },
+        tmpdir
+      );
       expect(adapters[0]).to.be.instanceOf(WorkspaceAdapter);
       expect(adapters.length).to.equal(1);
     });