github.com/ConsenSys/Quorum@v20.10.0+incompatible/.github/workflows/release.yml (about) 1 name: Release 2 on: 3 push: 4 tags: 5 - 'v*' 6 env: 7 GO_VERSION: 1.13 8 GOPATH: ${{ github.workspace }}/go 9 WORKING_DIR: ${{ github.workspace }}/go/src/github.com/ethereum/go-ethereum 10 jobs: 11 publish-docker: 12 name: Publish Docker Image 13 runs-on: ubuntu-latest 14 steps: 15 - name: 'Checkout' 16 uses: actions/checkout@v2 17 - name: 'Extract Docker Image Tag' 18 id: extract 19 run: | 20 REF=${{ github.ref }} 21 echo ::set-output name=image_tag::$(echo $REF | sed 's/refs\/tags\/v//g') 22 echo ::set-output name=image_tag_minor_latest::$(echo $REF | sed -e 's/refs\/tags\/v//g' -e 's/^\([[:digit:]]*\.[[:digit:]]*\).*/\1/') 23 - name: 'Build and publish to Docker Hub' 24 uses: docker/build-push-action@v1 25 with: 26 username: ${{ secrets.DOCKER_USERNAME }} 27 password: ${{ secrets.DOCKER_ACCESS_TOKEN }} 28 repository: ${{ secrets.DOCKER_REPO }} 29 tags: ${{ steps.extract.outputs.image_tag }}, ${{ steps.extract.outputs.image_tag_minor_latest }} 30 add_git_labels: true 31 build: 32 name: 'Build binary for ${{ matrix.os }}' 33 strategy: 34 fail-fast: false 35 matrix: 36 os: ["ubuntu-latest", "macos-latest"] 37 runs-on: ${{ matrix.os }} 38 steps: 39 - name: 'Setup Go ${{ env.GO_VERSION }}' 40 uses: actions/setup-go@v1 41 with: 42 go-version: ${{ env.GO_VERSION }} 43 - name: 'Prepare environment' 44 id: env 45 run: | 46 echo "::add-path::$(go env GOPATH)/bin" 47 echo "::set-output name=key::$(go env GOOS)_$(go env GOARCH)" 48 echo "::set-output name=version::${GITHUB_REF##*/}" 49 - name: 'Check out project files' 50 uses: actions/checkout@574281d 51 with: 52 submodules: recursive 53 path: ${{ env.WORKING_DIR }} 54 - name: 'Build geth' 55 working-directory: ${{ env.WORKING_DIR }} 56 run: | 57 make geth 58 mkdir -p build/artifact 59 tar cfvz build/artifact/geth_${{ steps.env.outputs.version }}_${{ steps.env.outputs.key }}.tar.gz -C build/bin geth 60 - name: 'Upload artifact' 61 uses: actions/upload-artifact@v2 62 with: 63 path: ${{ env.WORKING_DIR }}/build/artifact 64 name: ${{ steps.env.outputs.key }} 65 prepare-bintray: 66 name: 'Prepare Bintray' 67 runs-on: ubuntu-latest 68 steps: 69 - name: 'Setup jfrog CLI' 70 uses: jfrog/setup-jfrog-cli@v1 71 - name: 'Create new version in Bintray' 72 id: prepare_bintray 73 run: | 74 TAG="${GITHUB_REF##*/}" 75 PACKAGE="${{ secrets.BINTRAY_PACKAGE }}" # e.g.: quorumengineering/quorum/geth 76 VERSION="$PACKAGE/$TAG" 77 jfrog bt package-show --key ${{ secrets.BINTRAY_API_KEY }} --user ${{ secrets.BINTRAY_USER }} $PACKAGE 78 echo "Checking $VERSION" 79 jfrog bt version-show --key ${{ secrets.BINTRAY_API_KEY }} --user ${{ secrets.BINTRAY_USER }} $VERSION && x=0 || x=1 80 if [ $x -eq 0 ]; then 81 echo "$VERSION already exists" 82 else 83 jfrog bt version-create --key ${{ secrets.BINTRAY_API_KEY }} --user ${{ secrets.BINTRAY_USER }} \ 84 --vcs-tag $TAG --released $(date -u +"%Y-%m-%dT%H:%M:%SZ") \ 85 $VERSION 86 fi 87 deploy-bintray: 88 name: 'Deploy binaries to Bintray' 89 needs: 90 - build 91 - prepare-bintray 92 runs-on: ubuntu-latest 93 steps: 94 - name: 'Setup jfrog CLI' 95 uses: jfrog/setup-jfrog-cli@v1 96 - name: 'Download artifacts' 97 uses: actions/download-artifact@v2 98 with: 99 path: artifact 100 - name: 'Upload artifacts to Bintray' 101 run: | 102 TAG="${GITHUB_REF##*/}" 103 jfrog bt upload --key ${{ secrets.BINTRAY_API_KEY }} --user ${{ secrets.BINTRAY_USER }} --publish --override \ 104 "artifact/*/*.*" \ 105 ${{ secrets.BINTRAY_PACKAGE }}/$TAG \ 106 $TAG/ 107 draft-release: 108 name: 'Draft Github release' 109 needs: 110 - deploy-bintray 111 - publish-docker 112 runs-on: ubuntu-latest 113 steps: 114 - name: 'Check out project files' 115 uses: actions/checkout@v2 116 - name: 'Generate release notes' 117 id: release_notes 118 run: | 119 git fetch --depth=1 origin +refs/tags/*:refs/tags/* 120 package="${{ secrets.BINTRAY_PACKAGE }}" 121 repo="${package%/*}" 122 file="generated-release-notes.md" 123 current_version="${GITHUB_REF##*/}" 124 last_version=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=1 --max-count=1`) 125 last_release_date=$(git log -1 --format=%cd --date=short $last_version) 126 echo "Last version: $last_version on $last_release_date" 127 # pulling from git logs 128 curl -q -s -H "Accept: application/vnd.github.v3+json" \ 129 "https://api.github.com/search/issues?q=repo:ConsenSys/quorum+is:pr+is:merged+merged%3A>=$last_release_date+sort%3Aupdated-desc" | jq -r '"* " + (.items[]|.title + " #" + (.number|tostring))' \ 130 >> $file 131 # pulling file hashes from Bintray 132 echo "" >> $file 133 echo "| Filename | SHA256 Hash |" >> $file 134 echo "|:---------|:------------|" >> $file 135 curl -q -s -u ${{ secrets.BINTRAY_USER }}:${{ secrets.BINTRAY_API_KEY}} "https://api.bintray.com/packages/$package/versions/$current_version/files" \ 136 | jq '.[] | select(.name | endswith(".asc") | not) | "|[\(.name)](https://bintray.com/$repo/download_file?file_path=\(.path))|`\(.sha256)`|"' -r \ 137 >> $file 138 content=$(cat $file) 139 # escape newline 140 content="${content//'%'/'%25'}" 141 content="${content//$'\n'/'%0A'}" 142 content="${content//$'\r'/'%0D'}" 143 echo "::set-output name=content::$content" 144 - name: 'Create Github draft release' 145 uses: actions/create-release@v1 146 env: 147 # This token is provided by Actions, you do not need to create your own token 148 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 149 with: 150 tag_name: ${{ github.ref }} 151 release_name: ${{ github.ref }} 152 body: | 153 ${{ steps.release_notes.outputs.content }} 154 draft: true 155 prerelease: false 156 notify: 157 if: always() 158 name: 'Notify' 159 needs: 160 - build 161 - deploy-bintray 162 - publish-docker 163 - draft-release 164 runs-on: ubuntu-latest 165 steps: 166 - name: 'Setup metadata' 167 id: setup 168 run: | 169 gitref_path="${{ github.ref }}" 170 gitref_path=${gitref_path/refs\/heads/tree} # for refs/heads/my-branch 171 gitref_path=${gitref_path/refs\/tags/tree} # for refs/tags/v1.0.0 172 gitref_path=${gitref_path#refs\/} # for refs/pull/123/merge 173 gitref_path=${gitref_path%/merge} # for refs/pull/123/merge 174 echo "::set-output name=gitref-path::$gitref_path" 175 echo "::set-output name=version::${GITHUB_REF##*/}" 176 - name: 'Prepare Slack message with full info' 177 id: status 178 uses: actions/github-script@0.8.0 179 with: 180 script: | 181 var gitref_path = "${{ steps.setup.outputs.gitref-path }}" 182 //////////////////////////////////// 183 // retrieve workflow run data 184 //////////////////////////////////// 185 console.log("get workflow run") 186 const wf_run = await github.actions.getWorkflowRun({ 187 owner: context.repo.owner, 188 repo: context.repo.repo, 189 run_id: ${{ github.run_id }} 190 }) 191 console.log(wf_run.data) 192 console.log("get jobs for workflow run:", wf_run.data.jobs_url) 193 const jobs_response = await github.request(wf_run.data.jobs_url) 194 //////////////////////////////////// 195 // build slack notification message 196 //////////////////////////////////// 197 // some utility functions 198 var date_diff_func = function(start, end) { 199 var duration = end - start 200 // format the duration 201 var delta = duration / 1000 202 var days = Math.floor(delta / 86400) 203 delta -= days * 86400 204 var hours = Math.floor(delta / 3600) % 24 205 delta -= hours * 3600 206 var minutes = Math.floor(delta / 60) % 60 207 delta -= minutes * 60 208 var seconds = Math.floor(delta % 60) 209 var format_func = function(v, text, check) { 210 if (v <= 0 && check) { 211 return "" 212 } else { 213 return v + text 214 } 215 } 216 return format_func(days, "d", true) + format_func(hours, "h", true) + format_func(minutes, "m", true) + format_func(seconds, "s", false) 217 } 218 var status_icon_func = function(s) { 219 switch (s) { 220 case "w_success": 221 return ":white_check_mark:" 222 case "w_failure": 223 return ":no_entry:" 224 case "w_cancelled": 225 return ":warning:" 226 case "success": 227 return "\u2713" 228 case "failure": 229 return "\u2717" 230 default: 231 return "\u20e0" 232 } 233 } 234 // build the message 235 var job_blocks = [] 236 var is_wf_success = true 237 var is_wf_failure = false 238 for (j of jobs_response.data.jobs) { 239 console.log(j.name, ":", j.status, j.conclusion, j.started_at, j.completed_at) 240 // ignore the current job running this script 241 if (j.status != "completed") { 242 continue 243 } 244 if (j.conclusion != "success") { 245 is_wf_success = false 246 } 247 if (j.conclusion == "failure") { 248 is_wf_failure = true 249 } 250 job_blocks.push({ 251 type: "section", 252 text: { 253 type: "mrkdwn", 254 text: `${status_icon_func(j.conclusion)} <${j.html_url}|${j.name}> took ${date_diff_func(new Date(j.started_at), new Date(j.completed_at))}` 255 } 256 }) 257 } 258 var workflow_status = "w_cancelled" 259 if (is_wf_success) { 260 workflow_status = "w_success" 261 } else if (is_wf_failure) { 262 workflow_status = "w_failure" 263 } 264 var context_elements = [ 265 { 266 "type": "mrkdwn", 267 "text": "*Repo:* <https://github.com/${{ github.repository }}|${{ github.repository }}>" 268 }, 269 { 270 "type": "mrkdwn", 271 "text": `*Branch:* <https://github.com/${{ github.repository }}/${gitref_path}|${{ github.ref }}>` 272 }, 273 { 274 "type": "mrkdwn", 275 "text": `*Event:* ${wf_run.data.event}` 276 }, 277 { 278 "type": "mrkdwn", 279 "text": `*Commit:* <https://github.com/${{ github.repository }}/commit/${wf_run.data.head_commit.id}|${wf_run.data.head_commit.id.substr(0, 8)}>` 280 }, 281 { 282 "type": "mrkdwn", 283 "text": `*Author:* ${wf_run.data.head_commit.author.name}` 284 } 285 ] 286 var header_blocks = [ 287 { 288 type: "section", 289 text: { 290 type: "mrkdwn", 291 text: `${status_icon_func(workflow_status)} *${{ github.workflow }} ${{ steps.setup.outputs.version }}* <${wf_run.data.html_url}|#${{ github.run_number }}> took ${date_diff_func(new Date(wf_run.data.created_at), new Date(wf_run.data.updated_at))}` 292 } 293 }, 294 { 295 type: "context", 296 elements: context_elements, 297 }, 298 { 299 type: "divider" 300 } 301 ] 302 var slack_msg = { 303 blocks: [].concat(header_blocks, job_blocks) 304 } 305 return slack_msg 306 - name: 'Prepare Slack message with partial info' 307 id: short_status 308 if: failure() 309 uses: actions/github-script@0.8.0 310 with: 311 script: | 312 //////////////////////////////////// 313 // retrieve workflow run data 314 //////////////////////////////////// 315 const wf_run = await github.actions.getWorkflowRun({ 316 owner: context.repo.owner, 317 repo: context.repo.repo, 318 run_id: ${{ github.run_id }} 319 }) 320 var date_diff_func = function(start, end) { 321 var duration = end - start 322 // format the duration 323 var delta = duration / 1000 324 var days = Math.floor(delta / 86400) 325 delta -= days * 86400 326 var hours = Math.floor(delta / 3600) % 24 327 delta -= hours * 3600 328 var minutes = Math.floor(delta / 60) % 60 329 delta -= minutes * 60 330 var seconds = Math.floor(delta % 60) 331 var format_func = function(v, text, check) { 332 if (v <= 0 && check) { 333 return "" 334 } else { 335 return v + text 336 } 337 } 338 return format_func(days, "d", true) + format_func(hours, "h", true) + format_func(minutes, "m", true) + format_func(seconds, "s", false) 339 } 340 var slack_msg = { 341 blocks: [ 342 { 343 type: "section", 344 text: { 345 type: "mrkdwn", 346 text: `:skull_and_crossbones: *${{ github.workflow }}* <${wf_run.data.html_url}|#${{ github.run_number }}> (took ${date_diff_func(new Date(wf_run.data.created_at), new Date(wf_run.data.updated_at))})` 347 } 348 } 349 ] 350 } 351 return slack_msg 352 - name: 'Send to Slack' 353 if: always() 354 run: | 355 cat <<JSON > long_message.json 356 ${{ steps.status.outputs.result }} 357 JSON 358 cat <<JSON > short_message.json 359 ${{ steps.short_status.outputs.result }} 360 JSON 361 _post() { 362 curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} -H "Content-type: application/json" --data "@${1}" 363 } 364 _post "long_message.json" || _post "short_message.json" 365