Всем привет!

В этой статье я хочу рассказать, как я сделал удобный автодеплой нашего ui-kit на npm с помощью pipeline's gitlab.

Что хотелось сделать?

  • Автоматическое обновление версии пакета при пуше изменений.

  • Автоматический деплой новой версии на npm.

Автоматическое обновление версии пакета при пуше изменений

Начнем с создания файла, который будет обновлять версию нашего пакета. Тут все просто:

  1. Возьмем нашу прошлую версию из package.json

  2. Добавим к ней 1

  3. Положим обратно

Я использовал версии до 100 на каждом уровне, т.е от 0.0.1 до 99.99.99.

bumpVersion.js

import fs from 'fs';
// Берем наш package.json file
const packageFile = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
// Берем оттуда его версию
const version = packageFile.version;
// разбиваем на уровни
const [l3, l2, l1] = version.split('.').map(v => Number(v));
// Далее смотрим сколько уже было версий, считаем из расчета 
const oldVersion = l1 + l2 * 100 + l3 * 100 * 100;
// Инкрементим версию
const newVersion = oldVersion + 1;
// Записываем новую версию
const [newL3, newL2, newL1] = [Math.floor(newVersion / (100 * 100)), Math.floor(newVersion % (100 * 100) / 100), newVersion % 100];
packageFile.version = `${newL3}.${newL2}.${newL1}`;
// Кладем файл обратно
fs.writeFileSync('./package.json', JSON.stringify(packageFile));

Далее нам нужно вызвать этот скрипт перед деплоем и запушить изменения. Для этого нам нужно написать конфигурацию для ci/cd.

Но для начала нам нужно разобраться с тем, как мы будем пушить изменения из пайплайна. Для этого нам понадобятся креды gitlab, чтобы gitlab мог идентифицировать нас как своих)

Я решил действовать через Access Tokens gitlab. Здесь у нас два варианта либо использовать Access Tokens своего аккаунта, либо использовать Access Token конкретного репозитория.

Где получить Access Token своего аккаунта

  1. Переходим по ссылке.

  2. Создаем токен с правами на чтение и запись, не забываем сохранить сам токен, потом его нельзя будет посмотреть.

Где получить Access Token конкретного репозитория

  1. Заходим в наш репозиторий.

  2. Выбираем раздел Settings -> Access Tokens, создаем токен с правами на чтение и запись, также не забываем его сохранить, так как потом его нельзя будет посмотреть.

Далее переходим к написанию самой джобы для ci/cd.

.gitlab-ci.yml

stages:
  - deploy

deploy:
  stage: deploy
  image: node:16.17.0
  before_script:
    - git remote remove origin
    # Создаем авторизованный remote
    - git remote add origin https://<Access Token Name>:<Access Token Token>@gitlab.com/<Your Repository Name>.git
  script:
    # Прокидываем name + email, чтобы gitlab не сыпал ошибки
    - git config --global user.name "YourName"
    - git config --global user.email "YourEmail"
    # Вызываем наш скрипт, который инкрементирует версию
    - node bumpVersion.js
    # Добавляем и пушим наши изменения в ветку откуда стригерился pipeline
    - git add ./package.json
    - git commit -m "bump package.json version"
    # Используем опцию gitlab -o ci.skip, для того, чтобы наш коммит не тригерил новый pipeline
    - git push origin HEAD:$CI_COMMIT_REF_NAME -o ci.skip
  rules:
    - when: manual
  allow_failure: false

Версия пакета обновляется, можем перейти к следующему этапу.

Автоматический деплой новой версии на npm

Начнем с того, что получим токен на https://www.npmjs.com/.

  • Заходим на https://www.npmjs.com/

  • Тыкаем на свой профиль в правом верхнем углу и выбираем Access Tokens

  • Далее Generate New Token -> Classic Token и там создаем publish токен, также не забываем его сохранить, так как его потом нельзя будет посмотреть

Дописываем нашу ci/cd джобу.

.gitlab-cy.yml

stages:
  - deploy

