diff --git a/package.json b/package.json index 94fbdd6..077ea5d 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "dependencies": { "@types/lodash": "^4.14.52", "@types/node": "^7.0.5", - "@types/q": "0.x.x", "@types/request": "0.x.x", "@types/shelljs": "^0.7.0", "@types/through2": "^2.0.32", @@ -40,7 +39,6 @@ "lodash": "^4.17.4", "npmextra": "^2.0.3", "projectinfo": "^3.0.1", - "q": "^1.4.1", "request": "^2.79.0", "shelljs": "^0.7.6", "smartcli": "^2.0.1", diff --git a/ts/npmci.bash.ts b/ts/npmci.bash.ts index 2d0b30a..c329771 100644 --- a/ts/npmci.bash.ts +++ b/ts/npmci.bash.ts @@ -19,7 +19,8 @@ checkNvm() * @param commandArg - The command to execute * @param retryArg - The retryArg: 0 to any positive number will retry, -1 will always succeed, -2 will return undefined */ -export let bash = (commandArg: string, retryArg: number = 2, bareArg: boolean = false): string => { +export let bash = (commandArg: string, retryArg: number = 2, bareArg: boolean = false): Promise => { + let done = plugins.q.defer() let exitCode: number let stdOut: string let execResult @@ -43,6 +44,7 @@ export let bash = (commandArg: string, retryArg: number = 2, bareArg: boolean = // determine how bash reacts to error and success if (exitCode !== 0 && i === retryArg) { // something went wrong and retries are exhausted if (failOnError) { + plugins.beautylog.error('something went wrong and retries are exhausted') process.exit(1) } } else if (exitCode === 0) { // everything went fine, or no error wanted @@ -55,19 +57,19 @@ export let bash = (commandArg: string, retryArg: number = 2, bareArg: boolean = } else { plugins.beautylog.log('ShellExec would be: ' + commandArg) } - return stdOut + return done.promise } /** * bashBare allows usage of bash without sourcing any files like nvm */ -export let bashBare = (commandArg: string, retryArg: number = 2) => { +export let bashBare = (commandArg: string, retryArg: number = 2): Promise => { return bash(commandArg, retryArg, true) } /** * bashNoError allows executing stuff without throwing an error */ -export let bashNoError = (commandArg: string): string => { +export let bashNoError = (commandArg: string): Promise => { return bash(commandArg, -1) } diff --git a/ts/npmci.build.docker.ts b/ts/npmci.build.docker.ts index 975f25b..f323388 100644 --- a/ts/npmci.build.docker.ts +++ b/ts/npmci.build.docker.ts @@ -1,43 +1,38 @@ import * as plugins from './npmci.plugins' import * as paths from './npmci.paths' import * as NpmciEnv from './npmci.env' -import {bashBare} from './npmci.bash' +import { bashBare } from './npmci.bash' /** * builds a cwd of Dockerfiles by triggering a promisechain */ -export let build = function(){ - let done = plugins.q.defer() - readDockerfiles() - .then(sortDockerfiles) - .then(mapDockerfiles) - .then(buildDockerfiles) - .then(pushDockerfiles) - .then(() => { - done.resolve() - }) - return done.promise +export let build = async () => { + await readDockerfiles() + .then(sortDockerfiles) + .then(mapDockerfiles) + .then(buildDockerfiles) + .then(pushDockerfiles) } /** * creates instance of class Dockerfile for all Dockerfiles in cwd * @returns Promise */ -export let readDockerfiles = function(): plugins.q.Promise{ - let done = plugins.q.defer() - let readDockerfilesArray: Dockerfile[] = [] - plugins.gulp.src('./Dockerfile*') - .pipe(plugins.through2.obj(function(file,enc,cb){ - let myDockerfile = new Dockerfile({ - filePath: file.path, - read: true - }) - readDockerfilesArray.push(myDockerfile) - cb(null,file) - },function(){ - done.resolve(readDockerfilesArray) - })) - return done.promise +export let readDockerfiles = async (): Promise => { + let fileTree = await plugins.smartfile.fs.listFileTree(paths.cwd, './Dockerfile*') + + // create the Dockerfile array + let readDockerfilesArray: Dockerfile[] = [] + for (let dockerfilePath of fileTree) { + let myDockerfile = new Dockerfile({ + filePath: dockerfilePath, + read: true + }) + readDockerfilesArray.push(myDockerfile) + } + + return readDockerfilesArray + } /** @@ -45,249 +40,235 @@ export let readDockerfiles = function(): plugins.q.Promise{ * @param sortableArrayArg an array of instances of class Dockerfile * @returns Promise */ -export let sortDockerfiles = function(sortableArrayArg: Dockerfile[]): plugins.q.Promise{ - let done = plugins.q.defer() - let sortedArray: Dockerfile[] = [] - let cleanTagsOriginal = cleanTagsArrayFunction(sortableArrayArg,sortedArray) - let sorterFunctionCounter: number = 0 - let sorterFunction = function(){ - sortableArrayArg.forEach((dockerfileArg) => { - let cleanTags = cleanTagsArrayFunction(sortableArrayArg,sortedArray) - if (cleanTags.indexOf(dockerfileArg.baseImage) === -1 && sortedArray.indexOf(dockerfileArg) === -1) { - sortedArray.push(dockerfileArg) - }; - if (cleanTagsOriginal.indexOf(dockerfileArg.baseImage) !== -1) { - dockerfileArg.localBaseImageDependent = true - }; - }) - if (sortableArrayArg.length === sortedArray.length) { - done.resolve(sortedArray) - } else if (sorterFunctionCounter < 10) { - sorterFunctionCounter++ - sorterFunction() - }; - } - sorterFunction() - return done.promise +export let sortDockerfiles = (sortableArrayArg: Dockerfile[]): plugins.q.Promise => { + let done = plugins.q.defer() + let sortedArray: Dockerfile[] = [] + let cleanTagsOriginal = cleanTagsArrayFunction(sortableArrayArg, sortedArray) + let sorterFunctionCounter: number = 0 + let sorterFunction = function () { + sortableArrayArg.forEach((dockerfileArg) => { + let cleanTags = cleanTagsArrayFunction(sortableArrayArg, sortedArray) + if (cleanTags.indexOf(dockerfileArg.baseImage) === -1 && sortedArray.indexOf(dockerfileArg) === -1) { + sortedArray.push(dockerfileArg) + }; + if (cleanTagsOriginal.indexOf(dockerfileArg.baseImage) !== -1) { + dockerfileArg.localBaseImageDependent = true + }; + }) + if (sortableArrayArg.length === sortedArray.length) { + done.resolve(sortedArray) + } else if (sorterFunctionCounter < 10) { + sorterFunctionCounter++ + sorterFunction() + }; + } + sorterFunction() + return done.promise } /** * maps local Dockerfiles dependencies to the correspoding Dockerfile class instances */ -export let mapDockerfiles = function(sortedArray: Dockerfile[]): plugins.q.Promise{ - let done = plugins.q.defer() - sortedArray.forEach((dockerfileArg) => { - if (dockerfileArg.localBaseImageDependent) { - sortedArray.forEach((dockfile2: Dockerfile) => { - if (dockfile2.cleanTag === dockerfileArg.baseImage) { - dockerfileArg.localBaseDockerfile = dockfile2 - } - }) - }; - }) - done.resolve(sortedArray) - return done.promise +export let mapDockerfiles = async (sortedArray: Dockerfile[]): plugins.q.Promise => { + sortedArray.forEach((dockerfileArg) => { + if (dockerfileArg.localBaseImageDependent) { + sortedArray.forEach((dockfile2: Dockerfile) => { + if (dockfile2.cleanTag === dockerfileArg.baseImage) { + dockerfileArg.localBaseDockerfile = dockfile2 + } + }) + }; + }) + return sortedArray } /** * builds the correspoding real docker image for each Dockerfile class instance */ -export let buildDockerfiles = (sortedArrayArg: Dockerfile[]) => { - let done = plugins.q.defer() - sortedArrayArg.forEach(function(dockerfileArg){ - dockerfileArg.build() - }) - done.resolve(sortedArrayArg) - return done.promise +export let buildDockerfiles = async (sortedArrayArg: Dockerfile[]) => { + sortedArrayArg.forEach(async function (dockerfileArg) { + await dockerfileArg.build() + }) + return sortedArrayArg } /** * pushes the real Dockerfile images to a Docker registry */ -export let pushDockerfiles = function(sortedArrayArg: Dockerfile[]){ - let done = plugins.q.defer() - sortedArrayArg.forEach(function(dockerfileArg){ - dockerfileArg.push(NpmciEnv.buildStage) - }) - done.resolve(sortedArrayArg) - return done.promise +export let pushDockerfiles = async (sortedArrayArg: Dockerfile[]) => { + sortedArrayArg.forEach(async (dockerfileArg) => { + await dockerfileArg.push(NpmciEnv.buildStage) + }) + return sortedArrayArg } /** * pulls corresponding real Docker images for instances of Dockerfile from a registry. * This is needed if building, testing, and publishing of Docker images is carried out in seperate CI stages. */ -export let pullDockerfileImages = (sortableArrayArg: Dockerfile[],registryArg = 'registry.gitlab.com') => { - let done = plugins.q.defer() - sortableArrayArg.forEach((dockerfileArg) => { - dockerfileArg.pull(registryArg) - }) - done.resolve(sortableArrayArg) - return done.promise +export let pullDockerfileImages = async (sortableArrayArg: Dockerfile[], registryArg = 'registry.gitlab.com') => { + sortableArrayArg.forEach(async (dockerfileArg) => { + await dockerfileArg.pull(registryArg) + }) + return sortableArrayArg } /** * tests all Dockerfiles in by calling class Dockerfile.test(); * @param sortedArrayArg Dockerfile[] that contains all Dockerfiles in cwd */ -export let testDockerfiles = (sortedArrayArg: Dockerfile[]) => { - let done = plugins.q.defer() - sortedArrayArg.forEach(function(dockerfileArg){ - dockerfileArg.test() - }) - done.resolve(sortedArrayArg) - return done.promise +export let testDockerfiles = async (sortedArrayArg: Dockerfile[]) => { + sortedArrayArg.forEach(async (dockerfileArg) => { + await dockerfileArg.test() + }) + return sortedArrayArg } /** * class Dockerfile represents a Dockerfile on disk in npmci */ export class Dockerfile { - filePath: string - repo: string - version: string - cleanTag: string - buildTag: string - testTag: string - releaseTag: string - containerName: string - content: string - baseImage: string - localBaseImageDependent: boolean - localBaseDockerfile: Dockerfile - constructor(options: {filePath?: string,fileContents?: string|Buffer,read?: boolean}) { - this.filePath = options.filePath - this.repo = NpmciEnv.repo.user + '/' + NpmciEnv.repo.repo - this.version = dockerFileVersion(plugins.path.parse(options.filePath).base) - this.cleanTag = this.repo + ':' + this.version - this.buildTag = this.cleanTag - this.testTag = dockerTag('registry.gitlab.com',this.repo,this.version,'test') - this.releaseTag = dockerTag(NpmciEnv.dockerRegistry,this.repo,this.version) - this.containerName = 'dockerfile-' + this.version - if (options.filePath && options.read) { - this.content = plugins.smartfile.fs.toStringSync(plugins.path.resolve(options.filePath)) - }; - this.baseImage = dockerBaseImage(this.content) - this.localBaseImageDependent = false + filePath: string + repo: string + version: string + cleanTag: string + buildTag: string + testTag: string + releaseTag: string + containerName: string + content: string + baseImage: string + localBaseImageDependent: boolean + localBaseDockerfile: Dockerfile + constructor(options: { filePath?: string, fileContents?: string | Buffer, read?: boolean }) { + this.filePath = options.filePath + this.repo = NpmciEnv.repo.user + '/' + NpmciEnv.repo.repo + this.version = dockerFileVersion(plugins.path.parse(options.filePath).base) + this.cleanTag = this.repo + ':' + this.version + this.buildTag = this.cleanTag + this.testTag = dockerTag('registry.gitlab.com', this.repo, this.version, 'test') + this.releaseTag = dockerTag(NpmciEnv.dockerRegistry, this.repo, this.version) + this.containerName = 'dockerfile-' + this.version + if (options.filePath && options.read) { + this.content = plugins.smartfile.fs.toStringSync(plugins.path.resolve(options.filePath)) }; + this.baseImage = dockerBaseImage(this.content) + this.localBaseImageDependent = false + }; - /** - * builds the Dockerfile - */ - build() { - let done = plugins.q.defer() - plugins.beautylog.info('now building Dockerfile for ' + this.cleanTag) - bashBare('docker build -t ' + this.buildTag + ' -f ' + this.filePath + ' .') - NpmciEnv.dockerFilesBuilt.push(this) - done.resolve() - return done.promise - }; + /** + * builds the Dockerfile + */ + async build() { + plugins.beautylog.info('now building Dockerfile for ' + this.cleanTag) + await bashBare('docker build -t ' + this.buildTag + ' -f ' + this.filePath + ' .') + NpmciEnv.dockerFilesBuilt.push(this) + }; - /** - * pushes the Dockerfile to a registry - */ - push(stageArg) { - let done = plugins.q.defer() - let pushTag - switch (stageArg) { - case 'release': - pushTag = this.releaseTag - break - case 'test': - default: - pushTag = this.testTag - break - } - bashBare('docker tag ' + this.buildTag + ' ' + pushTag) - bashBare('docker push ' + pushTag) - done.resolve() - return done.promise - }; - - /** - * pulls the Dockerfile from a registry - */ - pull(registryArg: string) { - let pullTag = this.testTag - bashBare('docker pull ' + pullTag) - bashBare('docker tag ' + pullTag + ' ' + this.buildTag) - }; - - /** - * tests the Dockerfile; - */ - test() { - let testFile: string = plugins.path.join(paths.NpmciTestDir,'test_' + this.version + '.sh') - let testFileExists: boolean = plugins.smartfile.fs.fileExistsSync(testFile) - if (testFileExists) { - bashBare('docker run --name npmci_test_container ' + this.buildTag + ' mkdir /npmci_test') - bashBare('docker cp ' + testFile + ' npmci_test_container:/npmci_test/test.sh') - bashBare('docker commit npmci_test_container npmci_test_image') - bashBare('docker run npmci_test_image sh /npmci_test/test.sh') - bashBare('docker rm npmci_test_container') - bashBare('docker rmi --force npmci_test_image') - } else { - plugins.beautylog.warn('skipping tests for ' + this.cleanTag + ' because no testfile was found!') - } - }; - - /** - * gets the id of a Dockerfile - */ - getId() { - let containerId = bashBare('docker inspect --type=image --format=\"{{.Id}}\" ' + this.buildTag) - return containerId - }; -} - -/** - * - */ -export let dockerFileVersion = function(dockerfileNameArg: string): string{ - let versionString: string - let versionRegex = /Dockerfile_([a-zA-Z0-9\.]*)$/ - let regexResultArray = versionRegex.exec(dockerfileNameArg) - if (regexResultArray && regexResultArray.length === 2) { - versionString = regexResultArray[1] - } else { - versionString = 'latest' + /** + * pushes the Dockerfile to a registry + */ + async push(stageArg) { + let pushTag + switch (stageArg) { + case 'release': + pushTag = this.releaseTag + break + case 'test': + default: + pushTag = this.testTag + break } - return versionString + await bashBare('docker tag ' + this.buildTag + ' ' + pushTag) + await bashBare('docker push ' + pushTag) + }; + + /** + * pulls the Dockerfile from a registry + */ + async pull(registryArg: string) { + let pullTag = this.testTag + await bashBare('docker pull ' + pullTag) + await bashBare('docker tag ' + pullTag + ' ' + this.buildTag) + }; + + /** + * tests the Dockerfile; + */ + async test() { + let testFile: string = plugins.path.join(paths.NpmciTestDir, 'test_' + this.version + '.sh') + let testFileExists: boolean = plugins.smartfile.fs.fileExistsSync(testFile) + if (testFileExists) { + // run tests + await bashBare('docker run --name npmci_test_container ' + this.buildTag + ' mkdir /npmci_test') + await bashBare('docker cp ' + testFile + ' npmci_test_container:/npmci_test/test.sh') + await bashBare('docker commit npmci_test_container npmci_test_image') + await bashBare('docker run npmci_test_image sh /npmci_test/test.sh') + await bashBare('docker rm npmci_test_container') + await bashBare('docker rmi --force npmci_test_image') + } else { + plugins.beautylog.warn('skipping tests for ' + this.cleanTag + ' because no testfile was found!') + } + }; + + /** + * gets the id of a Dockerfile + */ + async getId() { + let containerId = await bashBare('docker inspect --type=image --format=\"{{.Id}}\" ' + this.buildTag) + return containerId + }; +} + +/** + * returns a version for a docker file + * @execution SYNC + */ +export let dockerFileVersion = (dockerfileNameArg: string): string => { + let versionString: string + let versionRegex = /Dockerfile_([a-zA-Z0-9\.]*)$/ + let regexResultArray = versionRegex.exec(dockerfileNameArg) + if (regexResultArray && regexResultArray.length === 2) { + versionString = regexResultArray[1] + } else { + versionString = 'latest' + } + return versionString } /** * */ -export let dockerBaseImage = function(dockerfileContentArg: string){ - let baseImageRegex = /FROM\s([a-zA-z0-9\/\-\:]*)\n?/ - let regexResultArray = baseImageRegex.exec(dockerfileContentArg) - return regexResultArray[1] +export let dockerBaseImage = function (dockerfileContentArg: string) { + let baseImageRegex = /FROM\s([a-zA-z0-9\/\-\:]*)\n?/ + let regexResultArray = baseImageRegex.exec(dockerfileContentArg) + return regexResultArray[1] } /** * */ -export let dockerTag = function(registryArg: string,repoArg: string,versionArg: string,suffixArg?: string): string{ - let tagString: string - let registry = registryArg - let repo = repoArg - let version = versionArg - if (suffixArg) { - version = versionArg + '_' + suffixArg - }; - tagString = registry + '/' + repo + ':' + version - return tagString +export let dockerTag = function (registryArg: string, repoArg: string, versionArg: string, suffixArg?: string): string { + let tagString: string + let registry = registryArg + let repo = repoArg + let version = versionArg + if (suffixArg) { + version = versionArg + '_' + suffixArg + }; + tagString = registry + '/' + repo + ':' + version + return tagString } /** * */ -export let cleanTagsArrayFunction = function(dockerfileArrayArg: Dockerfile[],trackingArrayArg: Dockerfile[]): string[]{ - let cleanTagsArray: string[] = [] - dockerfileArrayArg.forEach(function(dockerfileArg){ - if (trackingArrayArg.indexOf(dockerfileArg) === -1) { - cleanTagsArray.push(dockerfileArg.cleanTag) - } - }) - return cleanTagsArray +export let cleanTagsArrayFunction = function (dockerfileArrayArg: Dockerfile[], trackingArrayArg: Dockerfile[]): string[] { + let cleanTagsArray: string[] = [] + dockerfileArrayArg.forEach(function (dockerfileArg) { + if (trackingArrayArg.indexOf(dockerfileArg) === -1) { + cleanTagsArray.push(dockerfileArg.cleanTag) + } + }) + return cleanTagsArray } diff --git a/ts/npmci.build.ts b/ts/npmci.build.ts index cab0558..fa265f3 100644 --- a/ts/npmci.build.ts +++ b/ts/npmci.build.ts @@ -1,22 +1,23 @@ import * as plugins from './npmci.plugins' -import {bash} from './npmci.bash' +import { bash } from './npmci.bash' import * as env from './npmci.env' import * as buildDocker from './npmci.build.docker' /** * defines possible build services */ -export type TBuildService = 'docker'; +export type TBuildService = 'docker' /** * builds for a specific service */ -export let build = function(commandArg): plugins.q.Promise { - switch (commandArg) { - case 'docker': - return buildDocker.build() - default: - plugins.beautylog.log('build target ' + commandArg + ' not recognised!') - }; - return +export let build = async (commandArg): Promise => { + switch (commandArg) { + case 'docker': + await buildDocker.build() + break + default: + plugins.beautylog.log('build target ' + commandArg + ' not recognised!') + }; + return } diff --git a/ts/npmci.clean.ts b/ts/npmci.clean.ts index e39dfe6..19d6feb 100644 --- a/ts/npmci.clean.ts +++ b/ts/npmci.clean.ts @@ -4,9 +4,7 @@ import * as paths from './npmci.paths' /** * cleans npmci config files */ -export let clean = () => { - let done = plugins.q.defer() - plugins.smartfile.fs.removeSync(paths.NpmciPackageConfig) - done.resolve() - return done.promise +export let clean = async (): Promise => { + plugins.smartfile.fs.removeSync(paths.NpmciPackageConfig) + return } diff --git a/ts/npmci.plugins.ts b/ts/npmci.plugins.ts index e163516..00eb3e0 100644 --- a/ts/npmci.plugins.ts +++ b/ts/npmci.plugins.ts @@ -5,7 +5,7 @@ export import lodash = require('lodash') export import npmextra = require('npmextra') export import path = require('path') export import projectinfo = require('projectinfo') -export import q = require('q') +export import q = require('smartq') export let request = require('request') export import shelljs = require('shelljs') export import smartcli = require('smartcli') diff --git a/yarn.lock b/yarn.lock index 7b12157..f149260 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1676,7 +1676,7 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@4.1.0: +object-assign@4.1.0, object-assign@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" @@ -1684,10 +1684,6 @@ object-assign@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"