مرحبا بالجميع اسمي ايليا. أعمل في مجال تكنولوجيا المعلومات منذ حوالي 6 سنوات ، آخر سنتين - في شركة Yandex.Money كمطور أمامي. تشمل المسؤوليات صيانة / تطوير أجزاء من التطبيقات ، في الوقت الحالي مشروع "حسابي" (ولا ، ليس فقط "تصحيح المسافة البادئة الخاطئة" أو "تغيير لون الزر" أو "تبديل الشكل بسرعة").
في قسم التطوير ، لدينا مشروع تحديات داخلية - نسمي المهام التي لا تتعلق مباشرة بالمنتجات الرئيسية. هذه هي المهام التي ستكون مفيدة اجتماعيًا وستساعد على تحسين البنية التحتية و CI / CD والمزيد. على سبيل المثال ، لتنقيح برنامج التتبُّع الذي يخطر بالإصدارات ، أنشئ مكونًا إضافيًا لـ IDEA للتأكيد التلقائي حسب الكائن ، وأعد إنشاء مكتبة واجهة المستخدم القديمة. يمكن أخذ هذه "التحديات" حسب الرغبة - فهي رائعة لتخفيف مهام العمل.
في وقت ما ، أخذت منذ وقت طويل أنني كنت مهتمًا بمهمة تنفيذ التحقق التلقائي من حجم حزمة العميل للتطبيق. بعد كل شيء ، من الأفضل التحقق تلقائيًا من كل ما يمكن فحصه تلقائيًا.
بطبيعة الحال ، لم تكن النتيجة مجرد مهمة تنفيذية محددة ، ولكن مكتبة بها قواعد ووظائف عامة (أساسية / أساسية) لتنفيذ أي لعبة الداما (آمل). في عملية حل المشكلة ، كانت المخاريط مليئة وأريد أيضًا التحدث عنها.
لذلك ، هناك Jenkins ، Bitbucket ، mail (أو Telegram ، Slack - ما تحتاجه) والحاجة إلى التحقق من حجم الحزمة. نحن بحاجة إلى تكوين كل هؤلاء الأصدقاء.

هناك نوعان من عمليات الفحص التلقائية في Bitbucket لكل طلب سحب ، والتي بدونها يتعذر الدمج: يتم نقل المهمة في Jira إلى حالة "التحقق" ، ويتم بدء جميع عمليات الفحص التلقائي في Jenkins وإكمالها بنجاح. علاوة على ذلك ، وفقًا للخطاف الذي تم تكوينه في Bitbucket ، يتلقى Jenkins إشعارات حول تغيير الفرع الذي تم إطلاق حزمة الشيكات بالكامل من أجله. الوظيفة مع الشيك (comm_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.