Настроить CI/CD в репозитории SourceCraft

В SourceCraft встроен механизм для работы с CI/CD-процессами.

Конфигурация CI/CD задается для конкретного репозитория и хранится в корне репозитория в файле .src.ci.yaml.

Общий вид конфигурационного файла .src.ci.yaml:

on:
  pull_request:
    - workflows: [<список_рабочих_процессов>]
      filter:
        source_branches: [<список_исходных_веток>]
        target_branches: [<список_целевых_веток>]
        paths: [<список_путей>]

  push:
    - workflows: [<список_рабочих_процессов>]
      filter:
        branches: [<список_веток>]
        paths: [<список_путей>]

workflows:
  <имя_рабочего_процесса>:

    tasks:
      - name: <имя_задачи>
        
        cubes:
          - name: <имя_кубика>
            image: <путь_к_Docker-образу>
            script:
              - <выполняемый_скрипт>
...

В конфигурационном файле поддерживается использование секретов. Подробнее см. в разделе Использовать значение секрета в CI/CD.

Полную спецификацию файла .src.ci.yaml см. в репозитории templates в SourceCraft.

CI/CD-процессы запускаются событиями-триггерами. Такими событиями могут быть отправка изменений в ветку удаленного репозитория или создание пул-реквеста.

Для разных событий вы можете настроить разные рабочие процессы. Также срабатывание триггеров можно настроить для конкретных веток или путей в репозитории.

Описание элементов конфигурации см. справочнике CI/CD.

Вы можете настроить CI/CD при создании репозитория или в уже имеющемся.

Настроить CI/CD при создании репозитория

  1. Откройте главную страницу SourceCraft.

  2. На панели слева нажмите Create repository.

  3. В открывшемся окне задайте параметры репозитория.

  4. В блоке Configuration выберите Add a src yaml template.

  5. В выпадающем списке YAML выберите шаблон конфигурации CI/CD:

    • Docker;
    • HelloWorld;
    • Java;
    • NodeJS;
    • Python.

    Содержимое шаблонов см. в подразделе Примеры.

  6. Нажмите Create repository.

    В корне созданного репозитория будет размещен файл .src.yaml с шаблоном конфигурации CI/CD.

Настроить CI/CD в уже имеющемся репозитории

  1. Откройте главную страницу SourceCraft.

  2. На вкладке Home перейдите в раздел Repositories.

  3. Выберите репозиторий, в котором хотите настроить CI/CD.

  4. Склонируйте репозиторий:

    1. В правом верхнем углу нажмите кнопку Clone.

    2. В зависимости от способа подключения скопируйте ссылку для клонирования репозитория.

    3. В терминале выполните команду:

      git clone <ссылка_для_клонирования_репозитория>
      
    4. Перейдите в склонированный репозиторий:

      cd <имя_репозитория>
      
  5. Сформируйте файл конфигурации CI/CD .src.ci.yaml согласно описанию в справочнике CI/CD или воспользуйтесь шаблонами из подраздела Примеры.

  6. Добавьте файл конфигурации CI/CD в индекс git, сделайте коммит и отправьте изменения в ветку main:

    git add .src.ci.yaml
    git commit -m "Added CI/CD configuration"
    git push -u origin main
    

Проверить выполнение CI/CD-процесса

  1. В зависимости от настроек, указанных в .src.ci.yaml, выполните событие-триггер.

  2. Проверьте выполнение CI/CD-процесса:

    1. На странице репозитория в разделе Code перейдите в секцию CI/CD.
    2. Выберите запущенный рабочий процесс (workflow).
    3. На открывшейся странице будут отображены все задачи (tasks) рабочего процесса, шаги задач — кубики (cubes), а также статусы и результаты выполнения.

Примеры

# Это базовый рабочий процесс (workflow), который 
# поможет вам начать работу с SourceCraft CI/CD

# Настройка события-триггера для запуска рабочего процесса
on:
  # Запуск рабочего процесса по отправке изменений в ветку main
  # удаленного репозитория или создание пул-реквеста в ветку main
  pull_request:
    - workflows: [sample-workflow]
      filter:
        source_branches: ["**", "!test**"]
        target_branches: "master"

  push:
    - workflows: [sample-workflow]
      filter:
        branches: ["main"]

