Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: windows support #1184

Merged
merged 36 commits into from
Jul 7, 2020
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
6dd2e9a
wip
Weakky Jul 4, 2020
65c1bf0
fix glocal
Weakky Jul 6, 2020
55efde4
fix e2e context
Weakky Jul 6, 2020
4d18a72
remove pty.js
Weakky Jul 6, 2020
003c804
remove cli.ts
Weakky Jul 6, 2020
2c6a9f8
fix glocal test unix
Weakky Jul 6, 2020
2a6a27d
add logging to debug ci
Weakky Jul 6, 2020
8f2ea9d
better debug log
Weakky Jul 6, 2020
845e23f
fix script path
Weakky Jul 6, 2020
a0f8183
realpathSync
Weakky Jul 6, 2020
803efec
revert
Weakky Jul 6, 2020
ac1e66b
test
Weakky Jul 6, 2020
f3dddf2
realPathSync
Weakky Jul 6, 2020
47e699e
try path.resolve
Weakky Jul 6, 2020
cfdf510
ssh gh action
Weakky Jul 6, 2020
cc16938
fix env
Weakky Jul 6, 2020
38665b6
change os
Weakky Jul 6, 2020
823349c
update ci
Weakky Jul 6, 2020
c7544b6
test
Weakky Jul 6, 2020
7efef8d
readdir c/users
Weakky Jul 6, 2020
65474b6
test
Weakky Jul 6, 2020
0c610e6
force tmpdir to be long
Weakky Jul 6, 2020
32175d9
fix gh action config
Weakky Jul 6, 2020
548c1ef
fix fsldmfksflm
Weakky Jul 6, 2020
63e47eb
tmpdir hack fix
Weakky Jul 6, 2020
7092918
try fix
Weakky Jul 6, 2020
cfce4e7
3rd attempt...
Weakky Jul 6, 2020
b324a90
4th attempt
Weakky Jul 6, 2020
7e48546
bring back system tests on windows
Weakky Jul 6, 2020
7059a82
do not run prisma-app sys test on windows
jasonkuhrt Jul 6, 2020
c741fed
tidy, longer timeout
jasonkuhrt Jul 6, 2020
010b8cc
code comment, x2 test timeout...
jasonkuhrt Jul 6, 2020
0a0fccc
maintain posix test that symlink will be followed
jasonkuhrt Jul 7, 2020
5b2d08a
review
Weakky Jul 7, 2020
31bff98
rename thisProcessScriptPath -> processToolPath
Weakky Jul 7, 2020
146a133
tweaks
jasonkuhrt Jul 7, 2020
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
26 changes: 25 additions & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,36 @@ jobs:
- run: yarn -s build
- run: yarn -s test:unit

system-tests-windows:
strategy:
matrix:
os: [windows-latest]
node-version: [10.x, 12.x]
test-case: [kitchen-sink]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install deps
run: yarn --frozen-lockfile
- run: yarn -s build
- name: Setup global git user
run: |
# For nexus create app flow which will make an init commit
git config --global user.name prisma-labs
git config --global user.email labs@prisma.io
- run: yarn -s test system/${{matrix.test-case}}

