From b6fc418fe5d674216e3a9ad9219ec7a7a0dc1624 Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Wed, 12 Apr 2023 12:41:31 +0200 Subject: [PATCH] .github: Port common update action code from old coreos-overlay --- .github/workflows/common.sh | 186 +++++++++++++++++++++++++ .github/workflows/figure-out-branch.sh | 67 +++++++++ .github/workflows/setup-flatcar-sdk.sh | 59 ++++++++ 3 files changed, 312 insertions(+) create mode 100644 .github/workflows/common.sh create mode 100755 .github/workflows/figure-out-branch.sh create mode 100755 .github/workflows/setup-flatcar-sdk.sh diff --git a/.github/workflows/common.sh b/.github/workflows/common.sh new file mode 100644 index 0000000000..faed205407 --- /dev/null +++ b/.github/workflows/common.sh @@ -0,0 +1,186 @@ +#!/bin/bash + +function fail() { + echo "$*" >/dev/stderr + exit 1 +} + +if [[ -z "${WORK_SCRIPTS_DIR:-}" ]]; then + fail "WORK_SCRIPTS_DIR env var unset. It should point to the scripts repo which will be updated." +fi + +if [[ ! -d "${WORK_SCRIPTS_DIR:-}" ]]; then + fail "WORK_SCRIPTS_DIR env var does not point to a directory. It should point to the scripts repo which will be updated." +fi + +readonly SDK_OUTER_TOPDIR="${WORK_SCRIPTS_DIR}" +readonly SDK_OUTER_OVERLAY="${SDK_OUTER_TOPDIR}/sdk_container/src/third_party/coreos-overlay" +readonly SDK_INNER_SRCDIR="/mnt/host/source/src" +readonly SDK_INNER_OVERLAY="${SDK_INNER_SRCDIR}/third_party/coreos-overlay" + +readonly BUILDBOT_USERNAME="Flatcar Buildbot" +readonly BUILDBOT_USEREMAIL="buildbot@flatcar-linux.org" + +# This enters the SDK container and executes the passed commands +# inside it. Requires PACKAGES_CONTAINER and SDK_NAME to be defined. +function enter() { + if [[ -z "${PACKAGES_CONTAINER}" ]]; then + fail "PACKAGES_CONTAINER env var unset. It should contain the name of the SDK container." + fi + if [[ -z "${SDK_NAME}" ]]; then + fail "SDK_NAME env var unset. It should contain the name of the SDK docker image." + fi + "${SDK_OUTER_TOPDIR}/run_sdk_container" \ + -n "${PACKAGES_CONTAINER}" \ + -C "${SDK_NAME}" \ + "${@}" +} + +# Return a valid ebuild file name for ebuilds of the given category name, +# package name, and the old version. If the single ebuild file already exists, +# then simply return that. If the file does not exist, then we should fall back +# to a similar file including $VERSION_OLD. +# For example, if VERSION_OLD == 1.0 and 1.0.ebuild does not exist, but only +# 1.0-r1.ebuild is there, then we figure out its most similar valid name by +# running "ls -1 ...*.ebuild | sort -ruV | head -n1". +function get_ebuild_filename() { + local pkg="${1}"; shift + local version="${1}"; shift + local name="${pkg##*/}" + local ebuild_basename="${pkg}/${name}-${version}" + + if [[ ! -d "${pkg}" ]]; then + fail "No such package in '${PWD}': '${pkg}'" + fi + if [ -f "${ebuild_basename}.ebuild" ]; then + echo "${ebuild_basename}.ebuild" + else + ls -1 "${ebuild_basename}"*.ebuild | sort --reverse --unique --version-sort | head --lines 1 + fi +} + +function prepare_git_repo() { + git -C "${SDK_OUTER_TOPDIR}" config user.name "${BUILDBOT_USERNAME}" + git -C "${SDK_OUTER_TOPDIR}" config user.email "${BUILDBOT_USEREMAIL}" +} + +# Regenerates a manifest file using an ebuild of a given package with +# a given version. +# +# Example: +# regenerate_manifest dev-lang/go 1.20.2 +function regenerate_manifest() { + local pkg="${1}"; shift + local version="${1}"; shift + local name="${pkg##*/}" + local ebuild_file + + ebuild_file="${SDK_INNER_OVERLAY}/${pkg}/${name}-${version}.ebuild" + enter ebuild "${ebuild_file}" manifest --force +} + +function join_by() { + local delimiter="${1-}" + local first="${2-}" + if shift 2; then + printf '%s' "${first}" "${@/#/${delimiter}}"; + fi +} + +# Generates a changelog entry. Usually the changelog entry is in a +# following form: +# +# - ([]()) +# +# Thus first three parameters of this function should be the name, +# version and URL. The changelog entries are files, so the fourth +# parameter is a name that will be a part of the filename. It often is +# a lower-case variant of the first parameter. +# +# Example: +# generate_update_changelog Go 1.20.2 'https://go.dev/doc/devel/release#go1.20.2' go +# +# Sometimes there's a bigger jump in versions, like from 1.19.1 to +# 1.19.4, so it is possible to pass extra version and URL pairs for +# the intermediate versions: +# +# generate_update_changelog Go 1.19.4 'https://go.dev/doc/devel/release#go1.19.4' go \ +# 1.19.2 'https://go.dev/doc/devel/release#go1.19.2' \ +# 1.19.3 'https://go.dev/doc/devel/release#go1.19.3' +function generate_update_changelog() { + local name="${1}"; shift + local version="${1}"; shift + local url="${1}"; shift + local update_name="${1}"; shift + # rest of parameters are version and link pairs for old versions + local file + local -a old_links + + file="changelog/updates/$(date '+%Y-%m-%d')-${update_name}-${version}-update.md" + + if [[ -d changelog/updates ]]; then + printf '%s %s ([%s](%s)' '-' "${name}" "${version}" "${url}" > "${file}" + if [[ $# -gt 0 ]]; then + echo -n ' (includes ' >> "${file}" + while [[ $# -gt 1 ]]; do + old_links+=( "[${1}](${2})" ) + shift 2 + done + printf '%s' "$(join_by ', ' "${old_links[@]}")" >> "${file}" + echo -n ')' >> "${file}" + fi + echo ')' >> "${file}" + fi +} + +# Regenerates manifest for given package, and commits changes made for +# that package. If there are new entries in changelog directory, these +# are committed too. Another two parameters are old and new versions +# of the package. +# +# Example: +# commit_changes dev-lang/go 1.19.1 1.19.4 +# +# Sometimes more files need to be added to the commit. In such cases +# extra paths can be specified and those will be passed to "git +# add". If an extra path is relative, it will be relative the overlay +# directory in the scripts repo. In order to use globs, it better to +# make sure that that absolute path is passed. +# +# commit_changes dev-lang/go 1.19.1 1.19.4 \ +# some/extra/directory \ +# some/file \ +# "${PWD}/some/globs"*'-suffix' +function commit_changes() { + local pkg="${1}"; shift + local old_version="${1}"; shift + local new_version="${1}"; shift + # rest of parameters are additional directories to add to the commit + local name="${pkg##*/}" + + regenerate_manifest "${pkg}" "${new_version}" + + pushd "${SDK_OUTER_OVERLAY}" + + git add "${pkg}" + if [[ -d changelog ]]; then + git add changelog + fi + for dir; do + git add "${dir}" + done + git commit -m "${pkg}: Update from ${old_version} to ${new_version}" + + popd +} + +# Prints the status of the git repo and cleans it up - reverts +# uncommitted changes, removes untracked files. It's usually called at +# the end of a script making changes to the repository in order to +# avoid unwanted changes to be a part of a PR created by the +# peter-evans/create-pull-request action that follows up. +function cleanup_repo() { + git -C "${SDK_OUTER_OVERLAY}" status + git -C "${SDK_OUTER_OVERLAY}" reset --hard HEAD + git -C "${SDK_OUTER_OVERLAY}" clean -ffdx +} diff --git a/.github/workflows/figure-out-branch.sh b/.github/workflows/figure-out-branch.sh new file mode 100755 index 0000000000..abf7365ab5 --- /dev/null +++ b/.github/workflows/figure-out-branch.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# Prints the following github outputs based on channel named passed to +# the script as a parameter. +# +# BRANCH is a name of the git branch related to the passed channel. +# +# SKIP tells whether the rest of the steps should be skipped, will be +# either 0 or 1. +# +# LINK is a link to release mirror for the following channel. Will be +# empty for main channel. +# +# LABEL is going to be mostly the same as the channel name, except +# that lts-old will be labeled as lts. + +set -euo pipefail + +if [[ ${#} -ne 1 ]]; then + echo "Expected a channel name as a parameter" >&2 + exit 1 +fi + +channel_name="${1}" +skip=0 +link='' +branch='' +label='' +case "${channel_name}" in + main) + branch='main' + ;; + lts-old) + curl -fsSLO --retry-delay 1 --retry 60 --retry-connrefused --retry-max-time 60 --connect-timeout 20 'https://lts.release.flatcar-linux.net/lts-info' + if [[ $(grep -e ':supported' lts-info | wc -l) -le 1 ]]; then + # Only one supported LTS, skip this workflow run + # as 'lts' matrix branch will handle updating the only + # supported LTS. + skip=1 + else + line=$(grep -e ':supported' lts-info | sort -V | head -n 1) + major=$(awk -F: '{print $1}' <<<"${line}") + year=$(awk -F: '{print $2}' <<<"${line}") + branch="flatcar-${major}" + link="https://lts.release.flatcar-linux.net/amd64-usr/current-${year}" + label='lts' + fi + rm -f lts-info + ;; + alpha|beta|stable|lts) + link="https://${channel_name}.release.flatcar-linux.net/amd64-usr/current" + major=$(curl -sSL "${link}/version.txt" | awk -F= '/FLATCAR_BUILD=/{ print $2 }') + branch="flatcar-${major}" + ;; + *) + echo "Unknown channel '${channel_name}'" >&2 + exit 1 +esac + +if [[ -z "${label}" ]]; then + label="${channel_name}" +fi + +echo "BRANCH=${branch}" >>"${GITHUB_OUTPUT}" +echo "SKIP=${skip}" >>"${GITHUB_OUTPUT}" +echo "LINK=${link}" >>"${GITHUB_OUTPUT}" +echo "LABEL=${label}" >>"${GITHUB_OUTPUT}" diff --git a/.github/workflows/setup-flatcar-sdk.sh b/.github/workflows/setup-flatcar-sdk.sh new file mode 100755 index 0000000000..419b801718 --- /dev/null +++ b/.github/workflows/setup-flatcar-sdk.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +set -euo pipefail + +if [[ -z "${WORK_SCRIPTS_DIR:-}" ]]; then + echo 'WORK_SCRIPTS_DIR unset, should be pointing to the scripts repo which will be updated' +fi + +sudo ln -sfn /bin/bash /bin/sh +sudo apt-get update +sudo apt-get install -y ca-certificates curl git gnupg lbzip2 lsb-release \ + qemu-user-static +sudo mkdir -p /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ + | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ + https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \ + | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +sudo apt-get update +sudo apt-get install -y docker-ce docker-ce-cli containerd.io \ + docker-compose-plugin + +pushd "${WORK_SCRIPTS_DIR}" + +source ci-automation/ci_automation_common.sh +source sdk_container/.repo/manifests/version.txt + +# run_sdk_container requires a tag to exist in the repo it resides, +# which may not be the case for forked repos. Add some fake tag in +# this case. +if ! git describe --tags &>/dev/null; then + git tag "${CHANNEL}-${FLATCAR_VERSION}" +fi + +arch="amd64" +sdk_name="flatcar-sdk-${arch}" + +if [[ "${CHANNEL}" = 'main' ]]; then + # for main channel, pull in alpha SDK + MIRROR_LINK='https://alpha.release.flatcar-linux.net/amd64-usr/current' +fi + +# Pin the docker image version to that of the latest release in the channel. +docker_sdk_vernum="$(curl -s -S -f -L "${MIRROR_LINK}/version.txt" \ + | grep -m 1 FLATCAR_SDK_VERSION= | cut -d = -f 2- \ +)" + +docker_image_from_registry_or_buildcache "${sdk_name}" "${docker_sdk_vernum}" + +sdk_full_name="$(docker_image_fullname "${sdk_name}" "${docker_sdk_vernum}")" + +docker_vernum="$(vernum_to_docker_image_version "${FLATCAR_VERSION_ID}")" +packages_container_name="flatcar-packages-${arch}-${docker_vernum}" + +popd + +echo "PACKAGES_CONTAINER=${packages_container_name}" >>"${GITHUB_OUTPUT}" +echo "SDK_NAME=${sdk_full_name}" >>"${GITHUB_OUTPUT}"