1
1
mirror of https://github.com/theoludwig/programming-challenges.git synced 2025-05-18 12:02:53 +02:00

feat(cli): add --ci option to run test command

This commit is contained in:
Divlo
2021-06-25 12:46:01 +02:00
parent b098e04cdc
commit c55c67e0a5
5 changed files with 69 additions and 62 deletions

View File

@ -4,7 +4,7 @@ import * as typanion from 'typanion'
import chalk from 'chalk'
import { Solution } from '../../services/Solution'
import { gitAffected } from '../../services/GitAffected'
import { GitAffected } from '../../services/GitAffected'
const successMessage = `${chalk.bold.green('Success:')} Tests passed! 🎉`
@ -35,10 +35,17 @@ export class RunTestCommand extends Command {
description: 'Only run the tests for the affected files in `git`.'
})
public isContinuousIntegration = Option.Boolean('--ci', false, {
description: 'Run the tests for the Continuous Integration (CI).'
})
async execute (): Promise<number> {
console.log()
try {
if (this.affected) {
const gitAffected = new GitAffected({
isContinuousIntegration: this.isContinuousIntegration
})
const solutions = await gitAffected.getAffectedSolutions()
for (const solution of solutions) {
await solution.test()

View File

@ -1,20 +1,66 @@
import simpleGit from 'simple-git'
import execa from 'execa'
import { Challenge } from './Challenge'
import { Solution } from './Solution'
const git = simpleGit()
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)/
)
class GitAffected {
export interface GitAffectedOptions {
isContinuousIntegration: boolean
}
export class GitAffected implements GitAffectedOptions {
public isContinuousIntegration: boolean
constructor (options: GitAffectedOptions) {
this.isContinuousIntegration = options.isContinuousIntegration
}
public parseGitOutput (output: string): string[] {
return output
.split('\n')
.map((line) => line.trim())
.filter((line) => line.length > 0)
}
public async getFilesUsingBaseAndHead (
base: string,
head: string
): Promise<string[]> {
const { stdout } = await execa.command(
`git diff --name-only --relative ${base} ${head}`
)
return this.parseGitOutput(stdout)
}
public async getUncommittedFiles (): Promise<string[]> {
return await this.getFilesUsingBaseAndHead('HEAD', '.')
}
public async getLatestPushedCommit (): Promise<string> {
const latestCommit = this.isContinuousIntegration ? '~1' : ''
const { stdout } = await execa.command(`git rev-parse origin/master${latestCommit}`)
return stdout
}
public async getUnpushedFiles (): Promise<string[]> {
return await this.getFilesUsingBaseAndHead(
await this.getLatestPushedCommit(),
'.'
)
}
public async getAffectedSolutions (): Promise<Solution[]> {
await git.add('.')
const diff = await git.diff(['--name-only', '--staged'])
const affectedSolutionsPaths = diff.split('\n').filter((currentDiff) => {
return solutionsRegex.test(currentDiff)
const files = Array.from(
new Set([
...(await this.getUnpushedFiles()),
...(await this.getUncommittedFiles())
])
)
const affectedSolutionsPaths = files.filter((filePath) => {
return solutionsRegex.test(filePath)
})
return affectedSolutionsPaths.map((solution) => {
const [, challengeName, , programmingLanguageName, solutionName] =
@ -29,5 +75,3 @@ class GitAffected {
})
}
}
export const gitAffected = new GitAffected()