diff options
author | Austin S. Hemmelgarn <austin@netdata.cloud> | 2022-03-09 08:30:47 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-09 08:30:47 -0500 |
commit | 00836aec828d6f4f2a4d4e38f160c0640d4e06e1 (patch) | |
tree | 939ee301293a24ace19732a71ca2a32b40597385 | |
parent | d8aba23d0f471ccb3f0107c4aac119cf35753f94 (diff) |
Final migration of release code off of Travis CI. (#12239)
* Initial version of release workflow.
* Remove release code from Travis config.
Final removal of the Travis CI code will be handled separately.
* Do not push changes if not running in GHA.
This simplifies testing the core logic locally.
* Remove remote branch existence checking.
It is not strictly nesescary for the expected execution context, and it
makes it harder to test locally safely.
* Fixed some minor oversights.
* Make git config repo local to make testing easier.
-rwxr-xr-x | .github/scripts/prepare-changelog.sh | 215 | ||||
-rw-r--r-- | .github/workflows/build.yml | 2 | ||||
-rw-r--r-- | .github/workflows/release.yml | 170 | ||||
-rw-r--r-- | .travis.yml | 86 | ||||
-rwxr-xr-x | netdata-installer.sh | 2 |
5 files changed, 387 insertions, 88 deletions
diff --git a/.github/scripts/prepare-changelog.sh b/.github/scripts/prepare-changelog.sh new file mode 100755 index 0000000000..4823112bac --- /dev/null +++ b/.github/scripts/prepare-changelog.sh @@ -0,0 +1,215 @@ +#!/bin/sh + +set -e + +REPO="${1}" +EVENT_NAME="${2}" +EVENT_TYPE="${3}" +EVENT_VERSION="${4}" + +############################################################## +# Utility functions + +generate_changelog() { + echo "::group::Generating changelog" + + if [ -n "${1}" ]; then + OPTS="--future-release ${1}" + fi + + # shellcheck disable=SC2086 + docker run -it -v "$(pwd)":/project markmandel/github-changelog-generator:latest \ + --user "netdata" \ + --project "netdata" \ + --token "${GITHUB_TOKEN}" \ + --since-tag "v1.10.0" \ + --unreleased-label "**Next release**" \ + --no-issues \ + --exclude-labels "stale,duplicate,question,invalid,wontfix,discussion,no changelog" \ + --max-issues 500 \ + --bug-labels IGNOREBUGS ${OPTS} + + echo "::endgroup::" +} + +commit_changes() { + branch="${1}" + msg="${2}" + tag="${3}" + + echo "::group::Committing changelog and version file and pushing changes." + + git checkout "${branch}" + git add packaging/version CHANGELOG.md + git commit -m "[ci skip] ${msg}" + if [ -n "${tag}" ]; then + git tag "${tag}" + opts="--tags" + fi + + if [ -n "${GITHUB_ACTIONS}" ]; then + git push -u origin ${opts} "${branch}" + else + echo "Not pushing changes as we are not running in GitHub Actions." + echo "Would have pushed ${branch} to origin, with additional options '${opts}'" + fi + + echo "::endgroup::" +} + +############################################################## +# Version validation functions + +check_version_format() { + if ! echo "${EVENT_VERSION}" | grep -qE '^v[[::digit::]]+\.[[::digit::]]+\.[[::digit::]]+$'; then + echo "::error::The supplied version (${EVENT_VERSION}) is not a valid version string." + return 1 + fi +} + +patch_is_zero() { + if ! echo "${EVENT_VERSION}" | grep -qE '^v[[::digit::]]+\.[[::digit::]]+\.0$'; then + echo "::error::The patch number for a ${EVENT_TYPE} build must be 0." + return 1 + fi +} + +minor_is_zero() { + if ! echo "${EVENT_VERSION}" | grep -qE '^v[[::digit::]]+\.0'; then + echo "::error::The minor version number for a ${EVENT_TYPE} build must be 0." + return 1 + fi +} + +major_matches() { + current_major="$(cut -f 1 -d '-' packaging/version | cut -f 1 -d '.' | cut -f 2 -d 'v')" + target_major="$(echo "${EVENT_VERSION}" | cut -f 1 -d '.' | cut -f 2 -d 'v')" + + if [ "${target_major}" != "${current_major}" ]; then + echo "::error::Major version mismatch, expected ${current_major} but got ${target_major}." + return 1 + fi +} + +minor_matches() { + current_minor="$(cut -f 1 -d '-' packaging/version | cut -f 2 -d '.')" + target_minor="$(echo "${EVENT_VERSION}" | cut -f 2 -d '.')" + + if [ "${target_minor}" != "${current_minor}" ]; then + echo "::error::Minor version mismatch, expected ${current_minor} but got ${target_minor}." + return 1 + fi +} + +check_for_existing_tag() { + if git tag | grep -qE "^${EVENT_VERSION}$"; then + echo "::error::A tag for version ${EVENT_VERSION} already exists." + return 1 + fi +} + +check_newer_major_version() { + current="$(cut -f 1 -d '-' packaging/version | cut -f 1 -d '.' | cut -f 2 -d 'v')" + target="$(echo "${EVENT_VERSION}" | cut -f 1 -d '.' | cut -f 2 -d 'v')" + + if [ "${target}" -le "${current}" ]; then + echo "::error::Version ${EVENT_VERSION} is not newer than the current version." + return 1 + fi +} + +check_newer_minor_version() { + current="$(cut -f 1 -d '-' packaging/version | cut -f 2 -d '.')" + target="$(echo "${EVENT_VERSION}" | cut -f 2 -d '.')" + + if [ "${target}" -le "${current}" ]; then + echo "::error::Version ${EVENT_VERSION} is not newer than the current version." + return 1 + fi +} + +check_newer_patch_version() { + current="$(cut -f 1 -d '-' packaging/version | cut -f 3 -d '.')" + target="$(echo "${EVENT_VERSION}" | cut -f 3 -d '.')" + + if [ "${target}" -le "${current}" ]; then + echo "::error::Version ${EVENT_VERSION} is not newer than the current version." + return 1 + fi +} + +############################################################## +# Core logic + +git config user.name "netdatabot" +git config user.email "bot@netdata.cloud" + +if [ "${REPO}" != "netdata/netdata" ]; then + echo "::notice::Not running in the netdata/netdata repository, not queueing a release build." + echo "::set-output name=run::false" +elif [ "${EVENT_NAME}" = 'schedule' ] || [ "${EVENT_TYPE}" = 'nightly' ]; then + echo "::notice::Preparing a nightly release build." + LAST_TAG=$(git describe --abbrev=0 --tags) + COMMITS_SINCE_RELEASE=$(git rev-list "${LAST_TAG}"..HEAD --count) + NEW_VERSION="${LAST_TAG}-$((COMMITS_SINCE_RELEASE + 1))-nightly" + generate_changelog "" || exit 1 + echo "${NEW_VERSION}" > packaging/version || exit 1 + commit_changes master "Update changelog and version for nightly build: ${NEW_VERSION}." + echo "::set-output name=run::true" + echo "::set-output name=ref::master" +elif [ "${EVENT_TYPE}" = 'patch' ] && [ "${EVENT_VERSION}" != "nightly" ]; then + echo "::notice::Preparing a patch release build." + check_version_format || exit 1 + check_for_existing_tag || exit 1 + branch_name="$(echo "${EVENT_VERSION}" | cut -f 1-2 -d '.')" + if [ -z "$(git branch --list "${branch_name}")" ]; then + echo "::error::Could not find a branch for the ${branch_name}.x release series." + exit 1 + fi + git checkout "${branch_name}" + minor_matches || exit 1 + major_matches || exit 1 + check_newer_patch_number || exit 1 + generate_changelog "${EVENT_VERSION}" || exit 1 + echo "${EVENT_VERSION}" > packaging/version || exit 1 + commit_changes "${branch_name}" "Patch release ${EVENT_VERSION}." "${EVENT_VERSION}" || exit 1 + echo "::set-output name=run::true" + echo "::set-output name=ref::${EVENT_VERSION}" +elif [ "${EVENT_TYPE}" = 'minor' ] && [ "${EVENT_VERSION}" != "nightly" ]; then + echo "::notice::Preparing a minor release build." + check_version_format || exit 1 + patch_is_zero || exit 1 + major_matches || exit 1 + check_newer_minor_version || exit 1 + check_for_existing_tag || exit 1 + branch_name="$(echo "${EVENT_VERSION}" | cut -f 1-2 -d '.')" + if [ -n "$(git branch --list "${branch_name}")" ]; then + echo "::error::A branch named ${branch_name} already exists in the repository." + exit 1 + fi + git branch "${branch_name}" + git checkout "${branch_name}" + generate_changelog "${EVENT_VERSION}" || exit 1 + echo "${EVENT_VERSION}" > packaging/version || exit 1 + commit_changes "${branch_name}" "Minor release ${EVENT_VERSION}." "${EVENT_VERSION}" || exit 1 + echo "::set-output name=run::true" + echo "::set-output name=ref::${EVENT_VERSION}" +elif [ "${EVENT_TYPE}" = 'major' ] && [ "${EVENT_VERSION}" != "nightly" ]; then + echo "::notice::Preparing a major release build." + check_version_format || exit 1 + minor_is_zero || exit 1 + patch_is_zero || exit 1 + check_newer_major_version || exit 1 + check_for_existing_tag || exit 1 + generate_changelog "${EVENT_VERSION}" || exit 1 + echo "${EVENT_VERSION}" > packaging/version || exit 1 + commit_changes master "Major release ${EVENT_VERSION}." "${EVENT_VERSION}" || exit 1 + echo "::set-output name=run::true" + echo "::set-output name=ref::${EVENT_VERSION}" +else + echo '::error::Unrecognized release type or invalid version.' + exit 1 +fi + +# shellcheck disable=SC2002 +echo "::set-output name=version::$(cat packaging/version | sed 's/^v//' packaging/version)" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 815615cb3a..9a24ce92eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ on: default: nightly required: true concurrency: # This keeps multiple instances of the job from running concurrently for the same ref and event type. - group: release-${{ github.ref }}-${{ github.event_name }} + group: build-${{ github.ref }}-${{ github.event_name }} cancel-in-progress: true jobs: build-dist: # Build the distribution tarball and store it as an artifact. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..5a2a7898bb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,170 @@ +--- +# Workflow for triggering a release. +name: Release +on: + schedule: + - cron: '0 0 * * *' + workflow_dispatch: # Dispatch runs build and validate, then push to the appropriate storage location. + inputs: + type: + description: Build Type + default: nightly + required: true + version: + description: Version Tag + default: nightly + required: true +concurrency: # This keeps multiple instances of the job from running concurrently for the same ref and event type. + group: release-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true +jobs: + update-changelogs: + name: Update changelog + runs-on: ubuntu-latest + outputs: + ref: ${{ steps.target.outputs.ref }} + version: ${{ steps.target.outputs.version }} + run: ${{ steps.target.outputs.run }} + steps: + - name: Checkout + id: checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + submodules: recursive + - name: Login to DockerHub # Needed to avoid ratelimits in the script we run in the next step. + id: login + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + - name: Prepare base ref + id: target + env: + GITHUB_TOKEN: ${{ secrets.NETDATABOT_GITHUB_TOKEN }} + run: >- + .github/scripts/prepare-changelog.sh \ + ${{ github.repository }} \ + ${{ github.event_name }} \ + ${{ github.event.inputs.type }} \ + ${{ github.event.inputs.version }} + - name: Failure Notification + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_COLOR: 'danger' + SLACK_FOOTER: '' + SLACK_ICON_EMOJI: ':github-actions:' + SLACK_TITLE: 'Failed to prepare changelog:' + SLACK_USERNAME: 'GitHub Actions' + SLACK_MESSAGE: >- + ${{ github.repository }}: Failed to prepare changelog. + Checkout: ${{ steps.checkout.outcome }} + Login to DockerHub: ${{ steps.login.outcome }} + Prepare base ref: ${{ steps.target.outcome }} + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} + if: failure() + + trigger-artifacts: + name: Trigger artifact builds + runs-on: ubuntu-latest + needs: update-changelogs + if: ${{ needs.update-changelogs.outputs.run }} == 'true' + steps: + - name: Checkout + id: checkout + uses: actions/checkout@v2 + with: + ref: ${{ needs.update-changelogs.outputs.ref }} + - name: Trigger build + id: trigger + uses: benc-uk/workflow-dispatch@v1 + with: + token: ${{ secrets.NETDATABOT_GITHUB_TOKEN }} + repo: ${{ github.repository }} + workflow: Build + ref: ${{ needs.update-changelogs.outputs.ref }} + inputs: '{"agent_version": "${{ needs.update-changelogs.outputs.version }}", "type": "${{ github.event.inputs.type }}"}' + - name: Failure Notification + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_COLOR: 'danger' + SLACK_FOOTER: '' + SLACK_ICON_EMOJI: ':github-actions:' + SLACK_TITLE: 'Failed to trigger ${{ github.event.inputs.type }} artifact builds:' + SLACK_USERNAME: 'GitHub Actions' + SLACK_MESSAGE: >- + ${{ github.repository }}: Failed to trigger ${{ github.event.inputs.type }} artifact builds. + Checkout: ${{ steps.checkout.outcome }} + Trigger build: ${{ steps.trigger.outcome }} + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} + if: failure() + + trigger-docker: + name: Trigger docker builds + runs-on: ubuntu-latest + needs: update-changelogs + if: ${{ needs.update-changelogs.outputs.run }} == 'true' + steps: + - name: Checkout + id: checkout + uses: actions/checkout@v2 + with: + ref: ${{ needs.update-changelogs.outputs.ref }} + - name: Trigger build + id: trigger + uses: benc-uk/workflow-dispatch@v1 + with: + token: ${{ secrets.NETDATABOT_GITHUB_TOKEN }} + repo: ${{ github.repository }} + workflow: Docker + ref: ${{ needs.update-changelogs.outputs.ref }} + inputs: '{"agent_version": "${{ needs.update-changelogs.outputs.version }}"}' + - name: Failure Notification + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_COLOR: 'danger' + SLACK_FOOTER: '' + SLACK_ICON_EMOJI: ':github-actions:' + SLACK_TITLE: 'Failed to trigger ${{ github.event.inputs.type }} Docker builds:' + SLACK_USERNAME: 'GitHub Actions' + SLACK_MESSAGE: >- + ${{ github.repository }}: Failed to trigger ${{ github.event.inputs.type }} Docker builds. + Checkout: ${{ steps.checkout.outcome }} + Trigger build: ${{ steps.trigger.outcome }} + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} + if: failure() + + trigger-packages: + name: Trigger package builds + runs-on: ubuntu-latest + needs: update-changelogs + if: ${{ needs.update-changelogs.outputs.run }} == 'true' + steps: + - name: Checkout + id: checkout + uses: actions/checkout@v2 + with: + ref: ${{ needs.update-changelogs.outputs.ref }} + - name: Trigger build + id: trigger + uses: benc-uk/workflow-dispatch@v1 + with: + token: ${{ secrets.NETDATABOT_GITHUB_TOKEN }} + repo: ${{ github.repository }} + workflow: Packages + ref: ${{ needs.update-changelogs.outputs.ref }} + inputs: '{"agent_version": "${{ needs.update-changelogs.outputs.version }}", "type": "${{ github.event.inputs.type }}"}' + - name: Failure Notification + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_COLOR: 'danger' + SLACK_FOOTER: '' + SLACK_ICON_EMOJI: ':github-actions:' + SLACK_TITLE: 'Failed to trigger ${{ github.event.inputs.type }} package builds:' + SLACK_USERNAME: 'GitHub Actions' + SLACK_MESSAGE: >- + ${{ github.repository }}: Failed to trigger ${{ github.event.inputs.type }} package builds. + Checkout: ${{ steps.checkout.outcome }} + Trigger build: ${{ steps.trigger.outcome }} + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} + if: failure() diff --git a/.travis.yml b/.travis.yml index ba80b30ef1..838799f8ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,26 +51,6 @@ stages: - name: Build process if: commit_message =~ /^((?!\[Package (amd64|arm64|i386) (DEB|RPM)( .*)?\]).)*$/ - # Nightly operations - - name: Nightly operations - if: branch = master AND type = cron AND env(RUN_NIGHTLY) = yes - - - name: Nightly release - if: branch = master AND type = cron AND env(RUN_NIGHTLY) = yes - - # Scheduled releases - - name: Support activities on main branch - if: branch = master AND type != pull_request AND type != cron AND repo = netdata/netdata - - # We don't run on release candidates - - name: Publish for release - if: >- - branch = master - AND type != pull_request - AND type != cron - AND tag !~ /(-rc)/ - AND commit_message =~ /\[netdata (release candidate|(major|minor|patch) release)\]/ - # Define stage implementation details # @@ -86,69 +66,3 @@ jobs: script: fakeroot ./netdata-installer.sh --install $HOME --dont-wait --dont-start-it --enable-plugin-nfacct --enable-plugin-freeipmi --disable-lto env: CFLAGS='-O1 -Wall -Wextra -Wformat-signedness -fstack-protector-all -fno-common -DNETDATA_INTERNAL_CHECKS=1 -D_FORTIFY_SOURCE=2 -DNETDATA_VERIFY_LOCKS=1' after_failure: post_message "TRAVIS_MESSAGE" "<!here> standard netdata build is failing (Still dont know which one, will improve soon)" - - - stage: Support activities on main branch - name: Generate changelog for release (only on special and tagged commit msg) - before_script: post_message "TRAVIS_MESSAGE" "Support activities on main branch initiated" "${NOTIF_CHANNEL}" - script: - - echo "GIT Branch:" && git branch - - echo "Last commit:" && git log -1 - - echo "GIT Describe:" && git describe - - echo "packaging/version:" && cat packaging/version - - if [[ -z "${GIT_TAG}" ]]; then echo "Running set tag for release" && set_tag_for_release; fi; - - .travis/generate_changelog_and_tag_release.sh - after_failure: post_message "TRAVIS_MESSAGE" "<!here> Changelog generation and tag of release, failed" - git: - depth: false - if: commit_message =~ /\[netdata (release candidate|(major|minor|patch) release)\]/ AND tag !~ /(-rc)/ OR (env(GIT_TAG) IS present AND NOT env(GIT_TAG) IS blank) - - # We only publish if a TAG has been set during packaging - - stage: Publish for release - name: Trigger release build and draft release creation - script: - - git checkout "${TRAVIS_BRANCH}" && export BUILD_VERSION="$(cat packaging/version)" - - .travis/trigger_artifact_build.sh "${GITHUB_TOKEN}" "${BUILD_VERSION}" "release" - after_failure: post_message "TRAVIS_MESSAGE" "<!here> Failed to trigger release artifact build during nightly release" "${NOTIF_CHANNEL}" - - - name: Trigger Docker image build and publish - script: - - git checkout "${TRAVIS_BRANCH}" && export BUILD_VERSION="$(cat packaging/version | cut -d'-' -f1)" - - .travis/trigger_docker_build.sh "${GITHUB_TOKEN}" "${BUILD_VERSION}" - after_failure: post_message "TRAVIS_MESSAGE" "<!here> Failed to trigger docker build during release" "${NOTIF_CHANNEL}" - - - name: Trigger DEB and RPM package build - script: - - git checkout "${TRAVIS_BRANCH}" && export BUILD_VERSION="$(cat packaging/version | sed 's/^v//' | cut -d'-' -f1)" - - .travis/trigger_package_build.sh "${GITHUB_TOKEN}" "${BUILD_VERSION}" "release" - after_failure: post_message "TRAVIS_MESSAGE" "<!here> Failed to trigger deb and rpm package build during release" "${NOTIF_CHANNEL}" - - - # This is the nightly pre-execution step (Jobs, preparatory steps for nightly, etc) - - stage: Nightly operations - # This is generating the changelog for nightly release and publish it - name: Generate nightly changelog - script: - - ".travis/nightlies.sh" - - ".travis/check_changelog_last_modification.sh" - after_failure: post_message "TRAVIS_MESSAGE" "<!here> Nightly changelog generation failed" - git: - depth: false - - # This is the nightly execution step - # - - stage: Nightly release - name: Trigger nightly artifact build and upload - script: - - git checkout "${TRAVIS_BRANCH}" && export BUILD_VERSION="$(cat packaging/version)" - - .travis/trigger_artifact_build.sh "${GITHUB_TOKEN}" "${BUILD_VERSION}" "nightly" - after_failure: post_message "TRAVIS_MESSAGE" "<!here> Failed to trigger release artifact build during nightly release" "${NOTIF_CHANNEL}" - - - name: Trigger Docker image build and publish - script: .travis/trigger_docker_build.sh "${GITHUB_TOKEN}" "nightly" - after_failure: post_message "TRAVIS_MESSAGE" "<!here> Failed to trigger docker build during nightly release" "${NOTIF_CHANNEL}" - - - name: Trigger DEB and RPM package build - script: - - git checkout "${TRAVIS_BRANCH}" && export BUILD_VERSION="$(cat packaging/version | sed 's/^v//')" - - .travis/trigger_package_build.sh "${GITHUB_TOKEN}" "${BUILD_VERSION}" "nightly" - after_failure: post_message "TRAVIS_MESSAGE" "<!here> Failed to trigger deb and rpm package build during nightly release" "${NOTIF_CHANNEL}" diff --git a/netdata-installer.sh b/netdata-installer.sh index b4ef6fbaf0..0c13f65c35 100755 --- a/netdata-installer.sh +++ b/netdata-installer.sh @@ -306,7 +306,7 @@ NETDATA_PREFIX= LIBS_ARE_HERE=0 NETDATA_ENABLE_ML="" NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS-}" -RELEASE_CHANNEL="nightly" # check .travis/create_artifacts.sh before modifying +RELEASE_CHANNEL="nightly" # valid values are 'nightly' and 'stable' IS_NETDATA_STATIC_BINARY="${IS_NETDATA_STATIC_BINARY:-"no"}" while [ -n "${1}" ]; do case "${1}" in |