惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Troy Hunt's Blog
P
Proofpoint News Feed
V
Vulnerabilities – Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
K
Kaspersky official blog
Cyberwarzone
Cyberwarzone
T
Tor Project blog
Cisco Talos Blog
Cisco Talos Blog
S
Securelist
L
Lohrmann on Cybersecurity
Security Latest
Security Latest
T
Threatpost
H
Heimdal Security Blog
W
WeLiveSecurity
A
Arctic Wolf
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
GRAHAM CLULEY
IT之家
IT之家
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
TaoSecurity Blog
TaoSecurity Blog
A
About on SuperTechFans
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
Last Week in AI
Last Week in AI
T
The Blog of Author Tim Ferriss
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Azure Blog
Microsoft Azure Blog
Hugging Face - Blog
Hugging Face - Blog
Google DeepMind News
Google DeepMind News
量子位
Stack Overflow Blog
Stack Overflow Blog
Know Your Adversary
Know Your Adversary
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
AI
AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
GbyAI
GbyAI
Vercel News
Vercel News
C
Cyber Attacks, Cyber Crime and Cyber Security
Latest news
Latest news
D
Darknet – Hacking Tools, Hacker News & Cyber Security
大猫的无限游戏
大猫的无限游戏
Forbes - Security
Forbes - Security

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Как использовать GitHub Actions и настроить интеграцию с PyPI для Python-проектов
ViAchKoN · 2026-04-29 · via Все публикации подряд на Хабре
Github actions

Github actions

Введение

Когда я создавал свой первый Python-пакет, dataclass-sqlalchemy-mixins(Github или pypi), я столкнулся с интересной задачей:как настроить CI/CD в GitHub так, чтобы при отправке новых изменений ничего не ломалось, а код автоматически публиковался в PyPI. О том, как опубликовать собственный пакет, я рассказывал в этой статье.

Обычно, чтобы проверить любой коммит, попадающий в master-ветку через pull request, необходимо запускать тесты. Кроме того, полезно использовать линтеры для проверки стиля кода, особенно если над проектом работают несколько разработчиков.

CI (Continuous Integration) — практика автоматической сборки и тестирования изменений в коде после их добавления в репозиторий.

CD (Continuous Delivery) — автоматизированная доставка кода в окружения разработки или продакшена.

Создание workflows

GitHub поддерживает Actions — автоматизированные процессы, которые могут запускать одну или несколько job, включая CI/CD-пайплайны. Подробнее о них можно прочитать в документации GitHub.

Workflows — это то, что GitHub будет запускать согласно вашей конфигурации.
Они должны находиться в директории .github/workflows и иметь формат .yaml.

Например, если мы хотим запускать тесты после каждого коммита, нужно создать файл test.yml. Я выбрал имя test для удобства и чтобы показать, что этот workflow отвечает именно за тесты, но название может быть любым.

name: "Test"

on:
  pull_request:
    types:
      - "opened"
      - "synchronize"
      - "reopened"
  push:
    branches:
      - '*'
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python 3.12
        id: setup-python
        uses: actions/setup-python@v5
        with:
          python-version: 3.12

      - name: Cache poetry install
        uses: actions/cache@v4
        with:
          path: ~/.local
          key: poetry-${{ steps.setup-python.outputs.python-version }}-1.7.1-0

      - uses: snok/install-poetry@v1
        with:
          version: 1.7.1
          virtualenvs-create: true
          virtualenvs-in-project: true

      - name: Load cached venv
        id: cached-poetry-dependencies
        uses: actions/cache@v4
        with:
          path: .venv
          key: venv-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}

      - name: Install dependencies
        if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
        run: poetry install --no-interaction

      - name: Run tests
        run: poetry run pytest  --cov-report=xml

Разберём основные элементы этого файла:

  • name — имя workflow.

  • pull_request — указывает, какие типы pull request будут запускать workflow.По умолчанию обычно рекомендуются openedsynchronize и reopened.Подробнее об этих типах можно прочитать здесь.

  • push — указывает ветки, при push в которые будет запускаться workflow.

  • jobs — workflow может состоять из одной или нескольких job, которые по умолчанию выполняются параллельно, но при необходимости их можно настроить и на последовательный запуск.

Теперь чуть подробнее о том, что происходит при выполнении job в этом примере. Во-первых, имя job можно использовать для настройки rulesets в репозитории или для конкретных веток. В данном случае будет запускаться только одна job — test. Про rulesets подробнее поговорим позже.

Ключ runs-on указывает, на какой операционной системе будет выполняться job. Настройка strategy: fail-fast: false означает, что GitHub не будет отменять все выполняющиеся и ожидающие job в matrix, если одна из job в матрице завершится с ошибкой. Параметр matrix мы рассмотрим немного позже.

Как видно, в steps много похожих записей в ключе uses. Например:

  • actions/setup-python@v5

  • actions/cache@v4

  • snok/install-poetry@v1

