diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6751a36c..09c368ae 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -26,27 +26,13 @@ jobs: steps: - uses: actions/checkout@v4 name: Check out code + + - name: Prepare Artifacts + run: | + ./hack/prepare-artifacts.sh ${{ github.ref_name }} + - name: Create Draft Release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OWNER: ${{ github.repository_owner }} - REPO: ${{ github.event.repository.name }} run: | - GH_EXTRA_ARGS="" - if [[ ${{ github.ref_name }} == *-rc.* ]]; then - GH_EXTRA_ARGS="--prerelease" - fi - gh release create ${{ github.ref_name }} \ - --draft \ - -t "${{ github.ref_name }}" \ - -R $OWNER/$REPO \ - --verify-tag \ - $GH_EXTRA_ARGS - - - name: Upload Release Artifacts - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OWNER: ${{ github.repository_owner }} - REPO: ${{ github.event.repository.name }} - run: | - gh release upload ${{ github.ref_name }} CHANGELOG.md -R $OWNER/$REPO + ./hack/create-release.sh ${{ github.ref_name }} diff --git a/hack/create-release.sh b/hack/create-release.sh new file mode 100755 index 00000000..e4ba90f5 --- /dev/null +++ b/hack/create-release.sh @@ -0,0 +1,47 @@ +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if [ -z "$1" ]; then + VERSION=$(awk -F= '/^VERSION/ { print $2 }' versions.mk | tr -d '[:space:]') +else + VERSION=$1 +fi + + +PRERELEASE_FLAG="" +REPO="stable" +if [[ ${VERSION} == v*-rc.* ]]; then + PRERELEASE_FLAG="--prerelease" + REPO="experimental" +fi + +REPOSITORY=NVIDIA/nvidia-container-toolkit + +echo "Creating draft release" +./hack/generate-changelog.sh --version ${VERSION} | \ + grep -v "### Version v" | \ + echo gh release create ${VERSION} --notes-file "-" \ + --draft \ + --title "${VERSION}" \ + -R "${REPOSITORY}" \ + --verify-tag \ + --prerelease + +echo "Uploading release artifacts for ${VERSION}" + +PACKAGE_ROOT=release-${VERSION}-${REPO} + +gh release upload ${VERSION} \ + ${PACKAGE_ROOT}/nvidia-container-toolkit-${VERSION}.*.tar.gz \ + -R ${REPOSITORY} diff --git a/hack/generate-changelog.sh b/hack/generate-changelog.sh index e2175f15..8324350c 100755 --- a/hack/generate-changelog.sh +++ b/hack/generate-changelog.sh @@ -24,14 +24,12 @@ Usage: $this --reference [--remote ] Options: --since specify the tag to start the changelog from (default: latest tag) - --remote specify the remote to fetch tags from (default: upstream) --version specify the version to be released --help/-h show this help and exit EOF } -REMOTE="upstream" VERSION="" REFERENCE= @@ -44,11 +42,6 @@ while [[ $# -gt 0 ]]; do shift # past argument shift # past value ;; - --remote) - REMOTE="$2" - shift # past argument - shift # past value - ;; --version) VERSION="$2" shift # past argument @@ -64,13 +57,22 @@ while [[ $# -gt 0 ]]; do done # Fetch the latest tags from the remote -git fetch $REMOTE --tags +remote=$( git remote -v | grep -E "NVIDIA/nvidia-container-toolkit(\.git)?\s" | grep -oE "^[a-z]+" | sort -u ) +>&2 echo "Detected remote as '${remote}'" +git fetch ${remote} --tags # if REFERENCE is not set, get the latest tag if [ -z "$REFERENCE" ]; then - REFERENCE=$(git describe --tags $(git rev-list --tags --max-count=1)) + most_recent_tag=$(git tag --sort=-creatordate | head -1) + if [ "${VERSION}" == "${most_recent_tag}" ]; then + REFERENCE=$(git tag --sort=-creatordate | head -2 | tail -1) + else + REFERENCE=${most_recent_tag} + fi fi +>&2 echo "Using ${REFERENCE} as previous version" + # Print the changelog echo "## Changelog" echo "" diff --git a/hack/prepare-artifacts.sh b/hack/prepare-artifacts.sh new file mode 100755 index 00000000..d6eb0bdb --- /dev/null +++ b/hack/prepare-artifacts.sh @@ -0,0 +1,53 @@ +#!/bin/bash -e + +# Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o pipefail + +# if arg1 is set, it will be used as the version number +if [ -z "$1" ]; then + VERSION=$(awk -F= '/^VERSION/ { print $2 }' versions.mk | tr -d '[:space:]') +else + VERSION=$1 +fi + +if [[ -z ${VERSION} ]]; then + echo "VERSION must be specified" + exit 1 +fi + +SHA=$(git rev-parse --short=8 ${VERSION}) + +IMAGE_NAME="ghcr.io/nvidia/container-toolkit" +IMAGE_TAG=${SHA}-packaging + +REPO="experimental" +if [[ ${VERSION/rc./} == ${VERSION} ]]; then + REPO="stable" +fi + +PACKAGE_ROOT=release-${VERSION}-${REPO} + +./hack/pull-packages.sh \ + ${IMAGE_NAME}:${IMAGE_TAG} \ + ${PACKAGE_ROOT} + +PACKAGE_VERSION=${VERSION/-/\~} +PACKAGE_VERSION=${PACKAGE_VERSION#v} + +tar -czvf ${PACKAGE_ROOT}/nvidia-container-toolkit-${VERSION}.deb.amd64.tar.gz ${PACKAGE_ROOT}/packages/ubuntu18.04/amd64/*_${PACKAGE_VERSION}-1_amd64.deb +tar -czvf ${PACKAGE_ROOT}/nvidia-container-toolkit-${VERSION}.deb.arm64.tar.gz ${PACKAGE_ROOT}/packages/ubuntu18.04/arm64/*_${PACKAGE_VERSION}-1_arm64.deb +tar -czvf ${PACKAGE_ROOT}/nvidia-container-toolkit-${VERSION}.rpm.aarch64.tar.gz ${PACKAGE_ROOT}/packages/centos7/aarch64/*-${PACKAGE_VERSION}-1.aarch64.rpm +tar -czvf ${PACKAGE_ROOT}/nvidia-container-toolkit-${VERSION}.rpm.x86_64.tar.gz ${PACKAGE_ROOT}/packages/centos7/x86_64/*-${PACKAGE_VERSION}-1.x86_64.rpm diff --git a/hack/prepare-release.sh b/hack/prepare-release.sh new file mode 100755 index 00000000..c4aaf4f2 --- /dev/null +++ b/hack/prepare-release.sh @@ -0,0 +1,186 @@ +#!/usr/bin/env bash + +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o pipefail + +this=`basename $0` + +usage () { +cat << EOF +Usage: $this [-h] [-a] RELEASE_VERSION + +Options: + --previous-version specify the previous version (default: latest tag) + --help/-h show this help and exit + +Example: + + $this {{ VERSION }} + +EOF +} + +validate_semver() { + local version=$1 + local semver_regex="^v([0-9]+)\.([0-9]+)\.([0-9]+)(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$" + + if [[ $version =~ $semver_regex ]]; then + major=${BASH_REMATCH[1]} + minor=${BASH_REMATCH[2]} + patch=${BASH_REMATCH[3]} + + # Check if major, minor, and patch are numeric + if ! [[ $major =~ ^[0-9]+$ ]] || ! [[ $minor =~ ^[0-9]+$ ]] || ! [[ $patch =~ ^[0-9]+$ ]]; then + echo "Invalid SemVer format: $version" + return 1 + fi + + # Validate prerelease if present + if [[ ! -z "${BASH_REMATCH[5]}" ]]; then + prerelease=${BASH_REMATCH[5]} + prerelease_regex="^([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)$" + if ! [[ $prerelease =~ $prerelease_regex ]]; then + echo "Invalid SemVer format: $version" + return 1 + fi + fi + + echo "Valid SemVer format: $version" + return 0 + else + echo "Invalid SemVer format: $version" + return 1 + fi +} + +# +# Parse command line +# +no_patching= +previous_version=$(git describe --tags $(git rev-list --tags --max-count=1)) +# Parse command line options +while [[ $# -gt 0 ]]; do + key="$1" + case $key in + --previous-version) + previous_version="$2" + shift 2 + ;; + --help/-h) usage + exit 0 + ;; + *) break + ;; + esac +done + +# Check that no extra args were provided +if [ $# -ne 1 ]; then + if [ $# -lt 1 ]; then + echo -e "ERROR: too few arguments\n" + else + echo -e "ERROR: unknown arguments: ${@:3}\n" + fi + usage + exit 1 +fi + +release=$1 +shift 1 + +container_image=nvcr.io/nvidia/k8s-device-plugin:$release + +# +# Check/parse release number +# +if [ -z "$release" ]; then + echo -e "ERROR: missing RELEASE_VERSION\n" + usage + exit 1 +fi + +# validate the release version +if ! validate_semver $release; then + echo -e "ERROR: invalid RELEASE_VERSION\n" + exit 1 +fi +semver=${release:1} + +# validate the previous version +if ! validate_semver $previous_version; then + echo -e "ERROR: invalid PREVIOUS_VERSION\n" + exit 1 +fi +pre_semver=${previous_version:1} + +# +# Modify files in the repo to point to new release +# +# Darwin or Linux +DOCKER="docker" +if [[ "$(uname)" == "Darwin" ]]; then + SED="$DOCKER run -i --rm -v $(PWD):$(PWD) -w $(PWD) alpine:latest sed" +else + SED="sed" +fi + +# TODO: We need to ensure that this tooling also works on `release-*` branches. +if [[ "$FORCE_BRANCH" != "yes" && "$(git rev-parse --abbrev-ref HEAD)" != "main" ]]; then + echo "Release scripts should be run on 'main'" + exit 1 +fi + +git fetch +git diff --quiet FETCH_HEAD +if [[ $? -ne 0 ]]; then + echo "Local changes detected:" + git diff FETCH_HEAD | cat + echo "Exiting" + exit 1 +fi + +# Create a release issue. +echo "Creating release tracking issue" +cat RELEASE.md | sed "s/{{ .VERSION }}/$release/g" | \ + gh issue create -F - \ + -R NVIDIA/cloud-native-team \ + --title "Release nvidia-container-toolkit $release" \ + --label release + + +echo "Creating a version bump branch: bump-release-${release}" +git checkout -f -b bump-release-${release} + +# Patch versions.mk +echo Patching versions.mk to refer to $release +$SED -i "s/^VERSION.*$/VERSION ?= $release/" versions.mk + +git add versions.mk +git commit -s -m "Bump version for $release release" + +if [[ $release != *-rc.* ]]; then + # Patch README.md + echo Patching README.md to refer to $release + $SED -E -i -e "s/([^[:space:]])$previous_version([^[:alnum:]]|$)/\1$release\2/g" README.md + $SED -E -i -e "s/$pre_semver/$semver/g" README.md + + git add -u README.md + git commit -s -m "Bump version to $release in README" +else + echo "Skipping README update for prerelease version" +fi + +echo "Please validated changes and create a pull request" diff --git a/scripts/pull-packages.sh b/hack/pull-packages.sh similarity index 95% rename from scripts/pull-packages.sh rename to hack/pull-packages.sh index f13750ee..f39bd675 100755 --- a/scripts/pull-packages.sh +++ b/hack/pull-packages.sh @@ -42,7 +42,7 @@ if [[ -z ${DIST_DIR} ]]; then exit 1 fi -if [[ -e ${DIST_DIR} ]]; then +if [[ x"${IGNORE_DIST_DIR}" != x"yes" && -e ${DIST_DIR} ]]; then echo "ERROR: The specified DIST_DIR ${DIST_DIR} exists." exit 1 fi diff --git a/scripts/release-packages.sh b/scripts/release-packages.sh index 7b2e72bb..b144afa3 100755 --- a/scripts/release-packages.sh +++ b/scripts/release-packages.sh @@ -58,7 +58,7 @@ fi PACKAGE_CACHE=release-${VERSION}-${REPO} echo "Fetching packages with SHA '${SHA}' as tag '${VERSION}' to ${PACKAGE_CACHE}" -${SCRIPTS_DIR}/pull-packages.sh \ +${SCRIPTS_DIR}/../hack/pull-packages.sh \ ${IMAGE_NAME}:${IMAGE_TAG} \ ${PACKAGE_CACHE}