diff --git a/.github/workflows/release-README.md b/.github/workflows/release-README.md new file mode 100644 index 00000000000..de33e877584 --- /dev/null +++ b/.github/workflows/release-README.md @@ -0,0 +1,65 @@ +# Release Workflows + +The three `release-*.yml` workflows are used at various points in the release process: + +## 1. `release-create-new.yml` + +Begin the release process for a new version. Create branches and update version numbers. + +### Start workflow on + +- The `branch/{major}.{minor}.x` branch if it exists for the target version, or +- The branch or tag to use as a base when forking the release branch (e.g. `main`) + +### Inputs + +- `branch_version`: The 'X.Y.Z' version to use for the release branch. +- `main_version`: Optional; If set, a pull request will be created to bump main to this `X.Y.Z` version. + +### Actions + +- Creates release branch if needed. +- Updates release version directly on github release branch. +- If requested, creates pull request to update main to `main_version`. + +## 2. `release-update-rc.yml` + +Test and tag a new release candidate from a prepared release branch. + +### Start workflow on + +The release branch that has been prepared for the release candidate. +The current HEAD commit will be used. + +### Inputs + +None. The version number is obtained from inspecting the repository state. + +### Actions + +- Reads the version from a new metadata file written by the update-version.sh script. +- Errors out if the version is already tagged. +- Determines the next rc for this version by inspecting existing tags. +- Runs the `pull_request` workflow to validate the release candidate. + This can be modified in the future to run a special rc acceptance workflow (sanitizers, benchmarks?). +- Tags the release candidate only if the CI workflow passes. + +## `release-finalize` + +Tag a final release from an existing release candidate. +Create release artifacts. + +### Start workflow on + +The release candidate tag to use for the final release. + +### Inputs + +None. + +### Actions + +- Parses version info from the provided tag. +- Pushes final release tag +- Generates source and install packages (zips and tgzs) +- Creates draft Github release with auto-generated release notes and source/install archives. diff --git a/.github/workflows/release-finalize.yml b/.github/workflows/release-finalize.yml new file mode 100644 index 00000000000..67e2aad6015 --- /dev/null +++ b/.github/workflows/release-finalize.yml @@ -0,0 +1,192 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + +name: "Release: 3. Create Final Release" + +# This workflow must be started on an release candidate tag. + +on: + workflow_dispatch: + +defaults: + run: + shell: bash --noprofile --norc -euo pipefail {0} + +jobs: + create-release: + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ github.token }} + permissions: + contents: write + outputs: + rc_tag: ${{ steps.prepare.outputs.rc_tag }} + release_tag: ${{ steps.prepare.outputs.release_tag }} + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + + - name: Prepare environment + id: prepare + run: | + log_and_export_vars() { + for var in "$@"; do + printf "%-15s %s\n" "$var:" "${!var}" | tee -a $GITHUB_STEP_SUMMARY + echo "${var}=${!var}" | tee -a $GITHUB_ENV | tee -a $GITHUB_OUTPUT + done + } + + # The ref must match a release candidate tag. Parse version info: + tag_regex="^refs/tags/v([0-9]+)\.([0-9]+)\.([0-9]+)-rc([0-9]+)$" + if [[ "${GITHUB_REF}" =~ ${tag_regex} ]]; then + major_version=${BASH_REMATCH[1]} + minor_version=${BASH_REMATCH[2]} + patch_version=${BASH_REMATCH[3]} + rc=${BASH_REMATCH[4]} + else + echo "::error::Invalid ref: ${GITHUB_REF}. Must be a release candidate tag (vX.Y.Z-rcN)." + exit 1 + fi + full_version="${major_version}.${minor_version}.${patch_version}" + release_tag="v${full_version}" + rc_tag="${release_tag}-rc${rc}" + repo_version=$(jq -r .full cccl-version.json) + + log_and_export_vars full_version major_version minor_version patch_version rc release_tag rc_tag repo_version + + if [[ "${repo_version}" != "${full_version}" ]]; then + echo "::error::cccl-version.json (${repo_version}) does not match release candidate tag (${rc_tag})." + exit 1 + fi + + # Ensure that there is no final release tag (vX.Y.Z) for the requested version. + release_tag_escaped=$(echo "${release_tag}" | sed 's/\./\\./g') + if git ls-remote --tags origin | grep -q "refs/tags/${release_tag_escaped}$"; then + echo "::error::Final release tag ${release_tag} already exists." + exit 1 + fi + + - name: Generate archives + id: archive + run: | + source_base=cccl-src-${release_tag} + package_base=cccl-${release_tag} + + echo "::group::Preparing source" + declare -a source_exclude=( + .aws + .cache + .config + .local + .git + .vscode + build + archives + ${source_base} + ${package_base} + ) + mkdir ${source_base} + rsync -av ${source_exclude[*]/#/--exclude=} . ${source_base} + echo "::endgroup::" + + ci/install_cccl.sh "${package_base}" + + mkdir archives + + source_tarball=${PWD}/archives/${source_base}.tar.gz + source_zipfile=${PWD}/archives/${source_base}.zip + package_tarball=${PWD}/archives/${package_base}.tar.gz + package_zipfile=${PWD}/archives/${package_base}.zip + + echo "source_tarball=${source_tarball}" >> $GITHUB_ENV + echo "source_zipfile=${source_zipfile}" >> $GITHUB_ENV + echo "package_tarball=${package_tarball}" >> $GITHUB_ENV + echo "package_zipfile=${package_zipfile}" >> $GITHUB_ENV + + echo "::group::Archiving: ${source_tarball}" + tar -cvzf ${source_tarball} ${source_base} + echo "::endgroup::" + + echo "::group::Archiving: ${source_zipfile}" + zip -rv9 ${source_zipfile} ${source_base} + echo "::endgroup::" + + echo "::group::Archiving: ${package_tarball}" + tar -cvzf ${package_tarball} ${package_base} + echo "::endgroup::" + + echo "::group::Archiving: ${package_zipfile}" + zip -rv9 ${package_zipfile} ${package_base} + echo "::endgroup::" + + echo "::group::Archive vs Source Sizes" + echo "Sources:" | tee -a $GITHUB_STEP_SUMMARY + du -sh ${source_base} ${source_tarball} ${source_zipfile} | tee -a $GITHUB_STEP_SUMMARY + echo "Installation Packages:" | tee -a $GITHUB_STEP_SUMMARY + du -sh ${package_base} ${package_tarball} ${package_zipfile} | tee -a $GITHUB_STEP_SUMMARY + echo "::endgroup::" + + rm -rf ${source_base} ${package_base} + + - name: Tag + run: | + git config user.name github-actions + git config user.email github-actions@github.com + + git tag -a -m "CCCL Release ${release_tag}" ${release_tag} ${rc_tag} + git push origin ${release_tag} + echo "Tagged release ${release_tag} from ${rc_tag}." | tee -a $GITHUB_STEP_SUMMARY + + - name: Draft Github Release + run: | + gh release create ${release_tag} \ + --draft \ + --generate-notes \ + --title "${release_tag}" \ + "${source_zipfile}#Source Archive (zip)" \ + "${source_tarball}#Source Archive (tar.gz)" \ + "${package_zipfile}#Installation Archive (zip)" \ + "${package_tarball}#Installation Archive (tar.gz)" + + - name: Notify Slack + if: ${{ success() }} + uses: slackapi/slack-github-action@v1.26.0 + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_NOTIFIER_BOT_TOKEN }} + SUMMARY_URL: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} + RC_TAG: ${{ steps.prepare.outputs.rc_tag }} + RELEASE_TAG: ${{ steps.prepare.outputs.release_tag }} + RELEASE_URL: https://github.com/${{github.repository}}/releases/tag/${{ steps.prepare.outputs.release_tag }} + with: + channel-id: ${{ secrets.SLACK_CHANNEL_RELEASE_LOG }} + slack-message: | + Release `${{ env.RELEASE_TAG }}` has been created from `${{ env.RC_TAG }}`. + + A draft Github release has been prepared at ${{ env.RELEASE_URL }}. + + Workflow summary: ${{ env.SUMMARY_URL }} + + - name: Notify Slack (failure) + if: ${{ failure() }} + uses: slackapi/slack-github-action@v1.26.0 + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_NOTIFIER_BOT_TOKEN }} + SUMMARY_URL: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} + with: + channel-id: ${{ secrets.SLACK_CHANNEL_RELEASE_LOG }} + slack-message: | + An error has occurred while creating a release from ${{ github.ref }}. + + Details: ${{ env.SUMMARY_URL }} diff --git a/CMakePresets.json b/CMakePresets.json index e6264a087ec..447a684c58f 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -352,7 +352,7 @@ }, { "name": "cccl-c-parallel", - "displayName" : "CCCL C Parallel Library", + "displayName": "CCCL C Parallel Library", "inherits": "base", "cacheVariables": { "CCCL_ENABLE_C": true, @@ -380,6 +380,10 @@ "name": "all-dev-debug", "configurePreset": "all-dev-debug" }, + { + "name": "install", + "configurePreset": "install" + }, { "name": "libcudacxx-codegen", "configurePreset": "libcudacxx-codegen", diff --git a/cccl-version.json b/cccl-version.json new file mode 100644 index 00000000000..b224890fec7 --- /dev/null +++ b/cccl-version.json @@ -0,0 +1,6 @@ +{ + "full": "2.7.0", + "major": 2, + "minor": 7, + "patch": 0 +} diff --git a/ci/install_cccl.sh b/ci/install_cccl.sh new file mode 100755 index 00000000000..15666d891e8 --- /dev/null +++ b/ci/install_cccl.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +set -eo pipefail + +target_dir=$(realpath "$1") +mkdir -p "$target_dir" + +# Move script to the root directory of the project +cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"; + +source ./pretty_printing.sh + +# Check if the correct number of arguments has been provided +function usage { + echo "Usage: $0 [OPTIONS] dir" + echo + echo "Installs CCCL to the provided directory" + + echo "Options:" + echo " -v/-verbose: Enable shell echo for debugging" + echo + echo "Examples:" + echo " $ $0 ~/my/prefix" + exit 1 +} + +while [[ "$#" -gt 0 ]]; do + case "$1" in + --verbose) VERBOSE=true; ;; + -v) VERBOSE=true; ;; + *) break ;; + esac + shift +done + +if [ $VERBOSE ]; then + set -x +fi + +# Move to cccl/ dir +pushd ".." > /dev/null +GROUP_NAME="🛠️ CMake Configure CCCL - Install" +run_command "$GROUP_NAME" cmake -G "Unix Makefiles" --preset install -DCMAKE_INSTALL_PREFIX="${target_dir}" +status=$? + +GROUP_NAME="🏗️ Install CCCL" +run_command "$GROUP_NAME" cmake --build --preset install --target install +status=$? +popd > /dev/null diff --git a/ci/update_version.sh b/ci/update_version.sh index 9184b98e6a9..c43303449bb 100755 --- a/ci/update_version.sh +++ b/ci/update_version.sh @@ -28,14 +28,15 @@ if [ -z "$major" ] || [ -z "$minor" ] || [ -z "$patch" ]; then fi # Version file paths +REPO_VERSION_FILE="cccl-version.json" CCCL_VERSION_FILE="libcudacxx/include/cuda/std/__cccl/version.h" THRUST_VERSION_FILE="thrust/thrust/version.h" CUB_VERSION_FILE="cub/cub/version.cuh" CCCL_CMAKE_VERSION_FILE="lib/cmake/cccl/cccl-config-version.cmake" -CUB_CMAKE_VERSION_FILE="cub/cub/cmake/cub-config-version.cmake" -LIBCUDACXX_CMAKE_VERSION_FILE="libcudacxx/lib/cmake/libcudacxx/libcudacxx-config-version.cmake" -THRUST_CMAKE_VERSION_FILE="thrust/thrust/cmake/thrust-config-version.cmake" -CUDAX_CMAKE_VERSION_FILE="cudax/lib/cmake/cudax/cudax-config-version.cmake" +CUB_CMAKE_VERSION_FILE="lib/cmake/cub/cub-config-version.cmake" +LIBCUDACXX_CMAKE_VERSION_FILE="lib/cmake/libcudacxx/libcudacxx-config-version.cmake" +THRUST_CMAKE_VERSION_FILE="lib/cmake/thrust/thrust-config-version.cmake" +CUDAX_CMAKE_VERSION_FILE="lib/cmake/cudax/cudax-config-version.cmake" CUDA_COOPERATIVE_VERSION_FILE="python/cuda_cooperative/cuda/cooperative/_version.py" CUDA_PARALLEL_VERSION_FILE="python/cuda_parallel/cuda/parallel/_version.py" @@ -78,7 +79,13 @@ update_file () { fi } -# Update version information in files +# Update version information in files: + +update_file "$REPO_VERSION_FILE" " \"full\":.*," " \"full\": \"$major.$minor.$patch\"," +update_file "$REPO_VERSION_FILE" " \"major\":.*" " \"major\": $major," +update_file "$REPO_VERSION_FILE" " \"minor\":.*" " \"minor\": $minor," +update_file "$REPO_VERSION_FILE" " \"patch\":.*" " \"patch\": $patch" + update_file "$CCCL_VERSION_FILE" "^#define CCCL_VERSION \([0-9]\+\)" "#define CCCL_VERSION $new_cccl_version" update_file "$THRUST_VERSION_FILE" "^#define THRUST_VERSION \([0-9]\+\)" "#define THRUST_VERSION $new_thrust_cub_version" update_file "$CUB_VERSION_FILE" "^#define CUB_VERSION \([0-9]\+\)" "#define CUB_VERSION $new_thrust_cub_version"