1
1
mirror of https://github.com/theoludwig/programming-challenges.git synced 2024-12-08 00:45:29 +01:00

fix(cli): changes to templates/docker, should run all affected tests

This commit is contained in:
Divlo 2021-11-09 16:45:42 +01:00
parent 9621751a4d
commit 17efe8a113
No known key found for this signature in database
GPG Key ID: 6F24DA54DA3967CF
10 changed files with 1241 additions and 1209 deletions

View File

@ -1,6 +1,3 @@
import fs from 'node:fs'
import path from 'node:path'
import { Command, Option } from 'clipanion' import { Command, Option } from 'clipanion'
import * as typanion from 'typanion' import * as typanion from 'typanion'
import chalk from 'chalk' import chalk from 'chalk'
@ -8,8 +5,7 @@ import chalk from 'chalk'
import { Solution } from '../../services/Solution' import { Solution } from '../../services/Solution'
import { GitAffected } from '../../services/GitAffected' import { GitAffected } from '../../services/GitAffected'
import { template } from '../../services/Template' import { template } from '../../services/Template'
import { Test, successMessage } from '../../services/Test'
const successMessage = `${chalk.bold.green('Success:')} Tests passed! 🎉`
export class RunTestCommand extends Command { export class RunTestCommand extends Command {
static paths = [['run', 'test']] static paths = [['run', 'test']]
@ -50,15 +46,6 @@ export class RunTestCommand extends Command {
description: 'Base of the current branch (usually master)' description: 'Base of the current branch (usually master)'
}) })
async runTests (solutions: Solution[]): Promise<number> {
for (const solution of solutions) {
await solution.test()
console.log('\n------------------------------\n')
}
console.log(successMessage)
return 0
}
async execute (): Promise<number> { async execute (): Promise<number> {
console.log() console.log()
try { try {
@ -66,35 +53,7 @@ export class RunTestCommand extends Command {
await template.verifySupportedProgrammingLanguage(this.programmingLanguage) await template.verifySupportedProgrammingLanguage(this.programmingLanguage)
} }
if (this.all) { if (this.all) {
const challengesPath = path.join( return await Test.runAllTests(this.programmingLanguage)
__dirname,
'..',
'..',
'..',
'challenges'
)
const challenges = await fs.promises.readdir(challengesPath)
const paths: string[] = []
for (const challenge of challenges) {
const solutionsPath = path.join(challengesPath, challenge, 'solutions')
const languagesSolution = (await fs.promises.readdir(solutionsPath)).filter(
(name) => {
if (this.programmingLanguage != null) {
return name === this.programmingLanguage
}
return name !== '.gitkeep'
}
)
for (const language of languagesSolution) {
const solutionPath = (await fs.promises.readdir(path.join(solutionsPath, language))).map((solutionName) => {
return `challenges/${challenge}/solutions/${language}/${solutionName}`
})
paths.push(...solutionPath)
}
}
const solutions = await Solution.getManyByPaths(paths)
await this.runTests(solutions)
return 0
} }
if (this.affected) { if (this.affected) {
const gitAffected = new GitAffected({ const gitAffected = new GitAffected({
@ -102,7 +61,7 @@ export class RunTestCommand extends Command {
base: this.base base: this.base
}) })
const solutions = await gitAffected.getAffectedSolutions() const solutions = await gitAffected.getAffectedSolutions()
return await this.runTests(solutions) return await Test.runManyWithSolutions(solutions)
} }
if ( if (
this.solutionName == null || this.solutionName == null ||

View File

@ -6,6 +6,10 @@ const solutionsRegex = new RegExp(
/challenges\/[\s\S]*\/solutions\/(c|cpp|cs|dart|java|javascript|python|rust|typescript)\/[\s\S]*\/(solution|Solution).(c|cpp|cs|dart|java|js|py|rs|ts)/ /challenges\/[\s\S]*\/solutions\/(c|cpp|cs|dart|java|javascript|python|rust|typescript)\/[\s\S]*\/(solution|Solution).(c|cpp|cs|dart|java|js|py|rs|ts)/
) )
const dockerRegex = new RegExp(
/templates\/docker\/(c|cpp|cs|dart|java|javascript|python|rust|typescript)\/Dockerfile/
)
export interface GitAffectedOptions { export interface GitAffectedOptions {
isContinuousIntegration: boolean isContinuousIntegration: boolean
base?: string base?: string
@ -70,6 +74,21 @@ export class GitAffected implements GitAffectedOptions {
const affectedSolutionsPaths = files.filter((filePath) => { const affectedSolutionsPaths = files.filter((filePath) => {
return solutionsRegex.test(filePath) return solutionsRegex.test(filePath)
}) })
return await Solution.getManyByPaths(affectedSolutionsPaths) const affectedDockerPaths = files.filter((filePath) => {
return dockerRegex.test(filePath)
})
const affectedLanguages = affectedDockerPaths.map((filePath) => {
const [,, programmingLanguageName] = filePath.replaceAll('\\', '/').split('/')
return programmingLanguageName
})
const solutionsChallenges = await Solution.getManyByPaths(affectedSolutionsPaths)
const solutionsDocker = await Solution.getManyByProgrammingLanguages(affectedLanguages)
const solutions: Solution[] = solutionsDocker
for (const solution of solutionsChallenges) {
if (!affectedLanguages.includes(solution.programmingLanguageName)) {
solutions.push(solution)
}
}
return solutions
} }
} }

View File

@ -1,4 +1,5 @@
import path from 'node:path' import path from 'node:path'
import fs from 'node:fs'
import { import {
createTemporaryEmptyFolder, createTemporaryEmptyFolder,
@ -102,6 +103,33 @@ export class Solution implements SolutionOptions {
return solution return solution
} }
static async getManyByProgrammingLanguages (programmingLanguages?: string[]): Promise<Solution[]> {
const languages = programmingLanguages ?? await template.getProgrammingLanguages()
const challengesPath = path.join(
__dirname,
'..',
'..',
'challenges'
)
const challenges = await fs.promises.readdir(challengesPath)
const paths: string[] = []
for (const challenge of challenges) {
const solutionsPath = path.join(challengesPath, challenge, 'solutions')
const languagesSolution = (await fs.promises.readdir(solutionsPath)).filter(
(name) => {
return name !== '.gitkeep' && languages.includes(name)
}
)
for (const language of languagesSolution) {
const solutionPath = (await fs.promises.readdir(path.join(solutionsPath, language))).map((solutionName) => {
return `challenges/${challenge}/solutions/${language}/${solutionName}`
})
paths.push(...solutionPath)
}
}
return await Solution.getManyByPaths(paths)
}
/** /**
* Get Solutions by relative paths. * Get Solutions by relative paths.
* @param paths relative to `challenges` (e.g: `challenges/hello-world/solutions/c/function`) * @param paths relative to `challenges` (e.g: `challenges/hello-world/solutions/c/function`)

View File

@ -5,7 +5,6 @@ import { replaceInFile } from 'replace-in-file'
import date from 'date-and-time' import date from 'date-and-time'
import { copyDirectory } from '../utils/copyDirectory' import { copyDirectory } from '../utils/copyDirectory'
import { isExistingPath } from '../utils/isExistingPath'
const TEMPLATE_PATH = path.join(__dirname, '..', '..', 'templates') const TEMPLATE_PATH = path.join(__dirname, '..', '..', 'templates')
const TEMPLATE_DOCKER_PATH = path.join(TEMPLATE_PATH, 'docker') const TEMPLATE_DOCKER_PATH = path.join(TEMPLATE_PATH, 'docker')
@ -94,9 +93,14 @@ class Template {
}) })
} }
public async getProgrammingLanguages (): Promise<string[]> {
const languages = await fs.promises.readdir(TEMPLATE_SOLUTION_PATH)
return languages.filter(language => language !== 'base')
}
public async verifySupportedProgrammingLanguage (language: string): Promise<void> { public async verifySupportedProgrammingLanguage (language: string): Promise<void> {
const templateLanguagePath = path.join(TEMPLATE_SOLUTION_PATH, language) const languages = await this.getProgrammingLanguages()
if (!(await isExistingPath(templateLanguagePath))) { if (!languages.includes(language)) {
throw new Error('This programming language is not supported yet.') throw new Error('This programming language is not supported yet.')
} }
} }

View File

@ -29,6 +29,8 @@ export interface TestOptions {
elapsedTimeMilliseconds: number elapsedTimeMilliseconds: number
} }
export const successMessage = `${chalk.bold.green('Success:')} Tests passed! 🎉`
export class Test implements TestOptions { export class Test implements TestOptions {
public index: number public index: number
public path: string public path: string
@ -132,6 +134,23 @@ export class Test implements TestOptions {
return { input, output } return { input, output }
} }
static async runManyWithSolutions (solutions: Solution[]): Promise<number> {
for (const solution of solutions) {
await solution.test()
console.log('\n------------------------------\n')
}
console.log(successMessage)
return 0
}
static async runAllTests (programmingLanguage?: string): Promise<number> {
const solutions = await Solution.getManyByProgrammingLanguages(
programmingLanguage != null ? [programmingLanguage] : undefined
)
await Test.runManyWithSolutions(solutions)
return 0
}
static async run (options: TestRunOptions): Promise<Test> { static async run (options: TestRunOptions): Promise<Test> {
const { input, output } = await Test.getInputOutput(options.path) const { input, output } = await Test.getInputOutput(options.path)
const start = performance.now() const start = performance.now()

2301
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -41,25 +41,25 @@
"date-and-time": "2.0.1", "date-and-time": "2.0.1",
"execa": "5.1.1", "execa": "5.1.1",
"ora": "5.4.1", "ora": "5.4.1",
"replace-in-file": "6.2.0", "replace-in-file": "6.3.2",
"table": "6.7.2", "table": "6.7.3",
"typanion": "3.5.0", "typanion": "3.7.1",
"validate-npm-package-name": "3.0.0" "validate-npm-package-name": "3.0.0"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "13.2.1", "@commitlint/cli": "14.1.0",
"@commitlint/config-conventional": "13.2.0", "@commitlint/config-conventional": "14.1.0",
"@types/date-and-time": "0.13.0", "@types/date-and-time": "0.13.0",
"@types/jest": "27.0.2", "@types/jest": "27.0.2",
"@types/mock-fs": "4.13.1", "@types/mock-fs": "4.13.1",
"@types/node": "16.10.8", "@types/node": "16.11.7",
"@types/validate-npm-package-name": "3.0.3", "@types/validate-npm-package-name": "3.0.3",
"editorconfig-checker": "4.0.2", "editorconfig-checker": "4.0.2",
"jest": "27.2.5", "jest": "27.3.1",
"markdownlint-cli": "0.29.0", "markdownlint-cli": "0.29.0",
"mock-fs": "5.1.1", "mock-fs": "5.1.2",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"ts-jest": "27.0.5", "ts-jest": "27.0.7",
"ts-standard": "10.0.0", "ts-standard": "10.0.0",
"typescript": "4.4.4" "typescript": "4.4.4"
} }

View File

@ -1,3 +1,3 @@
FROM dart:2.14.3 FROM dart:2.14.4
COPY ./ ./ COPY ./ ./
CMD ["dart", "run", "solution.dart"] CMD ["dart", "run", "solution.dart"]

View File

@ -1,4 +1,4 @@
FROM rust:1.55.0 FROM rust:1.56.1
COPY ./ ./ COPY ./ ./
RUN rustc solution.rs RUN rustc solution.rs
CMD ["./solution"] CMD ["./solution"]

View File

@ -1,4 +1,4 @@
FROM node:16.11.1 FROM node:16.13.0
RUN npm install --global ts-node typescript @types/node RUN npm install --global ts-node typescript @types/node
COPY ./ ./ COPY ./ ./
CMD ["ts-node", "solution.ts"] CMD ["ts-node", "solution.ts"]