deploy:
  stage: deploy
  image: node:16.17.0
  before_script:
    - git remote remove origin
    # Создаем авторизованный remote
    - git remote add origin https://<GitLab Access Token Name>:<GitLab Access Token Token>@gitlab.com/<Your Repository Name>.git
    # Подставляем наш полученный npm token
    - npm config set //registry.npmjs.org/:_authToken <NPM Access Token>
  script:
    # Прокидываем name + email, чтобы gitlab не сыпал ошибки
    - git config --global user.name "YourName"
    - git config --global user.email "YourEmail"
    # Вызываем наш скрипт, который инкрементирует версию
    - node bumpVersion.js
    # Добавляем и пушим наши изменения в ветку откуда стригерился pipeline
    - git add ./package.json
    - git commit -m "bump package.json version"
    # Используем опцию gitlab -o ci.skip, для того, чтобы наш коммит не тригерил новый pipeline
    - git push origin HEAD:$CI_COMMIT_REF_NAME -o ci.skip
    # Публикуем наш пакет
    - npm publish
  rules:
    - when: manual
  allow_failure: false

Финальный штрих

Добавим стадию build в нашу ci/cd конфигурацию, чтобы получить полный цикл.

.gitlab-ci.yml

stages:
  - deploy
  - build

build:
  stage: build
  image: node:16.17.0
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - ./dist/**
  allow_failure: false


deploy:
  stage: deploy
  image: node:16.17.0
  before_script:
    - git remote remove origin
    - git remote add origin https://<GitLab Access Token Name>:<GitLab Access Token Token>@gitlab.com/<Your Repository Name>.git
    - npm config set //registry.npmjs.org/:_authToken <NPM Access Token>
  script:
    - git config --global user.name "Your Name"
    - git config --global user.email "Your Email"
    - node bumpVersion.js
    - git add ./package.json
    - git commit -m "bump package.json version"
    - git push origin HEAD:$CI_COMMIT_REF_NAME -o ci.skip
    - npm publish
  rules:
    - when: manual
  allow_failure: false
Полученный результат
Полученный результат

Наслаждаемся пайплайном, который все делает за нас! :-)

Если статья показалась вам интересной, то у меня в планах еще много таких. Так что, если не хотите их пропустить - буду благодарен за подписку на мой Тг-канал.

Комментарии (6)


  1. Lavich
    31.05.2023 20:10
    +2

    1. Все токены для безопасности лучше всего убрать из кода в переменные окружения

    2. У "версии" не спроста есть три уровня - они показывают насколько сильно изменился пакет. Подробнее можно почитать вот здесь, например, https://semver.org/lang/ru/

    3. Этот js-скрипт можно было бы запускать в pre-push, использовав, например, husky. Тогда можно было бы избежать возни с токеном гитлаба. А запуск деплоя новой версии в npm-репозиторий можно привязать к изменению версии в package.json


    1. Dragonek Автор
      31.05.2023 20:10

      1. С токенами согласен, показывал как максимально просто сделать

      2. Спасибо большое, почитаю!

      3. Думал об этом, возможно дополню статью


    1. mdlufy
      31.05.2023 20:10

      Этот js-скрипт можно было бы запускать в pre-push

      Инкремент версии в pre-push? Кажется это нужно делать после всех джоб, чтобы лишний раз не занимать время при разработке. К тому же билд упасть же может


      1. Dragonek Автор
        31.05.2023 20:10

        Я видел, как в некоторых компаниях в pre-push прогоняются тесты и собирается билд, так что думаю в некоторых случаях это все таки применимо) Поэтому я бы не исключал этот вариант


    1. alxsk
      31.05.2023 20:10
      +1

      Про версии, я бы дополнил, что в принципе не особо сложно сделать автоматическую инкрементацию согласно semantic versioning, если на проекте используются (и главное соблюдаются) conventional commits. Подробнее тут можно почитать: https://www.conventionalcommits.org/en/v1.0.0/

      Общая идея:

      1. При релизе/деплое: достаем список ченджей гита с прошлого релиза (по тэгу)

      2. Смотрим какие были изменения (фиксы, фичи, ломающие изменения). Если что, для анализа conventional commits, генерации по нему change-list'ов и прочего есть готовые либы.

      3. Инкрементируем версию: патч - только фиксы, минор - фиксы + фичи, мажор - наличие ломающих изменений

      4. Публикуем/деплоим

      5. Пушим коммит с новой версией, плюс вешаем тег

      Вообще, conventional commits дает очень много профита, особенно на больших долгоиграющих проектах.


      1. Dragonek Автор
        31.05.2023 20:10

        Согласен, было бы красиво) Подумаю над этим.