workflows:
  sample-workflow:
    tasks:
      - name: sample-task
      
        cubes:
          # Запуск набора команд 
          - name: sample-cube1
            image: docker.io/library/node
            script:
              - echo Hello, world!
           
          - name: sample-cube2
            script:
              - echo Add other cubes to build,
              - echo test, and deploy your project.
on:
  push:
    - workflows: build-workflow 
      filter: 
        branches: ["main"]

workflows:
  build-workflow:
    tasks:
      - build-task

tasks:
  - name: build-task
    env:
        IMAGE_URI: dockerhub_account/hello-world
    cubes:
      - name: docker-build
        script:
          - docker build . --file Dockerfile --tag $IMAGE_URI:$(date +%s)
      # Опционально: отправка Docker-образа в реестр
      # Передайте в кубик данные для аутентификации в реестре,
      # например в Docker Hub или Yandex Container Registry
      # - name: push-dockerhub
      #   env:
      #     USER: username
      #     PAT: personal_access_token
      #   script:
      #     - echo $PAT | docker login --username $USER --password-stdin
      #     - docker push $IMAGE_URI

Чтобы протестировать CI\CD-процесс, отправьте в ветку main коммит с файлом Dockerfile:

FROM alpine  
CMD ["echo", "Hello World!!"]
on:
  push:
    - workflows: [sample-workflow]
      filter:
        branches: ["main"]

workflows:
  sample-workflow:
    tasks:
      - name: sample-task
        cubes:
          - name: sample-cube1
            image: docker.io/library/python
            script:
              - python -m pip install --upgrade pip
              - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi

Добавьте в файл .gitignore данные, специфичные для тестирования приложений на Python.

Пример .gitignore
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
#   For a library or package, you might want to ignore these files since the code is
#   intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# UV
#   Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
#   This is especially recommended for binary packages to ensure reproducibility, and is more
#   commonly ignored for libraries.
#uv.lock

# poetry
#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
#   This is especially recommended for binary packages to ensure reproducibility, and is more
#   commonly ignored for libraries.
#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
#   in version control.
#   https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
#  and can be added to the global gitignore or merged into this file.  For a more nuclear
#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# PyPI configuration file
.pypirc

Чтобы протестировать CI\CD-процесс, отправьте в ветку main коммит с файлом main.py:

print('Hello SourceCraft')
print('Hello SourceCraft')

for i in range(10):
    print(i)

# input 
hi = input()
print(hi)
on:
  push:
    - workflows: build-workflow 
      filter: 
        branches: ["main"]

workflows:
  build-workflow:
    tasks:
      - build-task

tasks:
  - name: build-task
    cubes:
      - name: build-npm
        image: docker.io/library/node
        script:
          - npm ci
          - npm run build --if-present
          - npm test

Чтобы протестировать CI\CD-процесс, отправьте в ветку main коммит со следующими файлами:

  • index.js:

    //index.js
    
    function helloNpm() {
        return "hello SourceCraft CI/CD"
    }
    
    module.exports = helloNpm
    
  • package.json:

    {
        "name": "sourcecraft-samples-nodejs",
        "version": "1.0.0",
        "description": "Sample for SourceCraft CI/CD",
        "license": "MIT",
        "author": "SourceCraft Team",
        "type": "commonjs",
        "main": "index.js",
        "scripts": {
          "test": "echo \"test passed\""
        }
    }
    
  • package-lock.json:

    {
        "name": "sourcecraft-samples-nodejs",
        "version": "1.0.0",
        "lockfileVersion": 3,
        "requires": true,
        "packages": {
          "": {
            "name": "sourcecraft-samples-nodejs",
            "version": "1.0.0",
            "license": "MIT"
          }
        }
    }
    
# Этот рабочий процесс (workflow) соберет Java-проект с помощью Maven
on:
  push:
    - workflows: publish-package-workflow
      filter:
        branches: ["main"]

workflows:
  publish-package-workflow:
    settings:
      max-cube-duration: 10m
      retry: 2
    tasks:
      - build-publish-task

