Рубрики
Uncategorized

Мое первое действие Github

Я начал использовать действия Github A, пока обратно, чтобы обрабатывать рабочие процессы в некоторых проектах, в основном для строительства … Теги с GitHub, действиями, дежопами.

Я начал использовать действия GitHub A, одновременно обратно для обработки рабочих процессов в некоторых проектах, в основном для создания изображений докеров или запущенных тестов. Их легко настроить, и MarketPlace Github имеет большое количество из них в различных целях, от управляющих тестов и трубопроводов развертывания, чтобы добавить кошек MEMES к вашему PRS.

Я хотел бы некоторое время посмотреть под капюшоном и посмотреть, как я могу создать свои собственные пользовательские действия и, наконец, последние выходные мне удалось пройти свою документацию и посмотреть на некоторые образцы и поставить что-то вместе. Это сводка моего первого действия GitHub.

Вы можете найти окончательное действие здесь или на Github Marketplace Отказ

Согласно Документы , есть 3 вида действий: Докер (использует контейнеры докеров, чтобы запустить операции действий в), JS (Действия, написанные в JS/TS), а Композитные шаги (может иметь несколько шагов).

У меня была простая идея для моего первого действия:

Мне нужно было что-то, чтобы заблокировать изменения (слиться и толчок) в данные ветви в течение периодов времени, указанных в качестве входов.

Действия JS звучали как хороший и простой способ сделать это.

