大家好,我叫伊利亚。我已经在IT部门工作了大约6年,最近2年-在Yandex.Money公司担任前端开发人员。职责包括在“我的帐户”项目中维护/开发应用程序的各个部分(不,它不只是“纠正错误的缩进”,“更改按钮的颜色”或“快速交换形状”)。
在开发部门,我们有一个内部的Challenges项目-我们称与主要产品没有直接关系的任务。这些都是对社会有用的任务,将有助于改善基础架构,CI / CD等。例如,要完善通知发布的漫游器,请为IDEA制作一个插件,以按对象自动生成断言并重构旧的UI库。这样的“挑战”可以随意采取-它们非常适合稀释业务任务。
有一次,我花了很长时间才对实现客户端捆绑软件应用程序大小的自动验证这一任务感兴趣。毕竟,可以自动检查的所有内容最好自动检查。
自然,结果不仅是一个特定的已实现任务,而且是一个具有规则和通用功能(核心/核心)的库,用于实现任何检查程序(我希望)。在解决问题的过程中,我也想谈谈锥体。
因此,有詹金斯(Jenkins),比特桶(Bitbucket),邮件(或电报,Slack-您需要什么)以及需要检查捆绑包的大小。我们需要结交所有这些朋友。

Bitbucket中的每个拉取请求都有2个自动检查,没有合并是不可能的:Jira中的任务被转移到“已验证”状态,并且Jenkins中的所有自动检查都已成功启动和完成。此外,根据Bitbucket中配置的挂钩,詹金斯会收到有关分支更改的通知,为此将启动整个检查包。带检查的作业(commit_checker)有很多管道:
- 启动皮棉脚本;
- 运行测试;
- — , pull request , merge build publish Nexus, npm;
- package.json.
, Bitbucket commit_checker. , , . challenge- commit_checker pipeline .
checker- -?
( c)
. , ( ) — pull request. , , . , : , , , , 3 . , ( ). , , merge .
. , , : 600 (, , , - ).
— , , pull request , merge , . .
, ...
, . , , API ( , Telegram). , .
. Jenkins job ( job). groove- , npm- , groove bin . , — , Bitbucket , merge .
, , : groove- node — .
: Groove Node?
, Node.
«, », 3
, . ( , Jira), . , .

, checker-core. , , .
. — : -, /, dist, , . — .
— pull request.
— ? :
- dev/master ( ), - . — .
- / . — , .
- Git , , package.json, API Bitbucket dev/master , . , .
— ?
, , , — . — . , , .
, , BitBucket ( Jenkins package.json). …
, , : «!», , , , .
?

. - , : , - .
. : , , … : « Jenkins? - », — , Jenkins ( ). -> -> -> .
, . , , (, ). , .
(, ) .
size-limit: , , .
. , … !
, roadmap .
, , size-limit , — , . , , API , CLI. . cli- . .
, -, , , .
:
Checker-core
!
/src —
|__ /tasks — ; , , , , . - `job`.
|__ /models — , ; `core`. , , , npm-. `job`, `tasks` , `job,` . , `tasks` `job`.
|__ /types — .
|__ /utils — (, , (npm)).
|__ /errors — , .
|__ /enums — .
|__ /decorators — , `utils`, `tasks`, `job`.
|__ /declarations — , Typescript.
Checker
Checker , . , , ..
Module
Module /, . ( , ..).
get-issue-assignees
. Checker project, assignee, lead.
Examples
import {
Checker,
Logger,
IChecker,
JiraManagerSettings,
GetIssueAssignee
} from 'checker-core';
import {JiraSettings} from 'jira-manager';
import {IJobSettings} from '../types/IJobSettings';
export class ExampleJob {
readonly _checker: IChecker;
_jiraSettings: JiraManagerSettings;
constructor(settings: IJobSettings) {
if (settings === void 0) {
throw new Error('Has no Checker settings');
}
this._checker = new Checker(settings.checker);
this._jiraSettings = new JiraSettings(settings.jira);
Logger.info('-- ExampleJob:');
Logger.info(this._checker.appName);
}
start() {
const getIssueAssignee = new GetIssueAssignee();
return getIssueAssignee.run(this._checker, this._jiraSettings);
}
}
get-last-merged-issue
. Checker .
Examples
import {Checker, Logger, IChecker, GetLastMergedIssue} from 'checker-core';
import {IJobSettings} from '../types/IJobSettings';
export class ExampleJob {
readonly _checker: IChecker;
constructor(settings: IJobSettings) {
if (settings === void 0) {
throw new Error('Has no Checker settings');
}
this._checker = new Checker(settings);
Logger.info('-- ExampleJob:');
Logger.info(this._checker.appName);
}
start() {
const getLastMergedIssue = new GetLastMergedIssue();
return getLastMergedIssue.run(this._checker);
}
}
get-last-commit-issue
. Checker .
Examples
import {Checker, Logger, IChecker, GetLastCommitIssue} from 'checker-core';
import {IJobSettings} from '../types/IJobSettings';
export class ExampleJob {
readonly _checker: IChecker;
constructor(settings: IJobSettings) {
if (settings === void 0) {
throw new Error('Has no Checker settings');
}
this._checker = new Checker(settings);
Logger.info('-- ExampleJob:');
Logger.info(this._checker.appName);
}
start() {
const getLastCommitIssue = new GetLastCommitIssue();
return getLastCommitIssue.run(this._checker);
}
}
send-notification send-smtp-notification
. .
send-notification send-smtp-notification — . smtp- IMailTransportSettings.
Examples
import {
Checker,
Logger,
IChecker,
IMailTransportSettings,
IMailContent,
SendSmtpNotification
} from 'checker-core';
import {IJobSettings} from '../types/IJobSettings';
export class ExampleJob {
readonly _checker: IChecker;
_emailSettings: IMailTransportSettings;
constructor(settings: IJobSettings) {
if (settings === void 0) {
throw new Error('Has no Checker settings');
}
this._checker = new Checker(settings.checker);
this._emailSettings = settings.email;
Logger.info('-- ExampleJob:');
Logger.info(this._checker.appName);
}
start() {
const sendSmtpNotification = new SendSmtpNotification();
const mailContent: IMailContent = {
subject: '',
content: ' , ?'
};
return sendSmtpNotification.run(this._checker, mailContent, this._emailSettings);
}
}
: , .
Logger
.
Npm
Nexus.
mailTransport
( mail linux nodemailer smtp).
Decorators
logAsyncMethod
, .
process.env.IS_DEBUG_MODE , .
validate
. .
Examples
import {
notNullProp, validate, required,
validInfo, notNull, requiredProp
} from 'checker-core';
class TestSum {
@validate
static sum(
@required
@notNull
@requiredProp(['a'])
@notNullProp(['a'])
@validInfo('a', Object)
a: Object,
@required
@notNull
@requiredProp(['b'])
@notNullProp(['b'])
@validInfo('b', Object)
b: Object
) {
return a.a + b.b;
}
}
Errors
MissingRequiredArgument
.
MissingRequiredProperty
, .
NullArgument
, null.
NullProperty
, , null.
TypeMismatch
.
bundle-size-checker
checker-core core, :
/src —
|__ /bin — , CLI , 2 : `job`. , , 1 `process.exit(1)`;
|__ /jobs — , (`checker` + , ), . `task`, `utils`, ;
|__ /tasks — ; , , , , . - `job`;
|__ /models — , , `core`. , , , npm-. `job`, `tasks` , `job`, . , `tasks` `job`;
|__ /types — ;
|__ /utils — (, , (npm));
|__ /errors — , ;
|__ /enums — ;
|__ /decorators — `utils`, `tasks`, `job`;
|__ /declarations — , Typescript.
, job — , , checker-, , , , - , , , ( , ..).
:
import path from 'path';
import {JiraSettings} from 'jira-manager';
import {
Logger,
JiraManagerSettings,
IMailTransportSettings,
MissingRequiredProperty
} from 'checker-core';
import {Module} from '../models/module';
import {CompareBundleSize} from '../tasks/compare-bundle-size';
import {Checker} from '../models';
import {IJobCheckBundleSizeSettings} from '../types/IJobCheckBundleSizeSettings';
import {IModule} from '../types/IModule';
import {IModuleSettings} from '../types/IModuleSettings';
import {GetMetaInfo} from '../tasks/get-meta-info';
import {CheckBundleSizeNotEmpty} from '../tasks/check-bundle-size-not-empty';
import {GetBundleSize} from '../tasks/get-bundle-size';
import {ReadFileError} from '../errors/ReadFileError';
import {IPackageJson} from '../types/IPackageJson';
import {IChecker} from '../types/IChecker';
import {FilterException} from '../tasks/filter-exception';
export class CheckBundleSize {
readonly _checker: IChecker;
readonly _jobName = 'CheckBundleSize';
_moduleSettings: IModuleSettings;
_checkerModule: IModule;
_jiraSettings: JiraManagerSettings;
_emailSettings: IMailTransportSettings;
constructor(settings: IJobCheckBundleSizeSettings) {
if (settings.checker === void 0) {
throw new MissingRequiredProperty(this._jobName, 'constructor', 'settings', 'checker');
}
this._moduleSettings = settings.module;
this._emailSettings = settings.emailSettings;
this._jiraSettings = new JiraSettings(settings.jira);
this._checker = new Checker(settings.checker);
try {
const packageJsonPath = path.resolve(this._checker.rootPath, 'package.json');
const packageJson: IPackageJson = require(packageJsonPath);
this._checkerModule = new Module(
packageJson,
this._moduleSettings.maxBundleSize,
this._moduleSettings.needCheckBundleSize
);
} catch (err) {
Logger.info('Can nott load package.json');
throw new ReadFileError(this._jobName, 'package.json');
}
Logger.info(`${this._jobName}:`);
Logger.info(this._checker.appName);
}
async start() {
try {
const getBundleSizeTask = new GetBundleSize();
const getMetaInfo = new GetMetaInfo();
const checkBundleSizeEmpty = new CheckBundleSizeNotEmpty();
const compareBundleSize = new CompareBundleSize();
const getBundleSize = await getBundleSizeTask.run(this._checker, this._checkerModule);
if (!getBundleSize) {
return;
}
await getMetaInfo.run(this._checker, this._jiraSettings);
await checkBundleSizeEmpty.run(this._checker, this._checkerModule);
await compareBundleSize.run(this._checker, this._checkerModule);
} catch (err) {
const filterException = new FilterException(this._emailSettings);
await filterException.run(this._checker v , this._checkerModule, err);
throw err;
}
}
}
bin , cli .
…
const checkBundleSize = new CheckBundleSize(settings);
checkBundleSize.start()
.then(() => {
process.exit(0);
})
.catch((err: Error) => {
console.error(err);
console.error(`Can fail build: ${canFailBuild}`);
if (canFailBuild) {
process.exit(1);
} else {
process.exit(0);
}
});
/ , , (, , ). , : , , . roadmap . , — .
, .
. : ? , open source.