Skip to content

Commit 458be26

Browse files
dan1wangsoldair
authored andcommitted
fix: npx command on Windows and make sure build/test work on Windows too (#306)
* Windows CI fix (#2) Make sure `npx gts init` runs `npm.cmd` on Windows. Necessary changes to test/ files so they will pass on Windows * chore: delete azure pipelines yml
1 parent 3341576 commit 458be26

File tree

8 files changed

+149
-40
lines changed

8 files changed

+149
-40
lines changed

package-lock.json

Lines changed: 98 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"write-file-atomic": "^2.3.0"
5454
},
5555
"devDependencies": {
56+
"@types/fs-extra": "^5.0.5",
5657
"@npm/types": "^1.0.1",
5758
"@types/diff": "^4.0.0",
5859
"@types/entities": "^1.1.0",
@@ -70,6 +71,7 @@
7071
"@types/update-notifier": "^2.2.0",
7172
"codecov": "^3.0.1",
7273
"execa": "^1.0.0",
74+
"fs-extra": "^7.0.1",
7375
"inline-fixtures": "^1.0.0",
7476
"js-green-licenses": "^0.5.0",
7577
"mocha": "^6.0.0",

src/init.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import * as inquirer from 'inquirer';
1818
import * as path from 'path';
1919

2020
import {
21-
getPkgManagerName,
21+
getPkgManagerCommand,
2222
readFilep as read,
2323
readJsonp as readJson,
2424
writeFileAtomicp as write,
@@ -76,7 +76,7 @@ export async function addScripts(
7676
options: Options
7777
): Promise<boolean> {
7878
let edits = false;
79-
const pkgManager = getPkgManagerName(options.yarn);
79+
const pkgManager = getPkgManagerCommand(options.yarn);
8080
const scripts: Bag<string> = {
8181
check: `gts check`,
8282
clean: 'gts clean',
@@ -282,7 +282,7 @@ export async function init(options: Options): Promise<boolean> {
282282
// --ignore-scripts so that compilation doesn't happen because there's no
283283
// source files yet.
284284
cp.spawnSync(
285-
getPkgManagerName(options.yarn),
285+
getPkgManagerCommand(options.yarn),
286286
['install', '--ignore-scripts'],
287287
{ stdio: 'inherit' }
288288
);

src/util.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ export function isYarnUsed(existsSync = fs.existsSync): boolean {
137137
return existsSync('yarn.lock');
138138
}
139139

140-
export function getPkgManagerName(isYarnUsed?: boolean): 'yarn' | 'npm' {
141-
return isYarnUsed ? 'yarn' : 'npm';
140+
export function getPkgManagerCommand(isYarnUsed?: boolean): string {
141+
return (
142+
(isYarnUsed ? 'yarn' : 'npm') + (process.platform === 'win32' ? '.cmd' : '')
143+
);
142144
}

test/mocha.opts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
--require source-map-support/register
2-
--timeout 30000
2+
--timeout 40000
33
--throw-deprecation

test/test-init.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ describe('init', () => {
187187
assert.strictEqual(result, true);
188188

189189
const contents = await readJson('./package.json');
190-
assert.strictEqual(contents.scripts.prepare, 'yarn run compile');
190+
const cmd = process.platform === 'win32' ? 'yarn.cmd' : 'yarn';
191+
assert.strictEqual(contents.scripts.prepare, cmd + ' run compile');
191192
}
192193
);
193194
});

test/test-kitchen.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import chalk from 'chalk';
22
import * as cp from 'child_process';
3-
import * as fs from 'fs';
3+
import * as fs from 'fs-extra';
44
import * as ncp from 'ncp';
55
import * as pify from 'pify';
66
import * as tmp from 'tmp';
@@ -16,6 +16,7 @@ const pkg = require('../../package.json');
1616

1717
const simpleExecp = pify(cp.exec);
1818
const renamep = pify(fs.rename);
19+
const movep = pify(fs.move);
1920
const ncpp = pify(ncp.ncp);
2021

2122
// TODO: improve the typedefinitions in @types/node. Right now they specify
@@ -67,7 +68,8 @@ describe('🚰 kitchen sink', () => {
6768
before(async () => {
6869
await simpleExecp('npm pack');
6970
const tarball = `${pkg.name}-${pkg.version}.tgz`;
70-
await renamep(tarball, `${stagingPath}/gts.tgz`);
71+
await renamep(tarball, 'gts.tgz');
72+
await movep('gts.tgz', `${stagingPath}/gts.tgz`);
7173
await ncpp('test/fixtures', `${stagingPath}/`);
7274
});
7375

@@ -137,7 +139,8 @@ describe('🚰 kitchen sink', () => {
137139
});
138140

139141
it('should terminate generated json files with newline', async () => {
140-
await simpleExecp('./node_modules/.bin/gts init -y', execOpts);
142+
const GTS = `${stagingPath}/kitchen/node_modules/.bin/gts`;
143+
await simpleExecp(`${GTS} init -y`, execOpts);
141144
assert.ok(
142145
fs
143146
.readFileSync(`${stagingPath}/kitchen/package.json`, 'utf8')
@@ -164,11 +167,11 @@ describe('🚰 kitchen sink', () => {
164167
it('should fix', async () => {
165168
const preFix = fs
166169
.readFileSync(`${stagingPath}/kitchen/src/server.ts`, 'utf8')
167-
.split('\n');
170+
.split(/[\n\r]+/);
168171
await simpleExecp('npm run fix', execOpts);
169172
const postFix = fs
170173
.readFileSync(`${stagingPath}/kitchen/src/server.ts`, 'utf8')
171-
.split('\n');
174+
.split(/[\n\r]+/);
172175
assert.strictEqual(preFix[0].trim() + ';', postFix[0]); // fix should have added a semi-colon
173176
});
174177

test/test-util.ts

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
ConfigFile,
2222
getTSConfig,
2323
isYarnUsed,
24-
getPkgManagerName,
24+
getPkgManagerCommand,
2525
} from '../src/util';
2626

2727
/**
@@ -46,35 +46,37 @@ function makeFakeFsExistsSync(
4646
): (path: PathLike) => boolean {
4747
return (path: PathLike) => expected.some(item => item === path);
4848
}
49+
50+
const FAKE_DIRECTORY = '/some/fake/directory';
51+
const PATH_TO_TSCONFIG = path.resolve(FAKE_DIRECTORY, 'tsconfig.json');
52+
const PATH_TO_CONFIG2 = path.resolve(FAKE_DIRECTORY, 'FAKE_CONFIG2');
53+
const PATH_TO_CONFIG3 = path.resolve(FAKE_DIRECTORY, 'FAKE_CONFIG3');
54+
4955
describe('util', () => {
5056
it('get should parse the correct tsconfig file', async () => {
51-
const FAKE_DIRECTORY = '/some/fake/directory';
5257
const FAKE_CONFIG1 = { files: ['b'] };
5358

5459
function fakeReadFilep(
5560
configPath: string,
5661
encoding: string
5762
): Promise<string> {
58-
assert.strictEqual(
59-
configPath,
60-
path.join(FAKE_DIRECTORY, 'tsconfig.json')
61-
);
63+
assert.strictEqual(configPath, PATH_TO_TSCONFIG);
6264
assert.strictEqual(encoding, 'utf8');
6365
return Promise.resolve(JSON.stringify(FAKE_CONFIG1));
6466
}
6567
const contents = await getTSConfig(FAKE_DIRECTORY, fakeReadFilep);
68+
6669
assert.deepStrictEqual(contents, FAKE_CONFIG1);
6770
});
6871

6972
it('should throw an error if it finds a circular reference', () => {
70-
const FAKE_DIRECTORY = '/some/fake/directory';
7173
const FAKE_CONFIG1 = { files: ['b'], extends: 'FAKE_CONFIG2' };
7274
const FAKE_CONFIG2 = { extends: 'FAKE_CONFIG3' };
7375
const FAKE_CONFIG3 = { extends: 'tsconfig.json' };
7476
const myMap = new Map();
75-
myMap.set('/some/fake/directory/tsconfig.json', FAKE_CONFIG1);
76-
myMap.set('/some/fake/directory/FAKE_CONFIG2', FAKE_CONFIG2);
77-
myMap.set('/some/fake/directory/FAKE_CONFIG3', FAKE_CONFIG3);
77+
myMap.set(PATH_TO_TSCONFIG, FAKE_CONFIG1);
78+
myMap.set(PATH_TO_CONFIG2, FAKE_CONFIG2);
79+
myMap.set(PATH_TO_CONFIG3, FAKE_CONFIG3);
7880

7981
return assert.rejects(
8082
() => getTSConfig(FAKE_DIRECTORY, createFakeReadFilep(myMap)),
@@ -84,7 +86,6 @@ describe('util', () => {
8486
});
8587

8688
it('should follow dependency chain caused by extends files', async () => {
87-
const FAKE_DIRECTORY = '/some/fake/directory';
8889
const FAKE_CONFIG1 = {
8990
compilerOptions: { a: 'n' },
9091
files: ['b'],
@@ -100,9 +101,9 @@ describe('util', () => {
100101
};
101102

102103
const myMap = new Map();
103-
myMap.set('/some/fake/directory/tsconfig.json', FAKE_CONFIG1);
104-
myMap.set('/some/fake/directory/FAKE_CONFIG2', FAKE_CONFIG2);
105-
myMap.set('/some/fake/directory/FAKE_CONFIG3', FAKE_CONFIG3);
104+
myMap.set(PATH_TO_TSCONFIG, FAKE_CONFIG1);
105+
myMap.set(PATH_TO_CONFIG2, FAKE_CONFIG2);
106+
myMap.set(PATH_TO_CONFIG3, FAKE_CONFIG3);
106107

107108
const contents = await getTSConfig(
108109
FAKE_DIRECTORY,
@@ -112,15 +113,14 @@ describe('util', () => {
112113
});
113114

114115
it('when a file contains an extends field, the base file is loaded first then overridden by the inherited files', async () => {
115-
const FAKE_DIRECTORY = '/some/fake/directory';
116116
const FAKE_CONFIG1 = { files: ['b'], extends: 'FAKE_CONFIG2' };
117117
const FAKE_CONFIG2 = { files: ['c'], extends: 'FAKE_CONFIG3' };
118118
const FAKE_CONFIG3 = { files: ['d'] };
119119
const combinedConfig = { compilerOptions: {}, files: ['b'] };
120120
const myMap = new Map();
121-
myMap.set('/some/fake/directory/tsconfig.json', FAKE_CONFIG1);
122-
myMap.set('/some/fake/directory/FAKE_CONFIG2', FAKE_CONFIG2);
123-
myMap.set('/some/fake/directory/FAKE_CONFIG3', FAKE_CONFIG3);
121+
myMap.set(PATH_TO_TSCONFIG, FAKE_CONFIG1);
122+
myMap.set(PATH_TO_CONFIG2, FAKE_CONFIG2);
123+
myMap.set(PATH_TO_CONFIG3, FAKE_CONFIG3);
124124

125125
const contents = await getTSConfig(
126126
FAKE_DIRECTORY,
@@ -130,7 +130,6 @@ describe('util', () => {
130130
});
131131

132132
it('when reading a file, all filepaths should be relative to the config file currently being read', async () => {
133-
const FAKE_DIRECTORY = '/some/fake/directory';
134133
const FAKE_CONFIG1 = { files: ['b'], extends: './foo/FAKE_CONFIG2' };
135134
const FAKE_CONFIG2 = { include: ['c'], extends: './bar/FAKE_CONFIG3' };
136135
const FAKE_CONFIG3 = { exclude: ['d'] };
@@ -141,9 +140,12 @@ describe('util', () => {
141140
include: ['c'],
142141
};
143142
const myMap = new Map();
144-
myMap.set('/some/fake/directory/tsconfig.json', FAKE_CONFIG1);
145-
myMap.set('/some/fake/directory/foo/FAKE_CONFIG2', FAKE_CONFIG2);
146-
myMap.set('/some/fake/directory/foo/bar/FAKE_CONFIG3', FAKE_CONFIG3);
143+
myMap.set(PATH_TO_TSCONFIG, FAKE_CONFIG1);
144+
myMap.set(path.resolve(FAKE_DIRECTORY, './foo/FAKE_CONFIG2'), FAKE_CONFIG2);
145+
myMap.set(
146+
path.resolve(FAKE_DIRECTORY, './foo/bar/FAKE_CONFIG3'),
147+
FAKE_CONFIG3
148+
);
147149

148150
const contents = await getTSConfig(
149151
FAKE_DIRECTORY,
@@ -153,7 +155,6 @@ describe('util', () => {
153155
});
154156

155157
it('function throws an error when reading a file that does not exist', () => {
156-
const FAKE_DIRECTORY = '/some/fake/directory';
157158
const myMap = new Map();
158159

159160
return assert.rejects(
@@ -178,13 +179,15 @@ describe('util', () => {
178179
assert.strictEqual(isYarnUsed(existsSync), false);
179180
});
180181

181-
it('getPkgManagerName returns npm by default', () => {
182-
assert.strictEqual(getPkgManagerName(), 'npm');
183-
assert.strictEqual(getPkgManagerName(), getPkgManagerName(false));
182+
const npmCmd = process.platform !== 'win32' ? 'npm' : 'npm.cmd';
183+
const yarnCmd = process.platform !== 'win32' ? 'yarn' : 'yarn.cmd';
184+
it('getPkgManagerCommand returns npm by default', () => {
185+
assert.strictEqual(getPkgManagerCommand(), npmCmd);
186+
assert.strictEqual(getPkgManagerCommand(), getPkgManagerCommand(false));
184187
});
185188

186-
it('getPkgManagerName returns yarn', () => {
187-
assert.strictEqual(getPkgManagerName(true), 'yarn');
189+
it('getPkgManagerCommand returns yarn', () => {
190+
assert.strictEqual(getPkgManagerCommand(true), yarnCmd);
188191
});
189192

190193
// TODO: test errors in readFile, JSON.parse.

0 commit comments

Comments
 (0)