From 3964ce1c153dfe01e230e69a49d2db2a281a9fcc Mon Sep 17 00:00:00 2001 From: Inga Lovinde <52715130+inga-lovinde@users.noreply.github.com> Date: Fri, 31 Mar 2017 17:04:36 +0300 Subject: [PATCH] Enabled noImplicitAny --- BuildServer/lib/builder.ts | 45 ++++++++--- BuildServer/lib/commenter.ts | 81 ++++++++++++------- BuildServer/lib/git/copy.ts | 47 ++++++----- BuildServer/lib/git/loader.ts | 58 +++++++------ BuildServer/lib/github-wrapper.ts | 8 +- BuildServer/lib/mail-sender.ts | 12 ++- BuildServer/lib/report-processor.ts | 41 +++++++--- BuildServer/lib/routes/manual.ts | 3 +- BuildServer/lib/routes/postreceive.ts | 14 ++-- BuildServer/lib/routes/release.ts | 7 +- BuildServer/lib/routes/status.ts | 42 ++++++---- BuildServer/lib/settings-wrapper.ts | 6 +- BuildServer/lib/status-processor.ts | 56 ++++++++++--- BuildServer/lib/task-processor.ts | 51 +++++++----- .../lib/tasks/cleanupafterdotnetbuild.ts | 22 +++-- BuildServer/lib/tasks/conditional.ts | 13 ++- BuildServer/lib/tasks/copy.ts | 4 +- BuildServer/lib/tasks/copyglob.ts | 22 +++-- BuildServer/lib/tasks/cssnano.ts | 18 ++--- BuildServer/lib/tasks/cssnanoall.ts | 24 +++--- BuildServer/lib/tasks/deletefromcode.ts | 4 +- BuildServer/lib/tasks/dotnetbuild.ts | 5 +- BuildServer/lib/tasks/dotnetbuildandtest.ts | 5 +- BuildServer/lib/tasks/dotnetbuilderwrapper.ts | 15 +++- .../lib/tasks/dotnetbuildwithoutcleanup.ts | 16 +++- BuildServer/lib/tasks/dotnetcheckstyle.ts | 12 ++- BuildServer/lib/tasks/dotnetcompile.ts | 23 ++++-- BuildServer/lib/tasks/dotnetnugetpack.ts | 9 ++- BuildServer/lib/tasks/dotnetnugetprocess.ts | 12 ++- .../lib/tasks/dotnetnugetprocessinternal.ts | 15 +++- BuildServer/lib/tasks/dotnetnugetpush.ts | 9 ++- BuildServer/lib/tasks/dotnetnugetpushonly.ts | 4 +- BuildServer/lib/tasks/dotnetnugetrestore.ts | 21 ++--- BuildServer/lib/tasks/dotnetnunit.ts | 4 +- BuildServer/lib/tasks/dotnetnunitall.ts | 25 +++--- BuildServer/lib/tasks/dotnetpackwebapp.ts | 10 ++- BuildServer/lib/tasks/dotnetrewrite.ts | 21 +++-- BuildServer/lib/tasks/echo.ts | 10 ++- BuildServer/lib/tasks/eslintbrowser.ts | 4 +- BuildServer/lib/tasks/eslintbrowserall.ts | 22 +++-- BuildServer/lib/tasks/noop.ts | 4 +- BuildServer/lib/tasks/packform.ts | 18 ++++- BuildServer/lib/tasks/parallel.ts | 10 ++- BuildServer/lib/tasks/sequential.ts | 10 ++- BuildServer/lib/tasks/uglifyjs.ts | 4 +- BuildServer/lib/tasks/uglifyjsall.ts | 24 +++--- BuildServer/lib/tasks/writefile.ts | 9 ++- BuildServer/lib/tasks/zip.ts | 11 ++- .../lib/types/augmentations/cssnano.ts | 10 +++ BuildServer/lib/types/augmentations/eslint.ts | 21 +++++ .../lib/types/augmentations/graceful-fs.ts | 6 ++ .../types/augmentations/json-parse-safe.ts | 5 ++ .../lib/types/augmentations/nodegit.ts | 34 ++++++++ .../lib/types/augmentations/stream-buffers.ts | 14 ++++ BuildServer/lib/types/dotnetbuilder-types.ts | 37 +++++++++ BuildServer/lib/types/index.ts | 5 ++ BuildServer/lib/types/report-types.ts | 8 +- BuildServer/lib/types/task-processor-types.ts | 10 ++- BuildServer/package.json | 4 +- BuildServer/tsconfig.json | 11 ++- 60 files changed, 731 insertions(+), 344 deletions(-) create mode 100644 BuildServer/lib/types/augmentations/cssnano.ts create mode 100644 BuildServer/lib/types/augmentations/eslint.ts create mode 100644 BuildServer/lib/types/augmentations/graceful-fs.ts create mode 100644 BuildServer/lib/types/augmentations/json-parse-safe.ts create mode 100644 BuildServer/lib/types/augmentations/nodegit.ts create mode 100644 BuildServer/lib/types/augmentations/stream-buffers.ts create mode 100644 BuildServer/lib/types/dotnetbuilder-types.ts diff --git a/BuildServer/lib/builder.ts b/BuildServer/lib/builder.ts index 751612b..0a4562a 100644 --- a/BuildServer/lib/builder.ts +++ b/BuildServer/lib/builder.ts @@ -13,13 +13,38 @@ import { writeReport } from "./report-processor"; import { processTask } from "./task-processor"; import { ReportResult, Settings } from "./types"; +interface IStatusOptions { + readonly description: string; + readonly owner: string; + readonly reponame: string; + readonly hash: string; + readonly state: "pending" | "success" | "error"; +} + +interface IBuildOptions { + readonly branch: string; + readonly owner: string; + readonly reponame: string; + readonly rev: string; + readonly skipGitLoader?: boolean; + readonly url: string; +} + +interface ISimpleCallback { + (err?: any): void; +} + +interface IBuildCallback { + (err?: any, result?: ReportResult): void; +} + const codePostfix = ""; const mailLazinessLevel = 1000; const maxDescriptionLength = 140; const maxTmpcodepathLength = 15; const twoDigits = 100; -const createFinalState = (isSuccess) => { +const createFinalState = (isSuccess: boolean) => { if (isSuccess) { return "success"; } @@ -27,7 +52,7 @@ const createFinalState = (isSuccess) => { return "error"; }; -const createBuildDoneMessage = (isSuccess, name) => { +const createBuildDoneMessage = (isSuccess: boolean, name: string) => { if (isSuccess) { return `Successfully built ${name}`; } @@ -35,7 +60,7 @@ const createBuildDoneMessage = (isSuccess, name) => { return `Build failed for ${name}`; }; -const notifyStatus = (settings: Settings, options, notifyStatusCallback) => { +const notifyStatus = (settings: Settings, options: IStatusOptions, notifyStatusCallback: ISimpleCallback) => { const status = { description: String(options.description || "").substr(0, maxDescriptionLength), owner: options.owner, @@ -57,7 +82,7 @@ const notifyStatus = (settings: Settings, options, notifyStatusCallback) => { }); }; -const wrapGitLoader: (skipGitLoader: boolean) => typeof gitLoader = (skipGitLoader) => { +const wrapGitLoader: (skipGitLoader?: boolean) => typeof gitLoader = (skipGitLoader) => { if (!skipGitLoader) { return gitLoader; } @@ -65,7 +90,7 @@ const wrapGitLoader: (skipGitLoader: boolean) => typeof gitLoader = (skipGitLoad return (_gitLoaderOptions, gitLoaderCallback) => process.nextTick(gitLoaderCallback); }; -export const build = (settings: Settings, options, buildCallback) => { +export const build = (settings: Settings, options: IBuildOptions, buildCallback: IBuildCallback) => { const url = options.url; const owner = options.owner; const reponame = options.reponame; @@ -100,7 +125,7 @@ export const build = (settings: Settings, options, buildCallback) => { mkdirsSync(join(settings.releasepath, owner, reponame, "$revs")); writeFileSync(join(settings.releasepath, owner, reponame, "$revs", `${rev}.branch`), branch); - const createErrorMessageForMail = (doneErr) => { + const createErrorMessageForMail = (doneErr: any) => { if (!doneErr) { return ""; } @@ -108,7 +133,7 @@ export const build = (settings: Settings, options, buildCallback) => { return `Error message: ${doneErr}\r\n\r\n`; }; - const createResultMessageForMail = (result) => { + const createResultMessageForMail = (result?: ReportResult) => { if (!result || !result.messages || !result.messages.$allMessages) { return JSON.stringify(result, null, " "); } @@ -116,7 +141,7 @@ export const build = (settings: Settings, options, buildCallback) => { return result.messages.$allMessages.map((msg) => `${msg.prefix}\t${msg.message}`).join("\r\n"); }; - const done = (doneErr, result?: ReportResult) => { + const done = (doneErr: any, result?: ReportResult) => { const allErrors = (result && result.errors && result.errors.$allMessages) || []; const allWarns = (result && result.warns && result.errors.$allMessages) || []; const allInfos = (result && result.infos && result.errors.$allMessages) || []; @@ -136,7 +161,7 @@ export const build = (settings: Settings, options, buildCallback) => { (parallelCallback) => sendMail({ from: settings.smtp.sender, headers: { "X-Laziness-level": mailLazinessLevel }, - subject: createBuildDoneMessage(doneErr, `${owner}/${reponame}/${branch}`), + subject: createBuildDoneMessage(!doneErr, `${owner}/${reponame}/${branch}`), text: `Build status URL: ${settings.siteRoot}status/${owner}/${reponame}/${rev}\r\n\r\n${createErrorMessageForMail(doneErr)}${createResultMessageForMail(result)}`, to: settings.smtp.receiver, }, parallelCallback), @@ -177,7 +202,7 @@ export const build = (settings: Settings, options, buildCallback) => { return done("MBSNotFound"); } - return readFile(join(exported, "mbs.json"), (readErr, data) => { + return readFile(join(exported, "mbs.json"), "utf8", (readErr, data) => { if (readErr) { return done(`MBSUnableToRead: ${readErr}`); } diff --git a/BuildServer/lib/commenter.ts b/BuildServer/lib/commenter.ts index 9acfc3b..476fc2b 100644 --- a/BuildServer/lib/commenter.ts +++ b/BuildServer/lib/commenter.ts @@ -6,15 +6,38 @@ import { createGithub, IGithub } from "./github-wrapper"; import { getStatusMessageFromRelease } from "./report-processor"; import { Settings } from "./types"; -interface ICommentOnPullRequestOptions { +interface IRepoOptions { + readonly branch: string; + readonly branchName: string; + readonly owner: string; + readonly reponame: string; +} + +interface IRepoCommitOptions extends IRepoOptions { + readonly rev: string; +} + +interface IPullRequestOptions { readonly action: string; - readonly baseRepoOptions: any; - readonly headRepoOptions: any; + readonly baseRepoOptions: IRepoOptions; + readonly headRepoOptions: IRepoCommitOptions; + readonly pullRequestNumber: number; } -interface ICheckPullRequestOptions extends ICommentOnPullRequestOptions { +interface IPullRequestOptionsWithGithub extends IPullRequestOptions { readonly github: IGithub; - readonly onTenthAttempt: () => void; +} + +interface ISimpleCallback { + (err?: any): void; +} + +interface IHasIssueCallback { + (err?: any, hasIssue?: boolean, issueTitle?: string): void; +} + +interface IHasReleasesCallback { + (err?: any, hasReleases?: boolean): void; } const featureNamePattern = /^feature-(\d+)(?:-[a-zA-Z0-9]+)+$/; @@ -24,14 +47,14 @@ const masterNamePattern = /^master$/; const httpNotFound = 404; const maxCommentLength = 64000; -const writeComment = (options, message, callback) => options.github.issues.createComment({ +const writeComment = (options: IPullRequestOptionsWithGithub, message: string, callback: ISimpleCallback) => options.github.issues.createComment({ body: message, number: options.pullRequestNumber, owner: options.baseRepoOptions.owner, repo: options.baseRepoOptions.reponame, }, callback); -const closePullRequest = (options, message, callback) => writeComment(options, message, (err) => { +const closePullRequest = (options: IPullRequestOptionsWithGithub, message: string, callback: ISimpleCallback) => writeComment(options, message, (err: any) => { if (err) { return callback(err); } @@ -44,7 +67,7 @@ const closePullRequest = (options, message, callback) => writeComment(options, m }, callback); }); -const checkHasIssue = (options: ICheckPullRequestOptions, issueNumber, callback) => options.github.issues.get({ +const checkHasIssue = (options: IPullRequestOptionsWithGithub, issueNumber: number, callback: IHasIssueCallback) => options.github.issues.get({ number: issueNumber, owner: options.baseRepoOptions.owner, repo: options.baseRepoOptions.reponame, @@ -61,7 +84,7 @@ const checkHasIssue = (options: ICheckPullRequestOptions, issueNumber, callback) return callback("Result is empty"); } - if (result.data.number.toString() !== issueNumber) { + if (result.data.number.toString() !== issueNumber.toString()) { return callback(null, false); } @@ -72,7 +95,7 @@ const checkHasIssue = (options: ICheckPullRequestOptions, issueNumber, callback) return callback(null, true, result.data.title); }); -const checkHasReleases = (options: ICheckPullRequestOptions, callback) => options.github.repos.getReleases({ +const checkHasReleases = (options: IPullRequestOptionsWithGithub, callback: IHasReleasesCallback) => options.github.repos.getReleases({ owner: options.baseRepoOptions.owner, per_page: 1, repo: options.baseRepoOptions.reponame, @@ -81,10 +104,10 @@ const checkHasReleases = (options: ICheckPullRequestOptions, callback) => option return callback(getReleasesErr); } - return callback(null, result && result.data && result.data.length); + return callback(null, Boolean(result && result.data && result.data.length)); }); -const checkPullRequest = (options: ICheckPullRequestOptions, callback) => { +const checkPullRequest = (options: IPullRequestOptionsWithGithub, callback: ISimpleCallback) => { const head = options.headRepoOptions; const base = options.baseRepoOptions; @@ -93,11 +116,11 @@ const checkPullRequest = (options: ICheckPullRequestOptions, callback) => { } if (head.owner === base.owner) { - if (!versionNamePattern.test(head.branchname) || !masterNamePattern.test(base.branchname)) { + if (!versionNamePattern.test(head.branchName) || !masterNamePattern.test(base.branchName)) { return closePullRequest(options, "Only merging from version to master is allowed", callback); } - return checkHasReleases(options, (hasReleasesErr, hasReleases) => { + return checkHasReleases(options, (hasReleasesErr, hasReleases?: boolean) => { if (hasReleasesErr) { return writeComment(options, "Unable to check for releases", callback); } @@ -107,25 +130,25 @@ const checkPullRequest = (options: ICheckPullRequestOptions, callback) => { } if (options.action === "opened") { - return writeComment(options, `Switching master branch to ${head.branchname} release`, callback); + return writeComment(options, `Switching master branch to ${head.branchName} release`, callback); } return process.nextTick(callback); }); } - if (!featureNamePattern.test(head.branchname)) { + if (!featureNamePattern.test(head.branchName)) { return closePullRequest(options, `Only merging from feature branch is allowed (pattern: \`${featureNamePattern}\`)`, callback); } - if (!versionNamePattern.test(base.branchname) && !masterNamePattern.test(base.branchname)) { - return closePullRequest(options, `Only merging to master or version branch is allowed; merging to '${base.branchname}' is not supported`, callback); + if (!versionNamePattern.test(base.branchName) && !masterNamePattern.test(base.branchName)) { + return closePullRequest(options, `Only merging to master or version branch is allowed; merging to '${base.branchName}' is not supported`, callback); } - const execResult = featureNamePattern.exec(head.branchname); - const issueNumber = execResult && execResult[1]; + const execResult = featureNamePattern.exec(head.branchName); + const issueNumber = (execResult && parseInt(execResult[1], 10)) || 0; // execResult will never be empty - return checkHasIssue(options, issueNumber, (hasIssueErr, hasIssue, issueTitle) => { + return checkHasIssue(options, issueNumber, (hasIssueErr, hasIssue?: boolean, issueTitle?: string) => { if (hasIssueErr) { return writeComment(options, `Unable to check for issue:\r\n\r\n${hasIssueErr}`, callback); } @@ -134,7 +157,7 @@ const checkPullRequest = (options: ICheckPullRequestOptions, callback) => { return closePullRequest(options, `Unable to find issue #${issueNumber}`, callback); } - const shouldHaveReleases = versionNamePattern.test(base.branchname); + const shouldHaveReleases = versionNamePattern.test(base.branchName); return checkHasReleases(options, (hasReleasesErr, hasReleases) => { if (hasReleasesErr) { @@ -150,7 +173,7 @@ const checkPullRequest = (options: ICheckPullRequestOptions, callback) => { } if (options.action === "opened") { - return writeComment(options, `Merging feature #${issueNumber} (${issueTitle}) to ${base.branchname}`, callback); + return writeComment(options, `Merging feature #${issueNumber} (${issueTitle}) to ${base.branchName}`, callback); } return process.nextTick(callback); @@ -158,17 +181,17 @@ const checkPullRequest = (options: ICheckPullRequestOptions, callback) => { }); }; -export const commentOnPullRequest = (settings: Settings, originalOptions: ICommentOnPullRequestOptions, callback) => { - const optionsGithub = { +export const commentOnPullRequest = (settings: Settings, originalOptions: IPullRequestOptions, callback: ISimpleCallback) => { + const options = { ...originalOptions, github: createGithub(settings, originalOptions.baseRepoOptions.owner), }; - const options = { - ...optionsGithub, - onTenthAttempt: () => writeComment(optionsGithub, "Waiting for build to finish...", _.noop), + const getStatusMessageOptions = { + ...options.headRepoOptions, + onTenthAttempt: () => writeComment(options, "Waiting for build to finish...", _.noop), }; - return checkPullRequest(options, () => getStatusMessageFromRelease(settings, options.headRepoOptions, (statusMessageErr, statusSuccessMessage) => { + return checkPullRequest(options, () => getStatusMessageFromRelease(settings, getStatusMessageOptions, (statusMessageErr, statusSuccessMessage) => { const escapedErr = String(statusMessageErr || "").substring(0, maxCommentLength) .replace(/`/g, "` "); const message = statusMessageErr diff --git a/BuildServer/lib/git/copy.ts b/BuildServer/lib/git/copy.ts index 9cf393d..25a3071 100644 --- a/BuildServer/lib/git/copy.ts +++ b/BuildServer/lib/git/copy.ts @@ -3,10 +3,24 @@ import { parallel } from "async"; import { EventEmitter } from "events"; import { mkdir, writeFile } from "fs"; +import { Commit, Tree, TreeEntry } from "nodegit"; import { join } from "path"; -import { Copier } from "recursive-tree-copy"; +import { createCopier } from "recursive-tree-copy"; -const safeGetEntries = (tree, callback) => { +interface ISource { + gitTree: Tree; + name: string; +} + +interface ISimpleCallback { + (err?: any): void; +} + +interface INewTreeCallback { + (err: any, newTree?: string): void; +} + +const safeGetEntries = (tree: ISource, callback: (err: any, entries?: TreeEntry[]) => void) => { try { return callback(null, tree.gitTree.entries()); } catch (err) { @@ -14,20 +28,20 @@ const safeGetEntries = (tree, callback) => { } }; -const gitToFsCopier = new Copier({ +const gitToFsCopier = createCopier({ concurrency: 4, - copyLeaf: (entry, targetDir, callback) => { + copyLeaf: (entry: TreeEntry, targetDir: string, callback: ISimpleCallback) => { const targetPath = join(targetDir, entry.name()); entry.getBlob((err, blob) => { - if (err) { + if (err || !blob) { return callback(err); } return writeFile(targetPath, blob.content(), callback); }); }, - createTargetTree: (tree, targetDir, callback) => { + createTargetTree: (tree: ISource, targetDir: string, callback: INewTreeCallback) => { const targetSubdir = join(targetDir, tree.name); mkdir(targetSubdir, (err) => { @@ -39,16 +53,16 @@ const gitToFsCopier = new Copier({ return callback(null, targetSubdir); }); }, - finalizeTargetTree: (_targetSubdir, callback) => callback(), - walkSourceTree: (tree) => { + finalizeTargetTree: (_targetSubdir: string, callback: ISimpleCallback) => callback(), + walkSourceTree: (tree: ISource) => { const emitter = new EventEmitter(); process.nextTick(() => safeGetEntries(tree, (getEntriesErr, entries) => { - if (getEntriesErr) { + if (getEntriesErr || !entries) { return emitter.emit("error", getEntriesErr); } - return parallel(entries.map((entry) => (callback) => { + return parallel(entries.map((entry) => (callback: ISimpleCallback) => { if (entry.isTree()) { return entry.getTree((getTreeErr, subTree) => { if (getTreeErr) { @@ -84,13 +98,10 @@ const gitToFsCopier = new Copier({ }, }); -export const gitToFs = (commit, exportDir, callback) => commit.getTree((err, tree) => { - if (err) { - return callback(err); - } - - return gitToFsCopier.copy({ +export const gitToFs = (commit: Commit, exportDir: string, callback: ISimpleCallback) => commit.getTree().then( + (tree) => gitToFsCopier.copy({ gitTree: tree, name: ".", - }, exportDir, callback); -}); + }, exportDir, callback), + (err) => callback(err), +); diff --git a/BuildServer/lib/git/loader.ts b/BuildServer/lib/git/loader.ts index 3d67360..7d1b667 100644 --- a/BuildServer/lib/git/loader.ts +++ b/BuildServer/lib/git/loader.ts @@ -5,7 +5,19 @@ import { Remote, Repository } from "nodegit"; import { gitToFs } from "./copy"; -const fixUrl = (url) => { +interface IOptions { + readonly branch: string; + readonly exported: string; + readonly hash: string; + readonly local: string; + readonly remote: string; +} + +interface ISimpleCallback { + (err?: any): void; +} + +const fixUrl = (url: string) => { if (!url.startsWith("https://")) { return url; } @@ -13,17 +25,7 @@ const fixUrl = (url) => { return `git://${url.substr("https://".length)}`; }; -/* Example: -options = { - "remote": "https://github.com/visionmedia/express.git", - "local": "D:\\data\\repositories\\visionmedia\\express.git\\", - "branch": "1.x", - "hash": "82e15cf321fccf3215068814d1ea1aeb3581ddb3", - "exported": "D:\\data\\exportedsource\\visionmedia\\express\\82e15cf321fccf3215068814d1ea1aeb3581ddb3\\", -} - */ - -export const gitLoader = (options, globalCallback) => { +export const gitLoader = (options: IOptions, globalCallback: ISimpleCallback) => { const url = fixUrl(options.remote); const path = `${options.local}/${options.hash}`; const exported = options.exported; @@ -33,30 +35,34 @@ export const gitLoader = (options, globalCallback) => { console.log(`Cloning ${url} to ${path}`); - Repository.init(path, 1) - .catch(globalCallback) - .then((repo) => Remote.create(repo, "origin", url) - .catch(globalCallback) - .then((remote) => remote.fetch([options.branch]) - .catch(globalCallback) - .then((errorNumber) => { + Repository.init(path, 1).then( + (repo) => Remote.create(repo, "origin", url).then( + (remote) => remote.fetch([options.branch]).then( + (errorNumber) => { if (errorNumber) { return globalCallback(`Failed to fetch commit: error number ${errorNumber}`); } console.log(`Cloned ${url} to ${path}`); - return repo.getCommit(options.hash) - .catch(globalCallback) - .then((commit) => { + return repo.getCommit(options.hash).then( + (commit) => { removeSync(exported); mkdirsSync(exported); - gitToFs(commit, exported, (err, result) => { + gitToFs(commit, exported, (err) => { repo.free(); - return globalCallback(err, result); + return globalCallback(err); }); - }); - }))); + }, + globalCallback, + ); + }, + globalCallback, + ), + globalCallback, + ), + globalCallback, + ); }; diff --git a/BuildServer/lib/github-wrapper.ts b/BuildServer/lib/github-wrapper.ts index a42657b..eb25f07 100644 --- a/BuildServer/lib/github-wrapper.ts +++ b/BuildServer/lib/github-wrapper.ts @@ -33,15 +33,17 @@ interface IStatusData { interface IGithub { readonly issues: { + createComment(params: RawGithub.IssuesCreateCommentParams, callback: ICallback): void; + edit(params: RawGithub.IssuesEditParams, callback: ICallback): void; get(params: RawGithub.IssuesGetParams, callback: ICallback): void; }; readonly repos: { - createStatus(params: RawGithub.ReposCreateStatusParams, callback: ICallback); - getReleases(params: RawGithub.ReposGetReleasesParams, callback: ICallback); + createStatus(params: RawGithub.ReposCreateStatusParams, callback: ICallback): void; + getReleases(params: RawGithub.ReposGetReleasesParams, callback: ICallback): void; }; } -const createGithub = (settings: Settings, repoOwner) => settings.createGithub(repoOwner) as any as IGithub; +const createGithub = (settings: Settings, repoOwner: string) => settings.createGithub(repoOwner) as IGithub; export { IGithub, diff --git a/BuildServer/lib/mail-sender.ts b/BuildServer/lib/mail-sender.ts index 05ba317..aa2c116 100644 --- a/BuildServer/lib/mail-sender.ts +++ b/BuildServer/lib/mail-sender.ts @@ -1,7 +1,15 @@ "use strict"; -export const send = (message, callback) => { +interface IMessage { + from: string; + headers: { [headerName: string]: any }; + subject: string; + text: string; + to: string; +} + +export const send = (message: IMessage, callback: () => void) => { console.log("Mail sender is not implemented"); - console.log(message.title); + console.log(message.subject); process.nextTick(callback); }; diff --git a/BuildServer/lib/report-processor.ts b/BuildServer/lib/report-processor.ts index ab22406..7d2e4f7 100644 --- a/BuildServer/lib/report-processor.ts +++ b/BuildServer/lib/report-processor.ts @@ -10,6 +10,24 @@ import { createGunzip, createGzip } from "zlib"; import { Message, Report, ReportResult, Settings } from "./types"; +interface IOptions { + readonly branch: string; + readonly branchName: string; + readonly owner: string; + readonly reponame: string; + readonly rev: string; +} + +interface IOptionsWithReport extends IOptions { + readonly files: string[]; + readonly report: Report; +} + +interface IGetStatusOptions extends IOptions { + readonly attemptsGetReport?: number; + readonly onTenthAttempt: () => void; +} + const reportFilename = "report.json.gz"; const maxAttemptsNumber = 100; const attemptsTimeout = 30000; @@ -26,7 +44,7 @@ const getAllErrors = (report: Report): Message[] => (report.result && report.res const getAllWarns = (report: Report): Message[] => (report.result && report.result.warns && report.result.errors.$allMessages) || []; const getAllInfos = (report: Report): Message[] => (report.result && report.result.infos && report.result.errors.$allMessages) || []; -export const writeReport = (releaseDir, err, result: ReportResult | undefined, callback) => { +export const writeReport = (releaseDir: string, err: string | null, result: ReportResult | undefined, callback: (err?: string) => void) => { const data = JSON.stringify({ date: Date.now(), err, @@ -51,7 +69,7 @@ export const writeReport = (releaseDir, err, result: ReportResult | undefined, c readable.stop(); }; -export const readReport = (releaseDir, callback) => { +export const readReport = (releaseDir: string, callback: (err: string | null, report?: Report) => void) => { const readStream = createReadStream(join(releaseDir, reportFilename)); const writable = new WritableStreamBuffer(); @@ -78,7 +96,7 @@ export const readReport = (releaseDir, callback) => { }); }; -export const loadReport = (settings: Settings, options, callback) => { +export const loadReport = (settings: Settings, options: IOptions, callback: (err: Error | string | null, result?: IOptionsWithReport) => void) => { const releaseDir = join(settings.releasepath, options.owner, options.reponame, options.branch, options.rev); glob("**", { @@ -86,22 +104,19 @@ export const loadReport = (settings: Settings, options, callback) => { mark: true, }, (err, files) => { if (err) { - return callback(err, options); + return callback(err); } const reportFile = join(releaseDir, reportFilename); return exists(reportFile, (reportFileExists) => { if (!reportFileExists) { - return callback("ReportFileNotFound", options); + return callback("ReportFileNotFound"); } return readReport(releaseDir, (readErr, report) => { - if (readErr) { - return callback(readErr, { - ...options, - files, - }); + if (readErr || !report) { + return callback(readErr); } return callback(null, { @@ -114,7 +129,7 @@ export const loadReport = (settings: Settings, options, callback) => { }); }; -export const getStatusMessageFromRelease = (settings: Settings, originalOptions, callback) => { +export const getStatusMessageFromRelease = (settings: Settings, originalOptions: IGetStatusOptions, callback: (err: string | null, statusMessage?: string) => void) => { const options = { ...originalOptions, attemptsGetReport: (Number(originalOptions.attemptsGetReport) || Number()) + 1, @@ -143,11 +158,11 @@ export const getStatusMessageFromRelease = (settings: Settings, originalOptions, } return setTimeout(() => readReport(releaseDir, (readErr, report) => { - if (readErr) { + if (readErr || !report) { return callback(readErr); } - if (report.result === "MBSNotFound") { + if (report.err === "MBSNotFound") { return callback("mbs.json is not found"); } diff --git a/BuildServer/lib/routes/manual.ts b/BuildServer/lib/routes/manual.ts index 1e723bf..727c8de 100644 --- a/BuildServer/lib/routes/manual.ts +++ b/BuildServer/lib/routes/manual.ts @@ -4,6 +4,7 @@ import * as express from "express"; import { build } from "../builder"; import { getSettings } from "../settings-wrapper"; +import { ReportResult } from "../types"; export const get: express.RequestHandler = (_req, res) => res.render("manual"); @@ -15,7 +16,7 @@ export const post: express.RequestHandler = (req, res) => { url: `https://pos-github.payonline.ru/${req.body.owner}/${req.body.reponame}`, }; - build(settings, options, (err, result) => { + build(settings, options, (err: string, result: ReportResult) => { console.log("Done processing manual request"); console.log(`Error: ${err}`); res.render("manual-done", { diff --git a/BuildServer/lib/routes/postreceive.ts b/BuildServer/lib/routes/postreceive.ts index bf743ce..84cbd55 100644 --- a/BuildServer/lib/routes/postreceive.ts +++ b/BuildServer/lib/routes/postreceive.ts @@ -10,12 +10,12 @@ import { HookParameters, HookPullRequestPayload, HookPushPayload } from "../type interface IBaseRepoOptions { branch: string; - branchname?: string; + branchName?: string; owner: string; reponame: string; } -const getBranchDescription = (options: IBaseRepoOptions) => `${options.owner}/${options.reponame}:${options.branchname || options.branch}`; +const getBranchDescription = (options: IBaseRepoOptions) => `${options.owner}/${options.reponame}:${options.branchName || options.branch}`; const processPush = (req: express.Request, res: express.Response, payload: HookPushPayload) => { const settings = getSettings(req.app); @@ -45,7 +45,7 @@ const processPullRequest = (req: express.Request, res: express.Response, payload const headRepo = head.repo; const headRepoOptions = { branch: `refs/heads/${head.ref}`, - branchname: head.ref, + branchName: head.ref, owner: headRepo.owner.name || headRepo.owner.login, reponame: headRepo.name, rev: head.sha, @@ -55,7 +55,7 @@ const processPullRequest = (req: express.Request, res: express.Response, payload const baseRepo = base.repo; const baseRepoOptions = { branch: `refs/heads/${base.ref}`, - branchname: base.ref, + branchName: base.ref, owner: baseRepo.owner.name || baseRepo.owner.login, reponame: baseRepo.name, }; @@ -84,16 +84,16 @@ const processPullRequest = (req: express.Request, res: express.Response, payload return res.send(""); } - return commentOnPullRequest(settings, options, (err, data) => { + return commentOnPullRequest(settings, options, (err) => { if (err) { console.log(`Unable to post comment: ${err}`); } - res.send(err || data); + res.end(); }); }; -const getPayload = (body) => { +const getPayload = (body: any) => { if (!body.payload) { return body; } diff --git a/BuildServer/lib/routes/release.ts b/BuildServer/lib/routes/release.ts index 2793fe8..a02f152 100644 --- a/BuildServer/lib/routes/release.ts +++ b/BuildServer/lib/routes/release.ts @@ -6,14 +6,15 @@ import { join } from "path"; import { readReport } from "../report-processor"; import { getSettings } from "../settings-wrapper"; +import { Report } from "../types"; -const getDatePart = (report) => { +const getDatePart = (report: Report) => { if (!report.date) { return "unknowndate"; } const date = new Date(report.date); - const paddingLeft = (str, paddingValue) => String(paddingValue + str).slice(-paddingValue.length); + const paddingLeft = (str: string | number, paddingValue: string) => String(paddingValue + str).slice(-paddingValue.length); const year = date.getFullYear(); const month = paddingLeft(date.getMonth() + 1, "00"); @@ -37,7 +38,7 @@ export default ((req, res, next) => { const releasePath = join(getSettings(req.app).releasepath, options.owner, options.reponame, options.branch, options.rev); readReport(releasePath, (err, report) => { - if (err) { + if (err || !report) { return next(err); } diff --git a/BuildServer/lib/routes/status.ts b/BuildServer/lib/routes/status.ts index a19b438..0d436ad 100644 --- a/BuildServer/lib/routes/status.ts +++ b/BuildServer/lib/routes/status.ts @@ -5,13 +5,25 @@ import { parse } from "url"; import { getSettings } from "../settings-wrapper"; import { getReport } from "../status-processor"; +import { Report } from "../types"; -const parseOptionsFromReferer = (path, callback) => { +interface IOptions { + readonly branchName: string; + readonly owner: string; + readonly reponame: string; + readonly rev: string; +} + +interface IOptionsWithReport extends IOptions { + readonly report: Report; +} + +const parseOptionsFromReferer = (path: string, callback: (err: string | null, options?: IOptions) => void) => { const pathParts = path.split("/").filter((value) => value); const [, secondPart, thirdPart] = pathParts; if (!secondPart) { - return callback("BadRequest", {}); + return callback("BadRequest"); } if (thirdPart === "tree") { @@ -35,7 +47,7 @@ const parseOptionsFromReferer = (path, callback) => { }); }; -const createShowReport = (res: express.Response) => (err, inputOptions) => { +const createShowReport = (res: express.Response) => (err: string | null, inputOptions: IOptions | undefined) => { const options = { ...inputOptions || {}, err, @@ -45,31 +57,33 @@ const createShowReport = (res: express.Response) => (err, inputOptions) => { }; export const image: express.RequestHandler = (req, res) => { - const getAdditionalOptions = (err, options) => { + const getAdditionalOptions = (err: string | null, options?: IOptionsWithReport) => { if (err === "ReportFileNotFound") { return { status: "Building" }; } - if (err) { + if (err || !options) { return { message: err, status: "StatusError", }; } - if (options.report.result === "MBSNotFound") { + if (options.report.err === "MBSNotFound") { return { status: "MBSNotUsed" }; } - if (options.report.err) { + if (options.report.err || !options.report.result) { return { message: options.report.err, status: "Error", }; } - if ((options.report.result.warns.$allMessages || []).length) { - const [firstWarn] = options.report.result.warns.$allMessages; + const result = options.report.result; + + if ((result.warns.$allMessages || []).length) { + const [firstWarn] = result.warns.$allMessages; return { message: firstWarn.message, @@ -77,7 +91,7 @@ export const image: express.RequestHandler = (req, res) => { }; } - const allInfos = options.report.result.infos.$allMessages || []; + const allInfos = result.infos.$allMessages || []; if (allInfos.length) { return { @@ -89,7 +103,7 @@ export const image: express.RequestHandler = (req, res) => { return { status: "OK" }; }; - const handle = (err, options) => { + const handle = (err: string | null, options?: IOptionsWithReport) => { res.setHeader("Content-Type", "image/svg+xml"); res.render("status-image", { ...options, @@ -97,9 +111,9 @@ export const image: express.RequestHandler = (req, res) => { }); }; - parseOptionsFromReferer(parse(req.headers.referer || "").pathname || "", (err, options) => { + parseOptionsFromReferer(parse(req.headers.referer || "").pathname || "", (err: string | null, options: IOptions) => { if (err) { - return handle(err, options); + return handle(err); } return getReport(getSettings(req.app), options, handle); @@ -119,7 +133,7 @@ export const page: express.RequestHandler = (req, res) => { }; export const pageFromGithub: express.RequestHandler = (req, res) => parseOptionsFromReferer(req.params[0], (err, options) => { - if (err) { + if (err || !options) { return createShowReport(res)(err, options); } diff --git a/BuildServer/lib/settings-wrapper.ts b/BuildServer/lib/settings-wrapper.ts index 399a919..934fcfe 100644 --- a/BuildServer/lib/settings-wrapper.ts +++ b/BuildServer/lib/settings-wrapper.ts @@ -1,10 +1,12 @@ "use strict"; +import * as express from "express"; + import { Settings } from "./types"; -const getSettings = (app): Settings => app.get("mbsSettings"); +const getSettings = (app: express.Application): Settings => app.get("mbsSettings"); -const setSettings = (app, settings: Settings) => app.set("mbsSettings", settings); +const setSettings = (app: express.Application, settings: Settings) => app.set("mbsSettings", settings); export { getSettings, diff --git a/BuildServer/lib/status-processor.ts b/BuildServer/lib/status-processor.ts index 91bc24b..3a1b262 100644 --- a/BuildServer/lib/status-processor.ts +++ b/BuildServer/lib/status-processor.ts @@ -4,19 +4,49 @@ import { exists, readFile } from "fs"; import { join } from "path"; import { loadReport } from "./report-processor"; -import { Settings } from "./types"; - -const addBranchInfo = (settings: Settings, options, callback) => { +import { Report, Settings } from "./types"; + +interface IOptionsWithBranchInfo { + readonly branch: string; + readonly branchName: string; + readonly owner: string; + readonly reponame: string; +} + +interface IOptionsWithRevInfo { + readonly owner: string; + readonly reponame: string; + readonly rev: string; +} + +interface IOptionsComplete extends IOptionsWithBranchInfo, IOptionsWithRevInfo { +} + +interface IGetReportOptions { + readonly branch?: string; + readonly branchName?: string; + readonly owner: string; + readonly reponame: string; + readonly rev?: string; +} + +interface IOptionsWithReport extends IOptionsComplete { + readonly report: Report; +} + +type Callback = (err: any, result?: ResultOptions) => void; + +const addBranchInfo = (settings: Settings, options: IOptionsWithRevInfo, callback: Callback) => { const branchFile = join(settings.releasepath, options.owner, options.reponame, "$revs", `${options.rev}.branch`); exists(branchFile, (exists) => { if (!exists) { - return callback("BranchFileNotFound", options); + return callback("BranchFileNotFound"); } return readFile(branchFile, (err, data) => { if (err) { - return callback(err, options); + return callback(err); } const branch = data.toString(); @@ -32,17 +62,17 @@ const addBranchInfo = (settings: Settings, options, callback) => { }); }; -const addRevInfo = (settings: Settings, options, callback) => { +const addRevInfo = (settings: Settings, options: IOptionsWithBranchInfo, callback: Callback) => { const revFile = join(settings.releasepath, options.owner, options.reponame, options.branch, "latest.id"); exists(revFile, (exists) => { if (!exists) { - return callback("RevFileNotFound", options); + return callback("RevFileNotFound"); } return readFile(revFile, (err, data) => { if (err) { - return callback(err, options); + return callback(err); } const rev = data.toString(); @@ -55,9 +85,9 @@ const addRevInfo = (settings: Settings, options, callback) => { }); }; -const parseOptions = (settings: Settings, options, callback) => { +const parseOptions = (settings: Settings, options: IGetReportOptions, callback: Callback) => { if (options.rev && !(/^[\da-f]{40}$/i).test(options.rev)) { - return callback(`Wrong rev format: ${options.rev}`, options); + return callback(`Wrong rev format: ${options.rev}`); } const result = { @@ -72,7 +102,7 @@ const parseOptions = (settings: Settings, options, callback) => { }, callback); } - if (/^[\da-f]{40}$/i.test(options.branchName)) { + if (options.branchName && /^[\da-f]{40}$/i.test(options.branchName)) { return addBranchInfo(settings, { ...result, rev: options.branchName, @@ -88,9 +118,9 @@ const parseOptions = (settings: Settings, options, callback) => { }, callback); }; -export const getReport = (settings: Settings, options, callback) => parseOptions(settings, options, (err, result) => { +export const getReport = (settings: Settings, options: IGetReportOptions, callback: Callback) => parseOptions(settings, options, (err: string, result: IOptionsComplete) => { if (err) { - return callback(err, {}); + return callback(err); } return loadReport(settings, result, callback); diff --git a/BuildServer/lib/task-processor.ts b/BuildServer/lib/task-processor.ts index c817ead..d107408 100644 --- a/BuildServer/lib/task-processor.ts +++ b/BuildServer/lib/task-processor.ts @@ -1,24 +1,28 @@ "use strict"; import tasks from "./tasks"; -import { MessagesRoot, ProcessTaskContext, Settings, TaskInfo, TaskProcessor, TaskProcessorCallback, TaskProcessorCore } from "./types"; +import { Messages, MessagesRoot, ProcessTaskContext, ReportResult, Settings, TaskInfo, TaskProcessor, TaskProcessorCallback, TaskProcessorCore } from "./types"; + +interface IFlags { + [flagName: string]: boolean; +} // TaskProcessor does not look like EventEmitter, so no need to extend EventEmitter and use `emit' here. const createTaskProcessor = (task: TaskInfo, outerProcessor: TaskProcessorCore, callback: TaskProcessorCallback) => { const errors: string[] = []; - const getOuterPrefix = (prefix) => { + const getOuterPrefix = (prefix?: string) => { if (task.name && prefix) { return `${task.name}/${prefix}`; } return String(task.name || "") + String(prefix || ""); }; - const onError = (message, prefix) => { + const onError = (message: string, prefix?: string) => { errors.push(message); outerProcessor.onError(message, getOuterPrefix(prefix)); }; - const onWarn = (message, prefix) => outerProcessor.onWarn(message, getOuterPrefix(prefix)); - const onInfo = (message, prefix) => outerProcessor.onInfo(message, getOuterPrefix(prefix)); + const onWarn = (message: string, prefix?: string) => outerProcessor.onWarn(message, getOuterPrefix(prefix)); + const onInfo = (message: string, prefix?: string) => outerProcessor.onInfo(message, getOuterPrefix(prefix)); let result: TaskProcessor; result = { @@ -35,47 +39,50 @@ const createTaskProcessor = (task: TaskInfo, outerProcessor: TaskProcessorCore, return result; }; -const pushMessage = (list, message, parts, index) => { - if (!index) { - list.$allMessages.push({ - message, - prefix: parts.join("/"), - }); - } - +const pushMessage = (list: Messages, message: string, parts: string[], index: number): void => { if (index < parts.length) { if (!list[parts[index]]) { list[parts[index]] = {}; } - return pushMessage(list[parts[index]], message, parts, index + 1); + return pushMessage(list[parts[index]] as Messages, message, parts, index + 1); } if (!list.$messages) { list.$messages = []; } - return list.$messages.push(message); + list.$messages.push(message); + return; +}; + +const pushMessageRoot = (list: MessagesRoot, message: string, parts: string[]): void => { + list.$allMessages.push({ + message, + prefix: parts.join("/"), + }); + + pushMessage((list as any) as Messages, message, parts, 0); }; -const addFlag = (flags) => (flagName) => { +const addFlag = (flags: IFlags) => (flagName: string) => { flags[flagName] = true; }; -const containsFlag = (flags) => (flagName) => flags[flagName]; +const containsFlag = (flags: IFlags) => (flagName: string) => flags[flagName]; -export const processTask = (settings: Settings, task, context: ProcessTaskContext, callback) => { +export const processTask = (settings: Settings, task: TaskInfo, context: ProcessTaskContext, callback: (err: any, result: ReportResult) => void) => { const errors: MessagesRoot = { $allMessages: [] }; const warns: MessagesRoot = { $allMessages: [] }; const infos: MessagesRoot = { $allMessages: [] }; const messages: MessagesRoot = { $allMessages: [] }; - const messageProcessor = (list) => (message, prefix) => { + const messageProcessor = (list: MessagesRoot) => (message: string, prefix: string) => { const parts = prefix.split("/"); - pushMessage(list, message, parts, 0); - pushMessage(messages, message, parts, 0); + pushMessageRoot(list, message, parts); + pushMessageRoot(messages, message, parts); }; - const flags = {}; + const flags: IFlags = {}; const processor = createTaskProcessor(task, { context: { ...context, diff --git a/BuildServer/lib/tasks/cleanupafterdotnetbuild.ts b/BuildServer/lib/tasks/cleanupafterdotnetbuild.ts index 6d93699..e2d3713 100644 --- a/BuildServer/lib/tasks/cleanupafterdotnetbuild.ts +++ b/BuildServer/lib/tasks/cleanupafterdotnetbuild.ts @@ -2,7 +2,8 @@ import * as glob from "glob"; -import { Task } from "../types"; +import { GenericTask } from "../types"; +import parallel from "./parallel"; export default ((_params, processor) => () => glob("**/obj/{Debug,Release}/*.{dll,pdb,xml}", { cwd: processor.context.exported, @@ -18,14 +19,11 @@ export default ((_params, processor) => () => glob("**/obj/{Debug,Release}/*.{dl return processor.done(); } - return processor.processTask({ - params: { - tasks: files.map((file) => ({ - name: file, - params: { filename: file }, - type: "deletefromcode", - })), - }, - type: "parallel", - }, processor.done); -})) as Task; + return parallel({ + tasks: files.map((file) => ({ + name: file, + params: { filename: file }, + type: "deletefromcode", + })), + }, processor)(); +})) as GenericTask<{}>; diff --git a/BuildServer/lib/tasks/conditional.ts b/BuildServer/lib/tasks/conditional.ts index 814b986..568a3a0 100644 --- a/BuildServer/lib/tasks/conditional.ts +++ b/BuildServer/lib/tasks/conditional.ts @@ -1,11 +1,18 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask, TaskInfo } from "../types"; + +interface IParameters { + readonly owner?: string; + readonly branch?: string; + readonly task: TaskInfo; + readonly otherwise?: TaskInfo; +} export default ((params, processor) => { const condition = (!params.owner || params.owner === processor.context.owner) && (!params.branch || params.branch === processor.context.branch || `refs/heads/${params.branch}` === processor.context.branch); const task = (condition && params.task) || params.otherwise; - return () => processor.processTask(task || { type: "noop" }, processor.done); -}) as Task; + return () => processor.processTask(task || { type: "noop", params: {} }, processor.done); +}) as GenericTask; diff --git a/BuildServer/lib/tasks/copy.ts b/BuildServer/lib/tasks/copy.ts index c39e051..b77690c 100644 --- a/BuildServer/lib/tasks/copy.ts +++ b/BuildServer/lib/tasks/copy.ts @@ -3,7 +3,7 @@ import { copy } from "fs-extra"; import { join } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; export default ((params, processor) => () => { const sourceFilePath = join(processor.context.exported, params.filename); @@ -20,4 +20,4 @@ export default ((params, processor) => () => { return processor.done(); }); -}) as Task; +}) as GenericTask<{ readonly filename: string }>; diff --git a/BuildServer/lib/tasks/copyglob.ts b/BuildServer/lib/tasks/copyglob.ts index 30eb4c9..7efe654 100644 --- a/BuildServer/lib/tasks/copyglob.ts +++ b/BuildServer/lib/tasks/copyglob.ts @@ -2,7 +2,8 @@ import * as glob from "glob"; -import { Task } from "../types"; +import { GenericTask } from "../types"; +import parallel from "./parallel"; export default ((params, processor) => () => glob(params.mask, { cwd: processor.context.exported, @@ -18,14 +19,11 @@ export default ((params, processor) => () => glob(params.mask, { return processor.done(); } - return processor.processTask({ - params: { - tasks: files.map((file) => ({ - name: file, - params: { filename: file }, - type: "copy", - })), - }, - type: "parallel", - }, processor.done); -})) as Task; + return parallel({ + tasks: files.map((file) => ({ + name: file, + params: { filename: file }, + type: "copy", + })), + }, processor)(); +})) as GenericTask<{ readonly mask: string }>; diff --git a/BuildServer/lib/tasks/cssnano.ts b/BuildServer/lib/tasks/cssnano.ts index fb31287..dccd06f 100644 --- a/BuildServer/lib/tasks/cssnano.ts +++ b/BuildServer/lib/tasks/cssnano.ts @@ -4,12 +4,12 @@ import { process as cssnanoProcess } from "cssnano"; import { readFile, writeFile } from "fs"; import { join } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; export default ((params, processor) => () => { const filePath = join(processor.context.exported, params.filename); - readFile(filePath, (readErr, css) => { + readFile(filePath, "utf8", (readErr, css) => { if (readErr) { processor.onError(`Unable to read stylesheet ${params.filename}: ${readErr}`); @@ -17,20 +17,20 @@ export default ((params, processor) => () => { } return cssnanoProcess(css) - .catch((cssErr) => { - processor.onError(`Unable to uglify stylesheet: ${cssErr}`); - processor.done(); - }) .then((result) => { - writeFile(filePath, result.css, (writeErr) => { + writeFile(filePath, result.content, (writeErr) => { if (writeErr) { processor.onError(`Unable to write uglified stylesheet for ${params.filename}: ${writeErr}`); } else { - processor.onInfo(`Saved uglified stylesheet for ${params.filename}; uglified length: ${result.css.length}`); + processor.onInfo(`Saved uglified stylesheet for ${params.filename}; uglified length: ${result.content.length}`); } processor.done(); }); + }) + .catch((cssErr: string) => { + processor.onError(`Unable to uglify stylesheet: ${cssErr}`); + processor.done(); }); }); -}) as Task; +}) as GenericTask<{ readonly filename: string }>; diff --git a/BuildServer/lib/tasks/cssnanoall.ts b/BuildServer/lib/tasks/cssnanoall.ts index 6585aaf..d4ba5f3 100644 --- a/BuildServer/lib/tasks/cssnanoall.ts +++ b/BuildServer/lib/tasks/cssnanoall.ts @@ -2,11 +2,12 @@ import * as glob from "glob"; -import { Task } from "../types"; +import { GenericTask } from "../types"; +import parallel from "./parallel"; const flagDoneName = "cssnanoallDone"; -export default ((params, processor) => () => { +export default ((_params, processor) => () => { if (processor.context.containsFlag(flagDoneName)) { processor.onWarn("cssnanoall task is executed more than once; this is probably a bug in your mbs.json"); } @@ -23,15 +24,12 @@ export default ((params, processor) => () => { return processor.done(); } - return processor.processTask({ - params: { - tasks: files.map((file) => ({ - name: file, - params: { filename: file }, - type: "cssnano", - })), - }, - type: (params.preventParallelTests && "sequential") || "parallel", - }, processor.done); + return parallel({ + tasks: files.map((file) => ({ + name: file, + params: { filename: file }, + type: "cssnano", + })), + }, processor)(); }); -}) as Task; +}) as GenericTask<{}>; diff --git a/BuildServer/lib/tasks/deletefromcode.ts b/BuildServer/lib/tasks/deletefromcode.ts index 504f1c4..b0b5e83 100644 --- a/BuildServer/lib/tasks/deletefromcode.ts +++ b/BuildServer/lib/tasks/deletefromcode.ts @@ -3,7 +3,7 @@ import { remove } from "fs-extra"; import { join } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; export default ((params, processor) => () => { const sourceFilePath = join(processor.context.exported, params.filename); @@ -19,4 +19,4 @@ export default ((params, processor) => () => { return processor.done(); }); -}) as Task; +}) as GenericTask<{ readonly filename: string }>; diff --git a/BuildServer/lib/tasks/dotnetbuild.ts b/BuildServer/lib/tasks/dotnetbuild.ts index 9f450a6..76e8790 100644 --- a/BuildServer/lib/tasks/dotnetbuild.ts +++ b/BuildServer/lib/tasks/dotnetbuild.ts @@ -1,6 +1,6 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import sequential from "./sequential"; export default ((params, processor) => sequential({ @@ -12,7 +12,8 @@ export default ((params, processor) => sequential({ }, { name: "cleanup", + params: {}, type: "cleanupafterdotnetbuild", }, ], -}, processor)) as Task; +}, processor)) as GenericTask<{}>; diff --git a/BuildServer/lib/tasks/dotnetbuildandtest.ts b/BuildServer/lib/tasks/dotnetbuildandtest.ts index e0151c3..a8043ee 100644 --- a/BuildServer/lib/tasks/dotnetbuildandtest.ts +++ b/BuildServer/lib/tasks/dotnetbuildandtest.ts @@ -1,6 +1,6 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import sequential from "./sequential"; export default ((params, processor) => sequential({ @@ -17,7 +17,8 @@ export default ((params, processor) => sequential({ }, { name: "cleanup", + params: {}, type: "cleanupafterdotnetbuild", }, ], -}, processor)) as Task; +}, processor)) as GenericTask<{}>; diff --git a/BuildServer/lib/tasks/dotnetbuilderwrapper.ts b/BuildServer/lib/tasks/dotnetbuilderwrapper.ts index 6d11b12..eef2134 100644 --- a/BuildServer/lib/tasks/dotnetbuilderwrapper.ts +++ b/BuildServer/lib/tasks/dotnetbuilderwrapper.ts @@ -4,7 +4,16 @@ import { ChildProcess, spawn } from "child_process"; import * as JSONParse from "json-parse-safe"; import { WritableStreamBuffer } from "stream-buffers"; -import { Task } from "../types"; +import { BuilderRequest, GenericTask } from "../types"; + +interface IDotNetBuilderResponseMessage { + readonly Type: string; + readonly Body: string; +} + +interface IDotNetBuilderResponse { + readonly Messages: IDotNetBuilderResponseMessage[]; +} const wrapBuilder = (builder: ChildProcess, input: string, onExit: (code: number, result: string, builderError: string) => void) => { const stdoutPromise = new Promise((resolve, reject) => { @@ -56,7 +65,7 @@ export default ((params, processor) => () => { return processor.done(); } - const { value, error } = JSONParse(result); + const { value, error }: { value: IDotNetBuilderResponse, error: any } = JSONParse(result); if (error || !value || !value.Messages) { processor.onError(`Malformed JSON: ${error}`); @@ -86,4 +95,4 @@ export default ((params, processor) => () => { return processor.done(); }); -}) as Task; +}) as GenericTask; diff --git a/BuildServer/lib/tasks/dotnetbuildwithoutcleanup.ts b/BuildServer/lib/tasks/dotnetbuildwithoutcleanup.ts index b1ad800..ccc8df7 100644 --- a/BuildServer/lib/tasks/dotnetbuildwithoutcleanup.ts +++ b/BuildServer/lib/tasks/dotnetbuildwithoutcleanup.ts @@ -1,9 +1,19 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import sequential from "./sequential"; -const createTasks = function *(params) { +interface IParameters { + readonly skipMbsCheckStyle?: boolean; + readonly forceCodeAnalysis?: boolean; + readonly ignoreCodeAnalysis?: boolean; + readonly skipCodeSigning?: boolean; + readonly skipNugetRestore?: boolean; + readonly configuration: string; + readonly solution: string; +} + +const createTasks = function *(params: IParameters) { if (!params.skipMbsCheckStyle) { yield { params, @@ -40,4 +50,4 @@ export default ((params, processor) => { const tasks = Array.from(createTasks(params)); return sequential({ tasks }, processor); -}) as Task; +}) as GenericTask; diff --git a/BuildServer/lib/tasks/dotnetcheckstyle.ts b/BuildServer/lib/tasks/dotnetcheckstyle.ts index 27494ed..46c17d6 100644 --- a/BuildServer/lib/tasks/dotnetcheckstyle.ts +++ b/BuildServer/lib/tasks/dotnetcheckstyle.ts @@ -5,7 +5,11 @@ import { readFile } from "fs"; import * as glob from "glob"; import { join } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; + +interface IParameters { + ignoreCodeStyle: boolean; +} const autoGeneratedMarker = "//------------------------------------------------------------------------------\n" @@ -35,7 +39,7 @@ export default ((params, processor) => () => { return processor.done(); } - const processFile = (data, file) => { + const processFile = (data: string, file: string) => { if (data.includes("\r\n")) { return processor.onError(`Windows-style EOL (0D0A) found in file ${file}`); } @@ -57,7 +61,7 @@ export default ((params, processor) => () => { return processor.onInfo(`Checked file ${file}`); }; - return parallel(files.map((file) => (callback) => readFile( + return parallel(files.map((file) => (callback: (err?: any) => void) => readFile( join(processor.context.exported, file), { encoding: "utf8" }, (readErr, data) => { @@ -73,4 +77,4 @@ export default ((params, processor) => () => { }, )), processor.done); }); -}) as Task; +}) as GenericTask; diff --git a/BuildServer/lib/tasks/dotnetcompile.ts b/BuildServer/lib/tasks/dotnetcompile.ts index 3461226..c07d9d0 100644 --- a/BuildServer/lib/tasks/dotnetcompile.ts +++ b/BuildServer/lib/tasks/dotnetcompile.ts @@ -2,9 +2,20 @@ import { join } from "path"; -import { Task } from "../types"; +import { BuilderCompileRequest, GenericTask } from "../types"; import dotnetbuilderwrapper from "./dotnetbuilderwrapper"; +interface IParameters { + configuration: string; + overrideOutputDirectory: string; + skipCodeAnalysis: boolean; + solution: string; + target: string; + forceCodeAnalysis?: boolean; + skipCodeSigning?: boolean; + ignoreCodeAnalysis: boolean; +} + export default ((params, processor) => { if (processor.settings.isCodeAnalysisUnsupported && params.forceCodeAnalysis) { processor.onError("Code analysis is not supported"); @@ -24,17 +35,15 @@ export default ((params, processor) => { || params.ignoreCodeAnalysis || (processor.settings.ignoreCodeAnalysisByDefault && !params.forceCodeAnalysis); - const compileParams = { + const compileParams: BuilderCompileRequest = { Configuration: params.configuration, OutputDirectory: params.overrideOutputDirectory, SkipCodeAnalysis: skipCodeAnalysis, SolutionPath: join(processor.context.exported, params.solution), Target: params.target, command: "compile", + ...getAdditionalSigningParameters(), }; - return dotnetbuilderwrapper({ - ...compileParams, - ...getAdditionalSigningParameters(), - }, processor); -}) as Task; + return dotnetbuilderwrapper(compileParams, processor); +}) as GenericTask; diff --git a/BuildServer/lib/tasks/dotnetnugetpack.ts b/BuildServer/lib/tasks/dotnetnugetpack.ts index 6ec0071..ab2844a 100644 --- a/BuildServer/lib/tasks/dotnetnugetpack.ts +++ b/BuildServer/lib/tasks/dotnetnugetpack.ts @@ -1,12 +1,17 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import dotnetnugetprocessinternal from "./dotnetnugetprocessinternal"; +interface IParameters { + readonly name: string; + readonly nuspec: string; +} + export default ((params, processor) => dotnetnugetprocessinternal({ ...params, getFinalTask: (nupkg) => ({ params: { filename: nupkg }, type: "copy", }), -}, processor)) as Task; +}, processor)) as GenericTask; diff --git a/BuildServer/lib/tasks/dotnetnugetprocess.ts b/BuildServer/lib/tasks/dotnetnugetprocess.ts index d33d9e2..afde11c 100644 --- a/BuildServer/lib/tasks/dotnetnugetprocess.ts +++ b/BuildServer/lib/tasks/dotnetnugetprocess.ts @@ -1,8 +1,16 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import conditional from "./conditional"; +interface IParameters { + readonly major: string; + readonly nuspecName: string; + readonly version: string; + readonly withoutCommitSha: boolean; + readonly masterRepoOwner: string; +} + export default ((params, processor) => conditional({ branch: "master", otherwise: { @@ -28,4 +36,4 @@ export default ((params, processor) => conditional({ }, type: "dotnetnugetpush", }, -}, processor)) as Task; +}, processor)) as GenericTask; diff --git a/BuildServer/lib/tasks/dotnetnugetprocessinternal.ts b/BuildServer/lib/tasks/dotnetnugetprocessinternal.ts index ec81bf6..aaa998d 100644 --- a/BuildServer/lib/tasks/dotnetnugetprocessinternal.ts +++ b/BuildServer/lib/tasks/dotnetnugetprocessinternal.ts @@ -2,14 +2,23 @@ import { join } from "path"; -import { Task, TaskProcessor } from "../types"; +import { GenericTask, TaskInfo, TaskProcessor } from "../types"; import sequential from "./sequential"; +interface IParameters { + readonly withoutCommitSha?: boolean; + readonly major?: string; + readonly version?: string; + readonly name: string; + readonly nuspec: string; + readonly getFinalTask: (nupkg: string) => TaskInfo; +} + const postfixLength = 16; const fourDigits = 10000; const twoDigits = 100; -const addPostfix = (version, params, processor: TaskProcessor) => { +const addPostfix = (version: string, params: IParameters, processor: TaskProcessor) => { if (params.withoutCommitSha) { return version; } @@ -40,4 +49,4 @@ export default ((params, processor) => { params.getFinalTask(nupkg), ], }, processor); -}) as Task; +}) as GenericTask; diff --git a/BuildServer/lib/tasks/dotnetnugetpush.ts b/BuildServer/lib/tasks/dotnetnugetpush.ts index fb1d964..bd1533d 100644 --- a/BuildServer/lib/tasks/dotnetnugetpush.ts +++ b/BuildServer/lib/tasks/dotnetnugetpush.ts @@ -1,12 +1,17 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import dotnetnugetprocessinternal from "./dotnetnugetprocessinternal"; +interface IParameters { + readonly name: string; + readonly nuspec: string; +} + export default ((params, processor) => dotnetnugetprocessinternal({ ...params, getFinalTask: (nupkg) => ({ params: { Package: nupkg }, type: "dotnetnugetpushonly", }), -}, processor)) as Task; +}, processor)) as GenericTask; diff --git a/BuildServer/lib/tasks/dotnetnugetpushonly.ts b/BuildServer/lib/tasks/dotnetnugetpushonly.ts index ff214fa..d8cab8b 100644 --- a/BuildServer/lib/tasks/dotnetnugetpushonly.ts +++ b/BuildServer/lib/tasks/dotnetnugetpushonly.ts @@ -2,7 +2,7 @@ import { join } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import dotnetbuilderwrapper from "./dotnetbuilderwrapper"; export default ((params, processor) => dotnetbuilderwrapper({ @@ -10,4 +10,4 @@ export default ((params, processor) => dotnetbuilderwrapper({ NugetHost: processor.settings.nugetHost, Package: join(processor.context.exported, params.Package), command: "nugetpush", -}, processor)) as Task; +}, processor)) as GenericTask<{ readonly Package: string }>; diff --git a/BuildServer/lib/tasks/dotnetnugetrestore.ts b/BuildServer/lib/tasks/dotnetnugetrestore.ts index 1a2f69f..c3d4501 100644 --- a/BuildServer/lib/tasks/dotnetnugetrestore.ts +++ b/BuildServer/lib/tasks/dotnetnugetrestore.ts @@ -2,18 +2,11 @@ import { join } from "path"; -import { Task } from "../types"; -import sequential from "./sequential"; +import { GenericTask } from "../types"; +import dotnetbuilderwrapper from "./dotnetbuilderwrapper"; -export default ((params, processor) => sequential({ - tasks: [ - { - params: { - BaseDirectory: processor.context.exported, - SolutionPath: join(processor.context.exported, params.solution), - command: "nugetrestore", - }, - type: "dotnetbuilderwrapper", - }, - ], -}, processor)) as Task; +export default ((params, processor) => dotnetbuilderwrapper({ + BaseDirectory: processor.context.exported, + SolutionPath: join(processor.context.exported, params.solution), + command: "nugetrestore", +}, processor)) as GenericTask<{ readonly solution: string }>; diff --git a/BuildServer/lib/tasks/dotnetnunit.ts b/BuildServer/lib/tasks/dotnetnunit.ts index e274c37..8eebb33 100644 --- a/BuildServer/lib/tasks/dotnetnunit.ts +++ b/BuildServer/lib/tasks/dotnetnunit.ts @@ -2,10 +2,10 @@ import { join } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import dotNetBuilderWrapper from "./dotnetbuilderwrapper"; export default ((params, processor) => dotNetBuilderWrapper({ TestLibraryPath: join(processor.context.exported, params.assembly), command: "nunit", -}, processor)) as Task; +}, processor)) as GenericTask<{ readonly assembly: string }>; diff --git a/BuildServer/lib/tasks/dotnetnunitall.ts b/BuildServer/lib/tasks/dotnetnunitall.ts index eb0f9f4..3f611a3 100644 --- a/BuildServer/lib/tasks/dotnetnunitall.ts +++ b/BuildServer/lib/tasks/dotnetnunitall.ts @@ -2,7 +2,9 @@ import * as glob from "glob"; -import { Task } from "../types"; +import { GenericTask } from "../types"; +import parallel from "./parallel"; +import sequential from "./sequential"; const flagDoneName = "dotnetnunitallDone"; @@ -13,6 +15,8 @@ export default ((params, processor) => () => { processor.context.addFlag(flagDoneName); + const task = params.preventParallelTests ? sequential : parallel; + glob("**/{bin,build}/**/*.{Tests,Test,UnitTests}.dll", { cwd: processor.context.exported, dot: true, @@ -29,15 +33,12 @@ export default ((params, processor) => () => { return processor.done(); } - return processor.processTask({ - params: { - tasks: files.map((file) => ({ - name: file, - params: { assembly: file }, - type: "dotnetnunit", - })), - }, - type: (params.preventParallelTests && "sequential") || "parallel", - }, processor.done); + return task({ + tasks: files.map((file) => ({ + name: file, + params: { assembly: file }, + type: "dotnetnunit", + })), + }, processor)(); }); -}) as Task; +}) as GenericTask<{ readonly preventParallelTests?: boolean }>; diff --git a/BuildServer/lib/tasks/dotnetpackwebapp.ts b/BuildServer/lib/tasks/dotnetpackwebapp.ts index 4978dc1..a6f4672 100644 --- a/BuildServer/lib/tasks/dotnetpackwebapp.ts +++ b/BuildServer/lib/tasks/dotnetpackwebapp.ts @@ -4,9 +4,15 @@ import { readFileSync } from "fs"; import { render } from "mustache"; import { join } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import sequential from "./sequential"; +interface IParameters { + readonly configuration: string; + readonly isCodeAnalysisUnsupported: boolean; + readonly skipCodeSigning: boolean; +} + const msbuildTemplate = readFileSync(join(__dirname, "/dotnetpackwebapp.template.msbuild"), { encoding: "utf8" }); const deployTemplate = readFileSync(join(__dirname, "/dotnetpackwebapp.template.bat"), { encoding: "utf8" }); const versionTemplate = readFileSync(join(__dirname, "/dotnetpackwebapp.template.version.aspx"), { encoding: "utf8" }); @@ -46,4 +52,4 @@ export default ((params, processor) => sequential({ type: "dotnetcompile", }, ], -}, processor)) as Task; +}, processor)) as GenericTask; diff --git a/BuildServer/lib/tasks/dotnetrewrite.ts b/BuildServer/lib/tasks/dotnetrewrite.ts index 3775ac3..97d3d57 100644 --- a/BuildServer/lib/tasks/dotnetrewrite.ts +++ b/BuildServer/lib/tasks/dotnetrewrite.ts @@ -5,24 +5,29 @@ import { readFile, writeFile } from "fs"; import * as glob from "glob"; import { join } from "path"; -import { Task, TaskProcessor } from "../types"; +import { GenericTask, TaskProcessor } from "../types"; + +interface IParameters { + readonly skipCodeSigning: boolean; +} + +type Callback = (err?: any, result?: string) => void; const flagDoneName = "dotnetrewriterDone"; -const processAssemblyInfo = (params, processor: TaskProcessor, appendInformationalVersion: boolean) => (originalContent, cb) => { - const processInternalsVisible = (content) => { +const processAssemblyInfo = (params: IParameters, processor: TaskProcessor, appendInformationalVersion: boolean) => (originalContent: string, cb: Callback) => { + const processInternalsVisible = (content: string) => { if (processor.settings.skipCodeSigning || params.skipCodeSigning) { return content; } const publicKey = processor.settings.codeSigningPublicKey; const pattern = /InternalsVisibleTo\s*\(\s*"([\w.]+)"\s*\)/g; - const replacer = (_match, p1) => `InternalsVisibleTo("${p1},PublicKey=${publicKey}")`; - return content.replace(pattern, replacer); + return content.replace(pattern, (_match, p1) => `InternalsVisibleTo("${p1},PublicKey=${publicKey}")`); }; - const processInformationalVersion = (content) => { + const processInformationalVersion = (content: string) => { if (!appendInformationalVersion) { return content; } @@ -55,7 +60,7 @@ export default ((params, processor) => () => { return processor.done(); } - return parallel(files.map((file) => (callback) => waterfall([ + return parallel(files.map((file) => (callback: Callback) => waterfall([ readFile.bind(null, join(processor.context.exported, file), { encoding: "utf8" }), processAssemblyInfo(params, processor, file.toLowerCase().includes("assemblyinfo.cs")), writeFile.bind(null, join(processor.context.exported, file)), @@ -68,4 +73,4 @@ export default ((params, processor) => () => { callback(err); })), processor.done); }); -}) as Task; +}) as GenericTask; diff --git a/BuildServer/lib/tasks/echo.ts b/BuildServer/lib/tasks/echo.ts index fa12a7c..d30a170 100644 --- a/BuildServer/lib/tasks/echo.ts +++ b/BuildServer/lib/tasks/echo.ts @@ -1,6 +1,12 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask } from "../types"; + +interface IParameters { + readonly error: string; + readonly warn: string; + readonly info: string; +} export default ((params, processor) => () => { if (params.error) { @@ -16,4 +22,4 @@ export default ((params, processor) => () => { } processor.done(); -}) as Task; +}) as GenericTask; diff --git a/BuildServer/lib/tasks/eslintbrowser.ts b/BuildServer/lib/tasks/eslintbrowser.ts index 211ee0a..1adf3ee 100644 --- a/BuildServer/lib/tasks/eslintbrowser.ts +++ b/BuildServer/lib/tasks/eslintbrowser.ts @@ -3,7 +3,7 @@ import { CLIEngine } from "eslint"; import { join } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; const errorSeverity = 2; @@ -32,4 +32,4 @@ export default ((params, processor) => () => { }); processor.done(); -}) as Task; +}) as GenericTask<{ readonly filename: string }>; diff --git a/BuildServer/lib/tasks/eslintbrowserall.ts b/BuildServer/lib/tasks/eslintbrowserall.ts index d4a1170..e3e3751 100644 --- a/BuildServer/lib/tasks/eslintbrowserall.ts +++ b/BuildServer/lib/tasks/eslintbrowserall.ts @@ -2,7 +2,8 @@ import * as glob from "glob"; -import { Task } from "../types"; +import { GenericTask } from "../types"; +import parallel from "./parallel"; const flagDoneName = "eslintbrowserallDone"; @@ -25,15 +26,12 @@ export default ((params, processor) => () => { return processor.done(); } - return processor.processTask({ - params: { - tasks: files.filter((file) => !excludeFiles.includes(file)).map((file) => ({ - name: file, - params: { filename: file }, - type: "eslintbrowser", - })), - }, - type: (params.preventParallelTests && "sequential") || "parallel", - }, processor.done); + return parallel({ + tasks: files.filter((file) => !excludeFiles.includes(file)).map((file) => ({ + name: file, + params: { filename: file }, + type: "eslintbrowser", + })), + }, processor)(); }); -}) as Task; +}) as GenericTask<{ readonly excludeFiles?: string[] }>; diff --git a/BuildServer/lib/tasks/noop.ts b/BuildServer/lib/tasks/noop.ts index 899dd24..64b24ee 100644 --- a/BuildServer/lib/tasks/noop.ts +++ b/BuildServer/lib/tasks/noop.ts @@ -1,5 +1,5 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask } from "../types"; -export default ((_params, processor) => processor.done()) as Task; +export default ((_params, processor) => processor.done) as GenericTask<{}>; diff --git a/BuildServer/lib/tasks/packform.ts b/BuildServer/lib/tasks/packform.ts index dd67e38..78186a6 100644 --- a/BuildServer/lib/tasks/packform.ts +++ b/BuildServer/lib/tasks/packform.ts @@ -1,16 +1,26 @@ "use strict"; -import { Task } from "../types"; +import { GenericTask } from "../types"; import sequential from "./sequential"; +interface IParameters { + readonly eslintExcludeFiles: boolean; +} + export default ((params, processor) => sequential({ tasks: [ { params: { excludeFiles: params.eslintExcludeFiles }, type: "eslintbrowserall", }, - { type: "uglifyjsall" }, - { type: "cssnanoall" }, + { + params: { }, + type: "uglifyjsall", + }, + { + params: { }, + type: "cssnanoall", + }, { params: { data: processor.context.versionInfo, @@ -26,4 +36,4 @@ export default ((params, processor) => sequential({ type: "zip", }, ], -}, processor)) as Task; +}, processor)) as GenericTask; diff --git a/BuildServer/lib/tasks/parallel.ts b/BuildServer/lib/tasks/parallel.ts index 6923e5a..f80ba16 100644 --- a/BuildServer/lib/tasks/parallel.ts +++ b/BuildServer/lib/tasks/parallel.ts @@ -2,8 +2,12 @@ import { parallel } from "async"; -import { Task, TaskProcessor } from "../types"; +import { GenericTask, TaskInfo, TaskProcessor, TaskProcessorCallback } from "../types"; -const mapper = (processor: TaskProcessor) => (task) => (callback) => processor.processTask(task, callback); +interface IParameters { + tasks: TaskInfo[]; +}; -export default ((params, processor) => () => parallel(params.tasks.map(mapper(processor)), processor.done)) as Task; +const mapper = (processor: TaskProcessor) => (task: TaskInfo) => (callback: TaskProcessorCallback) => processor.processTask(task, callback); + +export default ((params, processor) => () => parallel(params.tasks.map(mapper(processor)), processor.done)) as GenericTask; diff --git a/BuildServer/lib/tasks/sequential.ts b/BuildServer/lib/tasks/sequential.ts index 7509d8a..03ca165 100644 --- a/BuildServer/lib/tasks/sequential.ts +++ b/BuildServer/lib/tasks/sequential.ts @@ -2,8 +2,12 @@ import { series } from "async"; -import { Task, TaskProcessor } from "../types"; +import { GenericTask, TaskInfo, TaskProcessor, TaskProcessorCallback } from "../types"; -const mapper = (processor: TaskProcessor) => (task) => (callback) => processor.processTask(task, callback); +interface IParameters { + tasks: TaskInfo[]; +}; -export default ((params, processor) => () => series(params.tasks.map(mapper(processor)), processor.done)) as Task; +const mapper = (processor: TaskProcessor) => (task: TaskInfo) => (callback: TaskProcessorCallback) => processor.processTask(task, callback); + +export default ((params, processor) => () => series(params.tasks.map(mapper(processor)), processor.done)) as GenericTask; diff --git a/BuildServer/lib/tasks/uglifyjs.ts b/BuildServer/lib/tasks/uglifyjs.ts index 9449fd5..54891df 100644 --- a/BuildServer/lib/tasks/uglifyjs.ts +++ b/BuildServer/lib/tasks/uglifyjs.ts @@ -4,7 +4,7 @@ import { writeFile } from "fs"; import { join, normalize } from "path"; import { minify } from "uglify-js"; -import { Task } from "../types"; +import { GenericTask } from "../types"; export default ((params, processor) => () => { const filePath = normalize(join(processor.context.exported, params.filename)); @@ -19,4 +19,4 @@ export default ((params, processor) => () => { processor.done(); }); -}) as Task; +}) as GenericTask<{ readonly filename: string }>; diff --git a/BuildServer/lib/tasks/uglifyjsall.ts b/BuildServer/lib/tasks/uglifyjsall.ts index 4139707..c7fb27b 100644 --- a/BuildServer/lib/tasks/uglifyjsall.ts +++ b/BuildServer/lib/tasks/uglifyjsall.ts @@ -2,11 +2,12 @@ import * as glob from "glob"; -import { Task } from "../types"; +import { GenericTask } from "../types"; +import parallel from "./parallel"; const doneFlagName = "uglifyjsallDone"; -export default ((params, processor) => () => { +export default ((_params, processor) => () => { if (processor.context.containsFlag(doneFlagName)) { processor.onWarn("dotnetnunitall task is executed more than once; this is probably a bug in your mbs.json"); } @@ -23,15 +24,12 @@ export default ((params, processor) => () => { return processor.done(); } - return processor.processTask({ - params: { - tasks: files.map((file) => ({ - name: file, - params: { filename: file }, - type: "uglifyjs", - })), - }, - type: (params.preventParallelTests && "sequential") || "parallel", - }, processor.done); + return parallel({ + tasks: files.map((file) => ({ + name: file, + params: { filename: file }, + type: "uglifyjs", + })), + }, processor)(); }); -}) as Task; +}) as GenericTask<{}>; diff --git a/BuildServer/lib/tasks/writefile.ts b/BuildServer/lib/tasks/writefile.ts index a230b98..4cd2782 100644 --- a/BuildServer/lib/tasks/writefile.ts +++ b/BuildServer/lib/tasks/writefile.ts @@ -3,7 +3,12 @@ import { writeFile } from "fs"; import { join } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; + +interface IParameters { + readonly data: string; + readonly filename: string; +} export default ((params, processor) => () => { const filePath = join(processor.context.exported, params.filename); @@ -19,4 +24,4 @@ export default ((params, processor) => () => { return processor.done(); }); -}) as Task; +}) as GenericTask; diff --git a/BuildServer/lib/tasks/zip.ts b/BuildServer/lib/tasks/zip.ts index 9f16516..334acf5 100644 --- a/BuildServer/lib/tasks/zip.ts +++ b/BuildServer/lib/tasks/zip.ts @@ -4,7 +4,12 @@ import { create as createArchiver } from "archiver"; import { createWriteStream } from "fs"; import { join, normalize } from "path"; -import { Task } from "../types"; +import { GenericTask } from "../types"; + +interface IParameters { + readonly directory?: string; + readonly archive: string; +} export default ((params, processor) => () => { const sourceDirectoryPath = normalize(join(processor.context.exported, String(params.directory || ""))); @@ -17,8 +22,8 @@ export default ((params, processor) => () => { output.on("close", processor.done); - archive.on("error", (err) => processor.onError(`Error while compressing: ${err}`)); + archive.on("error", (err: any) => processor.onError(`Error while compressing: ${err}`)); archive.pipe(output); archive.directory(sourceDirectoryPath, false); archive.finalize(); -}) as Task; +}) as GenericTask; diff --git a/BuildServer/lib/types/augmentations/cssnano.ts b/BuildServer/lib/types/augmentations/cssnano.ts new file mode 100644 index 0000000..f0c0659 --- /dev/null +++ b/BuildServer/lib/types/augmentations/cssnano.ts @@ -0,0 +1,10 @@ +/* tslint:disable:max-classes-per-file variable-name */ +declare module "cssnano" { + // cssnano invokes postcss; all types are from postcss API reference + + interface IResult { + content: string; + } + + export function process(content: string): Promise; +} diff --git a/BuildServer/lib/types/augmentations/eslint.ts b/BuildServer/lib/types/augmentations/eslint.ts new file mode 100644 index 0000000..ee0fd37 --- /dev/null +++ b/BuildServer/lib/types/augmentations/eslint.ts @@ -0,0 +1,21 @@ +/* tslint:disable:max-classes-per-file variable-name */ +declare module "eslint" { + interface IMessage { + readonly column: any; + readonly fatal: boolean; + readonly line: any; + readonly lineId: any; + readonly message: any; + readonly ruleId: any; + readonly severity: number; + } + + interface IResult { + readonly messages: IMessage[]; + } + + export class CLIEngine { + public constructor(params: { configFile: string }); + public executeOnFiles(files: string[]): { results: IResult[] }; + } +} diff --git a/BuildServer/lib/types/augmentations/graceful-fs.ts b/BuildServer/lib/types/augmentations/graceful-fs.ts new file mode 100644 index 0000000..d82ba9c --- /dev/null +++ b/BuildServer/lib/types/augmentations/graceful-fs.ts @@ -0,0 +1,6 @@ +/* tslint:disable:max-classes-per-file variable-name */ +declare module "graceful-fs" { + import * as fsContent from "fs"; + + export function gracefulify(fs: typeof fsContent): void; +} diff --git a/BuildServer/lib/types/augmentations/json-parse-safe.ts b/BuildServer/lib/types/augmentations/json-parse-safe.ts new file mode 100644 index 0000000..c9780b6 --- /dev/null +++ b/BuildServer/lib/types/augmentations/json-parse-safe.ts @@ -0,0 +1,5 @@ +/* tslint:disable:max-classes-per-file variable-name */ +declare module "json-parse-safe" { + const JSONParse: (json: string) => { error: Error | string | null, value: any }; + export = JSONParse; +} diff --git a/BuildServer/lib/types/augmentations/nodegit.ts b/BuildServer/lib/types/augmentations/nodegit.ts new file mode 100644 index 0000000..aa1ef15 --- /dev/null +++ b/BuildServer/lib/types/augmentations/nodegit.ts @@ -0,0 +1,34 @@ +/* tslint:disable:max-classes-per-file variable-name */ +declare module "nodegit" { + export class Blob { + public content(): Buffer; + } + + export class Commit { + // getTree(callback: (err: any, treeContent?: Tree) => void): Promise; + public getTree(): Promise; + } + + export class Remote { + public static create(repo: Repository, name: string, url: string): Promise; + public fetch(refSpecs: string[]): Promise; + } + + export class Repository { + public static init(path: string, is_bare: number): Promise; + public getCommit(oid: string): Promise; + public free(): void; + } + + export class Tree { + public entries(): TreeEntry[]; + } + + export class TreeEntry { + public getBlob(callback: (err: any, blob?: Blob) => void): Promise; + public getTree(callback: (err: any, treeContent?: Tree) => void): Promise; + public isFile(): boolean; + public isTree(): boolean; + public name(): string; + } +} diff --git a/BuildServer/lib/types/augmentations/stream-buffers.ts b/BuildServer/lib/types/augmentations/stream-buffers.ts new file mode 100644 index 0000000..54d2b05 --- /dev/null +++ b/BuildServer/lib/types/augmentations/stream-buffers.ts @@ -0,0 +1,14 @@ +/* tslint:disable:max-classes-per-file variable-name */ +declare module "stream-buffers" { + import * as stream from "stream"; + + export class ReadableStreamBuffer extends stream.Readable { + public constructor(options: { chunkSize: number, frequency: number }); + public put(data: string): void; + public stop(): void; + } + + export class WritableStreamBuffer extends stream.Writable { + public getContentsAsString(): string; + } +} diff --git a/BuildServer/lib/types/dotnetbuilder-types.ts b/BuildServer/lib/types/dotnetbuilder-types.ts new file mode 100644 index 0000000..c6c45a5 --- /dev/null +++ b/BuildServer/lib/types/dotnetbuilder-types.ts @@ -0,0 +1,37 @@ +export interface ICompileRequest { + readonly command: "compile"; + readonly SolutionPath: string; + readonly Target: string; + readonly Configuration: string; + readonly OutputDirectory: string; + readonly SigningKey?: string; + readonly SkipCodeAnalysis: boolean; +} + +export interface INugetPackRequest { + readonly command: "nugetpack"; + readonly BaseDirectory: string; + readonly SpecPath: string; + readonly OutputDirectory: string; + readonly Version: string; +} + +export interface INugetPushRequest { + readonly command: "nugetpush"; + readonly Package: string; + readonly NugetHost: string; + readonly ApiKey: string; +} + +export interface INugetRestoreRequest { + readonly command: "nugetrestore"; + readonly BaseDirectory: string; + readonly SolutionPath: string; +} + +export interface INunitRequest { + readonly command: "nunit"; + readonly TestLibraryPath: string; +} + +export type Request = ICompileRequest | INugetPackRequest | INugetPushRequest | INugetRestoreRequest | INunitRequest; diff --git a/BuildServer/lib/types/index.ts b/BuildServer/lib/types/index.ts index fe46036..dccc68b 100644 --- a/BuildServer/lib/types/index.ts +++ b/BuildServer/lib/types/index.ts @@ -1,8 +1,12 @@ +import * as BuilderTypes from "./dotnetbuilder-types"; import * as GithubTypes from "./github-types"; import * as ReportTypes from "./report-types"; import * as SettingsTypes from "./settings-types"; import * as TaskProcessorTypes from "./task-processor-types"; +export type BuilderCompileRequest = BuilderTypes.ICompileRequest; +export type BuilderRequest = BuilderTypes.Request; + export type HookPushPayload = GithubTypes.IHookPushPayload; export type HookPullRequestPayload = GithubTypes.IHookPullRequestPayload; export type HookParameters = GithubTypes.HookParameters; @@ -16,6 +20,7 @@ export type ReportResult = ReportTypes.IReportResult; export type Settings = SettingsTypes.Settings; export type ProcessTaskContext = TaskProcessorTypes.IProcessTaskContext; +export type GenericTask = TaskProcessorTypes.GenericTask; export type Task = TaskProcessorTypes.Task; export type TaskInfo = TaskProcessorTypes.ITaskInfo; export type TaskProcessor = TaskProcessorTypes.ITaskProcessor; diff --git a/BuildServer/lib/types/report-types.ts b/BuildServer/lib/types/report-types.ts index 21005a4..95e08b6 100644 --- a/BuildServer/lib/types/report-types.ts +++ b/BuildServer/lib/types/report-types.ts @@ -7,20 +7,20 @@ type IPartialMessageLeafContent = string[]; type IPartialMessageRootContent = IMessage[]; interface IPartialMessagesLeaf { - readonly $messages?: string[]; + $messages?: string[]; } // workaround for compatibility with PartialMessagesLeaf and PartialMessagesRoot interface IPartialMessagesRecursive { - readonly [propName: string]: Messages | IPartialMessageLeafContent; + [propName: string]: Messages | IPartialMessageLeafContent; } interface IPartialMessagesRecursiveRoot { - readonly [propName: string]: Messages | IPartialMessageRootContent | IPartialMessageLeafContent; + [propName: string]: Messages | IPartialMessageRootContent | IPartialMessageLeafContent; } interface IPartialMessagesRoot { - readonly $allMessages: IPartialMessageRootContent; + $allMessages: IPartialMessageRootContent; } export type Messages = IPartialMessagesRecursive & IPartialMessagesLeaf; diff --git a/BuildServer/lib/types/task-processor-types.ts b/BuildServer/lib/types/task-processor-types.ts index 223d178..373d309 100644 --- a/BuildServer/lib/types/task-processor-types.ts +++ b/BuildServer/lib/types/task-processor-types.ts @@ -31,13 +31,19 @@ export interface ITaskProcessor extends ITaskProcessorCore { readonly done: () => void; } +interface ITaskParameters { + readonly [paramName: string]: any; +} + export interface ITaskInfo { readonly name?: string; readonly type: string; - readonly params: any; + readonly params: ITaskParameters; } -export type Task = (params: any, processor: ITaskProcessor) => () => void; +export type GenericTask = (params: TParams, processor: ITaskProcessor) => () => void; + +export type Task = GenericTask; export interface ITasks { readonly [taskName: string]: Task; diff --git a/BuildServer/package.json b/BuildServer/package.json index 8dd25bc..baef79e 100644 --- a/BuildServer/package.json +++ b/BuildServer/package.json @@ -26,7 +26,7 @@ "morgan": "^1.7.0", "mustache": "~2.3.0", "nodegit": "~0.16.0", - "recursive-tree-copy": "0.0.1", + "recursive-tree-copy": "0.0.2", "serve-favicon": "^2.3.2", "serve-static": "^1.11.1", "stream-buffers": "^3.0.1", @@ -53,6 +53,6 @@ "@types/underscore": "^1.7.36", "tslint": "^4.4.2", "tslint-eslint-rules": "^3.4.0", - "typescript": "^2.2.1" + "typescript": "^2.2.2" } } diff --git a/BuildServer/tsconfig.json b/BuildServer/tsconfig.json index e445ecc..4d78198 100644 --- a/BuildServer/tsconfig.json +++ b/BuildServer/tsconfig.json @@ -4,7 +4,15 @@ "target": "es6", "alwaysStrict": true, "forceConsistentCasingInFileNames": true, + "lib": [ + "dom", + "es6", + "dom.iterable", + "scripthost", + "es7" + ], "noEmitOnError": true, + "noImplicitAny": true, "noImplicitReturns": true, "noImplicitThis": true, "noUnusedLocals": true, @@ -16,8 +24,7 @@ }, "include": [ "*.ts", - "lib/**/*.ts", - "routes/**/*.ts" + "lib/**/*.ts" ], "exclude": [ "node_modules/**/*.ts"