连续整合Maven工件与GitHub动作
#编程 #java #maven #ci

开发非平凡软件产品的主要要求是建立正式的工作流程,以进行连续集成和连续交付。无论是个人还是小组项目,CI/CD工作流程为从开发人员的框中获取代码到实时环境的基础。

,但它超越了这一点。 CI/CD允许在保持质量和可靠性的同时,经常部署代码。通常,这是在开发管道中特定点的自动单元和集成测试的帮助下完成的。测试将有助于确保新代码不会破坏现有代码。

连续集成是如此重要,以至于未能正式实施它会导致偶然的开发和代码质量的损失,这只会给工程团队带来更大的压力。您可以在此中阅读有关CI/CD的更多信息。

依赖管理

由于现代软件开发的性质,整个系统是通过依靠不同组件的功能来构建的。由于允许这些组件独立发展,因此需要有一种方法来确保它们保持兼容。我们不希望一个组件上的更新会导致错误在另一个组件中表现出来。因此,为了撰写软件,我们需要依靠依赖性管理。

依赖性管理使我们能够打包项目中的依赖项,并在需要的情况下优雅地升级这些依赖项。在Java生态系统中,有两个主要的依赖管理工具:Maven和Gradle。 Maven使用XML配置来定义项目构建,包括所有插件和依赖项。另一方面,Gradle使用基于凹槽 / Kotlin的域特定语言(DSL)来定义构建任务和依赖项。< / p>

让我们谈论版本化。

版本控制

版本控制是将唯一数字分配给软件工件的特定版本的过程。因此,在每个时间点,软件版本编号都会了解工件如何发展。

版本控制是依赖性管理的重要组成部分,因为它使我们能够跟踪依赖关系中的最新发展。

可能会出现一些问题:我们如何升级项目的依赖性版本?我们采用哪种格式进行版本控制?我们如何确保跟踪对依赖项的升级并且不会破坏现有功能?

当前,语义版本控制非常广泛使用。这里的外观:

给定一个版本编号:例如1.5.2,有3个部分:主要(1),次要(5),补丁(2)。

Major :进行不兼容的API更改时会更新;也就是说,可以使用该依赖关系破坏现有系统的更改。

次要:以向后兼容的方式添加功能时进行更新。

补丁:进行向后兼容的错误修复时更新。

现在我们可以深入研究git中的分支模型。

分支模型

分支模型是在共享代码库上工作时的一组规则开发人员。它们有助于构建分支和合并代码的方法,这有助于团队更有效地工作。我严格遵守一个分支模型,该模型使我可以根据GIT历史记录计算项目版本。软件开发中有一些分支模型:

  1. gitflow
  2. github流
  3. 基于躯干的开发

我将在gitflow上散发出更多的启示,因为它是最受欢迎的。 Gitflow使用不同的分支类型:

  • Master或Main:这是稳定的分支,其中包含发布到生产中的最后版本,应始终准备就绪。
  • 功能:功能分支是用于实现功能的。通常,开发人员将开发并编写与该功能分支上有关该功能的所有代码,然后再合并其开发
  • 开发:开发人员合并以在准备将功能集成到主人的功能中时,开发分支是整合计划发布版本的不同功能的分支
  • 版本:开发和用于准备生产版本的分支。测试发布分支时,通常将其合并为开发和主机。
  • hotfix :用于修复主分支上出现的错误。 Hotfix分支机构off Master,并合并回主,并在完成和测试时开发。

Gitflow模型最适合大型团队,尽管可能更繁琐。


git流量分支模型参考:https://nvie.com/posts/a-successful-git-branching-model/

一个过程在某种程度上是gitflow和稍微流行的Trunk-based development的组合。

  1. 创建两个永久分支:主要和开发。主要准备生产代码,开发功能集成。
  2. 在创作功能时,开发分支并创建一个带有功能/'的分支。例如,要在用户登录中工作,请创建一个名为“功能/用户login”的分支开发。
  3. 当功能准备就绪后,将最新功能代码推向远程存储库,并创建一个拉动请求以开发。
  4. 运行代码审核,源代码分析,自动化单元和功能分支的集成测试,以确保合并以合并。
  5. 合并代码以开发和运行自动化单元和集成测试,以确保功能合并没有破坏其他功能。
  6. 将代码合并到主分支。运行标签,版本控制并准备伪影的释放。
  7. 发布。
  8. 合并回发展。

这个过程流量和更流行的gitflow之间的主要区别是,我不创建释放分支。取而代之的是,在测试开发后,我合并到Main并在Main上运行发布管理。开发分支存在用于测试和集成目的。这将确保仅将经过全面测试的代码合并到MAIN。如果您希望高级开发人员在到达MAIN之前,可以自动(由CI触发)合并为MAIN的过程。

