Руководство

Сокращаем счёт за macOS в GitHub Actions по шагам

Большинство счетов за macOS в GitHub Actions раздуты минутами, которые ничего не дают команде. Пересборка кэшей. Матрицы, результаты которых никто не читает. Задачи для коммитов, которые уже заменены новыми. Это чек-лист изменений, упорядоченный по тому, сколько они экономят при минимуме работы. Где это помогает, приведён YAML.

1. Отменяйте устаревшие запуски

Если кто-то пушит дважды за минуту, первый запуск потрачен зря. Один блок в каждом workflow это прекращает:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

2. Уберите с macOS всё, что не является сборкой

Линтеры, проверки форматирования, заметки к релизу и уведомления в Slack работают на раннере Linux за десятую часть цены. Как и юнит-тесты общих Swift-пакетов, которые не трогают UIKit. Разделите workflow на задачу Linux и зависящую от неё задачу macOS. Тогда упавший линтер никогда не потратит минуту macOS.

3. Кэшируйте пути, которые реально стоят времени

На hosted раннерах каждая задача начинается с пустой машины. Восстанавливайте дорогие папки по ключу, привязанному к lock-файлам:

- uses: actions/cache@v4
  with:
    path: |
      ~/Library/Developer/Xcode/DerivedData
      ~/Library/Caches/org.swift.swiftpm
      ~/.cocoapods
      Pods
    key: ${{ runner.os }}-${{ hashFiles('**/Package.resolved', '**/Podfile.lock') }}

DerivedData самая большая и самая хрупкая часть. Если инкрементальные сборки ведут себя странно, уберите её из кэша и оставьте кэши пакетов.

4. Полную матрицу запускайте только на main

Pull request редко нужны пять симуляторов. Для pull request собирайте одну конфигурацию. Полную матрицу устройств запускайте при слиянии в main или по ночному расписанию.

5. Фильтруйте по путям

Изменение README не должно запускать сборку iOS. Используйте paths-ignore в триггере workflow для документации, скриптов и всего, что вне таргета приложения.

6. Задайте таймауты

Зависший симулятор может съесть все шесть часов, которые даются по умолчанию. Задайте timeout-minutes для каждой задачи macOS чуть больше обычного времени сборки.

7. Перестаньте переустанавливать инструменты

Установка CocoaPods, fastlane или конкретного Xcode в каждой задаче сжигает минуты ещё до начала сборки. Используйте то, что уже есть в hosted образе, или кэшируйте установку.

8. Сократите срок хранения артефактов

Архивы и тестовые бандлы, которые хранятся 90 дней, постепенно наращивают плату за хранилище. Семи дней хватает для всего, что не уходит в стор.

9. После точки окупаемости перестаньте платить поминутно

Всё перечисленное выше немного урезает счёт. Но когда вы стабильно выше примерно 2,242 минут macOS в месяц, никакая экономия не обгонит фиксированную цену. Выделенный M6 за $139 в месяц выполняет неограниченные минуты с прогретыми кэшами. Пункты 3 и 7 теряют смысл полностью. Калькулятор покажет, где находится ваша команда.

Частые вопросы

Что сильнее всего сокращает счёт за macOS в GitHub Actions?

+

Для большинства команд это отмена устаревших запусков через concurrency group и перенос работы, не связанной со сборкой, на Linux. Вместе они часто убирают треть оплачиваемых минут macOS двумя небольшими правками в YAML.

Стоит ли кэшировать DerivedData в GitHub Actions?

+

Часто да, но это самая хрупкая часть. Кэши пакетов (SwiftPM, CocoaPods) безопасны и экономят минуты в каждой задаче. DerivedData экономит больше, но может вызывать странные сбои инкрементальной сборки. Задайте для неё точный ключ и будьте готовы её убрать.

Нужно ли запускать матрицу устройств на каждый pull request?

+

Обычно нет. Одна конфигурация в pull request и полная матрица на main или ночью ловят те же регрессии за малую долю минут.

Когда всё это перестаёт иметь значение?

+

Выше примерно 2,242 минут macOS в месяц выделенный Mac за фиксированные $139 дешевле поминутной оплаты. Это так, как бы хорошо ни была оптимизирована поминутная схема. Прогретые кэши сами по себе убирают большую часть лишних трат.

Похожие руководства