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

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

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

Общий вид конфигурационного файла .sourcecraft/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:
                      - <выполняемый_скрипт>
        ...
        

Вы можете использовать вложенную структуру для элементов конфигурации или разметить их в виде отдельных блоков.

Пример конфигурации СI/CD в виде отдельных блоков
on:
          pull_request:
            - workflows: my-test-workflow
              filter:
                source_branches: ["**", "!test**"]
                target_branches: "main"
        
        workflows:
          my-test-workflow:
            tasks:
              - my-test-task
        
        tasks:
          - name: my-test-task
            cubes:
              - name: my-test-cube
                image: docker.io/library/node
                script:
                  - echo Hello, world!
        

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

Важно

Скоро перестанет поддерживаться хранение конфигурации CI/CD, правил ревью кода и политик веток в едином файле .src.ci.yaml в корне репозитория. Используйте отдельные файлы .sourcecraft/ci.yaml, .sourcecraft/review.yaml и .sourcecraft/branches.yaml.

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

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

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

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

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

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

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

  2. На панели слева нажмите Создать репозиторий.

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

  4. В блоке Настройки выберите Добавить шаблон cicd.

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

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

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

  6. Нажмите Создать репозиторий.

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

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

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

    1. Установите Git.

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

    3. На вкладке Домой перейдите в раздел Репозитории и выберите репозиторий.

    4. В правом верхнем углу нажмите кнопку Клонировать.

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

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

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

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

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

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

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

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

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

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

Примеры

# Это базовый рабочий процесс (workflow), который 
        # поможет вам начать работу с SourceCraft CI/CD
        
        # Настройка события-триггера для запуска рабочего процесса
        on:
          # Запуск рабочего процесса по отправке изменений в ветку main
          # удаленного репозитория или создание пул-реквеста в ветку main
          pull_request:
            - workflows: [sample-workflow]
              filter:
                source_branches: ["**", "!test**"]
                target_branches: "main"
        
          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!");
                }
            }
            

См. также