Автоматизация процесса сборки и публикации с помощью GitHub Actions (и реестра пакетов GitHub)

Это своего рода вопросы и ответы, я изложил свое решение в ответах.

Я участвую как в бета-версии GitHub Actions, так и в бета-версии реестра пакетов GitHub. Поскольку я очень ленив, я не только автоматизировал процесс сборки своего пакета npm, но и хотел автоматизировать его публикацию.
Для этого мне пришлось столкнуться с некоторыми проблемами:

  1. Как я могу убедиться, что задание "публикации" выполняется в только что созданной версии?
  2. Как я могу определить, когда версия пакета обновляется в GitHub Actions?
  3. Как я могу использовать результат этой проверки, чтобы изменить поведение рабочего процесса действий?
  4. Как я могу опубликовать пакет в npm из рабочего процесса?
  5. Как я могу после публикации в npm опубликовать ту же самую версию в реестре пакетов GitHub?

1 ответ

Решение

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

1. Убедитесь, что задание "публикации" выполняется в только что созданной версии.

Самый простой способ, который я нашел, - это просто объединить два задания в один рабочий процесс и заставить их запускаться каждый раз. push событие: задание публикации было ограничено для выполнения, только если на master ветку и после первой.

  • Строительная работа:

Ему необходимо собрать новую версию пакета, а затем зафиксировать ее в репозитории: фиксация имеет решающее значение, потому что это позволяет другому заданию выбрать собранную версию. Чтобы зафиксировать изменения, сделанные во время выполнения рабочего процесса, вы можете использовать одно из моих действий, add-and-commit: он отправит изменения в репозиторий GitHub, используя "поддельного" пользователя git.
Ваш рабочий процесс должен выглядеть примерно так:

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest

    steps: 
    - name: Checkout repository
      uses: actions/checkout@v1.0.0

    - name: Set up Node.js
      uses: actions/setup-node@v1.2.0
      with:
        node-version: '10.x'
    
    - name: Install dependencies
      run: npm install

    - name: Compile build
      run: npm run build # This can be whatever command you use to build your package

    - name: Commit changes
      uses: EndBug/add-and-commit@v2.1.0
      with: # More info about the arguments on the action page
        author_name: Displayed name
        author_email: Displayed email
        message: "Message for the commit"
        path: local/path/to/built/version
        pattern: "*.js" # Pattern that matches the files to commit
        force: true # Whether to use the --force flag
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This gets generated automatically
  • Опубликовать вакансию:

Мы хотим, чтобы он работал только в master ветвь после build завершено, поэтому мы можем установить его так:

publish:
  name: Publish to NPM & GitHub Package Registry
  runs-on: ubuntu-latest
  if: contains(github.ref, 'master') # This sets the branch
  needs: build # This makes it wait for the build job

2. Обнаружение изменения версии

Я не нашел хорошего способа сделать это, поэтому сделал другое действие, version-check: это действие сканирует коммиты каждого нажатия и пытается выяснить, включают ли они изменение версии.
Вам необходимо настроить эти два шага:

steps:
- name: Checkout repository
  uses: actions/checkout@v1.0.0
  with:
    ref: master

- name: Check version changes
  uses: EndBug/version-check@v1.0.0 # More info about the arguments on the action page
  id: check # This will be the reference for later

3. Использование результатов проверки для редактирования поведения рабочего процесса.

version-check обеспечивает два выхода: changed (было ли обновление) и type(тип обновления, например "патч", "незначительное", ...).
К этим выходам можно получить доступ через stepsконтекст, и вы можете использовать их, чтобы решить, запускать шаг или нет, используя ifсобственность. Это пример:

# check is the id we gave to the check step in the previous paragraph
- name: Version update detected
  if: steps.check.outputs.changed == 'true'
  run: 'echo "Version change! -> ${{ steps.check.outputs.type }}"'

4. Публикация пакета в NPM.

Опубликовать пакет в NPM довольно просто: вам нужно только настроить Node.js, а затем использовать npm publish, как на своей машине. Единственное отличие состоит в том, что вам понадобится токен для аутентификации: вы можете создать его на https://npmjs.com/. После того, как вы создали его, НЕ включайте его в рабочий процесс: вы можете сохранить его как "секрет", вы можете найти больше информации о них здесь.
В этом примере я предполагаю, что ваш секрет называетсяNPM_TOKEN:

- name: Set up Node.js for NPM
  if: steps.check.outputs.changed == 'true'
  uses: actions/setup-node@v1.2.0
  with:
    registry-url: 'https://registry.npmjs.org' # This is just the default registry URL

- name: Install dependencies
  if: steps.check.outputs.changed == 'true'
  run: npm install

- name: Publish the package to NPM
  if: steps.check.outputs.changed == 'true'
  run: npm publish
  env:
    NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} # NPM will automatically authenticate with this

5. Публикация пакета в реестре пакетов GitHub.

На данный момент с реестром пакетов GitHub не очень приятно работать, если вы хотите и дальше публиковать существующий пакет в npm: вот почему он требует, чтобы пакеты были ограничены, и это может испортить ситуацию (ваш пакет может не иметь области видимости или быть в области видимости под другим именем).
Я обнаружил, что самый простой способ справиться с этим - это обходной путь:

  • В своем рабочем процессе переустановите Node.js, но добавив URL-адрес реестра GPR и область вашего имени.
  • Создайте сценарий npm, который редактирует ваш package.json так, чтобы он изменял исходное имя пакета на то, которое вам нужно опубликовать в GPR (включая область действия)
  • После вызова этого сценария в рабочем процессе используйте npm publish как и раньше, но на этот раз с помощью встроенного GITHUB_TOKEN как NODE_AUTH_TOKEN.
{
  "name": "YourPackageName",
  ...
  "scripts": {
    "gpr-setup": "node scripts/gpr.js"
  }
}
// scripts/gpr.js

const fs = require('fs')
const { join } = require('path')

// Get the package obejct and change the name
const pkg = require('../package.json')
pkg.name = '@yourscope/YourPackageName'

// Update package.json with the udpated name
fs.writeFileSync(join(__dirname, '../package.json'), JSON.stringify(pkg))
- name: Set up Node.js for GPR
  if: steps.check.outputs.changed == 'true'
  uses: actions/setup-node@v1.2.0
  with:
    registry-url: 'https://npm.pkg.github.com/'
    scope: '@endbug'

- name: Set up the package for GPR
  if: steps.check.outputs.changed == 'true'
  run: npm run gpr-setup

- name: Publish the package to GPR
  if: steps.check.outputs.changed == 'true'
  run: npm publish
  env:
    NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Результат

Ваш пакет теперь опубликован как в NPM, так и в GPR (хотя описание необходимо добавить вручную в GPR). Вы можете найти все, о чем я говорю, в версии dbots 5.0.4:

Другие вопросы по тегам