tasks:
  - name: build-publish-task
    cubes:
      - name: setup-jdk-maven
        script:
          - sudo apt install openjdk-21-jdk -y
          - sudo apt install maven -y
          - java --version
          - mvn --version
      - name: test
        script:
          - echo 'test'
      - name: package
        script:
          - mvn package
        # Опционально: выгрузка артефакта с именем
        # sourcecraft-sample-maven-1.0-SNAPSHOT.jar из целевой директории.
        # Артефакт можно скачать из кубика в разделе CI/CD
        #artifacts: 
        #  paths:
        #    - target/sourcecraft-sample-maven-1.0-SNAPSHOT.jar

Добавьте в файл .gitignore данные, специфичные для тестирования приложений на Java.

Пример .gitignore
##############################
## Java
##############################
.mtj.tmp/
*.class
*.jar
*.war
*.ear
*.nar
hs_err_pid*
replay_pid*

##############################
## Maven
##############################
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
pom.xml.bak
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar

##############################
## Gradle
##############################
bin/
build/
.gradle
.gradletasknamecache
gradle-app.setting
!gradle-wrapper.jar

##############################
## IntelliJ
##############################
out/
.idea/
.idea_modules/
*.iml
*.ipr
*.iws

##############################
## Eclipse
##############################
.settings/
bin/
tmp/
.metadata
.classpath
.project
*.tmp
*.bak
*.swp
*~.nib
local.properties
.loadpath
.factorypath

##############################
## NetBeans
##############################
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml

##############################
## Visual Studio Code
##############################
.vscode/
.code-workspace

##############################
## OS X
##############################
.DS_Store

##############################
## Miscellaneous
##############################
*.log

Чтобы протестировать CI\CD-процесс, отправьте в ветку main коммит со следующими файлами:

  • pom.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.mycompany.app</groupId>
      <artifactId>sourcecraft-sample-maven</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <name>bondarevsky-maven</name>
      <!-- FIXME change it to the project's website -->
      <url>http://www.example.com</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.release>17</maven.compiler.release>
      </properties>
    
      <dependencyManagement>
        <dependencies>
          <dependency>
            <groupId>org.junit</groupId>
            <artifactId>junit-bom</artifactId>
            <version>5.11.0</version>
            <type>pom</type>
            <scope>import</scope>
          </dependency>
        </dependencies>
      </dependencyManagement>
    
      <dependencies>
        <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-api</artifactId>
          <scope>test</scope>
        </dependency>
        <!-- Optionally: parameterized tests support -->
        <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-params</artifactId>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
      <build>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
          <plugins>
            <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
            <plugin>
              <artifactId>maven-clean-plugin</artifactId>
              <version>3.4.0</version>
            </plugin>
            <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
            <plugin>
              <artifactId>maven-resources-plugin</artifactId>
              <version>3.3.1</version>
            </plugin>
            <plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.13.0</version>
            </plugin>
            <plugin>
              <artifactId>maven-surefire-plugin</artifactId>
              <version>3.3.0</version>
            </plugin>
            <plugin>
              <artifactId>maven-jar-plugin</artifactId>
              <version>3.4.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-install-plugin</artifactId>
              <version>3.1.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-deploy-plugin</artifactId>
              <version>3.1.2</version>
            </plugin>
            <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
            <plugin>
              <artifactId>maven-site-plugin</artifactId>
              <version>3.12.1</version>
            </plugin>
            <plugin>
              <artifactId>maven-project-info-reports-plugin</artifactId>
              <version>3.6.1</version>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    </project>
    
  • src/test/java/com/mycompany/app/AppTest.java:

    package com.mycompany.app;
    
    import static org.junit.jupiter.api.Assertions.assertTrue;
    
    import org.junit.jupiter.api.Test;
    
    /**
     * Unit test for simple App.
     */
    public class AppTest {
    
        /**
         * Rigorous Test :-)
         */
        @Test
        public void shouldAnswerWithTrue() {
            assertTrue(true);
        }
    }
    
  • src/main/java/com/mycompany/app/App.java:

    package com.mycompany.app;
    
    /**
     * Hello world!
     */
    public class App {
        public static void main(String[] args) {
            System.out.println("Hello World!");
        }
    }
    

См. также