1、CI/CD介绍
CI/CD网上的解释为持续集成、持续交付和持续部署。光这么说,可能确实有点迷茫,那我拿开发写代码来举个例子:
小明开发一套程序,需要利用IDE开发,开发好进行调试,然后放到服务器上运行,再解决服务器上的兼容问题,最终查看程序运行一段时间以后的稳定性。
但是当有了CI/CD以后的过程是怎么样的呢:
小明开发一套程序,更新代码后,后续的变更、构建、测试和发布,都由工作流程的自动化完成。
当然,上述的解释肯定是不完整的,毕竟这只是我的个人理解。
2、github actions
那我们这次利用github actions能做什么呢,我们主要拿github actions来进行自动化的构建和发布。
3、自动化
首先我们先在github网页版创建一个私人仓库:
本地执行如下命令:
mkdir actionstest cd actionstest/ git init git add README.md echo "# github actions test" >> README.md git add README.md git commit -m "first commit" git remote add https://github.com/Jumbo-WJB/actionstest git push -u origin master
本次我们拿JuicyPotato提权工具来进行演示。
本地执行:
git submodule add https://github.com/ohpe/juicy-potato git commit -m "add submodule" git push
现在我们仓库就有个juicy-potato的子仓库了:
现在我们要做的就是来编译这个项目。
进入Actions:
进入到如下界面,默认带了简单的语法和提示:
根据自我认知来介绍以下我知道的命令/语法:
# This is a basic workflow to help you get started with Actions name: CI #CI/CD项目名称 固定值 # Controls when the action will run. Triggers the workflow on push or pull request # events but only for the master branch on: # 固定值 push: # 固定值 branches: [ master ] pull_request: branches: [ master ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel 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 #调用模块 # Runs a single command using the runners shell - name: Run a one-line script #方法名称 run: echo Hello, world! # 方法动作 # Runs a set of commands using the runners shell - name: Run a multi-line script #方法名称 run: | #多条命令 echo Add other actions to build, # 方法动作 echo test, and deploy your project. # 方法动作
接下来我们要了解这个项目如何编译,我们看下原项目,大概知道可以用VS来编译:
下面就是找模块来编译了,这里利用https://github.com/warrenbuckley/Setup-Nuget
第一次我们的代码如下:
name: build juicy
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Checkout submodules
shell: bash
run: |
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
- name: Setup Nuget.exe
uses: warrenbuckley/Setup-Nuget@v1
- name: Nuget Restore
run: nuget restore $Env:GITHUB_WORKSPACE\juicy-potato\JuicyPotato\JuicyPotato.sln
- name: Build JuicyPotato
run: |
cd "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\"
.\MSBuild.exe $Env:GITHUB_WORKSPACE\juicy-potato\JuicyPotato\JuicyPotato.sln
上述代码主要意思是同步所有git代码,然后利用warrenbuckley/Setup-MSBuild模块对JuicyPotato.vcxproj进行编译,在把上面代码更新到yml中,保存以后,会自动进行编译,我们点击Actions能看到进展:
我们第一次代码报错了,点击红色X的地方能看到报错内容:
看提示是找不到sdk 8.1,根据搜索,发现vs2019默认不带这玩意,可以利用powershell安装,因此我们可以在编译的过程中加个安装sdk 8.1的方法:
- name: Install Windows 8.1 SDK shell: powershell run: | Invoke-WebRequest -Method Get -Uri https://go.microsoft.com/fwlink/p/?LinkId=323507 -OutFile sdksetup.exe -UseBasicParsing Start-Process -Wait sdksetup.exe -ArgumentList "/q", "/norestart", "/features", "OptionId.WindowsDesktopSoftwareDevelopmentKit", "OptionId.NetFxSoftwareDevelopmentKit"
最终我们成功的完善了环境并编译出来了exe:
现在要把编译出来exe,github这里叫artifact,传出来,这里用actions/upload-artifact模块:
- uses: actions/upload-artifact@master with: name: JuicyPotato path: juicy-potato\JuicyPotato\Release\x64\JuicyPotato.exe
这里的path路径可以在上图编译出来的exe路径找到:
现在可以下载回来并执行:
但每次编译再过来下载artifact并非我的本意,我想要自动发布到release,这里使用其他两个模块:
actions/create-release actions/upload-release-asset
模块在其github上都有示例,所以用起来还是比较方便的。
actions/upload-release-asset模块发布的时候,需要是压缩包,因此这里使用powershell把生成的exe压缩一下,再丢给actions/upload-release-asset去上传到release中:
完整代码如下:name: build juicy
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Checkout submodules
shell: bash
run: |
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
- name: Install Windows 8.1 SDK
shell: powershell
run: |
Invoke-WebRequest -Method Get -Uri https://go.microsoft.com/fwlink/p/?LinkId=323507 -OutFile sdksetup.exe -UseBasicParsing
Start-Process -Wait sdksetup.exe -ArgumentList "/q", "/norestart", "/features", "OptionId.WindowsDesktopSoftwareDevelopmentKit", "OptionId.NetFxSoftwareDevelopmentKit"
- name: Setup Nuget.exe
uses: warrenbuckley/Setup-Nuget@v1
- name: Nuget Restore
run: nuget restore $Env:GITHUB_WORKSPACE\juicy-potato\JuicyPotato\JuicyPotato.sln
- name: Build JuicyPotato
run: |
cd "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\"
.\MSBuild.exe $Env:GITHUB_WORKSPACE\juicy-potato\JuicyPotato\JuicyPotato.sln
- uses: actions/upload-artifact@master
with:
name: JuicyPotato
path: juicy-potato\JuicyPotato\Release\x64\JuicyPotato.exe
- name: zip_exe
shell: powershell
run: Compress-Archive -Path juicy-potato\JuicyPotato\Release\x64\JuicyPotato.exe -DestinationPath juicy-potato\JuicyPotato\Release\x64\JuicyPotato.zip
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: juicy-potato\JuicyPotato\Release\x64\JuicyPotato.zip
asset_name: JuicyPotato.zip
asset_content_type: application/zip
最后一段代码新增的几个参数中with是模块所需要的参数,env就是取secret作为全局变量,如果你在仓库的setting中设置了secret变量,也可以用这种方法取到,这样可以防止把敏感信息写死在代码里。