Enabled noImplicitAny

dependabot/npm_and_yarn/BuildServer/eslint-7.2.0
Inga 🏳‍🌈 8 years ago
parent 58c17fd975
commit 3964ce1c15
  1. 45
      BuildServer/lib/builder.ts
  2. 81
      BuildServer/lib/commenter.ts
  3. 47
      BuildServer/lib/git/copy.ts
  4. 58
      BuildServer/lib/git/loader.ts
  5. 8
      BuildServer/lib/github-wrapper.ts
  6. 12
      BuildServer/lib/mail-sender.ts
  7. 41
      BuildServer/lib/report-processor.ts
  8. 3
      BuildServer/lib/routes/manual.ts
  9. 14
      BuildServer/lib/routes/postreceive.ts
  10. 7
      BuildServer/lib/routes/release.ts
  11. 42
      BuildServer/lib/routes/status.ts
  12. 6
      BuildServer/lib/settings-wrapper.ts
  13. 56
      BuildServer/lib/status-processor.ts
  14. 51
      BuildServer/lib/task-processor.ts
  15. 22
      BuildServer/lib/tasks/cleanupafterdotnetbuild.ts
  16. 13
      BuildServer/lib/tasks/conditional.ts
  17. 4
      BuildServer/lib/tasks/copy.ts
  18. 22
      BuildServer/lib/tasks/copyglob.ts
  19. 18
      BuildServer/lib/tasks/cssnano.ts
  20. 24
      BuildServer/lib/tasks/cssnanoall.ts
  21. 4
      BuildServer/lib/tasks/deletefromcode.ts
  22. 5
      BuildServer/lib/tasks/dotnetbuild.ts
  23. 5
      BuildServer/lib/tasks/dotnetbuildandtest.ts
  24. 15
      BuildServer/lib/tasks/dotnetbuilderwrapper.ts
  25. 16
      BuildServer/lib/tasks/dotnetbuildwithoutcleanup.ts
  26. 12
      BuildServer/lib/tasks/dotnetcheckstyle.ts
  27. 23
      BuildServer/lib/tasks/dotnetcompile.ts
  28. 9
      BuildServer/lib/tasks/dotnetnugetpack.ts
  29. 12
      BuildServer/lib/tasks/dotnetnugetprocess.ts
  30. 15
      BuildServer/lib/tasks/dotnetnugetprocessinternal.ts
  31. 9
      BuildServer/lib/tasks/dotnetnugetpush.ts
  32. 4
      BuildServer/lib/tasks/dotnetnugetpushonly.ts
  33. 21
      BuildServer/lib/tasks/dotnetnugetrestore.ts
  34. 4
      BuildServer/lib/tasks/dotnetnunit.ts
  35. 25
      BuildServer/lib/tasks/dotnetnunitall.ts
  36. 10
      BuildServer/lib/tasks/dotnetpackwebapp.ts
  37. 21
      BuildServer/lib/tasks/dotnetrewrite.ts
  38. 10
      BuildServer/lib/tasks/echo.ts
  39. 4
      BuildServer/lib/tasks/eslintbrowser.ts
  40. 22
      BuildServer/lib/tasks/eslintbrowserall.ts
  41. 4
      BuildServer/lib/tasks/noop.ts
  42. 18
      BuildServer/lib/tasks/packform.ts
  43. 10
      BuildServer/lib/tasks/parallel.ts
  44. 10
      BuildServer/lib/tasks/sequential.ts
  45. 4
      BuildServer/lib/tasks/uglifyjs.ts
  46. 24
      BuildServer/lib/tasks/uglifyjsall.ts
  47. 9
      BuildServer/lib/tasks/writefile.ts
  48. 11
      BuildServer/lib/tasks/zip.ts
  49. 10
      BuildServer/lib/types/augmentations/cssnano.ts
  50. 21
      BuildServer/lib/types/augmentations/eslint.ts
  51. 6
      BuildServer/lib/types/augmentations/graceful-fs.ts
  52. 5
      BuildServer/lib/types/augmentations/json-parse-safe.ts
  53. 34
      BuildServer/lib/types/augmentations/nodegit.ts
  54. 14
      BuildServer/lib/types/augmentations/stream-buffers.ts
  55. 37
      BuildServer/lib/types/dotnetbuilder-types.ts
  56. 5
      BuildServer/lib/types/index.ts
  57. 8
      BuildServer/lib/types/report-types.ts
  58. 10
      BuildServer/lib/types/task-processor-types.ts
  59. 4
      BuildServer/package.json
  60. 11
      BuildServer/tsconfig.json

