Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions lib/Install.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
// @flow

const {exec} = require('child_process');
const spawn = require('cross-spawn');
const {unzip} = require('zlib');
const fs = require('fs');
const os = require('os');
const https = require('https');
const path = require('path');
const chalk = require('chalk');
const ElmJson = require('./ElmJson');
const Project = require('./Project');

Expand Down Expand Up @@ -117,6 +122,122 @@ function install(
return 'SuccessfullyInstalled';
}

async function downloadFileNative(url, filePath) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should add type annotations to all new functions in this file – for parameters and return types.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const usedCommand = `require("https").get(${JSON.stringify(url)})`;
const errorPrefix = `${usedCommand}\nThe above call errored: `;

return new Promise((resolve, reject) => {
const file = fs.createWriteStream(filePath);
let fileInfo = null;

const request = https.get(url, response => {
if (response.statusCode !== 200) {
fs.unlink(filePath, () => {
reject(new Error(`Failed to get '${url}' (${response.statusCode})`));
});
return;
}

fileInfo = {
mime: response.headers['content-type'],
size: parseInt(response.headers['content-length'], 10),
};

response.pipe(file);
});

// The destination stream is ended by the time it's called
file.on('finish', () => resolve(fileInfo));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We seem to resolve the promise with some data we never use here.


request.on('error', err => {
fs.unlink(filePath, () => reject(err));
});

file.on('error', err => {
fs.unlink(filePath, () => reject(err));
});

request.end();
});
}

async function installUnstableTestMaster(projectRootDir) {
console.log(chalk.yellow('Using the master version of elm-explorations/test'));
console.log(chalk.yellow('Note you might need to rm -rf ~/.elm and/or ./elm-stuff afterwards.'));

const pkg = 'elm-explorations/test';
const version = '1.2.2';
const pkgWithDash = pkg.replace('/','-');

const tempPath = path.join(
projectRootDir,
'elm-stuff',
'generated-code',
'elm-community',
'elm-test'
);
Comment thread
lydell marked this conversation as resolved.
Outdated
const zipballUrl = `https://codeload.github.com/${pkg}/zip/refs/heads/master`;
const zipballFilename = `${pkgWithDash}.zip`;
const zipballPath = path.join(tempPath, zipballFilename);
const homeDir = os.homedir();

// based on info in https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/
const elmHome = process.env.ELM_HOME ?? (
process.platform === 'win32'
? path.join(process.env.APPDATA, 'elm')
: path.join(homeDir, '.elm')
);
const packagePath = path.join(
elmHome,
'0.19.1',
'packages',
pkg,
version
);

fs.rmSync(tempPath, { recursive: true, force: true });
fs.rmSync(packagePath, { recursive: true, force: true });
fs.mkdirSync(tempPath, { recursive: true });
fs.mkdirSync(packagePath, { recursive: true });
await downloadFileNative(zipballUrl, zipballPath);
const unzipResult = spawn.sync(
'unzip',
[
'-o', // overwrite
zipballFilename, // file to unzip
'-d', tempPath // directory where to extract files
],
{
cwd: tempPath,
}
);
if (unzipResult.status !== 0) {
const tarResult = spawn.sync(
'tar',
[
'zxf', // eXtract Zipped File
zipballFilename, // file to unzip
'-C', tempPath // directory where to extract files
],
{
cwd: tempPath,
}
);
if (tarResult.status !== 0) {
throw new Error("Failed to unzip the elm-explorations/test repo zipfile");
}
}
fs.renameSync(
path.join(
tempPath,
'test-master'
),
packagePath
);
fs.rmSync(zipballPath, { recursive: true, force: true });
Comment thread
lydell marked this conversation as resolved.
Outdated
}

module.exports = {
install,
installUnstableTestMaster,
};
9 changes: 8 additions & 1 deletion lib/RunTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const DependencyProvider = require('./DependencyProvider.js');
const ElmJson = require('./ElmJson');
const FindTests = require('./FindTests');
const Generate = require('./Generate');
const Install = require('./Install');
const Project = require('./Project');
const Report = require('./Report');
const Supervisor = require('./Supervisor');
Expand Down Expand Up @@ -117,7 +118,7 @@ function watcherEventMessage(queue /*: typeof Queue */) /*: string */ {
return `${filePaths.length} files ${events.join('/')}`;
}

function runTests(
async function runTests(
dependencyProvider /*: DependencyProvider */,
projectRootDir /*: string */,
pathToElmBinary /*: string */,
Expand All @@ -128,11 +129,13 @@ function runTests(
report,
seed,
fuzz,
unstableUseTestMaster,
} /*: {
watch: boolean,
report: typeof Report.Report,
seed: number,
fuzz: number,
unstableUseTestMaster: boolean,
} */
) /*: Promise<number> */ {
let watcher = undefined;
Expand Down Expand Up @@ -249,6 +252,10 @@ function runTests(
}
}

if (unstableUseTestMaster) {
await Install.installUnstableTestMaster(projectRootDir);
}

if (watch) {
progressLogger.clearConsole();

Expand Down
8 changes: 6 additions & 2 deletions lib/elm-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ function main() {
'--color',
'Force colored console output (setting FORCE_COLOR to anything but 0 also works)'
)
.option(
'--unstable-use-test-master',
'Use the bleeding-edge version of the elm-explorations/test library'
Comment thread
lydell marked this conversation as resolved.
Outdated
)
.option(
'--compiler <path>',
'Use a custom path to an Elm executable (default: elm)',
Expand Down Expand Up @@ -241,12 +245,12 @@ function main() {
// commander would interpret the `tests` in `elm-test tests src` as a
// command and only run tests in `src/`, ignoring all files in `tests/`.
.command('__elmTestCommand__ [globs...]', { hidden: true, isDefault: true })
.action((testFileGlobs) => {
.action(async (testFileGlobs) => {
const options = program.opts();
const pathToElmBinary = getPathToElmBinary(options.compiler);
const projectRootDir = getProjectRootDir('tests');
const processes = Math.max(1, os.cpus().length);
RunTests.runTests(
await RunTests.runTests(
Comment thread
lydell marked this conversation as resolved.
Outdated
dependencyProvider,
projectRootDir,
pathToElmBinary,
Expand Down