从某种意义上说,此过程类似于基于树干的开发,其中主要和发展都是后备箱。在运行发布管理后,合并Main Back以开发。 github避免了周期性的构建,因此合并以开发不会触发ci。

让我们在GitHub动作上实施CI管道

首先,我们安装gitversion:

$ brew install gitversion

我使用gitversion来处理我的版本。

gitversion使用git提交历史记录来计算软件项目的版本。对某些模式进行了提交消息:

  1. 添加新功能时,提交消息应包括: +SEMVER:功能
  2. 添加错误修复时,提交消息应包括: +semver:patch
  3. 当提交引入打破变化时,该消息应包括: +SEMVER:MAXER

设置项目以进行语义版本支持。我使用bash脚本:

#! /bin/bash

git flow init
gitversion init
git commit -m "Setup Versioning"

上面的脚本将在命令提示符中显示一个向导,要求填写有关项目设置的信息。巫师非常简单易懂。完成后,您应该有一个 gitversion.yml 文件,在项目root中具有以下结构:

mode: ContinuousDeployment
branches: {}
ignore:
sha: []
merge-message-formats: {}

在项目的根文件夹中,您应该在.github/Workflows路径中声明3个工作流文件。这样的东西:

功能/热修正分支集成。 (/.github/workflows/non-mainline-branch-update.yml)


name: Feature/Hotfix Build

on:
  push:
    branches:
      - 'feature/*'
      - 'hotfix/*'

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - name: Set up JDK 17
    - uses: actions/checkout@v3
      uses: actions/setup-java@v3
      with:
        java-version: 17
        distribution: zulu

    - name: Cache SonarCloud packages
      uses: actions/cache@v3
      with:
        path: ~/.sonar/cache
        key: ${{ runner.os }}-sonar
        restore-keys: ${{ runner.os }}-sonar

    - name: Cache Maven packages
      uses: actions/cache@v3
      with:
        path: ~/.m2
        key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
        restore-keys: ${{ runner.os }}-m2-

    - name: Build and analyze
      env:
      run: mvn -B verify -s settings.xml -f pom.xml