@ -13,13 +13,38 @@ import { writeReport } from "./report-processor";
import { processTask } from "./task-processor"; import { processTask } from "./task-processor";
import { ReportResult, Settings } from "./types"; 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 codePostfix = "";
const mailLazinessLevel = 1000; const mailLazinessLevel = 1000;
const maxDescriptionLength = 140; const maxDescriptionLength = 140;
const maxTmpcodepathLength = 15; const maxTmpcodepathLength = 15;
const twoDigits = 100; const twoDigits = 100;
const createFinalState = (isSuccess) => { const createFinalState = (isSuccess: boolean) => {
if (isSuccess) { if (isSuccess) {
return "success"; return "success";
} }
@ -27,7 +52,7 @@ const createFinalState = (isSuccess) => {
return "error"; return "error";
}; };
const createBuildDoneMessage = (isSuccess, name) => { const createBuildDoneMessage = (isSuccess: boolean, name: string) => {
if (isSuccess) { if (isSuccess) {
return `Successfully built ${name}`; return `Successfully built ${name}`;
} }
@ -35,7 +60,7 @@ const createBuildDoneMessage = (isSuccess, name) => {
return `Build failed for ${name}`; return `Build failed for ${name}`;
}; };
const notifyStatus = (settings: Settings, options, notifyStatusCallback) => { const notifyStatus = (settings: Settings, options: IStatusOptions, notifyStatusCallback: ISimpleCallback) => {
const status = { const status = {
description: String(options.description || "").substr(0, maxDescriptionLength), description: String(options.description || "").substr(0, maxDescriptionLength),
owner: options.owner, 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) { if (!skipGitLoader) {
return gitLoader; return gitLoader;
} }
@ -65,7 +90,7 @@ const wrapGitLoader: (skipGitLoader: boolean) => typeof gitLoader = (skipGitLoad
return (_gitLoaderOptions, gitLoaderCallback) => process.nextTick(gitLoaderCallback); 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 url = options.url;
const owner = options.owner; const owner = options.owner;
const reponame = options.reponame; const reponame = options.reponame;
@ -100,7 +125,7 @@ export const build = (settings: Settings, options, buildCallback) => {
mkdirsSync(join(settings.releasepath, owner, reponame, "$revs")); mkdirsSync(join(settings.releasepath, owner, reponame, "$revs"));
writeFileSync(join(settings.releasepath, owner, reponame, "$revs", `${rev}.branch`), branch); writeFileSync(join(settings.releasepath, owner, reponame, "$revs", `${rev}.branch`), branch);
const createErrorMessageForMail = (doneErr) => { const createErrorMessageForMail = (doneErr: any) => {
if (!doneErr) { if (!doneErr) {
return ""; return "";
} }
@ -108,7 +133,7 @@ export const build = (settings: Settings, options, buildCallback) => {
return `Error message: ${doneErr}\r\n\r\n`; return `Error message: ${doneErr}\r\n\r\n`;
}; };
const createResultMessageForMail = (result) => { const createResultMessageForMail = (result?: ReportResult) => {
if (!result || !result.messages || !result.messages.$allMessages) { if (!result || !result.messages || !result.messages.$allMessages) {
return JSON.stringify(result, null, " "); 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"); 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 allErrors = (result && result.errors && result.errors.$allMessages) || [];
const allWarns = (result && result.warns && result.errors.$allMessages) || []; const allWarns = (result && result.warns && result.errors.$allMessages) || [];
const allInfos = (result && result.infos && result.errors.$allMessages) || []; const allInfos = (result && result.infos && result.errors.$allMessages) || [];
@ -136,7 +161,7 @@ export const build = (settings: Settings, options, buildCallback) => {
(parallelCallback) => sendMail({ (parallelCallback) => sendMail({
from: settings.smtp.sender, from: settings.smtp.sender,
headers: { "X-Laziness-level": mailLazinessLevel }, 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)}`, text: `Build status URL: ${settings.siteRoot}status/${owner}/${reponame}/${rev}\r\n\r\n${createErrorMessageForMail(doneErr)}${createResultMessageForMail(result)}`,
to: settings.smtp.receiver, to: settings.smtp.receiver,
}, parallelCallback), }, parallelCallback),
@ -177,7 +202,7 @@ export const build = (settings: Settings, options, buildCallback) => {
return done("MBSNotFound"); return done("MBSNotFound");
} }
return readFile(join(exported, "mbs.json"), (readErr, data) => { return readFile(join(exported, "mbs.json"), "utf8", (readErr, data) => {
if (readErr) { if (readErr) {
return done(`MBSUnableToRead: ${readErr}`); return done(`MBSUnableToRead: ${readErr}`);
} }

@ -6,15 +6,38 @@ import { createGithub, IGithub } from "./github-wrapper";
import { getStatusMessageFromRelease } from "./report-processor"; import { getStatusMessageFromRelease } from "./report-processor";
import { Settings } from "./types"; 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 action: string;
readonly baseRepoOptions: any; readonly baseRepoOptions: IRepoOptions;
readonly headRepoOptions: any; readonly headRepoOptions: IRepoCommitOptions;
readonly pullRequestNumber: number;
} }
interface ICheckPullRequestOptions extends ICommentOnPullRequestOptions { interface IPullRequestOptionsWithGithub extends IPullRequestOptions {
readonly github: IGithub; 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]+)+$/; const featureNamePattern = /^feature-(\d+)(?:-[a-zA-Z0-9]+)+$/;
@ -24,14 +47,14 @@ const masterNamePattern = /^master$/;
const httpNotFound = 404; const httpNotFound = 404;
const maxCommentLength = 64000; 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, body: message,
number: options.pullRequestNumber, number: options.pullRequestNumber,
owner: options.baseRepoOptions.owner, owner: options.baseRepoOptions.owner,
repo: options.baseRepoOptions.reponame, repo: options.baseRepoOptions.reponame,
}, callback); }, 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) { if (err) {
return callback(err); return callback(err);
} }
@ -44,7 +67,7 @@ const closePullRequest = (options, message, callback) => writeComment(options, m
}, callback); }, 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, number: issueNumber,
owner: options.baseRepoOptions.owner, owner: options.baseRepoOptions.owner,
repo: options.baseRepoOptions.reponame, repo: options.baseRepoOptions.reponame,
@ -61,7 +84,7 @@ const checkHasIssue = (options: ICheckPullRequestOptions, issueNumber, callback)
return callback("Result is empty"); return callback("Result is empty");
} }
if (result.data.number.toString() !== issueNumber) { if (result.data.number.toString() !== issueNumber.toString()) {
return callback(null, false); return callback(null, false);
} }
@ -72,7 +95,7 @@ const checkHasIssue = (options: ICheckPullRequestOptions, issueNumber, callback)
return callback(null, true, result.data.title); 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, owner: options.baseRepoOptions.owner,
per_page: 1, per_page: 1,
repo: options.baseRepoOptions.reponame, repo: options.baseRepoOptions.reponame,
@ -81,10 +104,10 @@ const checkHasReleases = (options: ICheckPullRequestOptions, callback) => option
return callback(getReleasesErr); 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 head = options.headRepoOptions;
const base = options.baseRepoOptions; const base = options.baseRepoOptions;
@ -93,11 +116,11 @@ const checkPullRequest = (options: ICheckPullRequestOptions, callback) => {
} }
if (head.owner === base.owner) { 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 closePullRequest(options, "Only merging from version to master is allowed", callback);
} }
return checkHasReleases(options, (hasReleasesErr, hasReleases) => { return checkHasReleases(options, (hasReleasesErr, hasReleases?: boolean) => {
if (hasReleasesErr) { if (hasReleasesErr) {
return writeComment(options, "Unable to check for releases", callback); return writeComment(options, "Unable to check for releases", callback);
} }
@ -107,25 +130,25 @@ const checkPullRequest = (options: ICheckPullRequestOptions, callback) => {
} }
if (options.action === "opened") { 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); 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); return closePullRequest(options, `Only merging from feature branch is allowed (pattern: \`${featureNamePattern}\`)`, callback);
} }
if (!versionNamePattern.test(base.branchname) && !masterNamePattern.test(base.branchname)) { 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); 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 execResult = featureNamePattern.exec(head.branchName);
const issueNumber = execResult && execResult[1]; 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) { if (hasIssueErr) {
return writeComment(options, `Unable to check for issue:\r\n\r\n${hasIssueErr}`, callback); 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); 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) => { return checkHasReleases(options, (hasReleasesErr, hasReleases) => {
if (hasReleasesErr) { if (hasReleasesErr) {
@ -150,7 +173,7 @@ const checkPullRequest = (options: ICheckPullRequestOptions, callback) => {
} }
if (options.action === "opened") { 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); return process.nextTick(callback);
@ -158,17 +181,17 @@ const checkPullRequest = (options: ICheckPullRequestOptions, callback) => {
}); });
}; };
export const commentOnPullRequest = (settings: Settings, originalOptions: ICommentOnPullRequestOptions, callback) => { export const commentOnPullRequest = (settings: Settings, originalOptions: IPullRequestOptions, callback: ISimpleCallback) => {
const optionsGithub = { const options = {
...originalOptions, ...originalOptions,
github: createGithub(settings, originalOptions.baseRepoOptions.owner), github: createGithub(settings, originalOptions.baseRepoOptions.owner),
}; };
const options = { const getStatusMessageOptions = {
...optionsGithub, ...options.headRepoOptions,
onTenthAttempt: () => writeComment(optionsGithub, "Waiting for build to finish...", _.noop), 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) const escapedErr = String(statusMessageErr || "").substring(0, maxCommentLength)
.replace(/`/g, "` "); .replace(/`/g, "` ");
const message = statusMessageErr const message = statusMessageErr

@ -3,10 +3,24 @@
import { parallel } from "async"; import { parallel } from "async";
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import { mkdir, writeFile } from "fs"; import { mkdir, writeFile } from "fs";
import { Commit, Tree, TreeEntry } from "nodegit";
import { join } from "path"; 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 { try {
return callback(null, tree.gitTree.entries()); return callback(null, tree.gitTree.entries());
} catch (err) { } catch (err) {
@ -14,20 +28,20 @@ const safeGetEntries = (tree, callback) => {
} }
}; };
const gitToFsCopier = new Copier({ const gitToFsCopier = createCopier({
concurrency: 4, concurrency: 4,
copyLeaf: (entry, targetDir, callback) => { copyLeaf: (entry: TreeEntry, targetDir: string, callback: ISimpleCallback) => {
const targetPath = join(targetDir, entry.name()); const targetPath = join(targetDir, entry.name());
entry.getBlob((err, blob) => { entry.getBlob((err, blob) => {
if (err) { if (err || !blob) {
return callback(err); return callback(err);
} }
return writeFile(targetPath, blob.content(), callback); return writeFile(targetPath, blob.content(), callback);
}); });
}, },
createTargetTree: (tree, targetDir, callback) => { createTargetTree: (tree: ISource, targetDir: string, callback: INewTreeCallback) => {
const targetSubdir = join(targetDir, tree.name); const targetSubdir = join(targetDir, tree.name);
mkdir(targetSubdir, (err) => { mkdir(targetSubdir, (err) => {
@ -39,16 +53,16 @@ const gitToFsCopier = new Copier({
return callback(null, targetSubdir); return callback(null, targetSubdir);
}); });
}, },
finalizeTargetTree: (_targetSubdir, callback) => callback(), finalizeTargetTree: (_targetSubdir: string, callback: ISimpleCallback) => callback(),
walkSourceTree: (tree) => { walkSourceTree: (tree: ISource) => {
const emitter = new EventEmitter(); const emitter = new EventEmitter();
process.nextTick(() => safeGetEntries(tree, (getEntriesErr, entries) => { process.nextTick(() => safeGetEntries(tree, (getEntriesErr, entries) => {
if (getEntriesErr) { if (getEntriesErr || !entries) {
return emitter.emit("error", getEntriesErr); return emitter.emit("error", getEntriesErr);
} }
return parallel(entries.map((entry) => (callback) => { return parallel(entries.map((entry) => (callback: ISimpleCallback) => {
if (entry.isTree()) { if (entry.isTree()) {
return entry.getTree((getTreeErr, subTree) => { return entry.getTree((getTreeErr, subTree) => {
if (getTreeErr) { if (getTreeErr) {
@ -84,13 +98,10 @@ const gitToFsCopier = new Copier({
}, },
}); });
export const gitToFs = (commit, exportDir, callback) => commit.getTree((err, tree) => { export const gitToFs = (commit: Commit, exportDir: string, callback: ISimpleCallback) => commit.getTree().then(
if (err) { (tree) => gitToFsCopier.copy({
return callback(err);
}
return gitToFsCopier.copy({
gitTree: tree, gitTree: tree,
name: ".", name: ".",
}, exportDir, callback); }, exportDir, callback),
}); (err) => callback(err),
);

@ -5,7 +5,19 @@ import { Remote, Repository } from "nodegit";
import { gitToFs } from "./copy"; 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://")) { if (!url.startsWith("https://")) {
return url; return url;
} }
@ -13,17 +25,7 @@ const fixUrl = (url) => {
return `git://${url.substr("https://".length)}`; return `git://${url.substr("https://".length)}`;
}; };
/* Example: export const gitLoader = (options: IOptions, globalCallback: ISimpleCallback) => {
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) => {
const url = fixUrl(options.remote); const url = fixUrl(options.remote);
const path = `${options.local}/${options.hash}`; const path = `${options.local}/${options.hash}`;
const exported = options.exported; const exported = options.exported;
@ -33,30 +35,34 @@ export const gitLoader = (options, globalCallback) => {
console.log(`Cloning ${url} to ${path}`); console.log(`Cloning ${url} to ${path}`);
Repository.init(path, 1) Repository.init(path, 1).then(
.catch(globalCallback) (repo) => Remote.create(repo, "origin", url).then(
.then((repo) => Remote.create(repo, "origin", url) (remote) => remote.fetch([options.branch]).then(
.catch(globalCallback) (errorNumber) => {
.then((remote) => remote.fetch([options.branch])
.catch(globalCallback)
.then((errorNumber) => {
if (errorNumber) { if (errorNumber) {
return globalCallback(`Failed to fetch commit: error number ${errorNumber}`); return globalCallback(`Failed to fetch commit: error number ${errorNumber}`);
} }
console.log(`Cloned ${url} to ${path}`); console.log(`Cloned ${url} to ${path}`);
return repo.getCommit(options.hash) return repo.getCommit(options.hash).then(
.catch(globalCallback) (commit) => {
.then((commit) => {
removeSync(exported); removeSync(exported);
mkdirsSync(exported); mkdirsSync(exported);
gitToFs(commit, exported, (err, result) => { gitToFs(commit, exported, (err) => {
repo.free(); repo.free();
return globalCallback(err, result); return globalCallback(err);
}); });
}); },
}))); globalCallback,
);
},
globalCallback,
),
globalCallback,
),
globalCallback,
);
}; };

@ -33,15 +33,17 @@ interface IStatusData {
interface IGithub { interface IGithub {
readonly issues: { readonly issues: {
createComment(params: RawGithub.IssuesCreateCommentParams, callback: ICallback<never>): void;
edit(params: RawGithub.IssuesEditParams, callback: ICallback<never>): void;
get(params: RawGithub.IssuesGetParams, callback: ICallback<IIssueData>): void; get(params: RawGithub.IssuesGetParams, callback: ICallback<IIssueData>): void;
}; };
readonly repos: { readonly repos: {
createStatus(params: RawGithub.ReposCreateStatusParams, callback: ICallback<IStatusData>); createStatus(params: RawGithub.ReposCreateStatusParams, callback: ICallback<IStatusData>): void;
getReleases(params: RawGithub.ReposGetReleasesParams, callback: ICallback<IReleaseData[]>); getReleases(params: RawGithub.ReposGetReleasesParams, callback: ICallback<IReleaseData[]>): 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 { export {
IGithub, IGithub,

@ -1,7 +1,15 @@
"use strict"; "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("Mail sender is not implemented");
console.log(message.title); console.log(message.subject);
process.nextTick(callback); process.nextTick(callback);
}; };

@ -10,6 +10,24 @@ import { createGunzip, createGzip } from "zlib";
import { Message, Report, ReportResult, Settings } from "./types"; 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 reportFilename = "report.json.gz";
const maxAttemptsNumber = 100; const maxAttemptsNumber = 100;
const attemptsTimeout = 30000; 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 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) || []; 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({ const data = JSON.stringify({
date: Date.now(), date: Date.now(),
err, err,
@ -51,7 +69,7 @@ export const writeReport = (releaseDir, err, result: ReportResult | undefined, c
readable.stop(); 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 readStream = createReadStream(join(releaseDir, reportFilename));
const writable = new WritableStreamBuffer(); 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); const releaseDir = join(settings.releasepath, options.owner, options.reponame, options.branch, options.rev);
glob("**", { glob("**", {
@ -86,22 +104,19 @@ export const loadReport = (settings: Settings, options, callback) => {
mark: true, mark: true,
}, (err, files) => { }, (err, files) => {
if (err) { if (err) {
return callback(err, options); return callback(err);
} }
const reportFile = join(releaseDir, reportFilename); const reportFile = join(releaseDir, reportFilename);
return exists(reportFile, (reportFileExists) => { return exists(reportFile, (reportFileExists) => {
if (!reportFileExists) { if (!reportFileExists) {
return callback("ReportFileNotFound", options); return callback("ReportFileNotFound");
} }
return readReport(releaseDir, (readErr, report) => { return readReport(releaseDir, (readErr, report) => {
if (readErr) { if (readErr || !report) {
return callback(readErr, { return callback(readErr);
...options,
files,
});
} }
return callback(null, { 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 = { const options = {
...originalOptions, ...originalOptions,
attemptsGetReport: (Number(originalOptions.attemptsGetReport) || Number()) + 1, attemptsGetReport: (Number(originalOptions.attemptsGetReport) || Number()) + 1,
@ -143,11 +158,11 @@ export const getStatusMessageFromRelease = (settings: Settings, originalOptions,
} }
return setTimeout(() => readReport(releaseDir, (readErr, report) => { return setTimeout(() => readReport(releaseDir, (readErr, report) => {
if (readErr) { if (readErr || !report) {
return callback(readErr); return callback(readErr);
} }
if (report.result === "MBSNotFound") { if (report.err === "MBSNotFound") {
return callback("mbs.json is not found"); return callback("mbs.json is not found");
} }

@ -4,6 +4,7 @@ import * as express from "express";
import { build } from "../builder"; import { build } from "../builder";
import { getSettings } from "../settings-wrapper"; import { getSettings } from "../settings-wrapper";
import { ReportResult } from "../types";
export const get: express.RequestHandler = (_req, res) => res.render("manual"); 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}`, 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("Done processing manual request");
console.log(`Error: ${err}`); console.log(`Error: ${err}`);
res.render("manual-done", { res.render("manual-done", {

@ -10,12 +10,12 @@ import { HookParameters, HookPullRequestPayload, HookPushPayload } from "../type
interface IBaseRepoOptions { interface IBaseRepoOptions {
branch: string; branch: string;
branchname?: string; branchName?: string;
owner: string; owner: string;
reponame: 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 processPush = (req: express.Request, res: express.Response, payload: HookPushPayload) => {
const settings = getSettings(req.app); const settings = getSettings(req.app);
@ -45,7 +45,7 @@ const processPullRequest = (req: express.Request, res: express.Response, payload
const headRepo = head.repo; const headRepo = head.repo;
const headRepoOptions = { const headRepoOptions = {
branch: `refs/heads/${head.ref}`, branch: `refs/heads/${head.ref}`,
branchname: head.ref, branchName: head.ref,
owner: headRepo.owner.name || headRepo.owner.login, owner: headRepo.owner.name || headRepo.owner.login,
reponame: headRepo.name, reponame: headRepo.name,
rev: head.sha, rev: head.sha,
@ -55,7 +55,7 @@ const processPullRequest = (req: express.Request, res: express.Response, payload
const baseRepo = base.repo; const baseRepo = base.repo;
const baseRepoOptions = { const baseRepoOptions = {
branch: `refs/heads/${base.ref}`, branch: `refs/heads/${base.ref}`,
branchname: base.ref, branchName: base.ref,
owner: baseRepo.owner.name || baseRepo.owner.login, owner: baseRepo.owner.name || baseRepo.owner.login,
reponame: baseRepo.name, reponame: baseRepo.name,
}; };
@ -84,16 +84,16 @@ const processPullRequest = (req: express.Request, res: express.Response, payload
return res.send(""); return res.send("");
} }
return commentOnPullRequest(settings, options, (err, data) => { return commentOnPullRequest(settings, options, (err) => {
if (err) { if (err) {
console.log(`Unable to post comment: ${err}`); console.log(`Unable to post comment: ${err}`);
} }
res.send(err || data); res.end();
}); });
}; };
const getPayload = (body) => { const getPayload = (body: any) => {
if (!body.payload) { if (!body.payload) {
return body; return body;
} }

@ -6,14 +6,15 @@ import { join } from "path";
import { readReport } from "../report-processor"; import { readReport } from "../report-processor";
import { getSettings } from "../settings-wrapper"; import { getSettings } from "../settings-wrapper";
import { Report } from "../types";
const getDatePart = (report) => { const getDatePart = (report: Report) => {
if (!report.date) { if (!report.date) {
return "unknowndate"; return "unknowndate";
} }
const date = new Date(report.date); 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 year = date.getFullYear();
const month = paddingLeft(date.getMonth() + 1, "00"); 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); const releasePath = join(getSettings(req.app).releasepath, options.owner, options.reponame, options.branch, options.rev);
readReport(releasePath, (err, report) => { readReport(releasePath, (err, report) => {
if (err) { if (err || !report) {
return next(err); return next(err);
} }

@ -5,13 +5,25 @@ import { parse } from "url";
import { getSettings } from "../settings-wrapper"; import { getSettings } from "../settings-wrapper";
import { getReport } from "../status-processor"; 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 pathParts = path.split("/").filter((value) => value);
const [, secondPart, thirdPart] = pathParts; const [, secondPart, thirdPart] = pathParts;
if (!secondPart) { if (!secondPart) {
return callback("BadRequest", {}); return callback("BadRequest");
} }
if (thirdPart === "tree") { 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 = { const options = {
...inputOptions || {}, ...inputOptions || {},
err, err,
@ -45,31 +57,33 @@ const createShowReport = (res: express.Response) => (err, inputOptions) => {
}; };
export const image: express.RequestHandler = (req, res) => { export const image: express.RequestHandler = (req, res) => {
const getAdditionalOptions = (err, options) => { const getAdditionalOptions = (err: string | null, options?: IOptionsWithReport) => {
if (err === "ReportFileNotFound") { if (err === "ReportFileNotFound") {
return { status: "Building" }; return { status: "Building" };
} }
if (err) { if (err || !options) {
return { return {
message: err, message: err,
status: "StatusError", status: "StatusError",
}; };
} }
if (options.report.result === "MBSNotFound") { if (options.report.err === "MBSNotFound") {
return { status: "MBSNotUsed" }; return { status: "MBSNotUsed" };
} }
if (options.report.err) { if (options.report.err || !options.report.result) {
return { return {
message: options.report.err, message: options.report.err,
status: "Error", status: "Error",
}; };
} }
if ((options.report.result.warns.$allMessages || []).length) { const result = options.report.result;
const [firstWarn] = options.report.result.warns.$allMessages;
if ((result.warns.$allMessages || []).length) {
const [firstWarn] = result.warns.$allMessages;
return { return {
message: firstWarn.message, 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) { if (allInfos.length) {
return { return {
@ -89,7 +103,7 @@ export const image: express.RequestHandler = (req, res) => {
return { status: "OK" }; return { status: "OK" };
}; };
const handle = (err, options) => { const handle = (err: string | null, options?: IOptionsWithReport) => {
res.setHeader("Content-Type", "image/svg+xml"); res.setHeader("Content-Type", "image/svg+xml");
res.render("status-image", { res.render("status-image", {
...options, ...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) { if (err) {
return handle(err, options); return handle(err);
} }
return getReport(getSettings(req.app), options, handle); 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) => { export const pageFromGithub: express.RequestHandler = (req, res) => parseOptionsFromReferer(req.params[0], (err, options) => {
if (err) { if (err || !options) {
return createShowReport(res)(err, options); return createShowReport(res)(err, options);
} }

@ -1,10 +1,12 @@
"use strict"; "use strict";
import * as express from "express";
import { Settings } from "./types"; 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 { export {
getSettings, getSettings,

@ -4,19 +4,49 @@ import { exists, readFile } from "fs";
import { join } from "path"; import { join } from "path";
import { loadReport } from "./report-processor"; import { loadReport } from "./report-processor";
import { Settings } from "./types"; import { Report, Settings } from "./types";
const addBranchInfo = (settings: Settings, options, callback) => { 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<ResultOptions> = (err: any, result?: ResultOptions) => void;
const addBranchInfo = (settings: Settings, options: IOptionsWithRevInfo, callback: Callback<IOptionsComplete>) => {
const branchFile = join(settings.releasepath, options.owner, options.reponame, "$revs", `${options.rev}.branch`); const branchFile = join(settings.releasepath, options.owner, options.reponame, "$revs", `${options.rev}.branch`);
exists(branchFile, (exists) => { exists(branchFile, (exists) => {
if (!exists) { if (!exists) {
return callback("BranchFileNotFound", options); return callback("BranchFileNotFound");
} }
return readFile(branchFile, (err, data) => { return readFile(branchFile, (err, data) => {
if (err) { if (err) {
return callback(err, options); return callback(err);
} }
const branch = data.toString(); 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<IOptionsComplete>) => {
const revFile = join(settings.releasepath, options.owner, options.reponame, options.branch, "latest.id"); const revFile = join(settings.releasepath, options.owner, options.reponame, options.branch, "latest.id");
exists(revFile, (exists) => { exists(revFile, (exists) => {
if (!exists) { if (!exists) {
return callback("RevFileNotFound", options); return callback("RevFileNotFound");
} }
return readFile(revFile, (err, data) => { return readFile(revFile, (err, data) => {
if (err) { if (err) {
return callback(err, options); return callback(err);
} }
const rev = data.toString(); 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<IOptionsComplete>) => {
if (options.rev && !(/^[\da-f]{40}$/i).test(options.rev)) { 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 = { const result = {
@ -72,7 +102,7 @@ const parseOptions = (settings: Settings, options, callback) => {
}, callback); }, callback);
} }
if (/^[\da-f]{40}$/i.test(options.branchName)) { if (options.branchName && /^[\da-f]{40}$/i.test(options.branchName)) {
return addBranchInfo(settings, { return addBranchInfo(settings, {
...result, ...result,
rev: options.branchName, rev: options.branchName,
@ -88,9 +118,9 @@ const parseOptions = (settings: Settings, options, callback) => {
}, callback); }, callback);
}; };
export const getReport = (settings: Settings, options, callback) => parseOptions(settings, options, (err, result) => { export const getReport = (settings: Settings, options: IGetReportOptions, callback: Callback<IOptionsWithReport>) => parseOptions(settings, options, (err: string, result: IOptionsComplete) => {
if (err) { if (err) {
return callback(err, {}); return callback(err);
} }
return loadReport(settings, result, callback); return loadReport(settings, result, callback);

@ -1,24 +1,28 @@
"use strict"; "use strict";
import tasks from "./tasks"; 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. // 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 createTaskProcessor = (task: TaskInfo, outerProcessor: TaskProcessorCore, callback: TaskProcessorCallback) => {
const errors: string[] = []; const errors: string[] = [];
const getOuterPrefix = (prefix) => { const getOuterPrefix = (prefix?: string) => {
if (task.name && prefix) { if (task.name && prefix) {
return `${task.name}/${prefix}`; return `${task.name}/${prefix}`;
} }
return String(task.name || "") + String(prefix || ""); return String(task.name || "") + String(prefix || "");
}; };
const onError = (message, prefix) => { const onError = (message: string, prefix?: string) => {
errors.push(message); errors.push(message);
outerProcessor.onError(message, getOuterPrefix(prefix)); outerProcessor.onError(message, getOuterPrefix(prefix));
}; };
const onWarn = (message, prefix) => outerProcessor.onWarn(message, getOuterPrefix(prefix)); const onWarn = (message: string, prefix?: string) => outerProcessor.onWarn(message, getOuterPrefix(prefix));
const onInfo = (message, prefix) => outerProcessor.onInfo(message, getOuterPrefix(prefix)); const onInfo = (message: string, prefix?: string) => outerProcessor.onInfo(message, getOuterPrefix(prefix));
let result: TaskProcessor; let result: TaskProcessor;
result = { result = {
@ -35,47 +39,50 @@ const createTaskProcessor = (task: TaskInfo, outerProcessor: TaskProcessorCore,
return result; return result;
}; };
const pushMessage = (list, message, parts, index) => { const pushMessage = (list: Messages, message: string, parts: string[], index: number): void => {
if (!index) {
list.$allMessages.push({
message,
prefix: parts.join("/"),
});
}
if (index < parts.length) { if (index < parts.length) {
if (!list[parts[index]]) { if (!list[parts[index]]) {
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) { if (!list.$messages) {
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; 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 errors: MessagesRoot = { $allMessages: [] };
const warns: MessagesRoot = { $allMessages: [] }; const warns: MessagesRoot = { $allMessages: [] };
const infos: MessagesRoot = { $allMessages: [] }; const infos: MessagesRoot = { $allMessages: [] };
const messages: MessagesRoot = { $allMessages: [] }; const messages: MessagesRoot = { $allMessages: [] };
const messageProcessor = (list) => (message, prefix) => { const messageProcessor = (list: MessagesRoot) => (message: string, prefix: string) => {
const parts = prefix.split("/"); const parts = prefix.split("/");
pushMessage(list, message, parts, 0); pushMessageRoot(list, message, parts);
pushMessage(messages, message, parts, 0); pushMessageRoot(messages, message, parts);
}; };
const flags = {}; const flags: IFlags = {};
const processor = createTaskProcessor(task, { const processor = createTaskProcessor(task, {
context: { context: {
...context, ...context,

@ -2,7 +2,8 @@
import * as glob from "glob"; 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}", { export default ((_params, processor) => () => glob("**/obj/{Debug,Release}/*.{dll,pdb,xml}", {
cwd: processor.context.exported, cwd: processor.context.exported,
@ -18,14 +19,11 @@ export default ((_params, processor) => () => glob("**/obj/{Debug,Release}/*.{dl
return processor.done(); return processor.done();
} }
return processor.processTask({ return parallel({
params: { tasks: files.map((file) => ({
tasks: files.map((file) => ({ name: file,
name: file, params: { filename: file },
params: { filename: file }, type: "deletefromcode",
type: "deletefromcode", })),
})), }, processor)();
}, })) as GenericTask<{}>;
type: "parallel",
}, processor.done);
})) as Task;

@ -1,11 +1,18 @@
"use strict"; "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) => { export default ((params, processor) => {
const condition = (!params.owner || params.owner === processor.context.owner) const condition = (!params.owner || params.owner === processor.context.owner)
&& (!params.branch || params.branch === processor.context.branch || `refs/heads/${params.branch}` === processor.context.branch); && (!params.branch || params.branch === processor.context.branch || `refs/heads/${params.branch}` === processor.context.branch);
const task = (condition && params.task) || params.otherwise; const task = (condition && params.task) || params.otherwise;
return () => processor.processTask(task || { type: "noop" }, processor.done); return () => processor.processTask(task || { type: "noop", params: {} }, processor.done);
}) as Task; }) as GenericTask<IParameters>;

@ -3,7 +3,7 @@
import { copy } from "fs-extra"; import { copy } from "fs-extra";
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
export default ((params, processor) => () => { export default ((params, processor) => () => {
const sourceFilePath = join(processor.context.exported, params.filename); const sourceFilePath = join(processor.context.exported, params.filename);
@ -20,4 +20,4 @@ export default ((params, processor) => () => {
return processor.done(); return processor.done();
}); });
}) as Task; }) as GenericTask<{ readonly filename: string }>;

@ -2,7 +2,8 @@
import * as glob from "glob"; import * as glob from "glob";
import { Task } from "../types"; import { GenericTask } from "../types";
import parallel from "./parallel";
export default ((params, processor) => () => glob(params.mask, { export default ((params, processor) => () => glob(params.mask, {
cwd: processor.context.exported, cwd: processor.context.exported,
@ -18,14 +19,11 @@ export default ((params, processor) => () => glob(params.mask, {
return processor.done(); return processor.done();
} }
return processor.processTask({ return parallel({
params: { tasks: files.map((file) => ({
tasks: files.map((file) => ({ name: file,
name: file, params: { filename: file },
params: { filename: file }, type: "copy",
type: "copy", })),
})), }, processor)();
}, })) as GenericTask<{ readonly mask: string }>;
type: "parallel",
}, processor.done);
})) as Task;

@ -4,12 +4,12 @@ import { process as cssnanoProcess } from "cssnano";
import { readFile, writeFile } from "fs"; import { readFile, writeFile } from "fs";
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
export default ((params, processor) => () => { export default ((params, processor) => () => {
const filePath = join(processor.context.exported, params.filename); const filePath = join(processor.context.exported, params.filename);
readFile(filePath, (readErr, css) => { readFile(filePath, "utf8", (readErr, css) => {
if (readErr) { if (readErr) {
processor.onError(`Unable to read stylesheet ${params.filename}: ${readErr}`); processor.onError(`Unable to read stylesheet ${params.filename}: ${readErr}`);
@ -17,20 +17,20 @@ export default ((params, processor) => () => {
} }
return cssnanoProcess(css) return cssnanoProcess(css)
.catch((cssErr) => {
processor.onError(`Unable to uglify stylesheet: ${cssErr}`);
processor.done();
})
.then((result) => { .then((result) => {
writeFile(filePath, result.css, (writeErr) => { writeFile(filePath, result.content, (writeErr) => {
if (writeErr) { if (writeErr) {
processor.onError(`Unable to write uglified stylesheet for ${params.filename}: ${writeErr}`); processor.onError(`Unable to write uglified stylesheet for ${params.filename}: ${writeErr}`);
} else { } 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(); processor.done();
}); });
})
.catch((cssErr: string) => {
processor.onError(`Unable to uglify stylesheet: ${cssErr}`);
processor.done();
}); });
}); });
}) as Task; }) as GenericTask<{ readonly filename: string }>;

@ -2,11 +2,12 @@
import * as glob from "glob"; import * as glob from "glob";
import { Task } from "../types"; import { GenericTask } from "../types";
import parallel from "./parallel";
const flagDoneName = "cssnanoallDone"; const flagDoneName = "cssnanoallDone";
export default ((params, processor) => () => { export default ((_params, processor) => () => {
if (processor.context.containsFlag(flagDoneName)) { if (processor.context.containsFlag(flagDoneName)) {
processor.onWarn("cssnanoall task is executed more than once; this is probably a bug in your mbs.json"); 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.done();
} }
return processor.processTask({ return parallel({
params: { tasks: files.map((file) => ({
tasks: files.map((file) => ({ name: file,
name: file, params: { filename: file },
params: { filename: file }, type: "cssnano",
type: "cssnano", })),
})), }, processor)();
},
type: (params.preventParallelTests && "sequential") || "parallel",
}, processor.done);
}); });
}) as Task; }) as GenericTask<{}>;

@ -3,7 +3,7 @@
import { remove } from "fs-extra"; import { remove } from "fs-extra";
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
export default ((params, processor) => () => { export default ((params, processor) => () => {
const sourceFilePath = join(processor.context.exported, params.filename); const sourceFilePath = join(processor.context.exported, params.filename);
@ -19,4 +19,4 @@ export default ((params, processor) => () => {
return processor.done(); return processor.done();
}); });
}) as Task; }) as GenericTask<{ readonly filename: string }>;

@ -1,6 +1,6 @@
"use strict"; "use strict";
import { Task } from "../types"; import { GenericTask } from "../types";
import sequential from "./sequential"; import sequential from "./sequential";
export default ((params, processor) => sequential({ export default ((params, processor) => sequential({
@ -12,7 +12,8 @@ export default ((params, processor) => sequential({
}, },
{ {
name: "cleanup", name: "cleanup",
params: {},
type: "cleanupafterdotnetbuild", type: "cleanupafterdotnetbuild",
}, },
], ],
}, processor)) as Task; }, processor)) as GenericTask<{}>;

@ -1,6 +1,6 @@
"use strict"; "use strict";
import { Task } from "../types"; import { GenericTask } from "../types";
import sequential from "./sequential"; import sequential from "./sequential";
export default ((params, processor) => sequential({ export default ((params, processor) => sequential({
@ -17,7 +17,8 @@ export default ((params, processor) => sequential({
}, },
{ {
name: "cleanup", name: "cleanup",
params: {},
type: "cleanupafterdotnetbuild", type: "cleanupafterdotnetbuild",
}, },
], ],
}, processor)) as Task; }, processor)) as GenericTask<{}>;

@ -4,7 +4,16 @@ import { ChildProcess, spawn } from "child_process";
import * as JSONParse from "json-parse-safe"; import * as JSONParse from "json-parse-safe";
import { WritableStreamBuffer } from "stream-buffers"; 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 wrapBuilder = (builder: ChildProcess, input: string, onExit: (code: number, result: string, builderError: string) => void) => {
const stdoutPromise = new Promise((resolve, reject) => { const stdoutPromise = new Promise((resolve, reject) => {
@ -56,7 +65,7 @@ export default ((params, processor) => () => {
return processor.done(); return processor.done();
} }
const { value, error } = JSONParse(result); const { value, error }: { value: IDotNetBuilderResponse, error: any } = JSONParse(result);
if (error || !value || !value.Messages) { if (error || !value || !value.Messages) {
processor.onError(`Malformed JSON: ${error}`); processor.onError(`Malformed JSON: ${error}`);
@ -86,4 +95,4 @@ export default ((params, processor) => () => {
return processor.done(); return processor.done();
}); });
}) as Task; }) as GenericTask<BuilderRequest>;

@ -1,9 +1,19 @@
"use strict"; "use strict";
import { Task } from "../types"; import { GenericTask } from "../types";
import sequential from "./sequential"; 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) { if (!params.skipMbsCheckStyle) {
yield { yield {
params, params,
@ -40,4 +50,4 @@ export default ((params, processor) => {
const tasks = Array.from(createTasks(params)); const tasks = Array.from(createTasks(params));
return sequential({ tasks }, processor); return sequential({ tasks }, processor);
}) as Task; }) as GenericTask<IParameters>;

@ -5,7 +5,11 @@ import { readFile } from "fs";
import * as glob from "glob"; import * as glob from "glob";
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
interface IParameters {
ignoreCodeStyle: boolean;
}
const autoGeneratedMarker const autoGeneratedMarker
= "//------------------------------------------------------------------------------\n" = "//------------------------------------------------------------------------------\n"
@ -35,7 +39,7 @@ export default ((params, processor) => () => {
return processor.done(); return processor.done();
} }
const processFile = (data, file) => { const processFile = (data: string, file: string) => {
if (data.includes("\r\n")) { if (data.includes("\r\n")) {
return processor.onError(`Windows-style EOL (0D0A) found in file ${file}`); 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 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), join(processor.context.exported, file),
{ encoding: "utf8" }, { encoding: "utf8" },
(readErr, data) => { (readErr, data) => {
@ -73,4 +77,4 @@ export default ((params, processor) => () => {
}, },
)), processor.done); )), processor.done);
}); });
}) as Task; }) as GenericTask<IParameters>;

@ -2,9 +2,20 @@
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { BuilderCompileRequest, GenericTask } from "../types";
import dotnetbuilderwrapper from "./dotnetbuilderwrapper"; 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) => { export default ((params, processor) => {
if (processor.settings.isCodeAnalysisUnsupported && params.forceCodeAnalysis) { if (processor.settings.isCodeAnalysisUnsupported && params.forceCodeAnalysis) {
processor.onError("Code analysis is not supported"); processor.onError("Code analysis is not supported");
@ -24,17 +35,15 @@ export default ((params, processor) => {
|| params.ignoreCodeAnalysis || params.ignoreCodeAnalysis
|| (processor.settings.ignoreCodeAnalysisByDefault && !params.forceCodeAnalysis); || (processor.settings.ignoreCodeAnalysisByDefault && !params.forceCodeAnalysis);
const compileParams = { const compileParams: BuilderCompileRequest = {
Configuration: params.configuration, Configuration: params.configuration,
OutputDirectory: params.overrideOutputDirectory, OutputDirectory: params.overrideOutputDirectory,
SkipCodeAnalysis: skipCodeAnalysis, SkipCodeAnalysis: skipCodeAnalysis,
SolutionPath: join(processor.context.exported, params.solution), SolutionPath: join(processor.context.exported, params.solution),
Target: params.target, Target: params.target,
command: "compile", command: "compile",
...getAdditionalSigningParameters(),
}; };
return dotnetbuilderwrapper({ return dotnetbuilderwrapper(compileParams, processor);
...compileParams, }) as GenericTask<IParameters>;
...getAdditionalSigningParameters(),
}, processor);
}) as Task;

@ -1,12 +1,17 @@
"use strict"; "use strict";
import { Task } from "../types"; import { GenericTask } from "../types";
import dotnetnugetprocessinternal from "./dotnetnugetprocessinternal"; import dotnetnugetprocessinternal from "./dotnetnugetprocessinternal";
interface IParameters {
readonly name: string;
readonly nuspec: string;
}
export default ((params, processor) => dotnetnugetprocessinternal({ export default ((params, processor) => dotnetnugetprocessinternal({
...params, ...params,
getFinalTask: (nupkg) => ({ getFinalTask: (nupkg) => ({
params: { filename: nupkg }, params: { filename: nupkg },
type: "copy", type: "copy",
}), }),
}, processor)) as Task; }, processor)) as GenericTask<IParameters>;

@ -1,8 +1,16 @@
"use strict"; "use strict";
import { Task } from "../types"; import { GenericTask } from "../types";
import conditional from "./conditional"; 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({ export default ((params, processor) => conditional({
branch: "master", branch: "master",
otherwise: { otherwise: {
@ -28,4 +36,4 @@ export default ((params, processor) => conditional({
}, },
type: "dotnetnugetpush", type: "dotnetnugetpush",
}, },
}, processor)) as Task; }, processor)) as GenericTask<IParameters>;

@ -2,14 +2,23 @@
import { join } from "path"; import { join } from "path";
import { Task, TaskProcessor } from "../types"; import { GenericTask, TaskInfo, TaskProcessor } from "../types";
import sequential from "./sequential"; 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 postfixLength = 16;
const fourDigits = 10000; const fourDigits = 10000;
const twoDigits = 100; const twoDigits = 100;
const addPostfix = (version, params, processor: TaskProcessor) => { const addPostfix = (version: string, params: IParameters, processor: TaskProcessor) => {
if (params.withoutCommitSha) { if (params.withoutCommitSha) {
return version; return version;
} }
@ -40,4 +49,4 @@ export default ((params, processor) => {
params.getFinalTask(nupkg), params.getFinalTask(nupkg),
], ],
}, processor); }, processor);
}) as Task; }) as GenericTask<IParameters>;

@ -1,12 +1,17 @@
"use strict"; "use strict";
import { Task } from "../types"; import { GenericTask } from "../types";
import dotnetnugetprocessinternal from "./dotnetnugetprocessinternal"; import dotnetnugetprocessinternal from "./dotnetnugetprocessinternal";
interface IParameters {
readonly name: string;
readonly nuspec: string;
}
export default ((params, processor) => dotnetnugetprocessinternal({ export default ((params, processor) => dotnetnugetprocessinternal({
...params, ...params,
getFinalTask: (nupkg) => ({ getFinalTask: (nupkg) => ({
params: { Package: nupkg }, params: { Package: nupkg },
type: "dotnetnugetpushonly", type: "dotnetnugetpushonly",
}), }),
}, processor)) as Task; }, processor)) as GenericTask<IParameters>;

@ -2,7 +2,7 @@
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
import dotnetbuilderwrapper from "./dotnetbuilderwrapper"; import dotnetbuilderwrapper from "./dotnetbuilderwrapper";
export default ((params, processor) => dotnetbuilderwrapper({ export default ((params, processor) => dotnetbuilderwrapper({
@ -10,4 +10,4 @@ export default ((params, processor) => dotnetbuilderwrapper({
NugetHost: processor.settings.nugetHost, NugetHost: processor.settings.nugetHost,
Package: join(processor.context.exported, params.Package), Package: join(processor.context.exported, params.Package),
command: "nugetpush", command: "nugetpush",
}, processor)) as Task; }, processor)) as GenericTask<{ readonly Package: string }>;

@ -2,18 +2,11 @@
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
import sequential from "./sequential"; import dotnetbuilderwrapper from "./dotnetbuilderwrapper";
export default ((params, processor) => sequential({ export default ((params, processor) => dotnetbuilderwrapper({
tasks: [ BaseDirectory: processor.context.exported,
{ SolutionPath: join(processor.context.exported, params.solution),
params: { command: "nugetrestore",
BaseDirectory: processor.context.exported, }, processor)) as GenericTask<{ readonly solution: string }>;
SolutionPath: join(processor.context.exported, params.solution),
command: "nugetrestore",
},
type: "dotnetbuilderwrapper",
},
],
}, processor)) as Task;

@ -2,10 +2,10 @@
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
import dotNetBuilderWrapper from "./dotnetbuilderwrapper"; import dotNetBuilderWrapper from "./dotnetbuilderwrapper";
export default ((params, processor) => dotNetBuilderWrapper({ export default ((params, processor) => dotNetBuilderWrapper({
TestLibraryPath: join(processor.context.exported, params.assembly), TestLibraryPath: join(processor.context.exported, params.assembly),
command: "nunit", command: "nunit",
}, processor)) as Task; }, processor)) as GenericTask<{ readonly assembly: string }>;

@ -2,7 +2,9 @@
import * as glob from "glob"; import * as glob from "glob";
import { Task } from "../types"; import { GenericTask } from "../types";
import parallel from "./parallel";
import sequential from "./sequential";
const flagDoneName = "dotnetnunitallDone"; const flagDoneName = "dotnetnunitallDone";
@ -13,6 +15,8 @@ export default ((params, processor) => () => {
processor.context.addFlag(flagDoneName); processor.context.addFlag(flagDoneName);
const task = params.preventParallelTests ? sequential : parallel;
glob("**/{bin,build}/**/*.{Tests,Test,UnitTests}.dll", { glob("**/{bin,build}/**/*.{Tests,Test,UnitTests}.dll", {
cwd: processor.context.exported, cwd: processor.context.exported,
dot: true, dot: true,
@ -29,15 +33,12 @@ export default ((params, processor) => () => {
return processor.done(); return processor.done();
} }
return processor.processTask({ return task({
params: { tasks: files.map((file) => ({
tasks: files.map((file) => ({ name: file,
name: file, params: { assembly: file },
params: { assembly: file }, type: "dotnetnunit",
type: "dotnetnunit", })),
})), }, processor)();
},
type: (params.preventParallelTests && "sequential") || "parallel",
}, processor.done);
}); });
}) as Task; }) as GenericTask<{ readonly preventParallelTests?: boolean }>;

@ -4,9 +4,15 @@ import { readFileSync } from "fs";
import { render } from "mustache"; import { render } from "mustache";
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
import sequential from "./sequential"; 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 msbuildTemplate = readFileSync(join(__dirname, "/dotnetpackwebapp.template.msbuild"), { encoding: "utf8" });
const deployTemplate = readFileSync(join(__dirname, "/dotnetpackwebapp.template.bat"), { encoding: "utf8" }); const deployTemplate = readFileSync(join(__dirname, "/dotnetpackwebapp.template.bat"), { encoding: "utf8" });
const versionTemplate = readFileSync(join(__dirname, "/dotnetpackwebapp.template.version.aspx"), { encoding: "utf8" }); const versionTemplate = readFileSync(join(__dirname, "/dotnetpackwebapp.template.version.aspx"), { encoding: "utf8" });
@ -46,4 +52,4 @@ export default ((params, processor) => sequential({
type: "dotnetcompile", type: "dotnetcompile",
}, },
], ],
}, processor)) as Task; }, processor)) as GenericTask<IParameters>;

@ -5,24 +5,29 @@ import { readFile, writeFile } from "fs";
import * as glob from "glob"; import * as glob from "glob";
import { join } from "path"; 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 flagDoneName = "dotnetrewriterDone";
const processAssemblyInfo = (params, processor: TaskProcessor, appendInformationalVersion: boolean) => (originalContent, cb) => { const processAssemblyInfo = (params: IParameters, processor: TaskProcessor, appendInformationalVersion: boolean) => (originalContent: string, cb: Callback) => {
const processInternalsVisible = (content) => { const processInternalsVisible = (content: string) => {
if (processor.settings.skipCodeSigning || params.skipCodeSigning) { if (processor.settings.skipCodeSigning || params.skipCodeSigning) {
return content; return content;
} }
const publicKey = processor.settings.codeSigningPublicKey; const publicKey = processor.settings.codeSigningPublicKey;
const pattern = /InternalsVisibleTo\s*\(\s*"([\w.]+)"\s*\)/g; 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) { if (!appendInformationalVersion) {
return content; return content;
} }
@ -55,7 +60,7 @@ export default ((params, processor) => () => {
return processor.done(); 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" }), readFile.bind(null, join(processor.context.exported, file), { encoding: "utf8" }),
processAssemblyInfo(params, processor, file.toLowerCase().includes("assemblyinfo.cs")), processAssemblyInfo(params, processor, file.toLowerCase().includes("assemblyinfo.cs")),
writeFile.bind(null, join(processor.context.exported, file)), writeFile.bind(null, join(processor.context.exported, file)),
@ -68,4 +73,4 @@ export default ((params, processor) => () => {
callback(err); callback(err);
})), processor.done); })), processor.done);
}); });
}) as Task; }) as GenericTask<IParameters>;

@ -1,6 +1,12 @@
"use strict"; "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) => () => { export default ((params, processor) => () => {
if (params.error) { if (params.error) {
@ -16,4 +22,4 @@ export default ((params, processor) => () => {
} }
processor.done(); processor.done();
}) as Task; }) as GenericTask<IParameters>;

@ -3,7 +3,7 @@
import { CLIEngine } from "eslint"; import { CLIEngine } from "eslint";
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
const errorSeverity = 2; const errorSeverity = 2;
@ -32,4 +32,4 @@ export default ((params, processor) => () => {
}); });
processor.done(); processor.done();
}) as Task; }) as GenericTask<{ readonly filename: string }>;

@ -2,7 +2,8 @@
import * as glob from "glob"; import * as glob from "glob";
import { Task } from "../types"; import { GenericTask } from "../types";
import parallel from "./parallel";
const flagDoneName = "eslintbrowserallDone"; const flagDoneName = "eslintbrowserallDone";
@ -25,15 +26,12 @@ export default ((params, processor) => () => {
return processor.done(); return processor.done();
} }
return processor.processTask({ return parallel({
params: { tasks: files.filter((file) => !excludeFiles.includes(file)).map((file) => ({
tasks: files.filter((file) => !excludeFiles.includes(file)).map((file) => ({ name: file,
name: file, params: { filename: file },
params: { filename: file }, type: "eslintbrowser",
type: "eslintbrowser", })),
})), }, processor)();
},
type: (params.preventParallelTests && "sequential") || "parallel",
}, processor.done);
}); });
}) as Task; }) as GenericTask<{ readonly excludeFiles?: string[] }>;

@ -1,5 +1,5 @@
"use strict"; "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<{}>;

@ -1,16 +1,26 @@
"use strict"; "use strict";
import { Task } from "../types"; import { GenericTask } from "../types";
import sequential from "./sequential"; import sequential from "./sequential";
interface IParameters {
readonly eslintExcludeFiles: boolean;
}
export default ((params, processor) => sequential({ export default ((params, processor) => sequential({
tasks: [ tasks: [
{ {
params: { excludeFiles: params.eslintExcludeFiles }, params: { excludeFiles: params.eslintExcludeFiles },
type: "eslintbrowserall", type: "eslintbrowserall",
}, },
{ type: "uglifyjsall" }, {
{ type: "cssnanoall" }, params: { },
type: "uglifyjsall",
},
{
params: { },
type: "cssnanoall",
},
{ {
params: { params: {
data: processor.context.versionInfo, data: processor.context.versionInfo,
@ -26,4 +36,4 @@ export default ((params, processor) => sequential({
type: "zip", type: "zip",
}, },
], ],
}, processor)) as Task; }, processor)) as GenericTask<IParameters>;

@ -2,8 +2,12 @@
import { parallel } from "async"; 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<IParameters>;

@ -2,8 +2,12 @@
import { series } from "async"; 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<IParameters>;

@ -4,7 +4,7 @@ import { writeFile } from "fs";
import { join, normalize } from "path"; import { join, normalize } from "path";
import { minify } from "uglify-js"; import { minify } from "uglify-js";
import { Task } from "../types"; import { GenericTask } from "../types";
export default ((params, processor) => () => { export default ((params, processor) => () => {
const filePath = normalize(join(processor.context.exported, params.filename)); const filePath = normalize(join(processor.context.exported, params.filename));
@ -19,4 +19,4 @@ export default ((params, processor) => () => {
processor.done(); processor.done();
}); });
}) as Task; }) as GenericTask<{ readonly filename: string }>;

@ -2,11 +2,12 @@
import * as glob from "glob"; import * as glob from "glob";
import { Task } from "../types"; import { GenericTask } from "../types";
import parallel from "./parallel";
const doneFlagName = "uglifyjsallDone"; const doneFlagName = "uglifyjsallDone";
export default ((params, processor) => () => { export default ((_params, processor) => () => {
if (processor.context.containsFlag(doneFlagName)) { if (processor.context.containsFlag(doneFlagName)) {
processor.onWarn("dotnetnunitall task is executed more than once; this is probably a bug in your mbs.json"); 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.done();
} }
return processor.processTask({ return parallel({
params: { tasks: files.map((file) => ({
tasks: files.map((file) => ({ name: file,
name: file, params: { filename: file },
params: { filename: file }, type: "uglifyjs",
type: "uglifyjs", })),
})), }, processor)();
},
type: (params.preventParallelTests && "sequential") || "parallel",
}, processor.done);
}); });
}) as Task; }) as GenericTask<{}>;

@ -3,7 +3,12 @@
import { writeFile } from "fs"; import { writeFile } from "fs";
import { join } from "path"; import { join } from "path";
import { Task } from "../types"; import { GenericTask } from "../types";
interface IParameters {
readonly data: string;
readonly filename: string;
}
export default ((params, processor) => () => { export default ((params, processor) => () => {
const filePath = join(processor.context.exported, params.filename); const filePath = join(processor.context.exported, params.filename);
@ -19,4 +24,4 @@ export default ((params, processor) => () => {
return processor.done(); return processor.done();
}); });
}) as Task; }) as GenericTask<IParameters>;

@ -4,7 +4,12 @@ import { create as createArchiver } from "archiver";
import { createWriteStream } from "fs"; import { createWriteStream } from "fs";
import { join, normalize } from "path"; 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) => () => { export default ((params, processor) => () => {
const sourceDirectoryPath = normalize(join(processor.context.exported, String(params.directory || ""))); const sourceDirectoryPath = normalize(join(processor.context.exported, String(params.directory || "")));
@ -17,8 +22,8 @@ export default ((params, processor) => () => {
output.on("close", processor.done); 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.pipe(output);
archive.directory(sourceDirectoryPath, false); archive.directory(sourceDirectoryPath, false);
archive.finalize(); archive.finalize();
}) as Task; }) as GenericTask<IParameters>;

@ -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<IResult>;
}

@ -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[] };
}
}

@ -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;
}

@ -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;
}

@ -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<Tree>;
public getTree(): Promise<Tree>;
}
export class Remote {
public static create(repo: Repository, name: string, url: string): Promise<Remote>;
public fetch(refSpecs: string[]): Promise<number>;
}
export class Repository {
public static init(path: string, is_bare: number): Promise<Repository>;
public getCommit(oid: string): Promise<Commit>;
public free(): void;
}
export class Tree {
public entries(): TreeEntry[];
}
export class TreeEntry {
public getBlob(callback: (err: any, blob?: Blob) => void): Promise<Tree>;
public getTree(callback: (err: any, treeContent?: Tree) => void): Promise<Tree>;
public isFile(): boolean;
public isTree(): boolean;
public name(): string;
}
}

@ -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;
}
}

@ -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;

@ -1,8 +1,12 @@
import * as BuilderTypes from "./dotnetbuilder-types";
import * as GithubTypes from "./github-types"; import * as GithubTypes from "./github-types";
import * as ReportTypes from "./report-types"; import * as ReportTypes from "./report-types";
import * as SettingsTypes from "./settings-types"; import * as SettingsTypes from "./settings-types";
import * as TaskProcessorTypes from "./task-processor-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 HookPushPayload = GithubTypes.IHookPushPayload;
export type HookPullRequestPayload = GithubTypes.IHookPullRequestPayload; export type HookPullRequestPayload = GithubTypes.IHookPullRequestPayload;
export type HookParameters = GithubTypes.HookParameters; export type HookParameters = GithubTypes.HookParameters;
@ -16,6 +20,7 @@ export type ReportResult = ReportTypes.IReportResult;
export type Settings = SettingsTypes.Settings; export type Settings = SettingsTypes.Settings;
export type ProcessTaskContext = TaskProcessorTypes.IProcessTaskContext; export type ProcessTaskContext = TaskProcessorTypes.IProcessTaskContext;
export type GenericTask<TParams> = TaskProcessorTypes.GenericTask<TParams>;
export type Task = TaskProcessorTypes.Task; export type Task = TaskProcessorTypes.Task;
export type TaskInfo = TaskProcessorTypes.ITaskInfo; export type TaskInfo = TaskProcessorTypes.ITaskInfo;
export type TaskProcessor = TaskProcessorTypes.ITaskProcessor; export type TaskProcessor = TaskProcessorTypes.ITaskProcessor;

@ -7,20 +7,20 @@ type IPartialMessageLeafContent = string[];
type IPartialMessageRootContent = IMessage[]; type IPartialMessageRootContent = IMessage[];
interface IPartialMessagesLeaf { interface IPartialMessagesLeaf {
readonly $messages?: string[]; $messages?: string[];
} }
// workaround for compatibility with PartialMessagesLeaf and PartialMessagesRoot // workaround for compatibility with PartialMessagesLeaf and PartialMessagesRoot
interface IPartialMessagesRecursive { interface IPartialMessagesRecursive {
readonly [propName: string]: Messages | IPartialMessageLeafContent; [propName: string]: Messages | IPartialMessageLeafContent;
} }
interface IPartialMessagesRecursiveRoot { interface IPartialMessagesRecursiveRoot {
readonly [propName: string]: Messages | IPartialMessageRootContent | IPartialMessageLeafContent; [propName: string]: Messages | IPartialMessageRootContent | IPartialMessageLeafContent;
} }
interface IPartialMessagesRoot { interface IPartialMessagesRoot {
readonly $allMessages: IPartialMessageRootContent; $allMessages: IPartialMessageRootContent;
} }
export type Messages = IPartialMessagesRecursive & IPartialMessagesLeaf; export type Messages = IPartialMessagesRecursive & IPartialMessagesLeaf;

@ -31,13 +31,19 @@ export interface ITaskProcessor extends ITaskProcessorCore {
readonly done: () => void; readonly done: () => void;
} }
interface ITaskParameters {
readonly [paramName: string]: any;
}
export interface ITaskInfo { export interface ITaskInfo {
readonly name?: string; readonly name?: string;
readonly type: string; readonly type: string;
readonly params: any; readonly params: ITaskParameters;
} }
export type Task = (params: any, processor: ITaskProcessor) => () => void; export type GenericTask<TParams> = (params: TParams, processor: ITaskProcessor) => () => void;
export type Task = GenericTask<ITaskParameters>;
export interface ITasks { export interface ITasks {
readonly [taskName: string]: Task; readonly [taskName: string]: Task;

@ -26,7 +26,7 @@
"morgan": "^1.7.0", "morgan": "^1.7.0",
"mustache": "~2.3.0", "mustache": "~2.3.0",
"nodegit": "~0.16.0", "nodegit": "~0.16.0",
"recursive-tree-copy": "0.0.1", "recursive-tree-copy": "0.0.2",
"serve-favicon": "^2.3.2", "serve-favicon": "^2.3.2",
"serve-static": "^1.11.1", "serve-static": "^1.11.1",
"stream-buffers": "^3.0.1", "stream-buffers": "^3.0.1",
@ -53,6 +53,6 @@
"@types/underscore": "^1.7.36", "@types/underscore": "^1.7.36",
"tslint": "^4.4.2", "tslint": "^4.4.2",
"tslint-eslint-rules": "^3.4.0", "tslint-eslint-rules": "^3.4.0",
"typescript": "^2.2.1" "typescript": "^2.2.2"
} }
} }

@ -4,7 +4,15 @@
"target": "es6", "target": "es6",
"alwaysStrict": true, "alwaysStrict": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"lib": [
"dom",
"es6",
"dom.iterable",
"scripthost",
"es7"
],
"noEmitOnError": true, "noEmitOnError": true,
"noImplicitAny": true,
"noImplicitReturns": true, "noImplicitReturns": true,
"noImplicitThis": true, "noImplicitThis": true,
"noUnusedLocals": true, "noUnusedLocals": true,
@ -16,8 +24,7 @@
}, },
"include": [ "include": [
"*.ts", "*.ts",
"lib/**/*.ts", "lib/**/*.ts"
"routes/**/*.ts"
], ],
"exclude": [ "exclude": [
"node_modules/**/*.ts" "node_modules/**/*.ts"

Loading…
Cancel
Save