initial CLI implementation
nclazz/depresolve/pipeline/head This commit looks good
Details
nclazz/depresolve/pipeline/head This commit looks good
Details
parent
20e38492c9
commit
e45a3118f5
|
@ -0,0 +1,83 @@
|
|||
pipeline {
|
||||
agent {
|
||||
docker 'node:lts-alpine3.16'
|
||||
}
|
||||
|
||||
environment {
|
||||
NPM_REGISTRY = 'https://nexus.nclazz.de/repository/npm_releases'
|
||||
NPM_CREDENTIALS = credentials('jenkins_nexus')
|
||||
NPM_MAIL = 'robots@nclazz.de'
|
||||
APIBUILDER_TOKEN = credentials('apibuilder_token')
|
||||
}
|
||||
|
||||
options {
|
||||
timeout(time: 30, unit: "MINUTES")
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Prepare build') {
|
||||
steps {
|
||||
sh 'yarn install'
|
||||
sh "yarn run registry:login --config-path ./.npmrc -u $NPM_CREDENTIALS_USR -p $NPM_CREDENTIALS_PSW -e $NPM_MAIL -r $NPM_REGISTRY"
|
||||
}
|
||||
}
|
||||
stage('Run build') {
|
||||
steps {
|
||||
sh 'yarn build:ci'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit(
|
||||
allowEmptyResults: true,
|
||||
testResults: '**/**/junit.xml'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Publish npm packages') {
|
||||
when {
|
||||
anyOf {
|
||||
allOf {
|
||||
branch 'master'
|
||||
buildingTag()
|
||||
}
|
||||
branch 'develop'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
sh 'yarn run publish:ci'
|
||||
}
|
||||
}
|
||||
// stage('Publish apibuilder specs') {
|
||||
// steps {
|
||||
// sh 'yarn publish:apibuilder'
|
||||
// }
|
||||
// }
|
||||
}
|
||||
post {
|
||||
always {
|
||||
cleanWs()
|
||||
}
|
||||
failure {
|
||||
slackSend(
|
||||
channel: "notifications",
|
||||
color: "danger",
|
||||
message: "There is a *build failure* in ${env.JOB_NAME}.\nBuild: ${env.RUN_DISPLAY_URL} "
|
||||
)
|
||||
}
|
||||
unstable {
|
||||
slackSend(
|
||||
channel: "notifications",
|
||||
color: "warning",
|
||||
message: "Some tests have failed in ${env.JOB_NAME}.\nBuild: ${env.RUN_DISPLAY_URL} "
|
||||
)
|
||||
}
|
||||
fixed {
|
||||
slackSend(
|
||||
channel: "notifications",
|
||||
color: "good",
|
||||
message: "The build ${env.JOB_NAME} completed successfully and is back to normal.\nBuild: ${env.RUN_DISPLAY_URL} "
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"name": "@nclazz/deptracker",
|
||||
"name": "@nclazz/depresolve",
|
||||
"version": "1.0.0",
|
||||
"description": "Track dependencies in any project",
|
||||
"main": "./dist/index.js",
|
||||
"bin": {
|
||||
"deptracker": "./dist/index.js"
|
||||
"depresolve": "./dist/cli/index.js"
|
||||
},
|
||||
"author": "Niclas Thobaben",
|
||||
"license": "MIT",
|
||||
|
|
|
@ -9,5 +9,8 @@ module.exports = {
|
|||
},
|
||||
publisher: {
|
||||
npm: npmPublisher({})
|
||||
},
|
||||
send: {
|
||||
npm: [ 'npm' ]
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
import { Project, ProjectRunner, ScmInfo } from '../project'
|
||||
|
||||
describe('ProjectLoader', () => {
|
||||
const newLoader = () => {
|
||||
return new ProjectRunner()
|
||||
}
|
||||
const newProjectOptions = (override?: Partial<Project>): Project => {
|
||||
return {
|
||||
name: 'my_project',
|
||||
|
@ -19,30 +16,25 @@ describe('ProjectLoader', () => {
|
|||
|
||||
describe('validateProject()', () => {
|
||||
it('throws error for missing name', () => {
|
||||
const loader = newLoader()
|
||||
expect(() => loader.validateProject(newProjectOptions({ name: undefined })))
|
||||
expect(() => ProjectRunner.validateProject(newProjectOptions({ name: undefined })))
|
||||
.toThrow(/Missing project name/)
|
||||
})
|
||||
it('throws error for missing scm info', () => {
|
||||
const loader = newLoader()
|
||||
expect(() => loader.validateProject(newProjectOptions({ scm: undefined })))
|
||||
expect(() => ProjectRunner.validateProject(newProjectOptions({ scm: undefined })))
|
||||
.toThrow(/Missing scm/)
|
||||
})
|
||||
it('throws error for invalid scm', () => {
|
||||
const loader = newLoader()
|
||||
expect(() => loader.validateProject(newProjectOptions({ scm: { type: 'git' } as ScmInfo })))
|
||||
expect(() => ProjectRunner.validateProject(newProjectOptions({ scm: { type: 'git' } as ScmInfo })))
|
||||
.toThrow(/Missing scm url/)
|
||||
})
|
||||
it('does not throw error for missing scm type', () => {
|
||||
const loader = newLoader()
|
||||
expect(() => loader.validateProject(newProjectOptions({ scm: { url: 'https://some-git.com' } })))
|
||||
expect(() => ProjectRunner.validateProject(newProjectOptions({ scm: { url: 'https://some-git.com' } })))
|
||||
.not.toThrow()
|
||||
})
|
||||
})
|
||||
describe('loadProject()', () => {
|
||||
it('loads project from js file', () => {
|
||||
const runner = newLoader()
|
||||
runner.loadProject(__dirname + '/deptracker.config.js')
|
||||
ProjectRunner.loadProject(__dirname + '/depresolver.config.js')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import {CommandModule} from 'yargs'
|
||||
import { ProjectRunner } from '../../project'
|
||||
|
||||
export const cmd: CommandModule = {
|
||||
command: 'resolve',
|
||||
describe: 'Resolve dependencies of this project',
|
||||
handler: async (argv) => {
|
||||
const runner: ProjectRunner = argv._project_runner as ProjectRunner
|
||||
const project = runner.project
|
||||
|
||||
console.debug('Start running resolve...')
|
||||
const result = await runner.resolve()
|
||||
|
||||
console.log(`------------------- ${project.name} -------------------`)
|
||||
Object.entries(result).forEach(([name,results]) => {
|
||||
console.log(`Resolver: ${name}`)
|
||||
results.forEach((result) => {
|
||||
const { name, type, location, version } = result.current
|
||||
const { version: rversion } = result.recommended
|
||||
console.log(` ${name} (${type}) ${version} -> ${rversion} (found in ${location})`)
|
||||
})
|
||||
})
|
||||
|
||||
console.debug('Finished running resolve.')
|
||||
},
|
||||
}
|
||||
|
||||
export const {
|
||||
command,
|
||||
aliases,
|
||||
describe,
|
||||
handler,
|
||||
builder,
|
||||
} = cmd
|
|
@ -0,0 +1,20 @@
|
|||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import { ArgumentsCamelCase } from 'yargs'
|
||||
import { ProjectRunner } from '../project'
|
||||
|
||||
export const prepareConfig = (argv: ArgumentsCamelCase) => {
|
||||
const configArg = argv.config as string
|
||||
const configPath = path.join(process.cwd(), configArg)
|
||||
|
||||
console.debug(`Load configuration from ${configPath}`)
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
console.error(`No config not found at ${configPath}!`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.debug('Create project runner')
|
||||
const project = ProjectRunner.loadProject(configPath)
|
||||
argv._project_runner = new ProjectRunner(project)
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import yargs from 'yargs'
|
||||
import { prepareConfig } from './config'
|
||||
import { prepareVerbose } from './verbose'
|
||||
|
||||
const runCLI = () => {
|
||||
// tslint:disable-next-line:no-unused-expression
|
||||
yargs(process.argv.slice(2))
|
||||
.commandDir('cmds')
|
||||
.options({
|
||||
verbose: {
|
||||
alias: 'v',
|
||||
describe: 'Enable verbose output',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
config: {
|
||||
alias: 'c',
|
||||
describe: 'Path to depresolve config file',
|
||||
type: 'string',
|
||||
default: './depresolve.config.js',
|
||||
},
|
||||
})
|
||||
.demandCommand()
|
||||
.middleware(prepareVerbose)
|
||||
.middleware(prepareConfig)
|
||||
.showHelpOnFail(true)
|
||||
.help()
|
||||
.argv
|
||||
}
|
||||
runCLI()
|
|
@ -0,0 +1,16 @@
|
|||
import { ArgumentsCamelCase } from 'yargs'
|
||||
|
||||
const _log = console.debug;
|
||||
const logOverride = function() {
|
||||
const new_args: any[] = ['[DEBUG]']
|
||||
// @ts-ignore
|
||||
new_args.push.apply(new_args, arguments);
|
||||
_log.apply(null, new_args);
|
||||
};
|
||||
|
||||
export const prepareVerbose = (argv: ArgumentsCamelCase) => {
|
||||
console.debug = () => {}
|
||||
if(argv.verbose) {
|
||||
console.debug = logOverride
|
||||
}
|
||||
}
|
|
@ -1 +1,4 @@
|
|||
// keep
|
||||
export * from './npm'
|
||||
export * from './resolver'
|
||||
export * from './publisher'
|
||||
export * from './project'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Resolver } from './resolver'
|
||||
import { Resolver, ResolveResult } from './resolver'
|
||||
import { Publisher } from './publisher'
|
||||
|
||||
export interface Project {
|
||||
|
@ -26,13 +26,30 @@ const validateScmInfo = (scm?: ScmInfo) => {
|
|||
|
||||
export class ProjectRunner {
|
||||
|
||||
public loadProject(path: string) {
|
||||
readonly project: Project
|
||||
|
||||
constructor(project: Project) {
|
||||
this.project = project
|
||||
}
|
||||
|
||||
public async resolve(limit?: string[]): Promise<Record<string, ResolveResult[]>> {
|
||||
const results: Record<string, ResolveResult[]> = {}
|
||||
const promises = Object.entries(this.project.resolver)
|
||||
.filter(([name,]) => !limit || limit.includes(name))
|
||||
.map(async ([name, resolver]) => {
|
||||
results[name] = await resolver.resolve()
|
||||
})
|
||||
await Promise.all(promises)
|
||||
return results
|
||||
}
|
||||
|
||||
public static loadProject(path: string) {
|
||||
const project = require(path) as Project
|
||||
this.validateProject(project)
|
||||
ProjectRunner.validateProject(project)
|
||||
return project as Project
|
||||
}
|
||||
|
||||
public validateProject(project: Project) {
|
||||
public static validateProject(project: Project) {
|
||||
if(!project.name) {
|
||||
throw Error('Missing project name')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue