Автоматизируй это.

Гиперавтоматизированный пайплайн

🍄🍄🍄🍄🍄

Aleksei Zolotykh.

Про радость...

Почему я так радуюсь каждому кейсу про беспилотники в суде? Потому что чем быстрее человечество научится решать юридические проблемы беспилотников, тем быстрее беспилотники окажутся на наших улицах.
Природные законы универсальны

💩💩💩 лучше чем 💩

Чем дольше что-то живет, тем больше вероятность, что оно будет жить дальше

Автоматизация

Чем быстрее обратная связь, тем лучше

CI/CD

Continuous Integration / Continuous Delivery

CI/CD

Continuous Integration / Continuous Delivery

💩💩💩 лучше чем 💩

Гитперавтоматизация

Чем быстрее упадед пайплайн, тем лучше
Пайплайн в широком смысле

                    ...
                        <ul class="tab">
                            <li>Login</li>
                            <li>SignUp</li>
                        </ul>
                    ...
                    

                    ...
                        <ul class="tab">
                            <li>{ i18n('Login')}</li>
                            <li>{ i18n('SignUp')}</li>
                        </ul>
                    ...
                    

Eslint.


      JSXText: (node) => {
        context.report({
          node,
          message: 'Text "{{value}}" should be localized',
          data: { value: node.value },
        });
      }
                    

eslint --fix


      JSXText: (node) => {
        context.report({
        ...
          fix: fixer => fixer.replaceText(node, fixI18n(value)),
        ...
        });
      }
                    

describe('test', () => {
    test('should works', () => {
        ...
    });
});
                    

ts - .eslintrc.js


module.exports = {
    parser: "@typescript-eslint/parser",
    plugins: ["@typescript-eslint"],
    parserOptions: {
        ecmaVersion: 2019,
        sourceType: "module",
        ecmaFeatures: { jsx: true },
    },
    settings: {
        react: {
            version: "detect"
        }
    }
};
                    

Имена переменных


let completed: boolean; //  ⛔️
let hasCompleted: boolean;
                    

Любое извращение на ваш вкус

package.json


  "dependencies": {
    "package-n1": "^1.1.0"
    "package-n2": "~5.1.0"
    "package-n3": "file:../foo/bar"
  }
                    

package.json


  "dependencies": {
    "@company/platform": "^1.1.0"
  }
                    

Lint для описания коммита.

github.com/conventional-changelog/commitlint

conventionalcommits.org

    <type>[optional scope]: <description>

    [optional body]

    [optional footer]
                    

npm install husky --save-dev


{
  "husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  }
}
                    

Тесты

Виды тестов

  • Что-то на Jest/Mocha (напишем потом)
  • Кто-то что-то там на Selenium (все время падают)

Напишем потом

Покрытие

istanbul.js.org

JEST config


{
...
    coverageThreshold: {
        global: {
            branches: 23,
            functions: 23,
            lines: 23,
            statements: 23,
        },
    }
...
}
                    

Smoke тесты

Каждый компонент должен как минимум ренедриться

JEST снапшоты

it('renders correctly', () => {
  const tree = renderer
    .create(Facebook)
    .toJSON();
  expect(tree).toMatchSnapshot();
});
                    

exports[`renders correctly 1`] = `

  Facebook

`;
                    

Snapshot для каждого компонента.

Clinton

github.com/SamVerschueren/clinton

Встроенные плагины

  • no-git-merge-conflict
  • pkg-description
  • use-travis
  • ...

module.exports = ctx => {
  findReactComponents(ctx.files).forEach(file => {
    if(!isTestFileExist(file)){
      ctx.report({
        message: `File ${file} does not exist.`
      });
    }
  })
};
                    

Автоматизировать можно все

Docker автоматизация

testcontainers.org/

npm i -D testcontainers
                    

  const container = await new GenericContainer("redis")
    .withExposedPorts(6379)
    .start();

  const redisClient = redis.createClient(
    container.getMappedPort(6379),
    container.getContainerIpAddress(),
  );
                    

const container = await GenericContainer.fromDockerfile(buildContext)
  .withBuildArg("ARG_KEY", "ARG_VALUE")
  .build();

const startedContainer = await container
  .withExposedPorts(8080)
  .start();
                    

Гитперавтоматизация

  • Вместо обучения
  • Меньше споров
  • Повышение качества
  • Ускорение разработки
  • Каждый случай автоматизации уникален

Спасибо!


twitter: @zolotyh

telegram: @aazolotyh

github: @zolotyh