а первый взгляд названия actions могут сбивать с толку, но на самом деле это просто пути к GitHub-репозиториям этих actions, без части @v. Например, исходный код первой action можно посмотреть по адресу https://github.com/actions/setup-python . To же самое относится и к другим actions. Часть @v используется для указания версии action.

Ключ with нужен для передачи параметров в action.Например, если мы хотим установить Python 3.12, мы передаём python-version: 3.12 в шаге Set up Python 3.12. Тот же подход применяется и в других шагах.

Если коротко, job test выполняет следующие действия:

  1. Устанавливает Python нужной версии.

  2. Устанавливает зависимость Poetry 1.7.1 с использованием кэша GitHub.

  3. Создаёт Python .venv в корне проекта, если кэш не найден. Кэш виртуального окружения зависит от версии Python и poetry.lock.

  4. Если закэшированное виртуальное окружение не найдено, устанавливаются зависимости проекта.

  5. Запускаются тесты.

Использование сервисов в workflows

Созданный workflow довольно простой и может не подойти для тестирования более сложных приложений или проектов. Дело в том, что таким проектам часто нужны дополнительные сервисы — например, базы данных или кэш. Конечно, можно писать тесты, которые будут мокать запросы к этим сервисам, но я бы не рекомендовал такой подход, так как он может снизить эффективность тестового покрытия. Я покажу, как добавить сервис в workflow, на примере PostgreSQL.

jobs:
  test:
    services:
      postgres:
        image: postgres:latest
        env:
          POSTGRES_PASSWORD: postgres
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

Добавление ключа services с именем нужного сервиса позволяет поднять его во время выполнения job.Более того, ему можно передавать настройки почти так же, как при использовании docker.

Использование нескольких параметров при запуске job

И наконец, важный случай — когда job нужно запускать с разными параметрами. Например, вам может понадобиться запускать её не только на последней версии Python, но и на нескольких версиях сразу, либо с разными зависимостями. Это особенно полезно, если нужно поддерживать обратную совместимость со старыми версиями зависимостей. Для этого в GitHub есть ключ strategy. Параметр matrix позволяет запускать одну и ту же job с несколькими наборами значений.

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.11", "3.12"]
        sqlalchemy-version: ["1.4.52", "2.0.31"]

Job с такой матрицей будет запускаться для каждой комбинации значений параметров.
В результате мы получим четыре запуска job со следующими сочетаниями версий Python и SQLAlchemy:

  • 3.111.4.52

  • 3.112.0.31

  • 3.121.4.52

  • 3.122.0.31

Доступ к параметрам внутри job можно получить через ${{ matrix.python-version }} или ${{ matrix.sqlalchemy-version }}.

      - name: Set up Python ${{ matrix.python-version }}
        id: setup-python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install sqlalchemy ${{ matrix.sqlalchemy-version }}
        run: pip install sqlalchemy==${{ matrix.sqlalchemy-version }}

Использование GitHub rulesets

Но иногда простого запуска job для проекта недостаточно. Бывают ситуации, когда нужно ограничить возможность слияния коммитов в master-ветку. Если вы работаете над проектом один, это может быть не так критично, но при командной разработке такая настройка крайне желательна. Она помогает избежать ситуации, когда кто-то случайно сливает коммит, который ломает код, даже если пайплайны падают.

Для этого GitHub предоставляет удобный инструмент под названием rulesets.Открыть его можно в настройках репозитория по адресу https://github.com/{Author}/{Repository}/settings/rules .После создания нового ruleset прокрутите страницу вниз до пункта Require status checks to pass, включите его и укажите, какие job должны завершаться успешно.Чтобы найти нужную проверку, начните вводить имя требуемой job, и GitHub предложит варианты.Обратите внимание: каждая job в matrix будет иметь собственное имя, поэтому их можно выбирать по отдельности.

Публикация в PyPI

В последней части я хотел бы рассказать о том, как настроить интеграцию с PyPI и публиковать новые версии через release. Для этого нужно создать отдельный yaml-файл с workflow для публикации.

name: Upload Python Package to PyPi on release

on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  deploy:

    runs-on: ubuntu-latest

    environment:
      name: pypi
      url: https://pypi.org/project/dataclass-sqlalchemy-mixins/

    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v3
      with:
        python-version: '3.x'

    - uses: snok/install-poetry@v1
      with:
        version: 1.7.1
        virtualenvs-create: true
        virtualenvs-in-project: true

    - name: Build package
      run: poetry build

    - name: Publish package
      uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}

Этот workflow:

  1. Устанавливает Python.

  2. Устанавливает зависимость Poetry 1.7.1 с использованием кэша GitHub.

  3. Собирает source- и wheel-архивы.

  4. Публикует пакет в PyPI.

Да, всё действительно настолько просто, как выглядит. Вам нужно только добавить PYPI_API_TOKEN в secrets репозитория (https://github.com/{Author}/{Repository}/settings/secrets/actions ). После этого создайте новый release (https://github.com/{Author}/{Repository}/releases), и пакет будет автоматически загружен.