上面的脚本是在与以下模式匹配的分支的推送事件上触发的:功能/*,hotfix/*。步骤名称描述在构建的每个步骤中所做的事情。

  1. 设置JDK环境,
  2. 恢复声纳的缓存。如果不适用于您,则可以跳过声纳缓存步骤。我使用声纳云来扫描我的工件,因此我需要包括声纳缓存步骤以加快构建。
  3. 修复Maven的缓存。这有助于避免重新下载依赖性,从而加快构建速度。缓存键与项目中的POM文件的哈希相关,因此POMS的更改将计算新的哈希案并触发依赖关系的重新下载。
  4. 最后一步将运行构建和分析

开发分支集成(/.github/workflows/develop-integration.yml)


name: Develop Branch Integration

on:
  pull_request:
    branches: [develop]
    types: [closed]

jobs:
  build:
    runs-on: ubuntu-latest

    if: github.event.pull_request.merged == true
    steps:
      - uses: actions/checkout@v3
      - name: Setup Java 17 env
        uses: actions/setup-java@v1
        with:
          java-version: 17

      - name: Cache Maven packages
        uses: actions/cache@v3
        with:
          path: ~/.m2
          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
          restore-keys: ${{ runner.os }}-m2-

      - name: Build and analyze
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
        run: mvn -B verify -s settings.xml -f pom.xml

      - name: Set Commit Message
        id: commit
        run: |
          ${{ startsWith(github.head_ref, 'feature/') }} && echo ::set-output name=message::"+semver: feature" \
          || echo ::set-output name=message::"+semver: patch"

      - name: Commit Build Message
        env:
          COMMIT_MSG: ${{ steps.commit.outputs.message }}
        run: |
          git config user.email ${{ secrets.GIT_EMAIL }}
          git config user.name ${{ secrets.GIT_USERNAME }}
          git add .
          git commit -m "$COMMIT_MSG" --allow-empty || true

      - name: Push changes
        uses: ad-m/github-push-action@master
        with:
          branch: develop
          github_token: ${{ secrets.GITHUB_TOKEN }}

  merge-main:
    name: Merge to Main
    needs: [build]
    runs-on: ubuntu-latest

    if: github.event.pull_request.merged == true
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Fetching
        run: |
          git fetch --all

      - name: Merge to Main
        uses: devmasx/merge-branch@v1.1.0
        with:
          type: now
          target_branch: 'main'
        env:
          GITHUB_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}

这些步骤是为了合并开发的条件。因此,摘要:if: github.event.pull_request.merged == true"。该构建几乎像以前的构建一样开始,但是这次有一个设置提交消息',我在输出中设置了一个我打算在下一个构建步骤中使用的消息。此消息将在“提交构建消息步骤”中使用,并将在提交中构成消息的一部分。

在主构建中,将通过gitversion利用提交消息来计算软件的版本。如果我合并了功能/*分支,我会使用消息– semver:else featureâ+semver:patch。为了打破文物引入的变化,我会手动发出一条信息 - +semver:专业的当地人。测试成功进行后,我提交更改以开发分支并自动触发合并到Main。

如果不声明您的git存储库设置中的秘密,上面的脚本将无法正常工作。转到 秘密和变量下的动作

当您将代码推到带有功能/*前缀的分支时,hotfix/*触发了上述管道。您可以在“操作”选项卡下检查作业的状态。

主分支集成(/.github/workflows/main-integration.yml)


name: Main Branch CI

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the main branch
on:
  push:
    branches: [main]

jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2
      - name: Fetching All
        run: |
          git fetch --prune --unshallow

      # Install .NET Core as it is required by GitVersion action
      - name: Setup .NET Core
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: |
            3.1.x
            5.0.x

      # Install Git Version
      - name: Installing GitVersion
        uses: gittools/actions/gitversion/setup@v0.9.3
        with:
          versionSpec: '5.3.x'

      # Use Git Version to compute version of the project
      - name: Use GitVersion
        id: gitversion
        uses: gittools/actions/gitversion/execute@v0.9.3

      # Setup Java environment
      - name: Setup Java 17 env
        uses: actions/setup-java@v1
        with:
          java-version: 17

      # Cache and restore Maven dependencies
      - name: Cache Maven packages
        uses: actions/cache@v3
        with:
          path: ~/.m2
          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
          restore-keys: ${{ runner.os }}-m2-

      # For a maven artifact, set version to what was computed by GitVersion in earlier step
      - name: Evaluate New Artifact Version
        run: |
          NEW_VERSION=${{ steps.gitversion.outputs.semVer }}
          echo "Artifact Semantic Version: $NEW_VERSION"
          mvn versions:set -DnewVersion=${NEW_VERSION}-SNAPSHOT -s settings.xml

      # Deploy artifact to repository. Could be ossrh, archiva etc. 
      - name: Build and Deploy with Maven
        env:
          ARTIFACT_REPO_USERNAME: ${{ secrets.ARTIFACT_REPO_USERNAME }}
          ARTIFACT_REPO_PASSWORD: ${{ secrets.ARTIFACT_REPO_PASSWORD }}
        run: |
          export MAVEN_OPTS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED"
          mvn clean deploy -s settings.xml -f pom.xml

      # Optional step where I like to write the version number to a file in the project root. 
      - name: Upgrading Version
        run: |
          RELEASE_TAG=${{ steps.gitversion.outputs.semVer }}
          echo $RELEASE_TAG > version.ver
          git config user.email ${{ secrets.GIT_EMAIL }}
          git config user.name ${{ secrets.GIT_USERNAME }}
          git add .
          git commit -m "Upgraded Version >> $RELEASE_TAG" || true

      - name: Push changes
        uses: ad-m/github-push-action@master
        with:
          branch: main
          github_token: ${{ secrets.GITHUB_TOKEN }}

  merge-develop:
    name: Merge to Develop
    needs: [build]
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: Fetching
      run: |
        git fetch --all
    - name: Merge to Develop
      uses: devmasx/merge-branch@v1.1.0
      with:
        type: now
        target_branch: develop
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

按照主构建中的评论应直接。我使用gitversion计算工件的版本,然后在调用mvn版本后部署工件:setâ。新版本致力于Main,然后合并回去开发。部署步骤将根据工件的性质而有所不同。例如,这可能是在Heroku上部署的服务。在这种情况下,我将有这样的步骤:


- name: Push changes to Heroku
  uses: akhileshns/heroku-deploy@v3.12.12
  with:
    heroku_api_key: ${{secrets.HEROKU_API_KEY}}
    heroku_app_name: ${{secrets.HEROKU_APP_NAME}}
    heroku_email: ${{secrets.HEROKU_EMAIL}}

我们真的可以做任何事情。部署到Heroku,AWS,GCP或推到Docker。根据我们的流程流动的任何作用。

这是一个序列图来回顾我们的CI的外观:

结论

在本文中,我们讨论了如何使用GitHub动作自动化Maven伪像的CI过程。通过使用GitHub操作,您可以轻松地配置和运行Maven命令,例如MVN Test'和MVN部署,每当将更改推到存储库时。这有助于尽早捕获错误,并确保代码始终处于可发布状态。

请注意,这是一个示例,可能有必要调整步骤和命令以匹配您的特定用例ð