commit
1c5c35403b
@ -1,13 +1,17 @@ |
|||||||
{ |
{ |
||||||
"scripts": { |
"scripts": { |
||||||
"start:server": "npx ts-node server.ts" |
"start:server": "tsc && node ./dist/server.js" |
||||||
}, |
}, |
||||||
"dependencies": { |
"dependencies": { |
||||||
"body-parser": "^1.20.2", |
"body-parser": "^1.20.3", |
||||||
"child_process": "^1.0.2", |
"child_process": "^1.0.2", |
||||||
"express": "^4.19.2", |
"express": "^4.20.0", |
||||||
"git-http-backend": "^1.1.2", |
"git-http-backend": "^1.1.2", |
||||||
"path": "^0.12.7", |
"path": "^0.12.7", |
||||||
"zlib": "^1.0.5" |
"zlib": "^1.0.5" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@types/node": "^22.5.4", |
||||||
|
"typescript": "^5.6.2" |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,25 @@ |
|||||||
|
{ |
||||||
|
"compilerOptions": { |
||||||
|
"target": "ES6", // Set the ECMAScript target version |
||||||
|
"module": "commonjs", // Specify module code generation |
||||||
|
"strict": true, |
||||||
|
"noImplicitAny": false, // Enable all strict type-checking options |
||||||
|
"esModuleInterop": true, // Emit additional code to make commonJS and ES modules work together |
||||||
|
"skipLibCheck": true, // Skip type checking of all declaration files (.d.ts) |
||||||
|
"forceConsistentCasingInFileNames": true, // Ensure file names are treated with case sensitivity |
||||||
|
"outDir": "./dist", // Redirect output structure to the 'dist' directory |
||||||
|
"rootDir": "./src", // Specify the root directory of input files |
||||||
|
"sourceMap": true, // Create source map files |
||||||
|
"types": [ |
||||||
|
"node" |
||||||
|
], // Add node types |
||||||
|
"moduleResolution": "node", // Ensure TypeScript resolves modules like Node.js |
||||||
|
}, |
||||||
|
"include": [ |
||||||
|
"src/**/*" // Include all TypeScript files in the src directory |
||||||
|
], |
||||||
|
"exclude": [ |
||||||
|
"node_modules", // Exclude the node_modules folder |
||||||
|
"**/*.test.ts" // Exclude test files |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
import { ElectronPlugin } from '@remixproject/engine-electron'; |
||||||
|
|
||||||
|
export class FoundryHandleDesktop extends ElectronPlugin { |
||||||
|
constructor() { |
||||||
|
super({ |
||||||
|
displayName: 'foundry', |
||||||
|
name: 'foundry', |
||||||
|
description: 'electron foundry', |
||||||
|
methods: ['sync', 'compile'] |
||||||
|
}) |
||||||
|
this.methods = ['sync', 'compile'] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
import { ElectronPlugin } from '@remixproject/engine-electron'; |
||||||
|
|
||||||
|
export class HardhatHandleDesktop extends ElectronPlugin { |
||||||
|
constructor() { |
||||||
|
super({ |
||||||
|
displayName: 'hardhat', |
||||||
|
name: 'hardhat', |
||||||
|
description: 'electron hardhat', |
||||||
|
methods: ['sync', 'compile'] |
||||||
|
}) |
||||||
|
this.methods = ['sync', 'compile'] |
||||||
|
} |
||||||
|
} |
@ -1,4 +1,6 @@ |
|||||||
{ |
{ |
||||||
"electron.openFolder": "Open Folder", |
"electron.openFolder": "Open Folder", |
||||||
"electron.recentFolders": "Recent Folders" |
"electron.recentFolders": "Recent Folders", |
||||||
|
"electron.gitClone": "Clone a Git Repository", |
||||||
|
"electron.openFolderMessage": "In order to use Git features, you can open a folder or clone a repository." |
||||||
} |
} |
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"gitui.openFolderMessage": "In order to use Git features, you can open a folder or clone a repository." |
||||||
|
} |
After Width: | Height: | Size: 62 KiB |
@ -0,0 +1,14 @@ |
|||||||
|
const fs = require('fs-extra'); |
||||||
|
const path = require('path'); |
||||||
|
|
||||||
|
exports.default = async function (context) { |
||||||
|
console.log('Running after-pack hook', context); |
||||||
|
const resourcesPath = context.appOutDir; |
||||||
|
console.log('resourcesPath', resourcesPath); |
||||||
|
console.log('context outdir', context.appOutDir); |
||||||
|
// Copy the node-pty module to the app folder
|
||||||
|
await fs.copy( |
||||||
|
path.join('./node_modules', 'node-pty'), |
||||||
|
path.join(resourcesPath, 'node_modules', 'node-pty') |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,12 @@ |
|||||||
|
const esbuild = require('esbuild'); |
||||||
|
|
||||||
|
esbuild.build({ |
||||||
|
entryPoints: ['src/main.ts', 'src/preload.ts'], // Your TypeScript entry point
|
||||||
|
outdir: 'build', // Output bundled file
|
||||||
|
bundle: true, // Bundle all dependencies
|
||||||
|
platform: 'node', // Target Node.js platform
|
||||||
|
external: ['electron', 'fsevents', 'node-pty'], // Exclude native modules
|
||||||
|
target: ['node20'], // Match the Node.js version for Electron
|
||||||
|
tsconfig: 'tsconfig.json', // Your TypeScript config
|
||||||
|
minify: false, // Optional: Minify for production
|
||||||
|
}).catch(() => process.exit(1)); |
@ -0,0 +1,14 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
set -e |
||||||
|
TEST_EXITCODE=0 |
||||||
|
yarn run build:e2e && node ./splice_tests.js |
||||||
|
TESTFILES=$(node ./splice_tests.js | grep -i 'git' | circleci tests split --split-by=timings) |
||||||
|
for TESTFILE in $TESTFILES; do |
||||||
|
yarn run test --use-isogit --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || yarn run test --use-isogit --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || TEST_EXITCODE=1 |
||||||
|
done |
||||||
|
|
||||||
|
echo "$TEST_EXITCODE" |
||||||
|
if [ "$TEST_EXITCODE" -eq 1 ] |
||||||
|
then |
||||||
|
exit 1 |
||||||
|
fi |
@ -0,0 +1,24 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
# Read the version from package.json |
||||||
|
version=$(awk -F'"' '/"version":/ {print $4}' package.json) |
||||||
|
|
||||||
|
# Determine the command to run based on the version |
||||||
|
if [[ $version == *"beta"* ]]; then |
||||||
|
command="yarn esbuild -c beta.json" |
||||||
|
elif [[ $version == *"alpha"* ]]; then |
||||||
|
command="yarn esbuild -c alpha.json" |
||||||
|
elif [[ $version == *"insiders"* ]]; then |
||||||
|
command="yarn esbuild -c insiders.json" |
||||||
|
else |
||||||
|
command="yarn esbuild -c latest.json" |
||||||
|
fi |
||||||
|
|
||||||
|
# Append any arguments passed in CLI |
||||||
|
for arg in "$@"; do |
||||||
|
command+=" $arg" |
||||||
|
done |
||||||
|
|
||||||
|
# Print and run the command |
||||||
|
echo "Running command: $command" |
||||||
|
$command |
@ -0,0 +1,24 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
# Read the version from package.json |
||||||
|
version=$(awk -F'"' '/"version":/ {print $4}' package.json) |
||||||
|
|
||||||
|
# Determine the command to run based on the version |
||||||
|
if [[ $version == *"beta"* ]]; then |
||||||
|
command="yarn tscbuild -c beta.json" |
||||||
|
elif [[ $version == *"alpha"* ]]; then |
||||||
|
command="yarn tscbuild -c alpha.json" |
||||||
|
elif [[ $version == *"insiders"* ]]; then |
||||||
|
command="yarn tscbuild -c insiders.json" |
||||||
|
else |
||||||
|
command="yarn tscbuild -c latest.json" |
||||||
|
fi |
||||||
|
|
||||||
|
# Append any arguments passed in CLI |
||||||
|
for arg in "$@"; do |
||||||
|
command+=" $arg" |
||||||
|
done |
||||||
|
|
||||||
|
# Print and run the command |
||||||
|
echo "Running command: $command" |
||||||
|
$command |
@ -0,0 +1,24 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
# Read the version from package.json |
||||||
|
version=$(awk -F'"' '/"version":/ {print $4}' package.json) |
||||||
|
|
||||||
|
# Determine the command to run based on the version |
||||||
|
if [[ $version == *"beta"* ]]; then |
||||||
|
command="yarn dist -c beta.json" |
||||||
|
elif [[ $version == *"alpha"* ]]; then |
||||||
|
command="yarn dist -c alpha.json" |
||||||
|
elif [[ $version == *"insiders"* ]]; then |
||||||
|
command="yarn dist -c insiders.json" |
||||||
|
else |
||||||
|
command="yarn dist -c latest.json" |
||||||
|
fi |
||||||
|
|
||||||
|
# Append any arguments passed in CLI |
||||||
|
for arg in "$@"; do |
||||||
|
command+=" $arg" |
||||||
|
done |
||||||
|
|
||||||
|
# Print and run the command |
||||||
|
echo "Running command: $command" |
||||||
|
$command |
@ -0,0 +1,248 @@ |
|||||||
|
import { Profile } from "@remixproject/plugin-utils"; |
||||||
|
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" |
||||||
|
import chokidar from 'chokidar' |
||||||
|
import { ElectronBasePluginRemixdClient } from "../lib/remixd" |
||||||
|
import fs from 'fs' |
||||||
|
import * as utils from '../lib/utils' |
||||||
|
|
||||||
|
import { basename, join } from "path"; |
||||||
|
import { spawn } from "child_process"; |
||||||
|
const profile: Profile = { |
||||||
|
name: 'foundry', |
||||||
|
displayName: 'electron foundry', |
||||||
|
description: 'electron foundry', |
||||||
|
} |
||||||
|
|
||||||
|
export class FoundryPlugin extends ElectronBasePlugin { |
||||||
|
clients: any[] |
||||||
|
constructor() { |
||||||
|
super(profile, clientProfile, FoundryPluginClient) |
||||||
|
this.methods = [...super.methods] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const clientProfile: Profile = { |
||||||
|
name: 'foundry', |
||||||
|
displayName: 'electron foundry', |
||||||
|
description: 'electron foundry', |
||||||
|
methods: ['sync', 'compile'] |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
class FoundryPluginClient extends ElectronBasePluginRemixdClient { |
||||||
|
|
||||||
|
watcher: chokidar.FSWatcher |
||||||
|
warnlog: boolean |
||||||
|
buildPath: string |
||||||
|
cachePath: string |
||||||
|
logTimeout: NodeJS.Timeout |
||||||
|
processingTimeout: NodeJS.Timeout |
||||||
|
|
||||||
|
async onActivation(): Promise<void> { |
||||||
|
console.log('Foundry plugin activated') |
||||||
|
this.call('terminal', 'log', { type: 'log', value: 'Foundry plugin activated' }) |
||||||
|
this.on('fs' as any, 'workingDirChanged', async (path: string) => { |
||||||
|
console.log('workingDirChanged foundry', path) |
||||||
|
this.currentSharedFolder = path |
||||||
|
this.startListening() |
||||||
|
}) |
||||||
|
this.currentSharedFolder = await this.call('fs' as any, 'getWorkingDir') |
||||||
|
if(this.currentSharedFolder) this.startListening() |
||||||
|
} |
||||||
|
|
||||||
|
startListening() { |
||||||
|
this.buildPath = utils.absolutePath('out', this.currentSharedFolder) |
||||||
|
this.cachePath = utils.absolutePath('cache', this.currentSharedFolder) |
||||||
|
console.log('Foundry plugin checking for', this.buildPath, this.cachePath) |
||||||
|
if (fs.existsSync(this.buildPath) && fs.existsSync(this.cachePath)) { |
||||||
|
this.listenOnFoundryCompilation() |
||||||
|
} else { |
||||||
|
this.listenOnFoundryFolder() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
listenOnFoundryFolder() { |
||||||
|
console.log('Foundry out folder doesn\'t exist... waiting for the compilation.') |
||||||
|
try { |
||||||
|
if (this.watcher) this.watcher.close() |
||||||
|
this.watcher = chokidar.watch(this.currentSharedFolder, { depth: 1, ignorePermissionErrors: true, ignoreInitial: true }) |
||||||
|
// watch for new folders
|
||||||
|
this.watcher.on('addDir', (path: string) => { |
||||||
|
console.log('add dir foundry', path) |
||||||
|
if (fs.existsSync(this.buildPath) && fs.existsSync(this.cachePath)) { |
||||||
|
this.listenOnFoundryCompilation() |
||||||
|
} |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
compile() { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const cmd = `forge build` |
||||||
|
const options = { cwd: this.currentSharedFolder, shell: true } |
||||||
|
const child = spawn(cmd, options) |
||||||
|
let result = '' |
||||||
|
let error = '' |
||||||
|
child.stdout.on('data', (data) => { |
||||||
|
const msg = `[Foundry Compilation]: ${data.toString()}` |
||||||
|
console.log('\x1b[32m%s\x1b[0m', msg) |
||||||
|
result += msg + '\n' |
||||||
|
}) |
||||||
|
child.stderr.on('data', (err) => { |
||||||
|
error += `[Foundry Compilation]: ${err.toString()} \n` |
||||||
|
}) |
||||||
|
child.on('close', () => { |
||||||
|
if (error && result) resolve(error + result) |
||||||
|
else if (error) reject(error) |
||||||
|
else resolve(result) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
checkPath() { |
||||||
|
if (!fs.existsSync(this.buildPath) || !fs.existsSync(this.cachePath)) { |
||||||
|
this.listenOnFoundryFolder() |
||||||
|
return false |
||||||
|
} |
||||||
|
if (!fs.existsSync(join(this.cachePath, 'solidity-files-cache.json'))) return false |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
private async processArtifact() { |
||||||
|
if (!this.checkPath()) return |
||||||
|
const folderFiles = await fs.promises.readdir(this.buildPath) // "out" folder
|
||||||
|
try { |
||||||
|
const cache = JSON.parse(await fs.promises.readFile(join(this.cachePath, 'solidity-files-cache.json'), { encoding: 'utf-8' })) |
||||||
|
// name of folders are file names
|
||||||
|
for (const file of folderFiles) { |
||||||
|
const path = join(this.buildPath, file) // out/Counter.sol/
|
||||||
|
const compilationResult = { |
||||||
|
input: {}, |
||||||
|
output: { |
||||||
|
contracts: {}, |
||||||
|
sources: {} |
||||||
|
}, |
||||||
|
inputSources: { sources: {}, target: '' }, |
||||||
|
solcVersion: null, |
||||||
|
compilationTarget: null |
||||||
|
} |
||||||
|
compilationResult.inputSources.target = file |
||||||
|
await this.readContract(path, compilationResult, cache) |
||||||
|
this.emit('compilationFinished', compilationResult.compilationTarget, { sources: compilationResult.input }, 'soljson', compilationResult.output, compilationResult.solcVersion) |
||||||
|
} |
||||||
|
|
||||||
|
clearTimeout(this.logTimeout) |
||||||
|
this.logTimeout = setTimeout(() => { |
||||||
|
// @ts-ignore
|
||||||
|
this.call('terminal', 'log', { type: 'log', value: `receiving compilation result from Foundry. Select a file to populate the contract interaction interface.` }) |
||||||
|
console.log('Syncing compilation result from Foundry') |
||||||
|
}, 1000) |
||||||
|
|
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async triggerProcessArtifact() { |
||||||
|
// prevent multiple calls
|
||||||
|
clearTimeout(this.processingTimeout) |
||||||
|
this.processingTimeout = setTimeout(async () => await this.processArtifact(), 1000) |
||||||
|
} |
||||||
|
|
||||||
|
listenOnFoundryCompilation() { |
||||||
|
try { |
||||||
|
console.log('Foundry out folder exists... processing the artifact.') |
||||||
|
if (this.watcher) this.watcher.close() |
||||||
|
this.watcher = chokidar.watch(this.cachePath, { depth: 0, ignorePermissionErrors: true, ignoreInitial: true }) |
||||||
|
this.watcher.on('change', async () => await this.triggerProcessArtifact()) |
||||||
|
this.watcher.on('add', async () => await this.triggerProcessArtifact()) |
||||||
|
this.watcher.on('unlink', async () => await this.triggerProcessArtifact()) |
||||||
|
// process the artifact on activation
|
||||||
|
this.triggerProcessArtifact() |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async readContract(contractFolder, compilationResultPart, cache) { |
||||||
|
const files = await fs.promises.readdir(contractFolder) |
||||||
|
for (const file of files) { |
||||||
|
const path = join(contractFolder, file) |
||||||
|
const content = await fs.promises.readFile(path, { encoding: 'utf-8' }) |
||||||
|
compilationResultPart.inputSources.sources[file] = { content } |
||||||
|
await this.feedContractArtifactFile(file, content, compilationResultPart, cache) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async feedContractArtifactFile(path, content, compilationResultPart, cache) { |
||||||
|
const contentJSON = JSON.parse(content) |
||||||
|
const contractName = basename(path).replace('.json', '') |
||||||
|
|
||||||
|
let sourcePath = '' |
||||||
|
if (contentJSON?.metadata?.settings?.compilationTarget) { |
||||||
|
for (const key in contentJSON.metadata.settings.compilationTarget) { |
||||||
|
if (contentJSON.metadata.settings.compilationTarget[key] === contractName) { |
||||||
|
sourcePath = key |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!sourcePath) return |
||||||
|
|
||||||
|
const currentCache = cache.files[sourcePath] |
||||||
|
if (!currentCache.artifacts[contractName]) return |
||||||
|
|
||||||
|
// extract source and version
|
||||||
|
const metadata = contentJSON.metadata |
||||||
|
if (metadata.compiler && metadata.compiler.version) { |
||||||
|
compilationResultPart.solcVersion = metadata.compiler.version |
||||||
|
} else { |
||||||
|
compilationResultPart.solcVersion = '' |
||||||
|
console.log('\x1b[32m%s\x1b[0m', 'compiler version not found, please update Foundry to the latest version.') |
||||||
|
} |
||||||
|
|
||||||
|
if (metadata.sources) { |
||||||
|
for (const path in metadata.sources) { |
||||||
|
const absPath = utils.absolutePath(path, this.currentSharedFolder) |
||||||
|
try { |
||||||
|
const content = await fs.promises.readFile(absPath, { encoding: 'utf-8' }) |
||||||
|
compilationResultPart.input[path] = { content } |
||||||
|
} catch (e) { |
||||||
|
compilationResultPart.input[path] = { content: '' } |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
console.log('\x1b[32m%s\x1b[0m', 'sources input not found, please update Foundry to the latest version.') |
||||||
|
} |
||||||
|
|
||||||
|
compilationResultPart.compilationTarget = sourcePath |
||||||
|
// extract data
|
||||||
|
if (!compilationResultPart.output['sources'][sourcePath]) compilationResultPart.output['sources'][sourcePath] = {} |
||||||
|
compilationResultPart.output['sources'][sourcePath] = { |
||||||
|
ast: contentJSON['ast'], |
||||||
|
id: contentJSON['id'] |
||||||
|
} |
||||||
|
if (!compilationResultPart.output['contracts'][sourcePath]) compilationResultPart.output['contracts'][sourcePath] = {} |
||||||
|
|
||||||
|
contentJSON.bytecode.object = contentJSON.bytecode.object.replace('0x', '') |
||||||
|
contentJSON.deployedBytecode.object = contentJSON.deployedBytecode.object.replace('0x', '') |
||||||
|
compilationResultPart.output['contracts'][sourcePath][contractName] = { |
||||||
|
abi: contentJSON.abi, |
||||||
|
evm: { |
||||||
|
bytecode: contentJSON.bytecode, |
||||||
|
deployedBytecode: contentJSON.deployedBytecode, |
||||||
|
methodIdentifiers: contentJSON.methodIdentifiers |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async sync() { |
||||||
|
console.log('syncing Foundry with Remix...') |
||||||
|
this.processArtifact() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,220 @@ |
|||||||
|
import { Profile } from "@remixproject/plugin-utils"; |
||||||
|
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" |
||||||
|
import chokidar from 'chokidar' |
||||||
|
import { ElectronBasePluginRemixdClient } from "../lib/remixd" |
||||||
|
import fs from 'fs' |
||||||
|
import * as utils from '../lib/utils' |
||||||
|
|
||||||
|
import { basename, join } from "path"; |
||||||
|
import { spawn } from "child_process"; |
||||||
|
const profile: Profile = { |
||||||
|
name: 'hardhat', |
||||||
|
displayName: 'electron slither', |
||||||
|
description: 'electron slither', |
||||||
|
} |
||||||
|
|
||||||
|
export class HardhatPlugin extends ElectronBasePlugin { |
||||||
|
clients: any[] |
||||||
|
constructor() { |
||||||
|
super(profile, clientProfile, HardhatPluginClient) |
||||||
|
this.methods = [...super.methods] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const clientProfile: Profile = { |
||||||
|
name: 'hardhat', |
||||||
|
displayName: 'electron hardhat', |
||||||
|
description: 'electron hardhat', |
||||||
|
methods: ['sync', 'compile'] |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
class HardhatPluginClient extends ElectronBasePluginRemixdClient { |
||||||
|
watcher: chokidar.FSWatcher |
||||||
|
warnlog: boolean |
||||||
|
buildPath: string |
||||||
|
cachePath: string |
||||||
|
logTimeout: NodeJS.Timeout |
||||||
|
processingTimeout: NodeJS.Timeout |
||||||
|
|
||||||
|
async onActivation(): Promise<void> { |
||||||
|
console.log('Hardhat plugin activated') |
||||||
|
this.call('terminal', 'log', { type: 'log', value: 'Hardhat plugin activated' }) |
||||||
|
|
||||||
|
this.on('fs' as any, 'workingDirChanged', async (path: string) => { |
||||||
|
console.log('workingDirChanged hardhat', path) |
||||||
|
this.currentSharedFolder = path |
||||||
|
this.startListening() |
||||||
|
}) |
||||||
|
this.currentSharedFolder = await this.call('fs' as any, 'getWorkingDir') |
||||||
|
if(this.currentSharedFolder) this.startListening() |
||||||
|
} |
||||||
|
|
||||||
|
startListening() { |
||||||
|
this.buildPath = utils.absolutePath('artifacts/contracts', this.currentSharedFolder) |
||||||
|
if (fs.existsSync(this.buildPath)) { |
||||||
|
this.listenOnHardhatCompilation() |
||||||
|
} else { |
||||||
|
console.log('If you are using Hardhat, run `npx hardhat compile` or run the compilation with `Enable Hardhat Compilation` checked from the Remix IDE.') |
||||||
|
this.listenOnHardHatFolder() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
compile(configPath: string) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const cmd = `npx hardhat compile --config ${utils.normalizePath(configPath)}` |
||||||
|
const options = { cwd: this.currentSharedFolder, shell: true } |
||||||
|
const child = spawn(cmd, options) |
||||||
|
let result = '' |
||||||
|
let error = '' |
||||||
|
child.stdout.on('data', (data) => { |
||||||
|
const msg = `[Hardhat Compilation]: ${data.toString()}` |
||||||
|
console.log('\x1b[32m%s\x1b[0m', msg) |
||||||
|
result += msg + '\n' |
||||||
|
}) |
||||||
|
child.stderr.on('data', (err) => { |
||||||
|
error += `[Hardhat Compilation]: ${err.toString()} \n` |
||||||
|
}) |
||||||
|
child.on('close', () => { |
||||||
|
if (error && result) resolve(error + result) |
||||||
|
else if (error) reject(error) |
||||||
|
else resolve(result) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
checkPath() { |
||||||
|
if (!fs.existsSync(this.buildPath)) { |
||||||
|
this.listenOnHardHatFolder() |
||||||
|
return false |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
private async processArtifact() { |
||||||
|
console.log('processing artifact') |
||||||
|
if (!this.checkPath()) return |
||||||
|
// resolving the files
|
||||||
|
const folderFiles = await fs.promises.readdir(this.buildPath) |
||||||
|
const targetsSynced = [] |
||||||
|
// name of folders are file names
|
||||||
|
for (const file of folderFiles) { // ["artifacts/contracts/Greeter.sol/"]
|
||||||
|
const contractFilePath = join(this.buildPath, file) |
||||||
|
const stat = await fs.promises.stat(contractFilePath) |
||||||
|
if (!stat.isDirectory()) continue |
||||||
|
const files = await fs.promises.readdir(contractFilePath) |
||||||
|
const compilationResult = { |
||||||
|
input: {}, |
||||||
|
output: { |
||||||
|
contracts: {}, |
||||||
|
sources: {} |
||||||
|
}, |
||||||
|
solcVersion: null, |
||||||
|
target: null |
||||||
|
} |
||||||
|
for (const file of files) { |
||||||
|
if (file.endsWith('.dbg.json')) { // "artifacts/contracts/Greeter.sol/Greeter.dbg.json"
|
||||||
|
const stdFile = file.replace('.dbg.json', '.json') |
||||||
|
const contentStd = await fs.promises.readFile(join(contractFilePath, stdFile), { encoding: 'utf-8' }) |
||||||
|
const contentDbg = await fs.promises.readFile(join(contractFilePath, file), { encoding: 'utf-8' }) |
||||||
|
const jsonDbg = JSON.parse(contentDbg) |
||||||
|
const jsonStd = JSON.parse(contentStd) |
||||||
|
compilationResult.target = jsonStd.sourceName |
||||||
|
|
||||||
|
targetsSynced.push(compilationResult.target) |
||||||
|
const path = join(contractFilePath, jsonDbg.buildInfo) |
||||||
|
const content = await fs.promises.readFile(path, { encoding: 'utf-8' }) |
||||||
|
|
||||||
|
await this.feedContractArtifactFile(content, compilationResult) |
||||||
|
} |
||||||
|
if (compilationResult.target) { |
||||||
|
// we are only interested in the contracts that are in the target of the compilation
|
||||||
|
compilationResult.output = { |
||||||
|
...compilationResult.output, |
||||||
|
contracts: { [compilationResult.target]: compilationResult.output.contracts[compilationResult.target] } |
||||||
|
} |
||||||
|
this.emit('compilationFinished', compilationResult.target, { sources: compilationResult.input }, 'soljson', compilationResult.output, compilationResult.solcVersion) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
clearTimeout(this.logTimeout) |
||||||
|
this.logTimeout = setTimeout(() => { |
||||||
|
this.call('terminal', 'log', { value: 'receiving compilation result from Hardhat. Select a file to populate the contract interaction interface.', type: 'log' }) |
||||||
|
if (targetsSynced.length) { |
||||||
|
console.log(`Processing artifacts for files: ${[...new Set(targetsSynced)].join(', ')}`) |
||||||
|
// @ts-ignore
|
||||||
|
this.call('terminal', 'log', { type: 'log', value: `synced with Hardhat: ${[...new Set(targetsSynced)].join(', ')}` }) |
||||||
|
} else { |
||||||
|
console.log('No artifacts to process') |
||||||
|
// @ts-ignore
|
||||||
|
this.call('terminal', 'log', { type: 'log', value: 'No artifacts from Hardhat to process' }) |
||||||
|
} |
||||||
|
}, 1000) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
listenOnHardHatFolder() { |
||||||
|
console.log('Hardhat artifacts folder doesn\'t exist... waiting for the compilation.') |
||||||
|
try { |
||||||
|
if (this.watcher) this.watcher.close() |
||||||
|
this.watcher = chokidar.watch(this.currentSharedFolder, { depth: 2, ignorePermissionErrors: true, ignoreInitial: true }) |
||||||
|
// watch for new folders
|
||||||
|
this.watcher.on('addDir', (path: string) => { |
||||||
|
console.log('add dir hardhat', path) |
||||||
|
if (fs.existsSync(this.buildPath)) { |
||||||
|
this.listenOnHardhatCompilation() |
||||||
|
} |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log('listenOnHardHatFolder', e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async triggerProcessArtifact() { |
||||||
|
console.log('triggerProcessArtifact') |
||||||
|
// prevent multiple calls
|
||||||
|
clearTimeout(this.processingTimeout) |
||||||
|
this.processingTimeout = setTimeout(async () => await this.processArtifact(), 1000) |
||||||
|
} |
||||||
|
|
||||||
|
listenOnHardhatCompilation() { |
||||||
|
try { |
||||||
|
console.log('listening on Hardhat compilation...', this.buildPath) |
||||||
|
if (this.watcher) this.watcher.close() |
||||||
|
this.watcher = chokidar.watch(this.buildPath, { depth: 1, ignorePermissionErrors: true, ignoreInitial: true }) |
||||||
|
this.watcher.on('change', async () => await this.triggerProcessArtifact()) |
||||||
|
this.watcher.on('add', async () => await this.triggerProcessArtifact()) |
||||||
|
this.watcher.on('unlink', async () => await this.triggerProcessArtifact()) |
||||||
|
// process the artifact on activation
|
||||||
|
this.processArtifact() |
||||||
|
} catch (e) { |
||||||
|
console.log('listenOnHardhatCompilation', e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async sync() { |
||||||
|
console.log('syncing from Hardhat') |
||||||
|
this.processArtifact() |
||||||
|
} |
||||||
|
|
||||||
|
async feedContractArtifactFile(artifactContent, compilationResultPart) { |
||||||
|
const contentJSON = JSON.parse(artifactContent) |
||||||
|
compilationResultPart.solcVersion = contentJSON.solcVersion |
||||||
|
for (const file in contentJSON.input.sources) { |
||||||
|
const source = contentJSON.input.sources[file] |
||||||
|
const absPath = join(this.currentSharedFolder, file) |
||||||
|
if (fs.existsSync(absPath)) { // if not that is a lib
|
||||||
|
const contentOnDisk = await fs.promises.readFile(absPath, { encoding: 'utf-8' }) |
||||||
|
if (contentOnDisk === source.content) { |
||||||
|
compilationResultPart.input[file] = source |
||||||
|
compilationResultPart.output['sources'][file] = contentJSON.output.sources[file] |
||||||
|
compilationResultPart.output['contracts'][file] = contentJSON.output.contracts[file] |
||||||
|
if (contentJSON.output.errors && contentJSON.output.errors.length) { |
||||||
|
compilationResultPart.output['errors'] = contentJSON.output.errors.filter(error => error.sourceLocation.file === file) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,9 +0,0 @@ |
|||||||
export type branch = { |
|
||||||
name: string |
|
||||||
remote: remote |
|
||||||
} |
|
||||||
|
|
||||||
export type remote = { |
|
||||||
name: string |
|
||||||
url: string |
|
||||||
} |
|
@ -0,0 +1,195 @@ |
|||||||
|
import { spawn, ChildProcess } from "child_process" |
||||||
|
|
||||||
|
export async function getBranches(path: string): Promise<string> { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('git', ['branch'], { cwd: path }) |
||||||
|
let branches = '' |
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('stdout git branches', data.toString()) |
||||||
|
branches += data.toString() |
||||||
|
}) |
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.log('stderr git branches', data.toString()) |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
git.on('close', function () { |
||||||
|
resolve(branches) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
export async function getGitLog(path: string): Promise<string> { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('git', ['log'], { cwd: path }) |
||||||
|
let logs = '' |
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
logs += data.toString() |
||||||
|
}) |
||||||
|
git.stderr.on('err', function (data) { |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
git.on('close', function () { |
||||||
|
resolve(logs) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
export async function cloneOnServer(repo: string, path: string, name: string = 'bare') { |
||||||
|
console.log('cloning', repo, path) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn(`rm -rf ${name} && git`, ['clone', repo], { cwd: path, shell: true, detached: true }); |
||||||
|
|
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('stdout data cloning', data.toString()); |
||||||
|
if (data.toString().includes('done')) { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.log('stderr data cloning', data.toString()); |
||||||
|
if (data.toString().includes('into')) { |
||||||
|
setTimeout(() => { |
||||||
|
resolve(git); |
||||||
|
}, 5000) |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('error', (error) => { |
||||||
|
reject(`Process error: ${error.message}`); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('exit', (code, signal) => { |
||||||
|
if (code !== 0) { |
||||||
|
reject(`Process exited with code: ${code} and signal: ${signal}`); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export async function onLocalGitRepoAddFile(path: string, file: string) { |
||||||
|
console.log('adding file', file) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('touch', [file], { cwd: path }); |
||||||
|
|
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('stdout data adding file', data.toString()); |
||||||
|
if (data.toString().includes('done')) { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.error('stderr adding file', data.toString()); |
||||||
|
reject(data.toString()); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('error', (error) => { |
||||||
|
reject(`Process error: ${error.message}`); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('exit', (code, signal) => { |
||||||
|
if (code !== 0) { |
||||||
|
reject(`Process exited with code: ${code} and signal: ${signal}`); |
||||||
|
} else { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export async function onLocalGitRepoPush(path: string, branch: string = 'master') { |
||||||
|
console.log('pushing', path) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('git', ['push', 'origin', branch], { cwd: path, shell: true, detached: true }); |
||||||
|
|
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('stdout data pushing', data.toString()); |
||||||
|
if (data.toString().includes('done')) { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.error('stderr data pushing', data.toString()); |
||||||
|
if (data.toString().includes(branch)) { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('error', (error) => { |
||||||
|
reject(`Process error: ${error.message}`); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('exit', (code, signal) => { |
||||||
|
if (code !== 0) { |
||||||
|
reject(`Process exited with code: ${code} and signal: ${signal}`); |
||||||
|
} else { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export async function createCommitOnLocalServer(path: string, message: string) { |
||||||
|
console.log('committing', message, path) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('git add . && git', ['commit', '-m', message], { cwd: path, shell: true, detached: true }); |
||||||
|
|
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('data stdout committing', data.toString()); |
||||||
|
if (data.toString().includes(message)) { |
||||||
|
setTimeout(() => { |
||||||
|
resolve(git); |
||||||
|
}, 1000) |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.error('data commiting', data.toString()); |
||||||
|
reject(data.toString()); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('error', (error) => { |
||||||
|
console.error('error', error); |
||||||
|
reject(`Process error: ${error.message}`); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('exit', (code, signal) => { |
||||||
|
if (code !== 0) { |
||||||
|
console.error('exit', code, signal); |
||||||
|
reject(`Process exited with code: ${code} and signal: ${signal}`); |
||||||
|
} else { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export async function spawnGitServer(path: string): Promise<ChildProcess> { |
||||||
|
console.log(process.cwd()) |
||||||
|
try { |
||||||
|
const server = spawn('yarn && sh setup.sh && yarn start:server', [`${path}`], { cwd: process.cwd() + '/../remix-ide-e2e/src/githttpbackend/', shell: true, detached: true }) |
||||||
|
console.log('spawned', server.stdout.closed, server.stderr.closed) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.stdout.on('data', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
if ( |
||||||
|
data.toString().includes('is listening') |
||||||
|
|| data.toString().includes('address already in use') |
||||||
|
) { |
||||||
|
console.log('resolving') |
||||||
|
resolve(server) |
||||||
|
} |
||||||
|
}) |
||||||
|
server.stderr.on('err', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,157 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
import { ChildProcess, spawn, execSync } from 'child_process' |
||||||
|
import { homedir } from 'os' |
||||||
|
import path from 'path' |
||||||
|
import os from 'os' |
||||||
|
|
||||||
|
const projectDir = path.join('remix-desktop-test-' + Date.now().toString()) |
||||||
|
const dir = '/tmp/' + projectDir |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
installFoundry: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
await downloadFoundry() |
||||||
|
await installFoundry() |
||||||
|
await initFoundryProject() |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
addScript: function (browser: NightwatchBrowser) { |
||||||
|
// run script in console
|
||||||
|
browser.executeAsync(function (dir, done) { |
||||||
|
(window as any).electronAPI.openFolderInSameWindow(dir + '/hello_foundry/').then(done) |
||||||
|
}, [dir], () => { |
||||||
|
console.log('done window opened') |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewDivDraggableItemfoundry.toml"]', 10000) |
||||||
|
}, |
||||||
|
compile: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
console.log('generating compilation result') |
||||||
|
await buildFoundryProject() |
||||||
|
done() |
||||||
|
}) |
||||||
|
.expect.element('*[data-id="terminalJournal"]').text.to.contain('receiving compilation result from Foundry').before(60000) |
||||||
|
|
||||||
|
let contractAaddress |
||||||
|
browser.clickLaunchIcon('filePanel') |
||||||
|
.openFile('src') |
||||||
|
.openFile('src/Counter.sol') |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.selectContract('Counter') |
||||||
|
.createContract('') |
||||||
|
.getAddressAtPosition(0, (address) => { |
||||||
|
console.log(contractAaddress) |
||||||
|
contractAaddress = address |
||||||
|
}) |
||||||
|
.clickInstance(0) |
||||||
|
.clickFunction('increment - transact (not payable)') |
||||||
|
.perform((done) => { |
||||||
|
browser.testConstantFunction(contractAaddress, 'number - call', null, '0:\nuint256: 1').perform(() => { |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
async function downloadFoundry(): Promise<void> { |
||||||
|
console.log('downloadFoundry', process.cwd()) |
||||||
|
try { |
||||||
|
const server = spawn('curl -L https://foundry.paradigm.xyz | bash', [], { cwd: process.cwd(), shell: true, detached: true }) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.stdout.on('data', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
if ( |
||||||
|
data.toString().includes("simply run 'foundryup' to install Foundry") |
||||||
|
|| data.toString().includes("foundryup: could not detect shell, manually add") |
||||||
|
) { |
||||||
|
console.log('resolving') |
||||||
|
resolve() |
||||||
|
} |
||||||
|
}) |
||||||
|
server.stderr.on('err', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function installFoundry(): Promise<void> { |
||||||
|
console.log('installFoundry', process.cwd()) |
||||||
|
try { |
||||||
|
const server = spawn('export PATH="' + homedir() + '/.foundry/bin:$PATH" && foundryup', [], { cwd: process.cwd(), shell: true, detached: true }) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.stdout.on('data', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
if ( |
||||||
|
data.toString().includes("foundryup: done!") |
||||||
|
) { |
||||||
|
console.log('resolving') |
||||||
|
resolve() |
||||||
|
} |
||||||
|
}) |
||||||
|
server.stderr.on('err', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function initFoundryProject(): Promise<void> { |
||||||
|
console.log('initFoundryProject', homedir()) |
||||||
|
try { |
||||||
|
if (process.env.CIRCLECI) { |
||||||
|
spawn('git config --global user.email \"you@example.com\"', [], { cwd: homedir(), shell: true, detached: true }) |
||||||
|
spawn('git config --global user.name \"Your Name\"', [], { cwd: homedir(), shell: true, detached: true }) |
||||||
|
} |
||||||
|
spawn('mkdir ' + projectDir, [], { cwd: '/tmp/', shell: true, detached: true }) |
||||||
|
const server = spawn('export PATH="' + homedir() + '/.foundry/bin:$PATH" && forge init hello_foundry', [], { cwd: dir, shell: true, detached: true }) |
||||||
|
server.stdout.pipe(process.stdout) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.on('exit', function (exitCode) { |
||||||
|
console.log("Child exited with code: " + exitCode); |
||||||
|
console.log('end') |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
server.stderr.on('err', function (data) { |
||||||
|
console.log('err', data.toString()) |
||||||
|
}) |
||||||
|
server.stdout.on('data', function (data) { |
||||||
|
console.log('data', data.toString()) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function buildFoundryProject(): Promise<void> { |
||||||
|
console.log('buildFoundryProject', homedir()) |
||||||
|
try { |
||||||
|
const server = spawn('export PATH="' + homedir() + '/.foundry/bin:$PATH" && forge build', [], { cwd: dir + '/hello_foundry', shell: true, detached: true }) |
||||||
|
server.stdout.pipe(process.stdout) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.on('exit', function (exitCode) { |
||||||
|
console.log("Child exited with code: " + exitCode); |
||||||
|
console.log('end') |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
...{}//...process.platform.startsWith('linux') ? tests : {}
|
||||||
|
} |
@ -0,0 +1,203 @@ |
|||||||
|
import { ChildProcess, spawn } from "child_process" |
||||||
|
import kill from 'tree-kill' |
||||||
|
import { Nightwatch, NightwatchBrowser } from "nightwatch" |
||||||
|
import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" |
||||||
|
let gitserver: ChildProcess |
||||||
|
|
||||||
|
/* |
||||||
|
/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) |
||||||
|
/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD |
||||||
|
/ GROUP 2: branch operations CREATE & PUBLISH |
||||||
|
/ GROUP 3: file operations rename delete |
||||||
|
*/ |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform((done) => { |
||||||
|
console.log('kill server', gitserver.pid) |
||||||
|
kill(gitserver.pid) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
gitserver = await spawnGitServer('/tmp/') |
||||||
|
console.log('working directory', process.cwd()) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(5000) |
||||||
|
.waitForElementVisible('*[data-id="cloneButton"]') |
||||||
|
.click('*[data-id="cloneButton"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.click('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') |
||||||
|
.setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') |
||||||
|
.click('[data-id="fileSystem-modal-footer-ok-react"]') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
.hideToolTips() |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
// GROUP 1
|
||||||
|
|
||||||
|
'check file added #group1 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.addFile('test.txt', { content: 'hello world' }, 'README.md') |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
}, |
||||||
|
'look at the commit #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-ahead"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'sync the commit #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-panel"]') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
|
||||||
|
.waitForElementVisible('*[data-id="syncButton"]') |
||||||
|
.click('*[data-id="syncButton"]') |
||||||
|
.pause(2000) |
||||||
|
.waitForElementVisible('*[data-id="commitButton"]') |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the log #group1': async function (browser: NightwatchBrowser) { |
||||||
|
const logs = await getGitLog('/tmp/git/bare.git') |
||||||
|
console.log(logs) |
||||||
|
browser.assert.ok(logs.includes('testcommit')) |
||||||
|
}, |
||||||
|
'change a file #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
openFile('test.txt'). |
||||||
|
pause(1000). |
||||||
|
setEditorValue('changes', null) |
||||||
|
}, |
||||||
|
'stage changed file #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='modified-unstaged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='modified-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit2') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
}, |
||||||
|
'push the commit #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-push"]') |
||||||
|
.click('*[data-id="sourcecontrol-push"]') |
||||||
|
.pause(2000) |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit2-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}).pause(2000) |
||||||
|
}, |
||||||
|
'check the log for testcommit2 #group1': async function (browser: NightwatchBrowser) { |
||||||
|
const logs = await getGitLog('/tmp/git/bare.git') |
||||||
|
console.log(logs) |
||||||
|
browser.assert.ok(logs.includes('testcommit2')) |
||||||
|
}, |
||||||
|
'clone locally and add a file and push #group1': async function (browser: NightwatchBrowser) { |
||||||
|
await cloneOnServer('http://localhost:6868/bare.git', '/tmp/') |
||||||
|
await onLocalGitRepoAddFile('/tmp/bare/', 'test2.txt') |
||||||
|
await createCommitOnLocalServer('/tmp/bare/', 'testlocal') |
||||||
|
await onLocalGitRepoPush('/tmp/bare/', 'master') |
||||||
|
}, |
||||||
|
'run a git fetch #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(2000) |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-fetch-branch"]') |
||||||
|
|
||||||
|
.click('*[data-id="sourcecontrol-fetch-branch"]') |
||||||
|
.pause(2000) |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="commits-panel-behind"]') |
||||||
|
.click('*[data-id="commits-panel-behind"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testlocal-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'run pull from the header #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
click('*[data-id="sourcecontrol-button-pull"]') |
||||||
|
.waitForElementNotPresent('*[data-id="commits-panel-behind"]') |
||||||
|
}, |
||||||
|
'check if the file is added #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest2.txt"]') |
||||||
|
}, |
||||||
|
} |
||||||
|
const useIsoGit = process.argv.includes('--use-isogit'); |
||||||
|
if (process.platform.startsWith('win')) { |
||||||
|
module.exports = {} |
||||||
|
} |
||||||
|
else
|
||||||
|
module.exports = { ...tests } |
||||||
|
|
||||||
|
|
@ -0,0 +1,181 @@ |
|||||||
|
import { ChildProcess, spawn } from "child_process" |
||||||
|
import kill from 'tree-kill' |
||||||
|
import { Nightwatch, NightwatchBrowser } from "nightwatch" |
||||||
|
import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" |
||||||
|
let gitserver: ChildProcess |
||||||
|
|
||||||
|
/* |
||||||
|
/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) |
||||||
|
/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD |
||||||
|
/ GROUP 2: branch operations CREATE & PUBLISH |
||||||
|
/ GROUP 3: file operations rename delete |
||||||
|
*/ |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform((done) => { |
||||||
|
console.log('kill server', gitserver.pid) |
||||||
|
kill(gitserver.pid) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
gitserver = await spawnGitServer('/tmp/') |
||||||
|
console.log('working directory', process.cwd()) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(5000) |
||||||
|
.waitForElementVisible('*[data-id="cloneButton"]') |
||||||
|
.click('*[data-id="cloneButton"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.click('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') |
||||||
|
.setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') |
||||||
|
.click('[data-id="fileSystem-modal-footer-ok-react"]') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
.hideToolTips() |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
// GROUP 2
|
||||||
|
'create a branch #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="branches-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="newbranchname"]') |
||||||
|
.setValue('*[data-id="newbranchname"]', 'testbranch') |
||||||
|
.click('*[data-id="sourcecontrol-create-branch"]') |
||||||
|
.waitForElementVisible('*[data-id="branches-current-branch-testbranch"]') |
||||||
|
.pause(1000) |
||||||
|
}, |
||||||
|
'check if the branch is in the filePanel #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="workspaceGitBranchesDropdown"]') |
||||||
|
.click('[data-id="workspaceGitBranchesDropdown"]') |
||||||
|
.waitForElementVisible('*[data-id="workspaceGit-testbranch"]') |
||||||
|
.expect.element('[data-id="workspaceGit-testbranch"]').text.to.contain('✓ ') |
||||||
|
}, |
||||||
|
'publish the branch #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-panel"]') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="publishBranchButton"]') |
||||||
|
.pause(2000) |
||||||
|
.waitForElementNotVisible('*[data-id="publishBranchButton"]') |
||||||
|
}, |
||||||
|
'check if the branch is published #group2': async function (browser: NightwatchBrowser) { |
||||||
|
const branches = await getBranches('/tmp/git/bare.git') |
||||||
|
browser.assert.ok(branches.includes('testbranch')) |
||||||
|
}, |
||||||
|
'add file to new branch #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.addFile('test.txt', { content: 'hello world' }, 'README.md') |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(2000) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
.pause(1000) |
||||||
|
}, |
||||||
|
'check if the commit is ahead in the branches list #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="branches-panel"]') |
||||||
|
.click('*[data-id="branches-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="branches-current-branch-testbranch"]') |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-current-branch-testbranch']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
suppressNotFoundErrors: true |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='commits-panel-ahead']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
suppressNotFoundErrors: true |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branchdifference-commits-testbranch-ahead']//*[@data-id='commit-summary-testcommit-ahead']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branchdifference-commits-testbranch-ahead']//*[@data-id='commit-change-added-test.txt']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='local-branch-commits-testbranch']//*[@data-id='commit-summary-testcommit-ahead']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='local-branch-commits-testbranch']//*[@data-id='commit-change-added-test.txt']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch back to master #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-branch-master']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-current-branch-master']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check if test file is gone #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.txt"]') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const useIsoGit = process.argv.includes('--useIsoGit'); |
||||||
|
if (process.platform.startsWith('win')) { |
||||||
|
module.exports = {} |
||||||
|
} |
||||||
|
else
|
||||||
|
module.exports = { ...tests } |
@ -0,0 +1,153 @@ |
|||||||
|
import { ChildProcess, spawn } from "child_process" |
||||||
|
import kill from 'tree-kill' |
||||||
|
import { Nightwatch, NightwatchBrowser } from "nightwatch" |
||||||
|
import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" |
||||||
|
let gitserver: ChildProcess |
||||||
|
|
||||||
|
/* |
||||||
|
/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) |
||||||
|
/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD |
||||||
|
/ GROUP 2: branch operations CREATE & PUBLISH |
||||||
|
/ GROUP 3: file operations rename delete |
||||||
|
*/ |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform((done) => { |
||||||
|
console.log('kill server', gitserver.pid) |
||||||
|
kill(gitserver.pid) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
gitserver = await spawnGitServer('/tmp/') |
||||||
|
console.log('working directory', process.cwd()) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(5000) |
||||||
|
.waitForElementVisible('*[data-id="cloneButton"]') |
||||||
|
.click('*[data-id="cloneButton"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.click('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') |
||||||
|
.setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') |
||||||
|
.click('[data-id="fileSystem-modal-footer-ok-react"]') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
.hideToolTips() |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.saveScreenshot('./reports/screenshots/gitui.png') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.saveScreenshot('./reports/screenshots/gitui2.png') |
||||||
|
.pause(1000) |
||||||
|
.saveScreenshot('./reports/screenshots/gitui3.png') |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.pause(1000) |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
'check file added #group1 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.addFile('test.txt', { content: 'hello world' }, 'README.md') |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
}, |
||||||
|
|
||||||
|
// group 3
|
||||||
|
'rename a file #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.txt"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemtest.txt"]') |
||||||
|
.renamePath('test.txt', 'test_rename', 'test_rename.txt') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest_rename.txt"]') |
||||||
|
.pause(1000) |
||||||
|
}, |
||||||
|
'stage renamed file #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='deleted-unstaged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test_rename.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(2000) |
||||||
|
.click('*[data-id="sourcecontrol-add-all"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test_rename.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'undo the rename #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="unStageStagedtest_rename.txt"]') |
||||||
|
.click('*[data-id="unStageStagedtest_rename.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="unDoStagedtest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementNotPresent({ |
||||||
|
selector: "//*[@data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check if file is returned #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.txt"]') |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const useIsoGit = process.argv.includes('--use-isogit'); |
||||||
|
if (process.platform.startsWith('win')) { |
||||||
|
module.exports = {} |
||||||
|
} |
||||||
|
else
|
||||||
|
module.exports = { ...tests } |
@ -0,0 +1,200 @@ |
|||||||
|
import { ChildProcess, spawn } from "child_process" |
||||||
|
import kill from 'tree-kill' |
||||||
|
import { Nightwatch, NightwatchBrowser } from "nightwatch" |
||||||
|
import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" |
||||||
|
let gitserver: ChildProcess |
||||||
|
|
||||||
|
/* |
||||||
|
/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) |
||||||
|
/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD |
||||||
|
/ GROUP 2: branch operations CREATE & PUBLISH |
||||||
|
/ GROUP 3: file operations rename delete |
||||||
|
*/ |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform((done) => { |
||||||
|
console.log('kill server', gitserver.pid) |
||||||
|
kill(gitserver.pid) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
gitserver = await spawnGitServer('/tmp/') |
||||||
|
console.log('working directory', process.cwd()) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(5000) |
||||||
|
.waitForElementVisible('*[data-id="cloneButton"]') |
||||||
|
.click('*[data-id="cloneButton"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.click('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') |
||||||
|
.setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') |
||||||
|
.click('[data-id="fileSystem-modal-footer-ok-react"]') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
.hideToolTips() |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.pause(1000) |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
// GROUP 1
|
||||||
|
|
||||||
|
'check file added #group1 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.addFile('test.txt', { content: 'hello world' }, 'README.md') |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
}, |
||||||
|
'look at the commit #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-ahead"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'add second remote #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="add-manual-remoteurl"]') |
||||||
|
.setValue('*[data-id="add-manual-remoteurl"]', 'http://localhost:6868/bare2.git') |
||||||
|
.waitForElementVisible('*[data-id="add-manual-remotename"]') |
||||||
|
.setValue('*[data-id="add-manual-remotename"]', 'origin2') |
||||||
|
.waitForElementVisible('*[data-id="add-manual-remotebtn"]') |
||||||
|
.click('*[data-id="add-manual-remotebtn"]') |
||||||
|
}, |
||||||
|
'check the buttons #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="default-remote-check-origin"]') |
||||||
|
.waitForElementVisible('*[data-id="set-as-default-origin2"]') |
||||||
|
}, |
||||||
|
'check the commands #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch to origin2 #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="set-as-default-origin2"]') |
||||||
|
.click('*[data-id="set-as-default-origin2"]') |
||||||
|
}, |
||||||
|
'check the commands for origin2 #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin2')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'sync the commit #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-panel"]') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="syncButton"]') |
||||||
|
.click('*[data-id="syncButton"]') |
||||||
|
.waitForElementVisible('*[data-id="commitButton"]') |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the log #group4': async function (browser: NightwatchBrowser) { |
||||||
|
const logs = await getGitLog('/tmp/git/bare2.git') |
||||||
|
console.log(logs) |
||||||
|
browser.assert.ok(logs.includes('testcommit')) |
||||||
|
const logs2 = await getGitLog('/tmp/git/bare.git') |
||||||
|
console.log(logs2) |
||||||
|
console.log(logs2.includes('testcommit3')) |
||||||
|
browser.assert.ok(logs2.includes('testcommit3')) |
||||||
|
}, |
||||||
|
'switch to origin #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(5000) |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="set-as-default-origin"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="set-as-default-origin"]') |
||||||
|
}, |
||||||
|
'check the commands for origin #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the commit ahead #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-panel"]') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="syncButton"]') |
||||||
|
// do not sync
|
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-ahead"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
const useIsoGit = process.argv.includes('--use-isogit'); |
||||||
|
if (process.platform.startsWith('win')) { |
||||||
|
module.exports = {} |
||||||
|
} |
||||||
|
else
|
||||||
|
module.exports = { ...tests } |
@ -0,0 +1,255 @@ |
|||||||
|
import { NightwatchBrowser } from "nightwatch" |
||||||
|
|
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
|
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="initgit-btn"]') |
||||||
|
.click('*[data-id="initgit-btn"]') |
||||||
|
.waitForElementNotPresent('*[data-id="initgit-btn"]') |
||||||
|
}, |
||||||
|
'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="filepanel-login-github"]') |
||||||
|
.click('*[data-id="filepanel-login-github"]') |
||||||
|
}, |
||||||
|
'login to github #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="gitubUsername"]') |
||||||
|
.setValue('*[data-id="githubToken"]', process.env.dgit_token) |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
}, |
||||||
|
'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="connected-as-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-img-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-link-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel"]') |
||||||
|
}, |
||||||
|
'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]') |
||||||
|
}, |
||||||
|
'clone a repository #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.click('*[data-id="clone-panel"]') |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@data-id="fetch-repositories"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@id="repository-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@id="repository-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[contains(text(), "awesome-remix")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[contains(text(), "awesome-remix")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@id="branch-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@id="branch-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[contains(text(), "master")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@data-id="clonebtn-ethereum/awesome-remix-master"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@data-id="clonebtn-ethereum/awesome-remix-master"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[2]) |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check if there is a README.md file #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'check the commands panel #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'master')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'master')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the remotes #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
|
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel-content"]') |
||||||
|
.pause(2000) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-origin-default"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-current-branch-master"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-sync-origin"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]', |
||||||
|
locateStrategy: 'xpath', |
||||||
|
timeout: 10000 |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'check the commits of branch links #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="commit-summary-linking fixed-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch to branch links #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="branches-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-toggle-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-toggle-current-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the local branches #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-local-branches"]//*[@data-id="branches-toggle-current-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the local commits #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="commits-current-branch-links"]//*[@data-id="commit-summary-linking fixed-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="commits-current-branch-links"]//*[@data-id="commit-summary-linking fixed-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="commits-current-branch-links"]//*[@data-id="commit-change-modified-README.md"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the commands panel for links #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'links')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'links')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'disconnect github #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="disconnect-github"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="disconnect-github"]') |
||||||
|
.waitForElementNotPresent('*[data-id="connected-as-bunsenstraat"]') |
||||||
|
}, |
||||||
|
'check the FE for the disconnected auth user #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementNotPresent('*[data-id="filepanel-connected-img-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="filepanel-login-github"]') |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = tests |
@ -0,0 +1,190 @@ |
|||||||
|
import { NightwatchBrowser } from "nightwatch" |
||||||
|
|
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
|
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="initgit-btn"]') |
||||||
|
.click('*[data-id="initgit-btn"]') |
||||||
|
.waitForElementNotPresent('*[data-id="initgit-btn"]') |
||||||
|
}, |
||||||
|
'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="filepanel-login-github"]') |
||||||
|
.click('*[data-id="filepanel-login-github"]') |
||||||
|
}, |
||||||
|
'login to github #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="gitubUsername"]') |
||||||
|
.setValue('*[data-id="githubToken"]', process.env.dgit_token) |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
}, |
||||||
|
'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="connected-as-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-img-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-link-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel"]') |
||||||
|
}, |
||||||
|
'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]') |
||||||
|
}, |
||||||
|
'add a remote #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel"]') |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="fetch-repositories"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@id="repository-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@id="repository-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[contains(text(), "awesome-remix")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[contains(text(), "awesome-remix")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-remotename"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-remotename"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}, 'newremote') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-addremote"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-addremote"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote-default"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the commands panel for newremote #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'newremote')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.getAttribute({ |
||||||
|
selector: '//*[@data-id="sourcecontrol-pull"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}, 'disabled', (result) => { |
||||||
|
if (result.value) { |
||||||
|
browser.assert.fail('Button is disabled') |
||||||
|
} else { |
||||||
|
browser.assert.ok(true) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
'remove the remote #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-rm-newremote"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(2000) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-rm-newremote"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.waitForElementNotPresent({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote-default"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the commands panel for removed remote #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementNotPresent({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'newremote')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.getAttribute({ |
||||||
|
selector: '//*[@data-id="sourcecontrol-pull"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}, 'disabled', (result) => { |
||||||
|
if (result.value) { |
||||||
|
browser.assert.ok(true) |
||||||
|
} else { |
||||||
|
browser.assert.fail('Button is not disabled') |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = tests |
@ -0,0 +1,180 @@ |
|||||||
|
import { NightwatchBrowser } from "nightwatch" |
||||||
|
|
||||||
|
const useIsoGit = process.argv.includes('--use-isogit'); |
||||||
|
let commitCount = 0 |
||||||
|
let branchCount = 0 |
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
|
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="initgit-btn"]') |
||||||
|
.click('*[data-id="initgit-btn"]') |
||||||
|
.waitForElementNotPresent('*[data-id="initgit-btn"]') |
||||||
|
}, |
||||||
|
'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="filepanel-login-github"]') |
||||||
|
.click('*[data-id="filepanel-login-github"]') |
||||||
|
}, |
||||||
|
'login to github #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="gitubUsername"]') |
||||||
|
.setValue('*[data-id="githubToken"]', process.env.dgit_token) |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
}, |
||||||
|
'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="connected-as-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-img-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-link-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel"]') |
||||||
|
}, |
||||||
|
'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]') |
||||||
|
}, |
||||||
|
// pagination test
|
||||||
|
'clone repo #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="clone-panel"]') |
||||||
|
.click('*[data-id="clone-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="clone-url"]') |
||||||
|
.setValue('*[data-id="clone-url"]', 'https://github.com/yann300/remix-reward') |
||||||
|
.waitForElementVisible('*[data-id="clone-branch"]') |
||||||
|
.setValue('*[data-id="clone-branch"]', 'master') |
||||||
|
.waitForElementVisible('*[data-id="clone-btn"]') |
||||||
|
.click('*[data-id="clone-btn"]') |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[2]) |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Update settings for git #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubToken"]', 'invalidtoken') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.pause(1000) |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
}, |
||||||
|
'check the commits panel for pagination #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="commits-panel"]') |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.elements('xpath', '//*[@data-id="commits-current-branch-master"]//*[@data-type="commit-summary"]', function (result) { |
||||||
|
console.log('Number of commit-summary elements:', (result.value as any).length); |
||||||
|
if (useIsoGit) { |
||||||
|
commitCount = (result.value as any).length |
||||||
|
browser.assert.ok((result.value as any).length == 1) |
||||||
|
} else { |
||||||
|
commitCount = (result.value as any).length |
||||||
|
browser.assert.ok((result.value as any).length > 2) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'load more commits #group3': function (browser: NightwatchBrowser) { |
||||||
|
console.log('commitCount:', commitCount) |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="load-more-commits"]') |
||||||
|
.click('*[data-id="load-more-commits"]') |
||||||
|
.waitForElementVisible('*[data-id="loader-indicator"]') |
||||||
|
.waitForElementNotPresent('*[data-id="loader-indicator"]') |
||||||
|
.pause(2000) |
||||||
|
.elements('xpath', '//*[@data-id="commits-current-branch-master"]//*[@data-type="commit-summary"]', function (result) { |
||||||
|
console.log('Number of commit-summary elements:', (result.value as any).length); |
||||||
|
browser.assert.ok((result.value as any).length > commitCount) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'load more branches from remote #group3': function (browser: NightwatchBrowser) { |
||||||
|
|
||||||
|
browser |
||||||
|
.click('*[data-id="branches-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-remote-branches"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.elements('xpath', '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-type="branches-branch"]', function (result) { |
||||||
|
console.log('Number of branches elements:', (result.value as any).length); |
||||||
|
if (useIsoGit) { |
||||||
|
branchCount = (result.value as any).length |
||||||
|
browser.assert.ok((result.value as any).length == 1) |
||||||
|
} else { |
||||||
|
branchCount = (result.value as any).length |
||||||
|
browser.assert.ok((result.value as any).length > 2) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
if (useIsoGit) { |
||||||
|
|
||||||
|
browser.waitForElementVisible('*[data-id="remote-sync-origin"]') |
||||||
|
.click('*[data-id="remote-sync-origin"]') |
||||||
|
.waitForElementVisible('*[data-id="loader-indicator"]') |
||||||
|
.waitForElementNotPresent('*[data-id="loader-indicator"]') |
||||||
|
.pause(2000) |
||||||
|
.elements('xpath', '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-type="branches-branch"]', function (result) { |
||||||
|
console.log('Number of branches elements:', (result.value as any).length); |
||||||
|
browser.assert.ok((result.value as any).length > branchCount) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
browser.waitForElementVisible('*[data-id="show-more-branches-on-remote"]') |
||||||
|
.click('*[data-id="show-more-branches-on-remote"]') |
||||||
|
.pause(1000) |
||||||
|
.elements('xpath', '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-type="branches-branch"]', function (result) { |
||||||
|
console.log('Number of branches elements:', (result.value as any).length); |
||||||
|
browser.assert.ok((result.value as any).length > branchCount) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = tests |
@ -0,0 +1,90 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
import { ChildProcess, spawn, execSync } from 'child_process' |
||||||
|
import { homedir } from 'os' |
||||||
|
import path from 'path' |
||||||
|
import os from 'os' |
||||||
|
|
||||||
|
const dir = path.join('remix-desktop-test-' + Date.now().toString()) |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
setuphardhat: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
await setupHardhatProject() |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
addScript: function (browser: NightwatchBrowser) { |
||||||
|
// run script in console
|
||||||
|
browser.executeAsync(function (dir, done) { |
||||||
|
(window as any).electronAPI.openFolderInSameWindow('/tmp/' + dir).then(done) |
||||||
|
}, [dir], () => { |
||||||
|
console.log('done window opened') |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewDivDraggableItemhardhat.config.js"]', 10000) |
||||||
|
}, |
||||||
|
compile: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
console.log('generating compilation result') |
||||||
|
await compileHardhatProject() |
||||||
|
done() |
||||||
|
}) |
||||||
|
.expect.element('*[data-id="terminalJournal"]').text.to.contain('receiving compilation result from Hardhat').before(60000) |
||||||
|
let addressRef |
||||||
|
browser.clickLaunchIcon('filePanel') |
||||||
|
.openFile('contracts') |
||||||
|
.openFile('contracts/Token.sol') |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') |
||||||
|
.selectContract('Token') |
||||||
|
.createContract('') |
||||||
|
.clickInstance(0) |
||||||
|
.clickFunction('balanceOf - call', { types: 'address account', values: '0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c' }) |
||||||
|
.getAddressAtPosition(0, (address) => { |
||||||
|
addressRef = address |
||||||
|
}) |
||||||
|
.perform((done) => { |
||||||
|
browser.verifyCallReturnValue(addressRef, ['0:uint256: 1000000']) |
||||||
|
.perform(() => done()) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function compileHardhatProject(): Promise<void> { |
||||||
|
console.log(process.cwd()) |
||||||
|
try { |
||||||
|
const server = spawn('npx hardhat compile', [], { cwd: '/tmp/' + dir, shell: true, detached: true }) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.on('exit', function (exitCode) { |
||||||
|
console.log("Child exited with code: " + exitCode); |
||||||
|
console.log('end') |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function setupHardhatProject(): Promise<void> { |
||||||
|
console.log('setup hardhat project', dir) |
||||||
|
try { |
||||||
|
const server = spawn(`git clone https://github.com/NomicFoundation/hardhat-boilerplate ${dir} && cd ${dir} && yarn install && yarn add "@typechain/ethers-v5@^10.1.0" && yarn add "@typechain/hardhat@^6.1.2" && yarn add "typechain@^8.1.0" && echo "END"`, [], { cwd: '/tmp/', shell: true, detached: true }) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.on('exit', function (exitCode) { |
||||||
|
console.log("Child exited with code: " + exitCode); |
||||||
|
console.log('end') |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
...tests |
||||||
|
} |
@ -1 +1,2 @@ |
|||||||
export * from './lib/remix-api' |
export * from './lib/remix-api' |
||||||
|
export * from './lib/types/git' |
@ -1,10 +1,13 @@ |
|||||||
import { commitChange } from "@remix-ui/git"; |
import { commitChange } from "@remix-api"; |
||||||
import { IFileSystem } from "@remixproject/plugin-api" |
import { IFileSystem } from "@remixproject/plugin-api" |
||||||
|
|
||||||
// Extended interface with 'diff' method
|
// Extended interface with 'diff' method
|
||||||
export interface IExtendedFileSystem extends IFileSystem { |
export interface IExtendedFileSystem extends IFileSystem { |
||||||
methods: IFileSystem['methods'] & { |
methods: IFileSystem['methods'] & { |
||||||
|
/** Compare the differences between two files */ |
||||||
diff(change: commitChange): Promise<void> |
diff(change: commitChange): Promise<void> |
||||||
|
refresh(): Promise<void> |
||||||
|
hasGitSubmodules(): Promise<boolean> |
||||||
isGitRepo(): Promise<boolean> |
isGitRepo(): Promise<boolean> |
||||||
}; |
}; |
||||||
} |
} |
@ -0,0 +1,13 @@ |
|||||||
|
import { StatusEvents } from "@remixproject/plugin-utils"; |
||||||
|
|
||||||
|
export interface IFs { |
||||||
|
events: { |
||||||
|
workingDirChanged(path: string): Promise<void>, |
||||||
|
} & StatusEvents, |
||||||
|
methods: { |
||||||
|
selectFolder(path?: string, title?: string, button?: string): Promise<string>
|
||||||
|
openWindow(path?: string): Promise<void>, |
||||||
|
getWorkingDir(): Promise<string>, |
||||||
|
openFolderInSameWindow(path: string): Promise<void>, |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
import { StatusEvents } from "@remixproject/plugin-utils" |
||||||
|
import { ReadBlobResult, ReadCommitResult, StatusRow } from "isomorphic-git" |
||||||
|
import { commitChange, repositoriesInput, repository, cloneInputType, branchesInputType, branch, remote, logInputType, remoteCommitsInputType, pagedCommits, fetchInputType, pullInputType, pushInputType, currentBranchInput, branchInputType, checkoutInputType, addInputType, rmInputType, resolveRefInput, readBlobInput, commitInputType, statusInput, compareBranchesInput, branchDifference, initInputType, updateSubmodulesInput } from "../types/git" |
||||||
|
|
||||||
|
export interface IGitApi { |
||||||
|
events: { |
||||||
|
"checkout": () => void |
||||||
|
"clone": () => void |
||||||
|
"add": () => void |
||||||
|
"rm": () => void |
||||||
|
"commit": () => void |
||||||
|
"branch": () => void |
||||||
|
"init": () => void |
||||||
|
} & StatusEvents, |
||||||
|
methods: { |
||||||
|
getCommitChanges(oid1: string, oid2: string): Promise<commitChange[]> |
||||||
|
repositories(input: repositoriesInput): Promise<repository[]> |
||||||
|
clone(input: cloneInputType): Promise<any> |
||||||
|
branches(input?: branchesInputType): Promise<branch[]>, |
||||||
|
remotes(): Promise<remote[]>, |
||||||
|
log(input: logInputType): Promise<ReadCommitResult[]>, |
||||||
|
remotecommits(input: remoteCommitsInputType): Promise<pagedCommits[]> |
||||||
|
fetch(input: fetchInputType): Promise<any> |
||||||
|
pull(input: pullInputType): Promise<any> |
||||||
|
push(input: pushInputType): Promise<any> |
||||||
|
currentbranch(input?: currentBranchInput): Promise<branch> |
||||||
|
branch(input: branchInputType): Promise<void> |
||||||
|
checkout(input: checkoutInputType): Promise<void> |
||||||
|
add(input: addInputType): Promise<void> |
||||||
|
rm(input: rmInputType): Promise<void> |
||||||
|
resolveref(input: resolveRefInput): Promise<string> |
||||||
|
readblob(input: readBlobInput): Promise<ReadBlobResult> |
||||||
|
commit(input: commitInputType): Promise<string> |
||||||
|
addremote(input: remote): Promise<void> |
||||||
|
delremote(input: remote): Promise<void> |
||||||
|
status(input?: statusInput): Promise<Array<StatusRow>> |
||||||
|
compareBranches(input: compareBranchesInput): Promise<branchDifference> |
||||||
|
init(input?: initInputType): Promise<void> |
||||||
|
updateSubmodules: (input: updateSubmodulesInput) => Promise<void> |
||||||
|
version: () => Promise<string> |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,10 @@ |
|||||||
|
import { ITerminal } from "@remixproject/plugin-api/src/lib/terminal" |
||||||
|
import { StatusEvents } from "@remixproject/plugin-utils" |
||||||
|
|
||||||
|
export interface IExtendedTerminalApi extends ITerminal { |
||||||
|
events: { |
||||||
|
} & StatusEvents |
||||||
|
methods: ITerminal['methods'] & { |
||||||
|
logHtml(html: string): void |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,206 @@ |
|||||||
|
import { Endpoints } from "@octokit/types" |
||||||
|
import { AuthCallback, HttpClient, ReadCommitResult } from "isomorphic-git" |
||||||
|
|
||||||
|
export type branchDifference = { |
||||||
|
uniqueHeadCommits: ReadCommitResult[], |
||||||
|
uniqueRemoteCommits: ReadCommitResult[], |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export type commitChange = { |
||||||
|
type: commitChangeType |
||||||
|
path: string, |
||||||
|
hashModified: string, |
||||||
|
hashOriginal: string, |
||||||
|
original?: string, |
||||||
|
modified?: string, |
||||||
|
readonly?: boolean |
||||||
|
} |
||||||
|
|
||||||
|
export type commitChangeTypes = { |
||||||
|
"deleted": "D" |
||||||
|
"modified": "M" |
||||||
|
"added": "A", |
||||||
|
"unknown": "?" |
||||||
|
} |
||||||
|
|
||||||
|
export type pagedCommits = { |
||||||
|
page: number, |
||||||
|
perPage: number, |
||||||
|
total: number, |
||||||
|
hasNextPage: boolean, |
||||||
|
commits: ReadCommitResult[] |
||||||
|
} |
||||||
|
|
||||||
|
export enum syncStatus { |
||||||
|
"sync" = "sync", |
||||||
|
"publishBranch" = "publishBranch", |
||||||
|
"none" = "none", |
||||||
|
} |
||||||
|
|
||||||
|
export type repository = { |
||||||
|
name: string |
||||||
|
html_url: string |
||||||
|
owner: { |
||||||
|
login: string |
||||||
|
}, |
||||||
|
full_name: string |
||||||
|
default_branch: string |
||||||
|
id: number |
||||||
|
url: string |
||||||
|
} |
||||||
|
|
||||||
|
export type branch = { |
||||||
|
name: string |
||||||
|
remote: remote |
||||||
|
} |
||||||
|
|
||||||
|
export type remote = { |
||||||
|
name: string |
||||||
|
url: string |
||||||
|
} |
||||||
|
|
||||||
|
export type remoteBranch = { |
||||||
|
name: string |
||||||
|
} |
||||||
|
|
||||||
|
export type commitChangeType = keyof commitChangeTypes |
||||||
|
|
||||||
|
export type initInputType = { |
||||||
|
defaultBranch: string |
||||||
|
} |
||||||
|
|
||||||
|
export type author = { |
||||||
|
name: string, |
||||||
|
email: string, |
||||||
|
} |
||||||
|
|
||||||
|
export type updateSubmodulesInput = { |
||||||
|
dir?: string |
||||||
|
token?: string |
||||||
|
} |
||||||
|
|
||||||
|
export type remoteCommitsInputType = { |
||||||
|
owner: string, repo: string, token: string, branch: string, length: number, page: number |
||||||
|
} |
||||||
|
|
||||||
|
export type compareBranchesInput = { |
||||||
|
branch: branch, remote: remote |
||||||
|
} |
||||||
|
|
||||||
|
export type fetchInputType = { |
||||||
|
remote: remote, |
||||||
|
ref?: branch, |
||||||
|
remoteRef?: branch, |
||||||
|
depth?: number, |
||||||
|
singleBranch?: boolean, |
||||||
|
relative?: boolean, |
||||||
|
quiet?: boolean |
||||||
|
author?: author |
||||||
|
token?: string |
||||||
|
} |
||||||
|
|
||||||
|
export type logInputType = { |
||||||
|
ref: string, |
||||||
|
depth?: number, |
||||||
|
} |
||||||
|
|
||||||
|
export type pullInputType = { |
||||||
|
remote: remote,
|
||||||
|
ref: branch,
|
||||||
|
remoteRef?: branch |
||||||
|
author?: author |
||||||
|
token?: string |
||||||
|
} |
||||||
|
|
||||||
|
export type pushInputType = { |
||||||
|
remote: remote,
|
||||||
|
ref: branch,
|
||||||
|
remoteRef?: branch,
|
||||||
|
force?: boolean, |
||||||
|
author?: author, |
||||||
|
token?: string |
||||||
|
} |
||||||
|
|
||||||
|
export type branchInputType = { |
||||||
|
ref: string, |
||||||
|
checkout?: boolean |
||||||
|
refresh?: boolean |
||||||
|
force?: boolean |
||||||
|
} |
||||||
|
|
||||||
|
export type currentBranchInput = { |
||||||
|
fs: any, |
||||||
|
dir: string |
||||||
|
} |
||||||
|
|
||||||
|
export type checkoutInputType = { |
||||||
|
ref: string, |
||||||
|
force?: boolean, |
||||||
|
remote?: string |
||||||
|
refresh?: boolean |
||||||
|
fetch?: boolean |
||||||
|
} |
||||||
|
|
||||||
|
export type addInputType = { |
||||||
|
filepath: string | string[] |
||||||
|
} |
||||||
|
|
||||||
|
export type rmInputType = { |
||||||
|
filepath: string |
||||||
|
} |
||||||
|
|
||||||
|
export type resolveRefInput = { |
||||||
|
ref: string |
||||||
|
} |
||||||
|
|
||||||
|
export type readBlobInput = { |
||||||
|
oid: string, |
||||||
|
filepath: string |
||||||
|
} |
||||||
|
|
||||||
|
export type commitInputType = { |
||||||
|
author: { |
||||||
|
name: string, |
||||||
|
email: string, |
||||||
|
}, |
||||||
|
message: string, |
||||||
|
} |
||||||
|
|
||||||
|
export type branchesInputType = { |
||||||
|
fs?: any |
||||||
|
dir?: string |
||||||
|
} |
||||||
|
|
||||||
|
export interface cloneInputType { |
||||||
|
url: string, |
||||||
|
branch?: string, |
||||||
|
depth?: number, |
||||||
|
singleBranch?: boolean |
||||||
|
workspaceName?: string |
||||||
|
workspaceExists?: boolean |
||||||
|
token?: string |
||||||
|
dir?: string // where the clone should happen on desktop
|
||||||
|
} |
||||||
|
|
||||||
|
export interface repositoriesInput { token: string, page?: number, per_page?: number } |
||||||
|
|
||||||
|
export interface statusInput { ref: string, filepaths?: string[] } |
||||||
|
|
||||||
|
export type isoGitFSConfig = { |
||||||
|
fs: any, |
||||||
|
dir: string, |
||||||
|
} |
||||||
|
|
||||||
|
export type isoGitProxyConfig = { |
||||||
|
corsProxy: string |
||||||
|
http: HttpClient |
||||||
|
onAuth: AuthCallback |
||||||
|
} |
||||||
|
|
||||||
|
export type GitHubUser = Partial<Endpoints["GET /user"]["response"]['data']> & { |
||||||
|
isConnected: boolean |
||||||
|
} |
||||||
|
|
||||||
|
export type userEmails = Endpoints["GET /user/emails"]["response"]["data"] |
||||||
|
|
@ -0,0 +1 @@ |
|||||||
|
export { isoGit } from './src/isogit' |
@ -0,0 +1,345 @@ |
|||||||
|
import { GitHubUser, author, branch, cloneInputType, commitChange, compareBranchesInput, currentBranchInput, fetchInputType, isoGitFSConfig, isoGitProxyConfig, pullInputType, pushInputType, remote, userEmails } from "@remix-api" |
||||||
|
import git from 'isomorphic-git' |
||||||
|
import { |
||||||
|
Plugin |
||||||
|
} from '@remixproject/engine' |
||||||
|
import http from 'isomorphic-git/http/web' |
||||||
|
|
||||||
|
import { Octokit } from "octokit" |
||||||
|
import { ElectronBasePluginClient } from "@remixproject/plugin-electron" |
||||||
|
const currentbranch = async (input: currentBranchInput, fsConfig: isoGitFSConfig) => { |
||||||
|
|
||||||
|
try { |
||||||
|
const cmd = input ? fsConfig ? { ...fsConfig, ...input } : input : fsConfig |
||||||
|
|
||||||
|
const name = await git.currentBranch(cmd) |
||||||
|
let remote: remote = undefined |
||||||
|
try { |
||||||
|
const remoteName = await git.getConfig({ |
||||||
|
...fsConfig, |
||||||
|
path: `branch.${name}.remote` |
||||||
|
}) |
||||||
|
if (remoteName) { |
||||||
|
const remoteUrl = await git.getConfig({ |
||||||
|
...fsConfig, |
||||||
|
path: `remote.${remoteName}.url` |
||||||
|
}) |
||||||
|
remote = { name: remoteName, url: remoteUrl } |
||||||
|
} |
||||||
|
|
||||||
|
} catch (e) { |
||||||
|
// do nothing
|
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
remote: remote, |
||||||
|
name: name || '' |
||||||
|
} |
||||||
|
} catch (e) { |
||||||
|
return undefined |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const branches = async (fsConfig: isoGitFSConfig) => { |
||||||
|
try { |
||||||
|
|
||||||
|
const remotes = await isoGit.remotes(fsConfig) |
||||||
|
let branches: branch[] = [] |
||||||
|
branches = (await git.listBranches(fsConfig)).map((branch) => { return { remote: undefined, name: branch } }) |
||||||
|
for (const remote of remotes) { |
||||||
|
const cmd = { |
||||||
|
...fsConfig, |
||||||
|
remote: remote.name |
||||||
|
} |
||||||
|
const remotebranches = (await git.listBranches(cmd)).map((branch) => { return { remote: remote, name: branch } }) |
||||||
|
branches = [...branches, ...remotebranches] |
||||||
|
} |
||||||
|
return branches |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
return [] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const remotes = async (fsConfig: isoGitFSConfig) => { |
||||||
|
|
||||||
|
let remotes: remote[] = [] |
||||||
|
try { |
||||||
|
remotes = (await git.listRemotes({ ...fsConfig })).map((remote) => { return { name: remote.remote, url: remote.url } } |
||||||
|
) |
||||||
|
} catch (e) { |
||||||
|
// do nothing
|
||||||
|
} |
||||||
|
return remotes |
||||||
|
} |
||||||
|
|
||||||
|
const push = async (input: pushInputType, fsConfig: isoGitFSConfig, plugin: Plugin | ElectronBasePluginClient) => { |
||||||
|
const cmd = { |
||||||
|
force: input.force, |
||||||
|
ref: input.ref.name, |
||||||
|
remoteRef: input.remoteRef && input.remoteRef.name, |
||||||
|
remote: input.remote.name, |
||||||
|
author: await getAuthor(input, plugin), |
||||||
|
input, |
||||||
|
} |
||||||
|
|
||||||
|
const proxy = await isoGit.addIsomorphicGitProxyConfig(input, plugin) |
||||||
|
console.log({ ...fsConfig, ...cmd, ...proxy }) |
||||||
|
return await git.push({ ...fsConfig, ...cmd, ...proxy }) |
||||||
|
} |
||||||
|
|
||||||
|
const pull = async (input: pullInputType, fsConfig: isoGitFSConfig, plugin: Plugin | ElectronBasePluginClient) => { |
||||||
|
const cmd = { |
||||||
|
ref: input.ref.name, |
||||||
|
remoteRef: input.remoteRef && input.remoteRef.name, |
||||||
|
author: await getAuthor(input, plugin), |
||||||
|
remote: input.remote.name, |
||||||
|
input, |
||||||
|
} |
||||||
|
const proxy = await isoGit.addIsomorphicGitProxyConfig(input, plugin) |
||||||
|
console.log({ ...fsConfig, ...cmd, ...proxy }) |
||||||
|
return await git.pull({ ...fsConfig, ...cmd, ...proxy }) |
||||||
|
} |
||||||
|
|
||||||
|
const fetch = async (input: fetchInputType, fsConfig: isoGitFSConfig, plugin: Plugin | ElectronBasePluginClient) => { |
||||||
|
const cmd = { |
||||||
|
ref: input.ref && input.ref.name, |
||||||
|
remoteRef: input.remoteRef && input.remoteRef.name, |
||||||
|
author: await getAuthor(input, plugin), |
||||||
|
remote: input.remote && input.remote.name, |
||||||
|
depth: input.depth || 5, |
||||||
|
singleBranch: input.singleBranch, |
||||||
|
relative: input.relative, |
||||||
|
input |
||||||
|
} |
||||||
|
const proxy = await isoGit.addIsomorphicGitProxyConfig(input, plugin) |
||||||
|
console.log({ ...fsConfig, ...cmd, ...proxy }) |
||||||
|
return await git.fetch({ ...fsConfig, ...cmd, ...proxy }) |
||||||
|
} |
||||||
|
|
||||||
|
const clone = async (input: cloneInputType, fsConfig: isoGitFSConfig, plugin: Plugin | ElectronBasePluginClient) => { |
||||||
|
const proxy = await isoGit.addIsomorphicGitProxyConfig(input, plugin) |
||||||
|
const cmd = { |
||||||
|
url: input.url, |
||||||
|
singleBranch: input.singleBranch, |
||||||
|
ref: input.branch, |
||||||
|
depth: input.depth || 10, |
||||||
|
dir: input.dir, |
||||||
|
input |
||||||
|
} |
||||||
|
await git.clone({ ...fsConfig, ...cmd, ...proxy }) |
||||||
|
} |
||||||
|
|
||||||
|
const getAuthor = async (input, plugin: any) => { |
||||||
|
const author: author = { |
||||||
|
name: '', |
||||||
|
email: '' |
||||||
|
} |
||||||
|
if (input && input.name && input.email) { |
||||||
|
author.name = input.name |
||||||
|
author.email = input.email |
||||||
|
} else { |
||||||
|
const username = await plugin.call('config' as any, 'getAppParameter', 'settings/github-user-name') |
||||||
|
const email = await plugin.call('config' as any, 'getAppParameter', 'settings/github-email') |
||||||
|
const token = await plugin.call('config' as any, 'getAppParameter', 'settings/gist-access-token') |
||||||
|
if (username && email) { |
||||||
|
author.name = username |
||||||
|
author.email = email |
||||||
|
} else if (token) { |
||||||
|
|
||||||
|
const gitHubUser = await isoGit.getGitHubUser({ token }) |
||||||
|
|
||||||
|
if (gitHubUser) { |
||||||
|
author.name = gitHubUser.user.login |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return author |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const getGitHubUser = async(input: { token: string }): Promise<{ |
||||||
|
user: GitHubUser, |
||||||
|
emails: userEmails, |
||||||
|
scopes: string[] |
||||||
|
}> => { |
||||||
|
try { |
||||||
|
const octokit = new Octokit({ |
||||||
|
auth: input.token |
||||||
|
}) |
||||||
|
|
||||||
|
const user = await octokit.request('GET /user', { |
||||||
|
headers: { |
||||||
|
'X-GitHub-Api-Version': '2022-11-28' |
||||||
|
} |
||||||
|
}) |
||||||
|
const emails = await octokit.request('GET /user/emails') |
||||||
|
|
||||||
|
const scopes = user.headers['x-oauth-scopes'] || '' |
||||||
|
|
||||||
|
return { |
||||||
|
user: { |
||||||
|
...user.data, isConnected: |
||||||
|
user.data.login !== undefined && user.data.login !== null && user.data.login !== '' |
||||||
|
}, |
||||||
|
emails: emails.data, |
||||||
|
scopes: scopes && scopes.split(',').map(scope => scope.trim()) |
||||||
|
} |
||||||
|
} catch (e) { |
||||||
|
return null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const addIsomorphicGitProxyConfig = async (input: { |
||||||
|
url?: string, |
||||||
|
remote?: remote, |
||||||
|
provider?: 'github' | 'localhost', |
||||||
|
token?: string, |
||||||
|
}, plugin: any) => { |
||||||
|
|
||||||
|
const token = await plugin.call('config' as any, 'getAppParameter', 'settings/gist-access-token') |
||||||
|
|
||||||
|
let config: isoGitProxyConfig = { |
||||||
|
corsProxy: 'https://corsproxy.remixproject.org/', |
||||||
|
http, |
||||||
|
onAuth: url => { |
||||||
|
url |
||||||
|
const auth = { |
||||||
|
username: input.token || token, |
||||||
|
password: '' |
||||||
|
} |
||||||
|
return auth |
||||||
|
} |
||||||
|
} |
||||||
|
if (input.url) { |
||||||
|
|
||||||
|
const url = new URL(input.url) |
||||||
|
if (url.hostname.includes('localhost')) { |
||||||
|
config = { |
||||||
|
...config, |
||||||
|
corsProxy: null |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if ((input.remote && input.remote.url)) { |
||||||
|
|
||||||
|
const url = new URL(input.remote.url) |
||||||
|
if (url.hostname.includes('localhost')) { |
||||||
|
config = { |
||||||
|
...config, |
||||||
|
corsProxy: null, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (input.provider && input.provider === 'github') { |
||||||
|
config = { |
||||||
|
...config, |
||||||
|
corsProxy: 'https://corsproxy.remixproject.org/', |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (input.provider && input.provider === 'localhost') { |
||||||
|
config = { |
||||||
|
...config, |
||||||
|
corsProxy: null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return config |
||||||
|
} |
||||||
|
|
||||||
|
const getCommitChanges = async (commitHash1: string, commitHash2: string, fsConfig: isoGitFSConfig) => { |
||||||
|
const result: commitChange[] = await git.walk({ |
||||||
|
...fsConfig, |
||||||
|
trees: [git.TREE({ ref: commitHash1 }), git.TREE({ ref: commitHash2 })], |
||||||
|
map: async function (filepath, [A, B]) { |
||||||
|
|
||||||
|
if (filepath === '.') { |
||||||
|
return |
||||||
|
} |
||||||
|
try { |
||||||
|
if ((A && await A.type()) === 'tree' || B && (await B.type()) === 'tree') { |
||||||
|
return |
||||||
|
} |
||||||
|
} catch (e) { |
||||||
|
// ignore
|
||||||
|
} |
||||||
|
|
||||||
|
// generate ids
|
||||||
|
const Aoid = A && await A.oid() || undefined |
||||||
|
const Boid = B && await B.oid() || undefined |
||||||
|
|
||||||
|
const commitChange: Partial<commitChange> = { |
||||||
|
hashModified: commitHash1, |
||||||
|
hashOriginal: commitHash2, |
||||||
|
path: filepath, |
||||||
|
} |
||||||
|
|
||||||
|
// determine modification type
|
||||||
|
if (Aoid !== Boid) { |
||||||
|
commitChange.type = "modified" |
||||||
|
} |
||||||
|
if (Aoid === undefined) { |
||||||
|
commitChange.type = "deleted" |
||||||
|
} |
||||||
|
if (Boid === undefined || !commitHash2) { |
||||||
|
commitChange.type = "added" |
||||||
|
} |
||||||
|
if (Aoid === undefined && Boid === undefined) { |
||||||
|
commitChange.type = "unknown" |
||||||
|
} |
||||||
|
if (commitChange.type) |
||||||
|
return commitChange |
||||||
|
else |
||||||
|
return undefined |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
const compareBranches = async ({ branch, remote }: compareBranchesInput, fsConfig: isoGitFSConfig) => { |
||||||
|
// Get current branch commits
|
||||||
|
const headCommits = await git.log({ |
||||||
|
...fsConfig, |
||||||
|
ref: branch.name, |
||||||
|
depth: 10, |
||||||
|
}); |
||||||
|
|
||||||
|
// Get remote branch commits
|
||||||
|
const remoteCommits = await git.log({ |
||||||
|
...fsConfig, |
||||||
|
ref: `${remote.name}/${branch.name}`, |
||||||
|
depth: 10, |
||||||
|
}); |
||||||
|
|
||||||
|
// Convert arrays of commit objects to sets of commit SHAs
|
||||||
|
const headCommitSHAs = new Set(headCommits.map(commit => commit.oid)); |
||||||
|
const remoteCommitSHAs = new Set(remoteCommits.map(commit => commit.oid)); |
||||||
|
|
||||||
|
// Filter out commits that are only in the remote branch
|
||||||
|
const uniqueRemoteCommits = remoteCommits.filter(commit => !headCommitSHAs.has(commit.oid)); |
||||||
|
|
||||||
|
// filter out commits that are only in the local branch
|
||||||
|
const uniqueHeadCommits = headCommits.filter(commit => !remoteCommitSHAs.has(commit.oid)); |
||||||
|
|
||||||
|
return { |
||||||
|
uniqueHeadCommits, |
||||||
|
uniqueRemoteCommits, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
export const isoGit = { |
||||||
|
currentbranch, |
||||||
|
remotes, |
||||||
|
branches, |
||||||
|
getCommitChanges, |
||||||
|
compareBranches, |
||||||
|
addIsomorphicGitProxyConfig, |
||||||
|
push, |
||||||
|
pull, |
||||||
|
fetch, |
||||||
|
getGitHubUser, |
||||||
|
clone |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue