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

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

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

@ -5,7 +5,19 @@ import { Remote, Repository } from "nodegit";
import { gitToFs } from "./copy";
const fixUrl = (url) => {
interface IOptions {
readonly branch: string;
readonly exported: string;
readonly hash: string;
readonly local: string;
readonly remote: string;
}
interface ISimpleCallback {
(err?: any): void;
}
const fixUrl = (url: string) => {
if (!url.startsWith("https://")) {
return url;
}
@ -13,17 +25,7 @@ const fixUrl = (url) => {
return `git://${url.substr("https://".length)}`;
};
/* Example:
options = {
"remote": "https://github.com/visionmedia/express.git",
"local": "D:\\data\\repositories\\visionmedia\\express.git\\",
"branch": "1.x",
"hash": "82e15cf321fccf3215068814d1ea1aeb3581ddb3",
"exported": "D:\\data\\exportedsource\\visionmedia\\express\\82e15cf321fccf3215068814d1ea1aeb3581ddb3\\",
}
*/
export const gitLoader = (options, globalCallback) => {
export const gitLoader = (options: IOptions, globalCallback: ISimpleCallback) => {
const url = fixUrl(options.remote);
const path = `${options.local}/${options.hash}`;
const exported = options.exported;
@ -33,30 +35,34 @@ export const gitLoader = (options, globalCallback) => {
console.log(`Cloning ${url} to ${path}`);
Repository.init(path, 1)
.catch(globalCallback)
.then((repo) => Remote.create(repo, "origin", url)
.catch(globalCallback)
.then((remote) => remote.fetch([options.branch])
.catch(globalCallback)
.then((errorNumber) => {
Repository.init(path, 1).then(
(repo) => Remote.create(repo, "origin", url).then(
(remote) => remote.fetch([options.branch]).then(
(errorNumber) => {
if (errorNumber) {
return globalCallback(`Failed to fetch commit: error number ${errorNumber}`);
}
console.log(`Cloned ${url} to ${path}`);
return repo.getCommit(options.hash)
.catch(globalCallback)
.then((commit) => {
return repo.getCommit(options.hash).then(
(commit) => {
removeSync(exported);
mkdirsSync(exported);
gitToFs(commit, exported, (err, result) => {
gitToFs(commit, exported, (err) => {
repo.free();
return globalCallback(err, result);
return globalCallback(err);
});
});
})));
},
globalCallback,
);
},
globalCallback,
),
globalCallback,
),
globalCallback,
);
};

@ -33,15 +33,17 @@ interface IStatusData {
interface IGithub {
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;
};
readonly repos: {
createStatus(params: RawGithub.ReposCreateStatusParams, callback: ICallback<IStatusData>);
getReleases(params: RawGithub.ReposGetReleasesParams, callback: ICallback<IReleaseData[]>);
createStatus(params: RawGithub.ReposCreateStatusParams, callback: ICallback<IStatusData>): void;
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 {
IGithub,

@ -1,7 +1,15 @@
"use strict";
export const send = (message, callback) => {
interface IMessage {
from: string;
headers: { [headerName: string]: any };
subject: string;
text: string;
to: string;
}
export const send = (message: IMessage, callback: () => void) => {
console.log("Mail sender is not implemented");
console.log(message.title);
console.log(message.subject);
process.nextTick(callback);
};

@ -10,6 +10,24 @@ import { createGunzip, createGzip } from "zlib";
import { Message, Report, ReportResult, Settings } from "./types";
interface IOptions {
readonly branch: string;
readonly branchName: string;
readonly owner: string;
readonly reponame: string;
readonly rev: string;
}
interface IOptionsWithReport extends IOptions {
readonly files: string[];
readonly report: Report;
}
interface IGetStatusOptions extends IOptions {
readonly attemptsGetReport?: number;
readonly onTenthAttempt: () => void;
}
const reportFilename = "report.json.gz";
const maxAttemptsNumber = 100;
const attemptsTimeout = 30000;
@ -26,7 +44,7 @@ const getAllErrors = (report: Report): Message[] => (report.result && report.res
const getAllWarns = (report: Report): Message[] => (report.result && report.result.warns && report.result.errors.$allMessages) || [];
const getAllInfos = (report: Report): Message[] => (report.result && report.result.infos && report.result.errors.$allMessages) || [];
export const writeReport = (releaseDir, err, result: ReportResult | undefined, callback) => {
export const writeReport = (releaseDir: string, err: string | null, result: ReportResult | undefined, callback: (err?: string) => void) => {
const data = JSON.stringify({
date: Date.now(),
err,
@ -51,7 +69,7 @@ export const writeReport = (releaseDir, err, result: ReportResult | undefined, c
readable.stop();
};
export const readReport = (releaseDir, callback) => {
export const readReport = (releaseDir: string, callback: (err: string | null, report?: Report) => void) => {
const readStream = createReadStream(join(releaseDir, reportFilename));
const writable = new WritableStreamBuffer();
@ -78,7 +96,7 @@ export const readReport = (releaseDir, callback) => {
});
};
export const loadReport = (settings: Settings, options, callback) => {
export const loadReport = (settings: Settings, options: IOptions, callback: (err: Error | string | null, result?: IOptionsWithReport) => void) => {
const releaseDir = join(settings.releasepath, options.owner, options.reponame, options.branch, options.rev);
glob("**", {
@ -86,22 +104,19 @@ export const loadReport = (settings: Settings, options, callback) => {
mark: true,
}, (err, files) => {
if (err) {
return callback(err, options);
return callback(err);
}
const reportFile = join(releaseDir, reportFilename);
return exists(reportFile, (reportFileExists) => {
if (!reportFileExists) {
return callback("ReportFileNotFound", options);
return callback("ReportFileNotFound");
}
return readReport(releaseDir, (readErr, report) => {
if (readErr) {
return callback(readErr, {
...options,
files,
});
if (readErr || !report) {
return callback(readErr);
}
return callback(null, {
@ -114,7 +129,7 @@ export const loadReport = (settings: Settings, options, callback) => {
});
};
export const getStatusMessageFromRelease = (settings: Settings, originalOptions, callback) => {
export const getStatusMessageFromRelease = (settings: Settings, originalOptions: IGetStatusOptions, callback: (err: string | null, statusMessage?: string) => void) => {
const options = {
...originalOptions,
attemptsGetReport: (Number(originalOptions.attemptsGetReport) || Number()) + 1,
@ -143,11 +158,11 @@ export const getStatusMessageFromRelease = (settings: Settings, originalOptions,
}
return setTimeout(() => readReport(releaseDir, (readErr, report) => {
if (readErr) {
if (readErr || !report) {
return callback(readErr);
}
if (report.result === "MBSNotFound") {
if (report.err === "MBSNotFound") {
return callback("mbs.json is not found");
}

@ -4,6 +4,7 @@ import * as express from "express";
import { build } from "../builder";
import { getSettings } from "../settings-wrapper";
import { ReportResult } from "../types";
export const get: express.RequestHandler = (_req, res) => res.render("manual");
@ -15,7 +16,7 @@ export const post: express.RequestHandler = (req, res) => {
url: `https://pos-github.payonline.ru/${req.body.owner}/${req.body.reponame}`,
};
build(settings, options, (err, result) => {
build(settings, options, (err: string, result: ReportResult) => {
console.log("Done processing manual request");
console.log(`Error: ${err}`);
res.render("manual-done", {

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

@ -6,14 +6,15 @@ import { join } from "path";
import { readReport } from "../report-processor";
import { getSettings } from "../settings-wrapper";
import { Report } from "../types";
const getDatePart = (report) => {
const getDatePart = (report: Report) => {
if (!report.date) {
return "unknowndate";
}
const date = new Date(report.date);
const paddingLeft = (str, paddingValue) => String(paddingValue + str).slice(-paddingValue.length);
const paddingLeft = (str: string | number, paddingValue: string) => String(paddingValue + str).slice(-paddingValue.length);
const year = date.getFullYear();
const month = paddingLeft(date.getMonth() + 1, "00");
@ -37,7 +38,7 @@ export default ((req, res, next) => {
const releasePath = join(getSettings(req.app).releasepath, options.owner, options.reponame, options.branch, options.rev);
readReport(releasePath, (err, report) => {
if (err) {
if (err || !report) {
return next(err);
}

@ -5,13 +5,25 @@ import { parse } from "url";
import { getSettings } from "../settings-wrapper";
import { getReport } from "../status-processor";
import { Report } from "../types";
const parseOptionsFromReferer = (path, callback) => {
interface IOptions {
readonly branchName: string;
readonly owner: string;
readonly reponame: string;
readonly rev: string;
}
interface IOptionsWithReport extends IOptions {
readonly report: Report;
}
const parseOptionsFromReferer = (path: string, callback: (err: string | null, options?: IOptions) => void) => {
const pathParts = path.split("/").filter((value) => value);
const [, secondPart, thirdPart] = pathParts;
if (!secondPart) {
return callback("BadRequest", {});
return callback("BadRequest");
}
if (thirdPart === "tree") {
@ -35,7 +47,7 @@ const parseOptionsFromReferer = (path, callback) => {
});
};
const createShowReport = (res: express.Response) => (err, inputOptions) => {
const createShowReport = (res: express.Response) => (err: string | null, inputOptions: IOptions | undefined) => {
const options = {
...inputOptions || {},
err,
@ -45,31 +57,33 @@ const createShowReport = (res: express.Response) => (err, inputOptions) => {
};
export const image: express.RequestHandler = (req, res) => {
const getAdditionalOptions = (err, options) => {
const getAdditionalOptions = (err: string | null, options?: IOptionsWithReport) => {
if (err === "ReportFileNotFound") {
return { status: "Building" };
}
if (err) {
if (err || !options) {
return {
message: err,
status: "StatusError",
};
}
if (options.report.result === "MBSNotFound") {
if (options.report.err === "MBSNotFound") {
return { status: "MBSNotUsed" };
}
if (options.report.err) {
if (options.report.err || !options.report.result) {
return {
message: options.report.err,
status: "Error",
};
}
if ((options.report.result.warns.$allMessages || []).length) {
const [firstWarn] = options.report.result.warns.$allMessages;
const result = options.report.result;
if ((result.warns.$allMessages || []).length) {
const [firstWarn] = result.warns.$allMessages;
return {
message: firstWarn.message,
@ -77,7 +91,7 @@ export const image: express.RequestHandler = (req, res) => {
};
}
const allInfos = options.report.result.infos.$allMessages || [];
const allInfos = result.infos.$allMessages || [];
if (allInfos.length) {
return {
@ -89,7 +103,7 @@ export const image: express.RequestHandler = (req, res) => {
return { status: "OK" };
};
const handle = (err, options) => {
const handle = (err: string | null, options?: IOptionsWithReport) => {
res.setHeader("Content-Type", "image/svg+xml");
res.render("status-image", {
...options,
@ -97,9 +111,9 @@ export const image: express.RequestHandler = (req, res) => {
});
};
parseOptionsFromReferer(parse(req.headers.referer || "").pathname || "", (err, options) => {
parseOptionsFromReferer(parse(req.headers.referer || "").pathname || "", (err: string | null, options: IOptions) => {
if (err) {
return handle(err, options);
return handle(err);
}
return getReport(getSettings(req.app), options, handle);
@ -119,7 +133,7 @@ export const page: express.RequestHandler = (req, res) => {
};
export const pageFromGithub: express.RequestHandler = (req, res) => parseOptionsFromReferer(req.params[0], (err, options) => {
if (err) {
if (err || !options) {
return createShowReport(res)(err, options);
}

@ -1,10 +1,12 @@
"use strict";
import * as express from "express";
import { Settings } from "./types";
const getSettings = (app): Settings => app.get("mbsSettings");
const getSettings = (app: express.Application): Settings => app.get("mbsSettings");
const setSettings = (app, settings: Settings) => app.set("mbsSettings", settings);
const setSettings = (app: express.Application, settings: Settings) => app.set("mbsSettings", settings);
export {
getSettings,

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

@ -1,24 +1,28 @@
"use strict";
import tasks from "./tasks";
import { MessagesRoot, ProcessTaskContext, Settings, TaskInfo, TaskProcessor, TaskProcessorCallback, TaskProcessorCore } from "./types";
import { Messages, MessagesRoot, ProcessTaskContext, ReportResult, Settings, TaskInfo, TaskProcessor, TaskProcessorCallback, TaskProcessorCore } from "./types";
interface IFlags {
[flagName: string]: boolean;
}
// TaskProcessor does not look like EventEmitter, so no need to extend EventEmitter and use `emit' here.
const createTaskProcessor = (task: TaskInfo, outerProcessor: TaskProcessorCore, callback: TaskProcessorCallback) => {
const errors: string[] = [];
const getOuterPrefix = (prefix) => {
const getOuterPrefix = (prefix?: string) => {
if (task.name && prefix) {
return `${task.name}/${prefix}`;
}
return String(task.name || "") + String(prefix || "");
};
const onError = (message, prefix) => {
const onError = (message: string, prefix?: string) => {
errors.push(message);
outerProcessor.onError(message, getOuterPrefix(prefix));
};
const onWarn = (message, prefix) => outerProcessor.onWarn(message, getOuterPrefix(prefix));
const onInfo = (message, prefix) => outerProcessor.onInfo(message, getOuterPrefix(prefix));
const onWarn = (message: string, prefix?: string) => outerProcessor.onWarn(message, getOuterPrefix(prefix));
const onInfo = (message: string, prefix?: string) => outerProcessor.onInfo(message, getOuterPrefix(prefix));
let result: TaskProcessor;
result = {
@ -35,47 +39,50 @@ const createTaskProcessor = (task: TaskInfo, outerProcessor: TaskProcessorCore,
return result;
};
const pushMessage = (list, message, parts, index) => {
if (!index) {
list.$allMessages.push({
message,
prefix: parts.join("/"),
});
}
const pushMessage = (list: Messages, message: string, parts: string[], index: number): void => {
if (index < parts.length) {
if (!list[parts[index]]) {
list[parts[index]] = {};
}
return pushMessage(list[parts[index]], message, parts, index + 1);
return pushMessage(list[parts[index]] as Messages, message, parts, index + 1);
}
if (!list.$messages) {
list.$messages = [];
}
return list.$messages.push(message);
list.$messages.push(message);
return;
};
const pushMessageRoot = (list: MessagesRoot, message: string, parts: string[]): void => {
list.$allMessages.push({
message,
prefix: parts.join("/"),
});
pushMessage((list as any) as Messages, message, parts, 0);
};
const addFlag = (flags) => (flagName) => {
const addFlag = (flags: IFlags) => (flagName: string) => {
flags[flagName] = true;
};
const containsFlag = (flags) => (flagName) => flags[flagName];
const containsFlag = (flags: IFlags) => (flagName: string) => flags[flagName];
export const processTask = (settings: Settings, task, context: ProcessTaskContext, callback) => {
export const processTask = (settings: Settings, task: TaskInfo, context: ProcessTaskContext, callback: (err: any, result: ReportResult) => void) => {
const errors: MessagesRoot = { $allMessages: [] };
const warns: MessagesRoot = { $allMessages: [] };
const infos: MessagesRoot = { $allMessages: [] };
const messages: MessagesRoot = { $allMessages: [] };
const messageProcessor = (list) => (message, prefix) => {
const messageProcessor = (list: MessagesRoot) => (message: string, prefix: string) => {
const parts = prefix.split("/");
pushMessage(list, message, parts, 0);
pushMessage(messages, message, parts, 0);
pushMessageRoot(list, message, parts);
pushMessageRoot(messages, message, parts);
};
const flags = {};
const flags: IFlags = {};
const processor = createTaskProcessor(task, {
context: {
...context,

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

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

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

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

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

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

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

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

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

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

@ -1,9 +1,19 @@
"use strict";
import { Task } from "../types";
import { GenericTask } from "../types";
import sequential from "./sequential";
const createTasks = function *(params) {
interface IParameters {
readonly skipMbsCheckStyle?: boolean;
readonly forceCodeAnalysis?: boolean;
readonly ignoreCodeAnalysis?: boolean;
readonly skipCodeSigning?: boolean;
readonly skipNugetRestore?: boolean;
readonly configuration: string;
readonly solution: string;
}
const createTasks = function *(params: IParameters) {
if (!params.skipMbsCheckStyle) {
yield {
params,
@ -40,4 +50,4 @@ export default ((params, processor) => {
const tasks = Array.from(createTasks(params));
return sequential({ tasks }, processor);
}) as Task;
}) as GenericTask<IParameters>;

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

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

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

@ -1,8 +1,16 @@
"use strict";
import { Task } from "../types";
import { GenericTask } from "../types";
import conditional from "./conditional";
interface IParameters {
readonly major: string;
readonly nuspecName: string;
readonly version: string;
readonly withoutCommitSha: boolean;
readonly masterRepoOwner: string;
}
export default ((params, processor) => conditional({
branch: "master",
otherwise: {
@ -28,4 +36,4 @@ export default ((params, processor) => conditional({
},
type: "dotnetnugetpush",
},
}, processor)) as Task;
}, processor)) as GenericTask<IParameters>;

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

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

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

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

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

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

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

@ -5,24 +5,29 @@ import { readFile, writeFile } from "fs";
import * as glob from "glob";
import { join } from "path";
import { Task, TaskProcessor } from "../types";
import { GenericTask, TaskProcessor } from "../types";
interface IParameters {
readonly skipCodeSigning: boolean;
}
type Callback = (err?: any, result?: string) => void;
const flagDoneName = "dotnetrewriterDone";
const processAssemblyInfo = (params, processor: TaskProcessor, appendInformationalVersion: boolean) => (originalContent, cb) => {
const processInternalsVisible = (content) => {
const processAssemblyInfo = (params: IParameters, processor: TaskProcessor, appendInformationalVersion: boolean) => (originalContent: string, cb: Callback) => {
const processInternalsVisible = (content: string) => {
if (processor.settings.skipCodeSigning || params.skipCodeSigning) {
return content;
}
const publicKey = processor.settings.codeSigningPublicKey;
const pattern = /InternalsVisibleTo\s*\(\s*"([\w.]+)"\s*\)/g;
const replacer = (_match, p1) => `InternalsVisibleTo("${p1},PublicKey=${publicKey}")`;
return content.replace(pattern, replacer);
return content.replace(pattern, (_match, p1) => `InternalsVisibleTo("${p1},PublicKey=${publicKey}")`);
};
const processInformationalVersion = (content) => {
const processInformationalVersion = (content: string) => {
if (!appendInformationalVersion) {
return content;
}
@ -55,7 +60,7 @@ export default ((params, processor) => () => {
return processor.done();
}
return parallel(files.map((file) => (callback) => waterfall([
return parallel(files.map((file) => (callback: Callback) => waterfall([
readFile.bind(null, join(processor.context.exported, file), { encoding: "utf8" }),
processAssemblyInfo(params, processor, file.toLowerCase().includes("assemblyinfo.cs")),
writeFile.bind(null, join(processor.context.exported, file)),
@ -68,4 +73,4 @@ export default ((params, processor) => () => {
callback(err);
})), processor.done);
});
}) as Task;
}) as GenericTask<IParameters>;

@ -1,6 +1,12 @@
"use strict";
import { Task } from "../types";
import { GenericTask } from "../types";
interface IParameters {
readonly error: string;
readonly warn: string;
readonly info: string;
}
export default ((params, processor) => () => {
if (params.error) {
@ -16,4 +22,4 @@ export default ((params, processor) => () => {
}
processor.done();
}) as Task;
}) as GenericTask<IParameters>;

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

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

@ -1,5 +1,5 @@
"use strict";
import { Task } from "../types";
import { GenericTask } from "../types";
export default ((_params, processor) => processor.done()) as Task;
export default ((_params, processor) => processor.done) as GenericTask<{}>;

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

@ -2,8 +2,12 @@
import { parallel } from "async";
import { Task, TaskProcessor } from "../types";
import { GenericTask, TaskInfo, TaskProcessor, TaskProcessorCallback } from "../types";
const mapper = (processor: TaskProcessor) => (task) => (callback) => processor.processTask(task, callback);
interface IParameters {
tasks: TaskInfo[];
};
export default ((params, processor) => () => parallel(params.tasks.map(mapper(processor)), processor.done)) as Task;
const mapper = (processor: TaskProcessor) => (task: TaskInfo) => (callback: TaskProcessorCallback) => processor.processTask(task, callback);
export default ((params, processor) => () => parallel(params.tasks.map(mapper(processor)), processor.done)) as GenericTask<IParameters>;

@ -2,8 +2,12 @@
import { series } from "async";
import { Task, TaskProcessor } from "../types";
import { GenericTask, TaskInfo, TaskProcessor, TaskProcessorCallback } from "../types";
const mapper = (processor: TaskProcessor) => (task) => (callback) => processor.processTask(task, callback);
interface IParameters {
tasks: TaskInfo[];
};
export default ((params, processor) => () => series(params.tasks.map(mapper(processor)), processor.done)) as Task;
const mapper = (processor: TaskProcessor) => (task: TaskInfo) => (callback: TaskProcessorCallback) => processor.processTask(task, callback);
export default ((params, processor) => () => series(params.tasks.map(mapper(processor)), processor.done)) as GenericTask<IParameters>;

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

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

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

@ -4,7 +4,12 @@ import { create as createArchiver } from "archiver";
import { createWriteStream } from "fs";
import { join, normalize } from "path";
import { Task } from "../types";
import { GenericTask } from "../types";
interface IParameters {
readonly directory?: string;
readonly archive: string;
}
export default ((params, processor) => () => {
const sourceDirectoryPath = normalize(join(processor.context.exported, String(params.directory || "")));
@ -17,8 +22,8 @@ export default ((params, processor) => () => {
output.on("close", processor.done);
archive.on("error", (err) => processor.onError(`Error while compressing: ${err}`));
archive.on("error", (err: any) => processor.onError(`Error while compressing: ${err}`));
archive.pipe(output);
archive.directory(sourceDirectoryPath, false);
archive.finalize();
}) as Task;
}) as GenericTask<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 ReportTypes from "./report-types";
import * as SettingsTypes from "./settings-types";
import * as TaskProcessorTypes from "./task-processor-types";
export type BuilderCompileRequest = BuilderTypes.ICompileRequest;
export type BuilderRequest = BuilderTypes.Request;
export type HookPushPayload = GithubTypes.IHookPushPayload;
export type HookPullRequestPayload = GithubTypes.IHookPullRequestPayload;
export type HookParameters = GithubTypes.HookParameters;
@ -16,6 +20,7 @@ export type ReportResult = ReportTypes.IReportResult;
export type Settings = SettingsTypes.Settings;
export type ProcessTaskContext = TaskProcessorTypes.IProcessTaskContext;
export type GenericTask<TParams> = TaskProcessorTypes.GenericTask<TParams>;
export type Task = TaskProcessorTypes.Task;
export type TaskInfo = TaskProcessorTypes.ITaskInfo;
export type TaskProcessor = TaskProcessorTypes.ITaskProcessor;

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

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

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

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

Loading…
Cancel
Save