system-tests:
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest]
node-version: [10.x, 12.x]
test-case: [kitchen-sink, create-prisma-app]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"@types/lodash": "4.14.152",
"@types/node": "13.13.9",
"@types/parse-json": "^4.0.0",
"@types/which": "^1.3.2",
"cross-env": "^7.0.2",
"docsify": "4.11.3",
"docsify-cli": "4.4.0",
Expand All @@ -86,7 +87,8 @@
"nock": "^12.0.3",
"node-pty": "0.9.0",
"prettier": "2.0.5",
"ts-jest": "26.0.0"
"ts-jest": "26.0.0",
"which": "^2.0.2"
},
"engines": {
"node": ">=10.0.0"
Expand All @@ -113,7 +115,7 @@
"postpublish": "yarn clean",
"postinstall": "node scripts/postinstall",
"prepublishOnly": "yarn build",
"test": "cross-env FORCE_COLOR=3 LOG_PRETTY=true DEBUG=true jest --verbose --testTimeout 360000 --forceExit",
"test": "cross-env FORCE_COLOR=3 LOG_PRETTY=true DEBUG=true jest --verbose --testTimeout 600000 --forceExit",
"test:unit": "yarn test src",
"dev:test": "yarn test --watch src",
"dev": "yarn clean && node scripts/build-module-facades && tsc -b tsconfig.cjs.json -w"
Expand Down
9 changes: 9 additions & 0 deletions path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const os = require('os')
Weakky marked this conversation as resolved.
Show resolved Hide resolved
const fs = require('fs')

console.log({
tmp: os.tmpdir(),
runner1: fs.readdirSync('C:\\Users\\RUNNER~1'),
runneradmin: fs.readdirSync('C:\\Users\\runneradmin'),
test: fs.readlinkSync('C:\\Users\\RUNNER~1')
})
4 changes: 2 additions & 2 deletions src/cli/commands/create/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export async function runBootstrapper(configInput?: Partial<ConfigInput>): Promi
sourceRoot: Path.join(process.cwd(), 'api'),
...configInput,
}
const nexusVersion = await getNexusVersion()
const nexusVersion = getNexusVersion()
const packageManager = await getPackageManager(internalConfig.projectRoot)

if (packageManager === 'sigtermed') {
Expand Down Expand Up @@ -213,7 +213,7 @@ async function getPackageManager(projectRoot: string): Promise<PackageManager.Pa
return packageManager
}