Я начал с создания репо Действия/Типоприпечатка-действие шаблон. Этот шаблон содержит действие, которое ждет на несколько миллисекунд (переданных в качестве ввода) и передает время окончания его прогона в качестве вывода. Если что-то пойдет не так, он бросает ошибку и останавливает рабочий процесс.

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

  • package.json (Конечно!): Обновлена атрибуты и зависимости.
  • Action.yml : Определение действия, включая его входы и выходы, идет здесь.
  • SRC/** : Основная логика действия идет здесь.
  • __tests__ : Только если вам нужно проверить свой код!

Основная зависимость для действия JS является @ Действия/ядро . Он предоставляет функции, которые включают основные взаимодействия через рабочий процесс: например. Получение входов, настройки выходов и регистрации.

Есть и другие пакеты JS, предоставленные Github для использования в ваших действиях, хотя мне не нужно ни одного из них для моей цели. Вы можете увидеть список здесь Отказ

Мои изменения в package.json были тривиальными, поэтому я их пропускаю.

Следующий шаг обновил Action.yml и регулировка входов и выходов. Вот содержимое обновленного файла:

name: 'No Weekend Merge'
description: 'An action to prevent merges on weekends, or whenever that a merge should not happen'
author: 'ka7eh'
branding:
  icon: git-merge
  color: green
inputs:
  tz:
    required: true
    description: 'Timezone of the downtime periods'
    default: '0'
  mon:
    required: false
    description: 'When to block on Mondays'
  tue:
    required: false
    description: 'When to block on Tuesday'
  wed:
    required: false
    description: 'When to block on Wednesday'
  thu:
    required: false
    description: 'When to block on Thursday'
  fri:
    required: false
    description: 'When to block on Friday'
  sat:
    required: false
    description: 'When to block on Saturday'
  sun:
    required: false
    description: 'When to block on Sunday'
runs:
  using: 'node12'
  main: 'dist/index.js'

Первые 3 атрибута очевидны (имя, описание и автор).

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

В бежит Раздел Action.yml Я указываю узел 12 как мой бегун действий. Я также указываю на окончательную сборку кода, который идет в Dist (сборка обрабатывается TSC и @ vercel/ncc ; Проверьте построить и Пакет Сценарии в package.json ). Используя пакет, который включает в себя все необходимые зависимости, должны уменьшить сложность и источники ошибок при запуске действия в рабочем процессе.

Примечание: в настоящее время только узел 12 поддерживается для действий JS.

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

Последняя часть обновления в Action.yml это раздел входов. Я хочу позволить пользователям пройти периоды времени на каждый день недели, которые они хотят заблокировать изменения в некоторых филиалах. Поэтому я добавляю один вход на каждый день недели ( понедельник , ‘, …, солнце ), но сделайте их все возможными.

В настоящее время действия GitHub разрешают только входы строки. Таким образом, хороший способ получения периодов времени — это разделенный запятыми список временных интервалов в формате, как это: 00:00-07: 00,16: 30-23: 59 Отказ Этот пример означает изменение блока с полуночи до 7 часов утра и с 16:30 до полуночи.

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

Теперь я закончил с определкой моего действия. Следующим шагом является реализация логики. Въездная точка для действия — SRC/Main.ts Отказ Вот аннотированное содержание файла:

import * as core from '@actions/core'
import {isInDowntime, getUTCAdjustments} from './check'

const days = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']

async function run(): Promise {
  // Get the time that the action is called.
  const currentDate = new Date()

  try {
    // Parse `tz` (time zone) from the inputs.
    const tz = parseFloat(core.getInput('tz'))

    // Make adjustments to the current time to make sure we are checking for the correct time zone.
    const utcAdjustments = getUTCAdjustments(tz)
    currentDate.setUTCHours(currentDate.getUTCHours() + utcAdjustments.hours)
    currentDate.setUTCMinutes(
      currentDate.getUTCMinutes() + utcAdjustments.minutes
    )

    // We can set debugging info with `core.debug`. It helped me fix an issue I encountered when parsing the inputs.
    core.debug(`TZ: ${tz} - Day: ${currentDate.getUTCDay()}`)

    // Get the input for the current day of the week. If the input is not specified, it returns `undefined`. In such cases, fallback to an empty string.
    const downtimes = core.getInput(days[currentDate.getUTCDay()]) || ''
    core.debug(`Downtimes: ${downtimes}`)

    // We expect a comma-separated list of time periods, so split them by comma and check each time period with `isInDowntime` function. If the current time is in any of the time periods, throw an error and stop the workflow by calling `core.setFailed`.
    for (const downtime of downtimes.split(',')) {
      if (isInDowntime(currentDate, utcAdjustments, downtime)) {
        core.setFailed(
          `The PR cannot be merged at this time (${currentDate}) with the current settings (${downtime}).`
        )
      }
    }
  } catch (error) {
    // If any other errors happen, stop the workflow by calling `core.setFailed`. This also logs the error message in the output of the workflow.
    core.setFailed(`Error: ${error.message}. Run date: ${currentDate}.`)
  }
}

run()

Как уже упоминалось в Действия/Типоприпечатка-действие Шаблон, большинство операций CI/CD включают асинхронные процессы, и именно поэтому Беги это асинхронная функция.

Isindownteme Это функция, которая принимает дату, настройки UTC и периода времени и проверки, если данное время в период времени. Его содержание не является заботой этого поста, но я добавил аннотированную версию здесь:

export const isInDowntime = (
  date: Date,
  utcAdjustments: UTCAdjustments,
  downtime?: string
): boolean => {
  if (!downtime) {
    return false
  }

  // The regex pattern that captures the start and end hours and minutes of the time period.
  const result = /(?\d{2}):(?\d{2})-(?\d{2}):(?\d{2})/.exec(
    downtime
  )

  // If the input time period does not match the pattern and returns null, throw an error.
  if (!result) {
    throw new Error('Invalid downtime')
  }

  const groups = result.groups as DowntimePattern

  // Parse the captured groups in the regex match results as integer.
  const fromHour = parseInt(groups.fromHour, 10)
  const fromMinute = parseInt(groups.fromMinute, 10)
  const toHour = parseInt(groups.toHour, 10)
  const toMinute = parseInt(groups.toMinute, 10)

  // Double check the sections of the time period and make sure they are parsed as valid numbers and not NaN.
  for (const num of [fromHour, fromMinute, toHour, toMinute]) {
    if (Number.isNaN(num)) {
      throw new Error('Invalid downtime')
    }
  }

  // The next three blocks make sure hours and minutes are valid (between 0 and 23 for hours and 0 and 59 for minutes), and the start time is before the end time.
  for (const hour of [fromHour, toHour]) {
    if (hour < 0 || hour > 23) {
      throw new Error('Invalid downtime')
    }
  }

  for (const minute of [fromMinute, toMinute]) {
    if (minute < 0 || minute > 59) {
      throw new Error('Invalid downtime')
    }
  }

  if (fromHour > toHour || (fromHour === toHour && fromMinute > toMinute)) {
    throw new Error('Invalid downtime')
  }

  // Create two date objects, one for the start time and the other for the end time.
  // Both objects must be in the current working date, with their hours and minutes adjusted for UTC.
  const start = Date.UTC(
    date.getUTCFullYear(),
    date.getUTCMonth(),
    date.getUTCDate(),
    fromHour - utcAdjustments.hours,
    fromMinute - utcAdjustments.minutes
  )

  const end = Date.UTC(
    date.getUTCFullYear(),
    date.getUTCMonth(),
    date.getUTCDate(),
    toHour - utcAdjustments.hours,
    toMinute - utcAdjustments.minutes
  )

  // Finally, check if the given date is between the start and end times.
  return date.getTime() >= start && date.getTime() <= end
}

Я включил некоторые тесты в __тестс __/main.test.ts Чтобы проверить логику, хотя мне, вероятно, нужно больше сценариев, чтобы покрыть краевые чехлы, в основном вокруг часовых поясов.

Последний шаг — обновить рабочий процесс Включено в шаблон, чтобы он работает с обновленным кодом. Этот рабочий процесс запускает две задания: первый тестирует код и компилирования и связывает его. Вторая работа использует сам код как часть рабочего процесса со следующими входами:

with:
  tz: -5
  mon: 00:00-07:00,16:30-23:59
  tue: 00:00-07:00,16:30-23:59
  wed: 00:00-07:00,16:30-23:59
  thu: 00:00-07:00,16:30-23:59
  fri: 00:00-07:00,16:30-23:59
  sat: 00:00-23:59
  sun: 00:00-23:59

Эти входы устанавливают часовой пояс к центральному времени (-5) и изменениям блока до 7 часов утра и после 16:30 в будние дни и все дни в выходные дни.

Мне пришлось играть с конфигурацией несколько раз и вносить изменения в код, чтобы исправить ошибки, которые выдвинулись, когда я нажал мои изменения и завершил сломанный рабочий процесс. В конце концов, я получил его, работая, когда я увидел, что мой рабочий процесс не провалил из-за странных ошибок, но потому что я толкал изменения в выходные, которые я указываю как время простоя в рабочем процессе!

Перед публикацией акции на Github Marketplace я собрал короткую readme, описывающую то, что происходит, и тогда это было время выпуска!

Процесс публикации довольно легкий. Вы начинаете с разработки нового выпуска для вашего репо, похоже на то, как вы это делаете для любого проекта. Когда Github видит Action.yml В вашем корне проекта он знает, что это действие и включает в себя соответствующий контрольный список на странице выпуска и говорит вам, есть ли вещи, которые вы можете сделать, чтобы улучшить свое действие, например, Включите значок брендинга или добавить readme! После завершения проекта выпуска нажмите «Публикация» и «Действие» отображается на рынке.

Проверьте Действия GitHub Действия для получения дополнительной информации и посмотрите их быстрое руководство к действиям JS здесь Отказ

Я также видел этот тщательный курс на GitHub Labout Lab. , Но я еще не пробовал.

Получайте удовольствие, создавая свои собственные действия GitHub!:)

Оригинал: «https://dev.to/ka7eh/my-first-github-action-579j»