赞
踩
目录
(放个目录方便预览。目录是从博客复制过来的,点击会跳转到博客)
在上一篇文章《Qt使用github-Actions自动化编译》中,介绍了github-Actions的基本用法,
本文来介绍github-Actions的自动化发布。
结果预览
先来回顾一下,上一篇文章中的Qt项目的编译流程
Qt程序在编译完成后,发布的大致流程是:
1、 查找依赖库
2、制作压缩包或者安装包
3、上传压缩包或者安装包到网站、网盘。
Qt官方提供的查找依赖库的命令行工具,包括:Windows平台的Windeployqt、MacOS平台的Macosdeployqt。
在这两个平台,只使用Qt库的情况下,这两个工具足够了。
做压缩包比较简单。(我们常说的‘绿色软件’,就是一个压缩包)
一般安装7z、rar之类的压缩工具,用一条命令行就行了。
涛哥这里再说一下,github-Actions给所有平台都提供了PowerShell,而PowerShell内置了压缩命令Compress-Archive。
使用也很简单,只要路径和名字,例如:
Compress-Archive
做安装包,Qt官方有功能很全面的安装包制作工具:QtInstallFrameWork, 稍微翻看一下文档或者例子即可。本文先不展开了。
github 本身提供了’Release’功能,每个仓库都有一个’Release’页面
可以将打包好的压缩包或者安装包,直接上传上去, 供他人下载。
github-Actions还提供了 创建’Release’、上传’Release’的模板
actions/create-release
actions/upload-release-asset
这两个模板的用法也很简单,在yml文件中直接use就行了,不赘述了。
前面介绍了一些简单的理论,接下来通过实例,教大家github-Actions的使用。
以HelloActions-Qt项目为例,做一些定制。
需求如下:
1、每次提交代码,同时在Windows、MacOS、Ubuntu、Android、IOS五个平台编译
2、每次提交tag,在windows和MacOS平台制作软件包,并发布到同一个github-‘Release’
需求1已经实现了,着重讨论一下需求2:
‘每次提交tag’限定了发布的时机。
涛哥尝试了一番,最终得到答案。
回顾一下, Windows平台的编译配置:
name
steps中的每一个步骤,可以有触发条件。我们可以在这里指定,只有github的事件为tag时才执行:
- steps:
- 。。。
- # tag 打包
- - name: package
- if: startsWith(github.event.ref, 'refs/tags/')
- run: |
- 。。。
这里给出一个实际的打包步骤:
- # tag 打包
- - name: package
- if: startsWith(github.event.ref, 'refs/tags/')
- env:
- VCINSTALLDIR: 'C:Program Files (x86)Microsoft Visual Studio2019EnterpriseVC'
- archiveName: ${{ matrix.qt_ver }}-${{ matrix.qt_target }}-${{ matrix.qt_arch }}
- targetName: HelloActions-Qt.exe
- shell: pwsh
- run: |
- # 创建文件夹
- New-Item -ItemType Directory ${env:archiveName}
- # 拷贝exe
- Copy-Item bin${env:targetName} ${env:archiveName}
- # 拷贝依赖
- windeployqt --qmldir . ${env:archiveName}${env:targetName}
- # 打包zip
- Compress-Archive -Path ${env:archiveName} ${env:archiveName}'.zip'
- # 记录环境变量packageName给后续step
- $name = ${env:archiveName}
- echo "::set-env name=packageName::$name"
- # 打印环境变量packageName
- Write-Host 'packageName:'${env:packageName}
做一些说明:
其中的VCINSTALLDIR环境变量,是给windeployqt用的。有了这个环境变量,windeployqt会去msvc的安装路径提取‘运行时安装程序’。
打包完以后,将包名设置为环境变量,后续的步骤就可以通过环境变量拿到包名字了。
普通的设置环境变量,在步骤执行完成后就失效了,
这里使用github-Actions的‘记录命令’set-env ,具体可以参考文档github-Actions记录命令
文档说不要用双引号,应该都是针对linux的,我试出来的PowerShell用法如下:
- $name = ${env:archiveName}
- echo "::set-env name=packageName::$name"
先取环境变量到一个局部变量,再在‘记录命令’中引用局部变量。
如果只有一个平台、一种配置,直接用那两个模板就能解决问题。
这是官方给的例子upload-release-asset:
- steps:
- - name: Checkout code
- uses: actions/checkout@master
- - name: Build project # This would actually build your project, using zip for an example artifact
- run: |
- zip --junk-paths my-artifact README.md
- - name: Create Release
- id: create_release
- uses: actions/create-release@v1.0.0
- 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.0.1
- 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: ./my-artifact.zip
- asset_name: my-artifact.zip
- asset_content_type: application/zip
在多平台 或者 多配置的情况下,同一个tag, 只有第一个执行create-release的任务可以成功,后续任务
再次执行create-release时,该tag下已经有了同名的‘Release’,所以会create失败。
这个问题折磨了涛哥好一阵子。找不到现成的解决方案,涛哥就自己实现了一种:
调用REST API,涛哥依旧使用了方便的PowerShell,
实际的配置如下:
- # tag 查询github-Release
- - name: queryReleaseWin
- id: queryReleaseWin
- if: startsWith(github.event.ref, 'refs/tags/')
- shell: pwsh
- env:
- githubFullName: ${{ github.event.repository.full_name }}
- ref: ${{ github.event.ref }}
- run: |
- [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
- [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag}
- $response={}
- try {
- $response = Invoke-RestMethod -Uri $url -Method Get
- } catch {
- Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
- Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
- # 没查到,输出
- echo "::set-output name=needCreateRelease::true"
- return
- }
- [string]$latestUpUrl = $response.upload_url
- Write-Host 'latestUpUrl:'$latestUpUrl
- if ($latestUpUrl.Length -eq 0) {
- # 没查到,输出
- echo "::set-output name=needCreateRelease::true"
- }
- # tag 创建github-Release
- - name: createReleaseWin
- id: createReleaseWin
- if: startsWith(github.event.ref, 'refs/tags/') && steps.queryReleaseWin.outputs.needCreateRelease == 'true'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/create-release@v1.0.0
- with:
- tag_name: ${{ github.ref }}
- release_name: Release ${{ github.ref }}
- body: ${{ github.event.head_commit.message }}
- draft: false
- prerelease: false
- # tag 重定向upload_url到环境变量uploadUrl。
- - name: getLatestTagRelease
- if: startsWith(github.event.ref, 'refs/tags/')
- shell: pwsh
- env:
- githubFullName: ${{ github.event.repository.full_name }}
- upUrl: ${{ steps.createReleaseWin.outputs.upload_url }}
- ref: ${{ github.event.ref }}
- run: |
- # upUrl不为空,导出就完事
- if (${env:upUrl}.Length -gt 0) {
- $v=${env:upUrl}
- echo "::set-env name=uploadUrl::$v"
- return
- }
- # upUrl为空则重新获取
- [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
- [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag}
- $response = Invoke-RestMethod -Uri $url -Method Get
- [string]$latestUpUrl = $response.upload_url
- Write-Host 'latestUpUrl:'$latestUpUrl
- # 导出
- echo "::set-env name=uploadUrl::$latestUpUrl"
- Write-Host 'env uploadUrl:'${env:uploadUrl}
- # tag 上传Release
- - name: uploadRelease
- id: uploadRelease
- if: startsWith(github.event.ref, 'refs/tags/')
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-release-asset@v1.0.1
- with:
- upload_url: ${{ env.uploadUrl }}
- asset_path: ./${{ env.packageName }}.zip
- asset_name: ${{ env.packageName }}.zip
- asset_content_type: application/zip
- name: Windows
- on:
- # push代码时触发workflow
- push:
- # 忽略README.md
- paths-ignore:
- - 'README.md'
- - 'LICENSE'
- # pull_request时触发workflow
- pull_request:
- # 忽略README.md
- paths-ignore:
- - 'README.md'
- - 'LICENSE'
- jobs:
- build:
- name: Build
- # 运行平台, windows-latest目前是windows server 2019
- runs-on: windows-latest
- strategy:
- # 矩阵配置
- matrix:
- qt_ver: [5.12.6]
- qt_target: [desktop]
- qt_arch: [win64_msvc2017_64, win32_msvc2017]
- # 额外设置msvc_arch
- include:
- - qt_arch: win64_msvc2017_64
- msvc_arch: x64
- qt_arch_install: msvc2017_64
- - qt_arch: win32_msvc2017
- msvc_arch: x86
- qt_arch_install: msvc2017
- env:
- targetName: HelloActions-Qt.exe
- # 步骤
- steps:
- # 安装Qt
- - name: Install Qt
- # 使用外部action。这个action专门用来安装Qt
- uses: jurplel/install-qt-action@v2.0.0
- with:
- # Version of Qt to install
- version: ${{ matrix.qt_ver }}
- # Target platform for build
- target: ${{ matrix.qt_target }}
- # Architecture for Windows/Android
- arch: ${{ matrix.qt_arch }}
- # 拉取代码
- - uses: actions/checkout@v1
- with:
- fetch-depth: 1
- # 编译msvc
- - name: build-msvc
- shell: cmd
- env:
- vc_arch: ${{ matrix.msvc_arch }}
- run: |
- call "C:Program Files (x86)Microsoft Visual Studio2019EnterpriseVCAuxiliaryBuildvcvarsall.bat" %vc_arch%
- qmake
- nmake
- # tag 打包
- - name: package
- if: startsWith(github.event.ref, 'refs/tags/')
- env:
- VCINSTALLDIR: 'C:Program Files (x86)Microsoft Visual Studio2019EnterpriseVC'
- archiveName: ${{ matrix.qt_ver }}-${{ matrix.qt_target }}-${{ matrix.qt_arch }}
- shell: pwsh
- run: |
- # 创建文件夹
- New-Item -ItemType Directory ${env:archiveName}
- # 拷贝exe
- Copy-Item bin${env:targetName} ${env:archiveName}
- # 拷贝依赖
- windeployqt --qmldir . ${env:archiveName}${env:targetName}
- # 打包zip
- Compress-Archive -Path ${env:archiveName} ${env:archiveName}'.zip'
- # 记录环境变量packageName给后续step
- $name = ${env:archiveName}
- echo "::set-env name=packageName::$name"
- # 打印环境变量packageName
- Write-Host 'packageName:'${env:packageName}
- # tag 查询github-Release
- - name: queryReleaseWin
- id: queryReleaseWin
- if: startsWith(github.event.ref, 'refs/tags/')
- shell: pwsh
- env:
- githubFullName: ${{ github.event.repository.full_name }}
- ref: ${{ github.event.ref }}
- run: |
- [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
- [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag}
- $response={}
- try {
- $response = Invoke-RestMethod -Uri $url -Method Get
- } catch {
- Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
- Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
- # 没查到,输出
- echo "::set-output name=needCreateRelease::true"
- return
- }
- [string]$latestUpUrl = $response.upload_url
- Write-Host 'latestUpUrl:'$latestUpUrl
- if ($latestUpUrl.Length -eq 0) {
- # 没查到,输出
- echo "::set-output name=needCreateRelease::true"
- }
- # tag 创建github-Release
- - name: createReleaseWin
- id: createReleaseWin
- if: startsWith(github.event.ref, 'refs/tags/') && steps.queryReleaseWin.outputs.needCreateRelease == 'true'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/create-release@v1.0.0
- with:
- tag_name: ${{ github.ref }}
- release_name: Release ${{ github.ref }}
- body: ${{ github.event.head_commit.message }}
- draft: false
- prerelease: false
- # 重定向upload_url到环境变量uploadUrl。
- - name: getLatestTagRelease
- # tag 上一步无论成功还是失败都执行
- if: startsWith(github.event.ref, 'refs/tags/')
- shell: pwsh
- env:
- githubFullName: ${{ github.event.repository.full_name }}
- upUrl: ${{ steps.createReleaseWin.outputs.upload_url }}
- ref: ${{ github.event.ref }}
- run: |
- # upUrl不为空,导出就完事
- if (${env:upUrl}.Length -gt 0) {
- $v=${env:upUrl}
- echo "::set-env name=uploadUrl::$v"
- return
- }
- [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
- [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag}
- $response = Invoke-RestMethod -Uri $url -Method Get
- [string]$latestUpUrl = $response.upload_url
- Write-Host 'latestUpUrl:'$latestUpUrl
- echo "::set-env name=uploadUrl::$latestUpUrl"
- Write-Host 'env uploadUrl:'${env:uploadUrl}
- # tag 上传Release
- - name: uploadRelease
- id: uploadRelease
- if: startsWith(github.event.ref, 'refs/tags/')
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-release-asset@v1.0.1
- with:
- upload_url: ${{ env.uploadUrl }}
- asset_path: ./${{ env.packageName }}.zip
- asset_name: ${{ env.packageName }}.zip
- asset_content_type: application/zip
- name: MacOS
- on:
- push:
- paths-ignore:
- - 'README.md'
- - 'LICENSE'
- pull_request:
- paths-ignore:
- - 'README.md'
- - 'LICENSE'
- jobs:
- build:
- name: Build
- runs-on: ${{ matrix.os }}
- strategy:
- matrix:
- os: [macos-latest]
- qt_ver: [5.12.6]
- qt_arch: [clang_64]
- env:
- targetName: HelloActions-Qt
- steps:
- - name: Install Qt
- uses: jurplel/install-qt-action@v2.0.0
- with:
- version: ${{ matrix.qt_ver }}
- - uses: actions/checkout@v1
- with:
- fetch-depth: 1
- - name: build macos
- run: |
- qmake
- make
- # tag 打包
- - name: package
- if: startsWith(github.event.ref, 'refs/tags/')
- run: |
- # 拷贝依赖
- macdeployqt bin/${targetName}.app -qmldir=. -verbose=1 -dmg
- # tag 查询github-Release
- - name: queryRelease
- id: queryReleaseMacos
- if: startsWith(github.event.ref, 'refs/tags/')
- shell: pwsh
- env:
- githubFullName: ${{ github.event.repository.full_name }}
- ref: ${{ github.event.ref }}
- run: |
- [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
- [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag}
- $response={}
- try {
- $response = Invoke-RestMethod -Uri $url -Method Get
- } catch {
- Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
- Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
- # 没查到,输出
- echo "::set-output name=needCreateRelease::true"
- return
- }
- [string]$latestUpUrl = $response.upload_url
- Write-Host 'latestUpUrl:'$latestUpUrl
- if ($latestUpUrl.Length -eq 0) {
- # 没查到,输出
- echo "::set-output name=needCreateRelease::true"
- }
- # tag 创建github-Release
- - name: createReleaseWin
- id: createReleaseWin
- if: startsWith(github.event.ref, 'refs/tags/') && steps.queryReleaseMacos.outputs.needCreateRelease == 'true'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/create-release@v1.0.0
- with:
- tag_name: ${{ github.ref }}
- release_name: Release ${{ github.ref }}
- body: ${{ github.event.head_commit.message }}
- draft: false
- prerelease: false
- # 重定向upload_url到环境变量uploadUrl。
- - name: getLatestTagRelease
- # tag 上一步无论成功还是失败都执行
- if: startsWith(github.event.ref, 'refs/tags/')
- shell: pwsh
- env:
- githubFullName: ${{ github.event.repository.full_name }}
- upUrl: ${{ steps.queryReleaseMacos.outputs.upload_url }}
- ref: ${{ github.event.ref }}
- run: |
- # upUrl不为空,导出就完事
- if (${env:upUrl}.Length -gt 0) {
- $v=${env:upUrl}
- echo "::set-env name=uploadUrl::$v"
- return
- }
- [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
- [string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag}
- $response = Invoke-RestMethod -Uri $url -Method Get
- [string]$latestUpUrl = $response.upload_url
- Write-Host 'latestUpUrl:'$latestUpUrl
- echo "::set-env name=uploadUrl::$latestUpUrl"
- Write-Host 'env uploadUrl:'${env:uploadUrl}
- # tag 上传Release
- - name: uploadRelease
- id: uploadRelease
- if: startsWith(github.event.ref, 'refs/tags/')
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-release-asset@v1.0.1
- with:
- upload_url: ${{ env.uploadUrl }}
- asset_path: ./bin/${{ env.targetName }}.dmg
- asset_name: ${{ env.targetName }}.dmg
- asset_content_type: application/applefile
代码在github HelloActions-Qt
另外在涛哥的Qml控件库TaoQuick,也使用了这一套配置 TaoQuick
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。