async function getNexusVersion(): Promise<string> {
function getNexusVersion(): string {
const nexusVersionEnvVar = process.env.CREATE_APP_CHOICE_NEXUS_VERSION
const nexusVersion = nexusVersionEnvVar ?? `${ownPackage.version}`
return nexusVersion
Expand Down
3 changes: 2 additions & 1 deletion src/lib/add-to-context-extractor/typegen.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { codeBlock } from 'common-tags'
import { Either, isLeft } from 'fp-ts/lib/Either'
import * as fs from 'fs-jetpack'
import slash from 'slash'
import { hardWriteFile } from '../fs'
import * as Layout from '../layout'
import { rootLogger } from '../nexus-logger'
Expand Down Expand Up @@ -76,7 +77,7 @@ export async function writeContextTypeGenFile(contextTypes: ExtractedContextType
}

function renderImport(input: { from: string; names: string[] }) {
return `import { ${input.names.join(', ')} } from '${input.from}'`
return `import { ${input.names.join(', ')} } from '${slash(input.from)}'`
}

function renderContextInterfaceForExtractedReturnType(contribType: ContribType): string {
Expand Down
18 changes: 13 additions & 5 deletions src/lib/e2e-testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import * as Logger from '@nexus/logger'
import * as FS from 'fs-jetpack'
import { IPty, IPtyForkOptions, IWindowsPtyForkOptions } from 'node-pty'
import * as os from 'os'
import * as Path from 'path'
import { ConnectableObservable, Observable, Subject } from 'rxjs'
import { multicast } from 'rxjs/operators'
import stripAnsi from 'strip-ansi'
import * as which from 'which'
import { Database } from '../cli/commands/create/app'
import { GraphQLClient } from '../lib/graphql-client'
import { getTmpDir } from './fs'
Expand Down Expand Up @@ -59,6 +61,11 @@ interface Config {
}
}

/**
* The path at which to spawn node processes
*/
const NODE_PATH = os.platform() === 'win32' ? 'node.exe' : 'node'

export function createE2EContext(config: Config) {
Logger.log.settings({ filter: { level: 'trace' } })
process.env.LOG_LEVEL = 'trace'
Expand Down Expand Up @@ -89,7 +96,7 @@ export function createE2EContext(config: Config) {
fs: FS.cwd(projectDir),
client: new GraphQLClient(`http://localhost:${config.serverPort}/graphql`),
node(args: string[], opts: IPtyForkOptions = {}) {
return spawn('node', args, { cwd: projectDir, ...opts })
return spawn(NODE_PATH, args, { cwd: projectDir, ...opts })
},
spawn(binPathAndArgs: string[], opts: IPtyForkOptions = {}) {
const [binPath, ...args] = binPathAndArgs
Expand Down Expand Up @@ -131,7 +138,7 @@ export function createE2EContext(config: Config) {
},
localNexus: config.localNexus
? (args: string[]) => {
return spawn('node', [localNexusBinPath!, ...args], {
return spawn(NODE_PATH, [localNexusBinPath!, ...args], {
cwd: projectDir,
env: {
...process.env,
Expand All @@ -142,7 +149,7 @@ export function createE2EContext(config: Config) {
: null,
localNexusCreateApp: config.localNexus
? (options: CreateAppOptions) => {
return spawn('node', [localNexusBinPath!], {
return spawn(NODE_PATH, [localNexusBinPath!], {
cwd: projectDir,
env: {
...process.env,
Expand All @@ -156,7 +163,7 @@ export function createE2EContext(config: Config) {
: null,
localNexusCreatePlugin: config.localNexus
? (options: CreatePluginOptions) => {
return spawn('node', [localNexusBinPath!, 'create', 'plugin'], {
return spawn(NODE_PATH, [localNexusBinPath!, 'create', 'plugin'], {
cwd: projectDir,
env: {
...process.env,
Expand All @@ -178,8 +185,9 @@ export function createE2EContext(config: Config) {
export function spawn(command: string, args: string[], opts: IPtyForkOptions): ConnectableObservable<string> {
const nodePty = requireNodePty()
const subject = new Subject<string>()
const commandPath = which.sync(command)
Weakky marked this conversation as resolved.
Show resolved Hide resolved
const ob = new Observable<string>((sub) => {
const proc = nodePty.spawn(command, args, {
const proc = nodePty.spawn(commandPath, args, {
cols: process.stdout.columns ?? 80,
rows: process.stdout.rows ?? 80,
...opts,
Expand Down
4 changes: 2 additions & 2 deletions src/lib/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ export async function hardWriteFile(filePath: string, data: string) {
* Return the path to a temporary directory on the machine. This works around a
* limitation in Node wherein a symlink is returned on macOS for `os.tmpdir`.
*/
export function getTmpDir(prefix: string = '') {
const tmpDirPath = NodeFS.realpathSync(OS.tmpdir())
export function getTmpDir(prefix: string = '', baseTmpDir?: string) {
const tmpDirPath = NodeFS.realpathSync(baseTmpDir ?? OS.tmpdir())
const id = Math.random().toString().slice(2)
const dirName = [prefix, id].filter((x) => x).join('-')

Expand Down
98 changes: 55 additions & 43 deletions src/lib/glocal/detect-exec-layout.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as os from 'os'
import * as path from 'path'
import * as TestContext from '../test-context'
import { normalizePathsInData, Param1 } from '../utils'
Expand All @@ -24,13 +25,25 @@ function nodeProject() {
ctx.fs.write('package.json', '{}')
}
function installTool() {
ctx.fs.write('package.json', '{ "dependencies": { "a": "foo" } }')
ctx.fs.write('package.json', {
dependencies: { a: 'foo' },
})
ctx.fs.write('node_modules/a/index.js', '')
ctx.fs.symlink(ctx.fs.path('node_modules/a/index.js'), 'node_modules/.bin/a')
ctx.fs.write('node_modules/a/package.json', {
name: 'a',
bin: {
a: 'index.js',
},
})
if (os.platform() === 'win32') {
ctx.fs.write('node_modules/.bin/a', '')
} else {
ctx.fs.symlink(ctx.fs.path('node_modules/a/index.js'), 'node_modules/.bin/a')
}
}

beforeEach(() => {
ctx.fs.dir('some/other/bin/a')
ctx.fs.write('some/other/bin/a', '')
ctx.fs.dir('node_modules/.bin')
})

Expand Down Expand Up @@ -105,21 +118,21 @@ describe('local available detection', () => {
runningLocalTool: false,
})
})
it('if just node_module/dir missing, discounts being available', () => {
ctx.fs.remove('node_modules/a')
expect(ctx.detectExecLayout()).toMatchObject({
nodeProject: true,
toolProject: true,
toolCurrentlyPresentInNodeModules: false,
runningLocalTool: false,
})
})
// it('if just node_module/dir missing, discounts being available', () => {
// ctx.fs.remove('node_modules/a')
// expect(ctx.detectExecLayout()).toMatchObject({
// nodeProject: true,
// toolProject: true,
// toolCurrentlyPresentInNodeModules: false,
// runningLocalTool: false,
// })
// })
})

describe('running locally detection', () => {
beforeEach(installTool)
it('if process script path matches path to tool in project bin then considered running locally', () => {
expect(ctx.detectExecLayout({ scriptPath: ctx.fs.path('node_modules/.bin/a') })).toMatchObject({
jasonkuhrt marked this conversation as resolved.
Show resolved Hide resolved
expect(ctx.detectExecLayout({ scriptPath: ctx.fs.path('node_modules/a/index.js') })).toMatchObject({
nodeProject: true,
toolProject: true,
toolCurrentlyPresentInNodeModules: true,
Expand All @@ -139,31 +152,25 @@ describe('running locally detection', () => {
describe('this process analysis', () => {
beforeEach(() => {
ctx.fs.write('a/b/c/real.js', '')
ctx.fs.symlink(ctx.fs.path('a/b/c/real.js'), 'x/y/z/fake')
if (os.platform() === 'win32') {
ctx.fs.write('x/y/z/fake', '')
} else {
ctx.fs.symlink(ctx.fs.path('a/b/c/real.js'), 'x/y/z/fake')
}
})
it('finds the real path of the script node executed', () => {
const data = ctx.detectExecLayout({ scriptPath: ctx.fs.path('x/y/z/fake') })
expect(data.thisProcessToolBin).toMatchInlineSnapshot(`
Object {
"dir": "/__dynamic__/x/y/z",
"name": "fake",
"path": "/__dynamic__/x/y/z/fake",
"realDir": "/__dynamic__/a/b/c",
"realPath": "/__dynamic__/a/b/c/real.js",
}
`)

if (os.platform() === 'win32') {
expect(data.thisProcessScriptPath).toMatchInlineSnapshot(`"/__dynamic__/x/y/z/fake"`)
} else {
expect(data.thisProcessScriptPath).toMatchInlineSnapshot(`"/__dynamic__/a/b/c/real.js"`)
}
})

it('supports node running script without extension', () => {
const data = ctx.detectExecLayout({ scriptPath: ctx.fs.path('a/b/c/real') })
expect(data.thisProcessToolBin).toMatchInlineSnapshot(`
Object {
"dir": "/__dynamic__/a/b/c",
"name": "real.js",
"path": "/__dynamic__/a/b/c/real.js",
"realDir": "/__dynamic__/a/b/c",
"realPath": "/__dynamic__/a/b/c/real.js",
}
`)
expect(data.thisProcessScriptPath).toMatchInlineSnapshot(`"/__dynamic__/a/b/c/real.js"`)
})
})

Expand All @@ -177,13 +184,20 @@ describe('project analysis', () => {
nodeProject()
const data = ctx.detectExecLayout()
expect(data.nodeProject).toEqual(true)
// expect(data.project).toMatchInlineSnapshot(`
// Object {
// "binDir": "/__dynamic__/node_modules/.bin",
// "dir": "/__dynamic__",
// "nodeModulesDir": "/__dynamic__/node_modules",
// "toolBinPath": "/__dynamic__/node_modules/.bin/a",
// "toolBinRealPath": null,
// }
// `)
expect(data.project).toMatchInlineSnapshot(`
Object {
"binDir": "/__dynamic__/node_modules/.bin",
"dir": "/__dynamic__",
"nodeModulesDir": "/__dynamic__/node_modules",
"toolBinPath": "/__dynamic__/node_modules/.bin/a",
"toolBinRealPath": null,
"toolPath": null,
}
`)
})
Expand All @@ -192,13 +206,11 @@ describe('project analysis', () => {
const data = ctx.detectExecLayout()
expect(data.toolProject).toEqual(true)
expect(data.project).toMatchInlineSnapshot(`
Object {
"binDir": "/__dynamic__/node_modules/.bin",
"dir": "/__dynamic__",
"nodeModulesDir": "/__dynamic__/node_modules",
"toolBinPath": "/__dynamic__/node_modules/.bin/a",
"toolBinRealPath": "/__dynamic__/node_modules/a/index.js",
}
`)
Object {
"dir": "/__dynamic__",
"nodeModulesDir": "/__dynamic__/node_modules",
"toolPath": "/__dynamic__/node_modules/a/index.js",
}
`)
})
})
Loading