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