Разработка на ходу сегодня — не редкость. Termux позволяет превратить Android-устройство в компактную «лабораторию» для сборки и проверки проектов без доступа к полноценному CI-серверу. В этой статье покажу, как собрать автономный CI/CD пайплайн в Termux: от настройки окружения до автоматической сборки, тестирования и деплоя артефактов.
Идея автономного CI/CD в Termux
Классический CI/CD обычно включает несколько стадий: подготовка окружения, установка зависимостей, сборка, тестирование, анализ качества и доставка артефакта (деплой). В Termux мы переносим эти этапы на устройство и управляем ими с помощью сценариев shell.
Ключевые преимущества подхода:
- быстрая обратная связь при разработке;
- воспроизводимость команд (единый сценарий вместо ручных шагов);
- возможность подключить «локальный деплой» в домашней сети (без обхода блокировок);
- минимальные требования к внешней инфраструктуре.
Подготовка Termux: базовые инструменты
Начнём с обновления пакетов и установки необходимых утилит. В Termux обычно достаточно стандартного набора:
pkg update && pkg upgrade -y
pkg install -y git curl wget tar unzip ca-certificates openssh rsync
Дальше добавим базовые средства для сборки и тестирования. Конкретный набор зависит от стека (Node.js, Python, Java, Go). В примерах ниже я покажу универсальный подход: создаём проектный «pipeline-скрипт» и отдельные шаги.
Выбор типа проекта: пример для Node.js
Для демонстрации автономного пайплайна удобно взять Node.js-проект (он лёгкий и быстро проверяется). Установим Node.js и инструменты тестирования.
pkg install -y nodejs-lts
npm --version && node --version
Создадим структуру проекта для примера. Если у вас уже есть репозиторий — просто адаптируйте шаги.
mkdir -p ~/ci-termux-demo
cd ~/ci-termux-demo
npm init -y
Добавим тестовый фреймворк и скрипты. Например, используем Jest и ESLint.
npm install --save-dev jest eslint
npm init -y
Добавим минимальные файлы. Скрипты и конфиг лучше хранить в репозитории, чтобы пайплайн был переносимым.
mkdir -p src test
cat > src/index.js <<'EOF'
function add(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new TypeError('Inputs must be numbers');
}
return a + b;
}
module.exports = { add };
EOF
cat > test/index.test.js <<'EOF'
const { add } = require('../src/index');
describe('add', () => {
test('adds numbers', () => {
expect(add(2, 3)).toBe(5);
});
test('throws on invalid inputs', () => {
expect(() => add('2', 3)).toThrow(TypeError);
});
});
EOF
Скрипты сборки и тестов внутри package.json
Хотя Termux может выполнять любые команды, удобно стандартизировать стадию CI/CD через npm-скрипты.
node -e "const fs=require('fs');
const pkg=require('./package.json');
pkg.scripts=pkg.scripts||{};
pkg.scripts.build='node -e \"console.log(\\\"Build step placeholder\\\")\"';
pkg.scripts.test='jest';
pkg.scripts.lint='eslint .';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
"
Добавим базовую конфигурацию ESLint (минимально, чтобы не усложнять пример).
cat > .eslintrc.json <<'EOF'
{
"env": { "node": true, "es2021": true },
"extends": [],
"parserOptions": { "ecmaVersion": "latest" },
"rules": {}
}
EOF
Концепция пайплайна: единый сценарий stages
Практичный вариант — один «командный драйвер», который последовательно вызывает этапы. Назовём его pipeline.sh. Он будет:
- готовить окружение;
- устанавливать зависимости;
- выполнять сборку;
- запускать тесты;
- делать статический анализ;
- формировать артефакт для деплоя.
Шаг 1: установка зависимостей
Создадим pipeline-скрипт. В начале добавим установку зависимостей и явный контроль ошибок (чтобы при провале этапа пайплайн останавливался).
cat > pipeline.sh <<'EOF'
#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail
WORKDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$WORKDIR"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $"
}
log "Step: install dependencies"
npm ci --silent
EOF
chmod +x pipeline.sh
Чтобы npm ci работал корректно, вам нужен package-lock.json. При создании проекта он обычно появляется после первой установки зависимостей:
npm install
Теперь можно прогнать pipeline только до шага установки:
./pipeline.sh
Шаг 2: сборка (build)
Добавим этап сборки:
perl -0777 -i -pe 's/log "Step: install dependencies"
\snpm ci --silent/log "Step: install dependencies"
npm ci --silent
log "Step: build"
npm run build
/sm' pipeline.sh
Шаг 3: тестирование
Далее — запуск юнит-тестов. Важно, чтобы тесты реально возвращали ненулевой код при ошибках.
perl -0777 -i -pe 's/npm run build
log "Step: build"/npm run build
log "Step: test"
npm test
/sm' pipeline.sh
Проверьте, что тесты выполняются:
./pipeline.sh
Шаг 4: статический анализ (lint) и качество
Статический анализ полезен, даже если вы делаете небольшие изменения. Добавим npm run lint.
perl -0777 -i -pe 's/npm test
/npm test
log "Step: lint"
npm run lint
/sm' pipeline.sh
Запустите pipeline целиком:
./pipeline.sh
Шаг 5: формирование артефакта для деплоя
Для примера сделаем артефакт как архив проекта (или, в реальном проекте, результат сборки). Создадим папку dist и упакуем её (в нашем примере сборка заглушка, но механизм одинаковый).
mkdir -p dist
node -e "require('fs').writeFileSync('dist/artifact.txt', 'Build artifact generated on Termux at ' + new Date().toISOString());"
Расширим pipeline: после прохождения всех стадий он будет архивировать dist.
cat >> pipeline.sh <<'EOF'
log "Step: package artifact"
ARTIFACT_DIR="$WORKDIR/artifacts"
mkdir -p "$ARTIFACT_DIR"
VERSION="$(date +%Y%m%d_%H%M%S)"
ARCHIVE="$ARTIFACT_DIR/app_${VERSION}.tar.gz"
tar -czf "$ARCHIVE" dist
log "Artifact created: $ARCHIVE"
EOF
Деплой с Termux: локальная сеть и выгрузка артефакта
Полезный кейс автономного CI/CD — доставлять артефакт на устройство в той же локальной сети. Например, на небольшой сервер/хост в домашней сети. Важно: мы говорим именно о создании локальной сети для обслуживания собственных устройств, а не об обходе блокировок.
Схема деплоя может быть такой:
- Termux получает артефакт (мы его уже создаём);
- Termux копирует архив на целевой хост;
- целевой хост распаковывает артефакт в нужную директорию.
Для деплоя по SSH (если на целевом хосте включён доступ и вы имеете право администрировать) удобно использовать scp или rsync. В Termux scp обычно доступен через пакет openssh.
Добавим деплой-стадию. Замените параметры на свои:
cat >> pipeline.sh <<'EOF'
# -------- Optional Deploy --------
# Пример: деплой на удалённый хост по SSH в вашей локальной сети.
# Настройте переменные ниже или экспортируйте их перед запуском.
: "${DEPLOY_HOST:=}"
: "${DEPLOY_USER:=}"
: "${DEPLOY_PATH:=/opt/app}"
if [[ -n "${DEPLOY_HOST}" && -n "${DEPLOY_USER}" ]]; then
log "Step: deploy (scp)"
LATEST_ARCHIVE="$(ls -t "$WORKDIR/artifacts"/*.tar.gz | head -n 1)"
scp "$LATEST_ARCHIVE" "${DEPLOY_USER}@${DEPLOY_HOST}:/tmp/"
# На удалённой стороне: распаковать артефакт.
ssh "${DEPLOY_USER}@${DEPLOY_HOST}" "set -euo pipefail; \
tar -xzf /tmp/$(basename "$LATEST_ARCHIVE") -C /tmp; \
rm -rf /tmp/dist; \
mkdir -p '${DEPLOY_PATH}'; \
cp -r dist '${DEPLOY_PATH}/dist'; \
echo 'Deployed successfully';"
else
log "Deploy skipped: set DEPLOY_HOST and DEPLOY_USER to enable"
fi
EOF
Сделаем скрипт исполняемым (на всякий случай):
chmod +x pipeline.sh
Тестовый запуск деплоя (пример):
DEPLOY_HOST=192.168.1.50 DEPLOY_USER=youruser ./pipeline.sh
Автоматизация: запуск пайплайна по событиям
Чтобы CI/CD не запускать вручную, можно использовать:
- ручной вызов по расписанию (cron в Termux — зависит от вашей конфигурации);
- пост-коммит хуки (если вы делаете commit на локальном репозитории);
- ручной запуск одной командой перед тестом/перед деплоем.
Самый простой вариант — «точка входа»:
cat > run-ci-cd <<'EOF'
#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail
cd "$(dirname "$0")"
# При желании можно передавать DEPLOY_HOST/DEPLOY_USER через переменные окружения.
./pipeline.sh
EOF
chmod +x run-ci-cd
Запуск:
./run-ci-cd
Рекомендации по надёжности пайплайна
- Останавливайтесь на ошибках: используйте
set -euo pipefail. - Фиксируйте версии:
npm ciработает стабильнее, чем «обычный»npm installпри наличииpackage-lock.json. - Разделяйте артефакты: кладите в
artifacts/с датой/версией. - Храните конфиги в репозитории (кроме секретов).
- Секреты не коммитьте: переменные окружения/файлы вне репозитория.
Расширение на другие стеки
Переход на Python/Go/Java в Termux концептуально тот же: стадии остаются сборка → тесты → анализ → артефакт → деплой. Меняется лишь «команда сборки» и «команда тестов».
Например, для Python вы обычно получите аналогичный пайплайн через pip (или poetry) и тесты через pytest. Для Go — через go test и упаковку бинари. Для Java — через mvn test/gradle test и упаковку jar.
Если скажете ваш язык и пример проекта, можно адаптировать pipeline под вашу структуру.
Заключение
Автономный CI/CD в Termux — это практичный способ держать качество кода под контролем прямо на устройстве: выстраиваем стадии сборки, тестирования, линтинга и формируем артефакты, а затем при необходимости выполняем локальный деплой в вашей домашней сети. Такой подход ускоряет цикл «изменил → проверил → доставил» и делает процесс воспроизводимым.
Хотите собрать пайплайн под ваш конкретный стек (Node.js/Python/Java/Go) или интегрировать деплой в вашу локальную инфраструктуру? Обратитесь в РыбинскЛАБ — поможем спроектировать и внедрить автоматизацию CI/CD на Termux с учётом ваших задач.