Tout à la fois: vérification automatique de la taille du lot

Bonjour à tous, je m'appelle Ilya. Je travaille dans l'informatique depuis environ 6 ans, les 2 dernières années - dans la société Yandex.Money en tant que développeur front-end. Les responsabilités incluent la maintenance / le développement de parties des applications, au moment du projet «Mon compte» (et non, ce n'est pas seulement «corriger la mauvaise indentation», «changer la couleur du bouton» ou «échanger rapidement la forme»).


Dans le département de développement, nous avons un projet interne Challenges - nous appelons des tâches qui ne sont pas directement liées aux principaux produits. Ce sont des tâches qui seront socialement utiles et contribueront à améliorer l'infrastructure, le CI / CD et plus encore. Par exemple, pour affiner le bot notifiant les versions, créez un plug-in pour IDEA pour l'auto-génération d'assert par objet et refactorisez l'ancienne bibliothèque d'interface utilisateur. De tels «défis» peuvent être relevés à volonté - ils sont parfaits pour diluer les tâches commerciales.


À un moment donné, j'ai mis longtemps à m'intéresser à la tâche d'implémentation de la vérification automatique de la taille du bundle client de l'application. Après tout, il est préférable de vérifier automatiquement tout ce qui peut être vérifié automatiquement.


Naturellement, le résultat n'était pas seulement une tâche implémentée spécifique, mais une bibliothèque avec des règles et des fonctions générales (core / core) pour implémenter des vérificateurs (j'espère). Dans le processus de résolution du problème, les cônes étaient pleins dont je veux également parler.


Il y a donc Jenkins, Bitbucket, mail (ou Telegram, Slack - ce dont vous avez besoin) et la nécessité de vérifier la taille du bundle. Nous devons nous faire tous ces amis.


image


Il y a 2 vérifications automatiques dans Bitbucket pour chaque demande d'extraction, sans lesquelles la fusion est impossible: la tâche dans Jira est transférée à l'état "Vérifié", et toutes les vérifications automatiques dans Jenkins sont démarrées et terminées avec succès. En outre, selon le hook configuré dans Bitbucket, Jenkins reçoit des notifications sur un changement de branche, pour lequel l'ensemble des chèques est lancé. Le travail avec vérification (commit_checker) a beaucoup de pipeline:


  • lancer le script lint;
  • exĂ©cution de tests;
  • — , 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?


Groove— , - .1. : , JS, // JS, Groove.
2. .
Node1. : , Node.
2. , /.
3. /Jira API/Bitbucket API.
4. -, , [size-limit](https://www.npmjs.com/package/size-limit).
1. Node, Jenkins .
2. API Jenkins /.

, 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.


All Articles