123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- name: Release
- on:
- workflow_dispatch:
- tags:
- - 'v*'
- push:
- tags:
- - 'v*'
- env:
- GO_VERSION: 1.16
- GOPATH: ${{ github.workspace }}/go
- WORKING_DIR: ${{ github.workspace }}/go/src/github.com/ethereum/go-ethereum
- jobs:
- publish-docker:
- name: Publish Docker Images
- runs-on: ubuntu-20.04
- steps:
- - name: 'Check out project files'
- uses: actions/checkout@v3
- # https://github.com/docker/setup-qemu-action
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v2
- # https://github.com/docker/setup-buildx-action
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
- - name: 'Extract Docker Image Tag'
- id: extract
- run: |
- REF=${{ github.ref }}
- echo ::set-output name=image_tag::$(echo $REF | sed 's/refs\/tags\/v//g')
- echo ::set-output name=image_tag_minor_latest::$(echo $REF | sed -e 's/refs\/tags\/v//g' -e 's/^\([[:digit:]]*\.[[:digit:]]*\).*/\1/')
- - name: 'Build ARM image to Docker Hub'
- id: build
- run: |
- output_dir=${{ runner.temp }}/docker
- mkdir -p $output_dir
- docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_ACCESS_TOKEN }}
- docker buildx build --push --platform linux/amd64,linux/arm64 -t ${{ secrets.DOCKER_REPO }}:latest -t ${{ secrets.DOCKER_REPO }}:${{ steps.extract.outputs.image_tag }} -t ${{ secrets.DOCKER_REPO }}:${{ steps.extract.outputs.image_tag_minor_latest }} .
- build-binary:
- name: 'Build binary for ${{ matrix.os }}'
- strategy:
- fail-fast: false
- matrix:
- os: [ "ubuntu-20.04", "macos-latest" ]
- runs-on: ${{ matrix.os }}
- steps:
- - name: 'Setup Go ${{ env.GO_VERSION }}'
- uses: actions/setup-go@v1
- with:
- go-version: ${{ env.GO_VERSION }}
- - name: 'Prepare environment'
- id: env
- run: |
- echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- echo "::set-output name=key::$(go env GOOS)_$(go env GOARCH)"
- echo "::set-output name=version::${GITHUB_REF##*/}"
- - name: 'Check out project files'
- uses: actions/checkout@v2
- with:
- path: ${{ env.WORKING_DIR }}
- - name: 'Build geth'
- # For MacOS, We use gtar and run purge command to workaround issue
- # https://github.com/actions/virtual-environments/issues/2619
- id: build
- working-directory: ${{ env.WORKING_DIR }}
- run: |-
- make geth
- mkdir -p build/artifact
- tar_file=build/artifact/geth_${{ steps.env.outputs.version }}_${{ steps.env.outputs.key }}.tar.gz
- if [ "${{ matrix.os }}" == "macos-latest" ]; then
- sudo /usr/sbin/purge
- gtar cfvz ${tar_file} -C build/bin geth
- else
- tar cfvz ${tar_file} -C build/bin geth
- fi
- echo "::set-output name=tar_file::${tar_file}"
- echo "::set-output name=checksum::$(shasum -a 256 build/bin/geth | awk '{print $1}')"
- - name: 'Verify tarball'
- working-directory: ${{ env.WORKING_DIR }}
- run: |-
- cp ${{ steps.build.outputs.tar_file }} ${{ runner.temp }}
- pushd ${{ runner.temp}}
- tar xfvz *.tar.gz
- actual_checksum=$(shasum -a 256 geth | awk '{print $1}')
- echo "Checksum: ${actual_checksum}"
- popd
- if [ "${{ steps.build.outputs.checksum }}" != "${actual_checksum}" ]; then
- echo "::error::geth checksum validation fails"
- exit 1
- fi
- - name: 'Upload artifact'
- uses: actions/upload-artifact@v2
- with:
- path: ${{ env.WORKING_DIR }}/build/artifact
- name: ${{ steps.env.outputs.key }}
- if-no-files-found: error
- deploy-cloudsmith:
- name: 'Deploy binary to Cloudsmith for ${{ matrix.goarch }}'
- needs:
- - build-binary
- strategy:
- fail-fast: false
- matrix:
- goarch: [ "linux_amd64", "darwin_amd64" ]
- runs-on: ubuntu-latest
- steps:
- - name: 'Prepare environment'
- id: env
- run: |
- echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- echo "::set-output name=version::${GITHUB_REF##*/}"
- - name: 'Download artifacts'
- uses: actions/download-artifact@v2
- with:
- path: artifact
- - name: 'Upload artifacts to Cloudsmith'
- id: push
- uses: cloudsmith-io/action@master
- with:
- api-key: ${{ secrets.CLOUDSMITH_API_KEY }}
- command: "push"
- format: "raw"
- owner: "consensys"
- repo: "go-quorum"
- file: "artifact/${{ matrix.goarch }}/geth_${{ steps.env.outputs.version }}_${{ matrix.goarch }}.tar.gz"
- name: "geth_${{ steps.env.outputs.version }}_${{ matrix.goarch }}.tar.gz"
- summary: "GoQuorum ${{ steps.env.outputs.version }} - binary distribution for ${{ matrix.goarch }}"
- description: "See https://github.com/ConsenSys/quorum/"
- version: "${{ steps.env.outputs.version }}"
- draft-release:
- if: always()
- name: 'Draft Github release'
- needs:
- - deploy-cloudsmith
- - publish-docker
- runs-on: ubuntu-20.04
- steps:
- - name: 'Check out project files'
- uses: actions/checkout@v2
- - name: 'Generate release notes'
- id: release_notes
- run: |
- git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- file="generated-release-notes.md"
- current_version="${GITHUB_REF##*/}"
- last_version=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=1 --max-count=1`)
- last_release_date=$(git log -1 --format=%cd --date=short $last_version)
- echo "Last version: $last_version on $last_release_date"
- # pulling from git logs
- curl -q -s -H "Accept: application/vnd.github.v3+json" \
- "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))' \
- >> $file
- # pulling file hashes from Cloudsmith
- echo "" >> $file
- echo "| Filename | SHA256 Hash |" >> $file
- echo "|:---------|:------------|" >> $file
- curl --request GET \
- --url "https://api.cloudsmith.io/v1/packages/consensys/go-quorum/?query=version:$current_version" \
- --header 'Accept: application/json' \
- --header 'X-Api-Key: ${{ secrets.CLOUDSMITH_API_KEY }}' \
- | jq '.[] | select(.name | endswith(".asc") | not) | "|[\(.name)](\(.cdn_url))|`\(.checksum_sha256)`|"' -r \
- >> $file
- content=$(cat $file)
- # escape newline
- content="${content//'%'/'%25'}"
- content="${content//$'\n'/'%0A'}"
- content="${content//$'\r'/'%0D'}"
- echo "::set-output name=content::$content"
- - name: 'Create Github draft release'
- uses: actions/create-release@v1
- env:
- # This token is provided by Actions, you do not need to create your own token
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- tag_name: ${{ github.ref }}
- release_name: ${{ github.ref }}
- body: |
- ${{ steps.release_notes.outputs.content }}
- draft: true
- prerelease: false
- notify:
- if: always()
- name: 'Notify'
- needs:
- - build-binary
- - deploy-cloudsmith
- - publish-docker
- - draft-release
- runs-on: ubuntu-20.04
- steps:
- - name: 'Setup metadata'
- id: setup
- run: |
- gitref_path="${{ github.ref }}"
- gitref_path=${gitref_path/refs\/heads/tree} # for refs/heads/my-branch
- gitref_path=${gitref_path/refs\/tags/tree} # for refs/tags/v1.0.0
- gitref_path=${gitref_path#refs\/} # for refs/pull/123/merge
- gitref_path=${gitref_path%/merge} # for refs/pull/123/merge
- echo "::set-output name=gitref-path::$gitref_path"
- echo "::set-output name=version::${GITHUB_REF##*/}"
- - name: 'Prepare Slack message with full info'
- id: status
- uses: actions/github-script@0.8.0
- with:
- script: |
- var gitref_path = "${{ steps.setup.outputs.gitref-path }}"
- ////////////////////////////////////
- // retrieve workflow run data
- ////////////////////////////////////
- console.log("get workflow run")
- const wf_run = await github.actions.getWorkflowRun({
- owner: context.repo.owner,
- repo: context.repo.repo,
- run_id: ${{ github.run_id }}
- })
- console.log(wf_run.data)
- console.log("get jobs for workflow run:", wf_run.data.jobs_url)
- const jobs_response = await github.request(wf_run.data.jobs_url)
- ////////////////////////////////////
- // build slack notification message
- ////////////////////////////////////
- // some utility functions
- var date_diff_func = function(start, end) {
- var duration = end - start
- // format the duration
- var delta = duration / 1000
- var days = Math.floor(delta / 86400)
- delta -= days * 86400
- var hours = Math.floor(delta / 3600) % 24
- delta -= hours * 3600
- var minutes = Math.floor(delta / 60) % 60
- delta -= minutes * 60
- var seconds = Math.floor(delta % 60)
- var format_func = function(v, text, check) {
- if (v <= 0 && check) {
- return ""
- } else {
- return v + text
- }
- }
- return format_func(days, "d", true) + format_func(hours, "h", true) + format_func(minutes, "m", true) + format_func(seconds, "s", false)
- }
- var status_icon_func = function(s) {
- switch (s) {
- case "w_success":
- return ":white_check_mark:"
- case "w_failure":
- return ":no_entry:"
- case "w_cancelled":
- return ":warning:"
- case "success":
- return "\u2713"
- case "failure":
- return "\u2717"
- default:
- return "\u20e0"
- }
- }
- // build the message
- var job_blocks = []
- var is_wf_success = true
- var is_wf_failure = false
- for (j of jobs_response.data.jobs) {
- console.log(j.name, ":", j.status, j.conclusion, j.started_at, j.completed_at)
- // ignore the current job running this script
- if (j.status != "completed") {
- continue
- }
- if (j.conclusion != "success") {
- is_wf_success = false
- }
- if (j.conclusion == "failure") {
- is_wf_failure = true
- }
- job_blocks.push({
- type: "section",
- text: {
- type: "mrkdwn",
- 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))}`
- }
- })
- }
- var workflow_status = "w_cancelled"
- if (is_wf_success) {
- workflow_status = "w_success"
- } else if (is_wf_failure) {
- workflow_status = "w_failure"
- }
- var context_elements = [
- {
- "type": "mrkdwn",
- "text": "*Repo:* <https://github.com/${{ github.repository }}|${{ github.repository }}>"
- },
- {
- "type": "mrkdwn",
- "text": `*Branch:* <https://github.com/${{ github.repository }}/${gitref_path}|${{ github.ref }}>`
- },
- {
- "type": "mrkdwn",
- "text": `*Event:* ${wf_run.data.event}`
- },
- {
- "type": "mrkdwn",
- "text": `*Commit:* <https://github.com/${{ github.repository }}/commit/${wf_run.data.head_commit.id}|${wf_run.data.head_commit.id.substr(0, 8)}>`
- },
- {
- "type": "mrkdwn",
- "text": `*Author:* ${wf_run.data.head_commit.author.name}`
- }
- ]
- var header_blocks = [
- {
- type: "section",
- text: {
- type: "mrkdwn",
- 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))}`
- }
- },
- {
- type: "context",
- elements: context_elements,
- },
- {
- type: "divider"
- }
- ]
- var slack_msg = {
- blocks: [].concat(header_blocks, job_blocks)
- }
- return slack_msg
- - name: 'Prepare Slack message with partial info'
- id: short_status
- if: failure()
- uses: actions/github-script@0.8.0
- with:
- script: |
- ////////////////////////////////////
- // retrieve workflow run data
- ////////////////////////////////////
- const wf_run = await github.actions.getWorkflowRun({
- owner: context.repo.owner,
- repo: context.repo.repo,
- run_id: ${{ github.run_id }}
- })
- var date_diff_func = function(start, end) {
- var duration = end - start
- // format the duration
- var delta = duration / 1000
- var days = Math.floor(delta / 86400)
- delta -= days * 86400
- var hours = Math.floor(delta / 3600) % 24
- delta -= hours * 3600
- var minutes = Math.floor(delta / 60) % 60
- delta -= minutes * 60
- var seconds = Math.floor(delta % 60)
- var format_func = function(v, text, check) {
- if (v <= 0 && check) {
- return ""
- } else {
- return v + text
- }
- }
- return format_func(days, "d", true) + format_func(hours, "h", true) + format_func(minutes, "m", true) + format_func(seconds, "s", false)
- }
- var slack_msg = {
- blocks: [
- {
- type: "section",
- text: {
- type: "mrkdwn",
- 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))})`
- }
- }
- ]
- }
- return slack_msg
- - name: 'Send to Slack'
- if: always()
- run: |
- cat <<JSON > long_message.json
- ${{ steps.status.outputs.result }}
- JSON
- cat <<JSON > short_message.json
- ${{ steps.short_status.outputs.result }}
- JSON
- _post() {
- curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} -H "Content-type: application/json" --data "@${1}"
- }
- _post "long_message.json" || _post "short_message.json"
|