Сокращаем счёт за macOS в GitHub Actions по шагам
Большинство счетов за macOS в GitHub Actions раздуты минутами, которые ничего не дают команде. Пересборка кэшей. Матрицы, результаты которых никто не читает. Задачи для коммитов, которые уже заменены новыми. Это чек-лист изменений, упорядоченный по тому, сколько они экономят при минимуме работы. Где это помогает, приведён YAML.
1. Отменяйте устаревшие запуски
Если кто-то пушит дважды за минуту, первый запуск потрачен зря. Один блок в каждом workflow это прекращает:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true2. Уберите с 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 дешевле поминутной оплаты. Это так, как бы хорошо ни была оптимизирована поминутная схема. Прогретые кэши сами по себе убирают большую часть лишних трат.