commit
1c5c35403b
@ -1,13 +1,17 @@ |
||||
{ |
||||
"scripts": { |
||||
"start:server": "npx ts-node server.ts" |
||||
"start:server": "tsc && node ./dist/server.js" |
||||
}, |
||||
"dependencies": { |
||||
"body-parser": "^1.20.2", |
||||
"body-parser": "^1.20.3", |
||||
"child_process": "^1.0.2", |
||||
"express": "^4.19.2", |
||||
"express": "^4.20.0", |
||||
"git-http-backend": "^1.1.2", |
||||
"path": "^0.12.7", |
||||
"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.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/types/git' |
@ -1,10 +1,13 @@ |
||||
import { commitChange } from "@remix-ui/git"; |
||||
import { commitChange } from "@remix-api"; |
||||
import { IFileSystem } from "@remixproject/plugin-api" |
||||
|
||||
// Extended interface with 'diff' method
|
||||
export interface IExtendedFileSystem extends IFileSystem { |
||||
methods: IFileSystem['methods'] & { |
||||
/** Compare the differences between two files */ |
||||
diff(change: commitChange): Promise<void> |
||||
refresh(): Promise<void> |
||||
hasGitSubmodules(): 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