diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index e2e45868a1..17c6498c50 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -6,6 +6,26 @@ on: build-ctk-ver: type: string required: true + component: + description: "Component(s) to build docs for" + required: false + default: "all" + type: string + # below are the acceptable options: + # - cuda-core + # - cuda-bindings + # - cuda-python + # - all + git-tag: + description: "Target git tag to build docs for" + required: false + default: "" + type: string + is-release: + description: "Are we building release docs?" + required: false + default: false + type: boolean jobs: build: @@ -27,6 +47,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + ref: ${{ inputs.git-tag }} # TODO: cache conda env to speed up the workflow once conda-incubator/setup-miniconda#267 # is resolved @@ -114,23 +135,47 @@ jobs: pip install cuda_python*.whl - # This step sets the PR_NUMBER env var. + # This step sets the PR_NUMBER/BUILD_LATEST/BUILD_PREVIEW env vars. - name: Get PR number + if: ${{ !inputs.is-release }} uses: ./.github/actions/get_pr_number - - name: Build all (latest) docs - id: build + - name: Set up artifact directories + run: | + mkdir -p artifacts/docs + # create an empty folder for removal use + mkdir -p artifacts/empty_docs + + - name: Build all docs + if: ${{ inputs.component == 'all' }} + env: + DOC_ACTION: ${{ (inputs.is-release && '') || 'latest-only' }} run: | pushd cuda_python/docs/ - ./build_all_docs.sh latest-only + ./build_all_docs.sh $DOC_ACTION + if [[ -z "$DOC_ACTION" ]]; then + # At release time, we don't want to update the latest docs + rm -rf build/html/latest + fi ls -l build popd - - mkdir -p artifacts/docs mv cuda_python/docs/build/html/* artifacts/docs/ - # create an empty folder for removal use - mkdir -p artifacts/empty_docs + - name: Build component docs + if: ${{ inputs.component != 'all' }} + env: + DOC_ACTION: ${{ (inputs.is-release && '') || 'latest-only' }} + run: | + COMPONENT=$(echo "${{ inputs.component }}" | tr '-' '_') + pushd ${COMPONENT}/docs/ + ./build_docs.sh $DOC_ACTION + if [[ -z "$DOC_ACTION" ]]; then + # At release time, we don't want to update the latest docs + rm -rf build/html/latest + fi + ls -l build + popd + mv ${COMPONENT}/docs/build/html/* artifacts/docs/ # TODO: Consider removing this step? - name: Upload doc artifacts @@ -140,6 +185,7 @@ jobs: retention-days: 3 - name: Deploy or clean up doc preview + if: ${{ !inputs.is-release }} uses: ./.github/actions/doc_preview with: source-folder: ${{ (github.ref_name != 'main' && 'artifacts/docs') || @@ -147,12 +193,12 @@ jobs: pr-number: ${{ env.PR_NUMBER }} - name: Deploy doc update - if: ${{ github.ref_name == 'main' }} + if: ${{ github.ref_name == 'main' || inputs.is-release }} uses: JamesIves/github-pages-deploy-action@v4 with: git-config-name: cuda-python-bot git-config-email: cuda-python-bot@users.noreply.github.com folder: artifacts/docs/ target-folder: docs/ - commit-message: "Deploy latest docs: ${{ github.sha }}" + commit-message: "Deploy ${{ (inputs.is-release && 'release') || 'latest' }} docs: ${{ github.sha }}" clean: false diff --git a/.github/workflows/release-upload.yml b/.github/workflows/release-upload.yml new file mode 100644 index 0000000000..5fa58de92c --- /dev/null +++ b/.github/workflows/release-upload.yml @@ -0,0 +1,59 @@ +name: "CI: Upload git archive" + +on: + workflow_call: + inputs: + git-tag: + type: string + required: true + +concurrency: + # Concurrency group that uses the workflow name and PR number if available + # or commit SHA as a fallback. If a new build is triggered under that + # concurrency group while a previous build is running it will be canceled. + # Repeated pushes to a PR will cancel all previous builds, while multiple + # merges to main will not cancel. + group: ${{ github.workflow }}-${{ github.ref_name || github.sha }} + cancel-in-progress: true + +permissions: + contents: write + +jobs: + # create source archive and upload it to the published release + # URL to the archive: https://github.com/NVIDIA//releases/download//-.tar.gz + upload: + if: ${{ !github.event.repository.fork }} + runs-on: ubuntu-latest + env: + ARCHIVE_NAME: ${{ github.event.repository.name }}-${{ inputs.git-tag }} + steps: + - name: Checkout Source + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Create Release Directory + run: mkdir -p release + + - name: Archive Source + run: > + git archive + --format=tar.gz + --prefix="${{ env.ARCHIVE_NAME }}/" + --output="release/${{ env.ARCHIVE_NAME }}.tar.gz" + ${{ inputs.git-tag }} + + - name: Compute Checksum + run: > + sha256sum "release/${{ env.ARCHIVE_NAME }}.tar.gz" + | awk '{print $1}' + > "release/${{ env.ARCHIVE_NAME }}.tar.gz.sha256sum" + + - name: Upload Archive + env: + GH_TOKEN: ${{ github.token }} + run: > + gh release upload + ${{ inputs.git-tag }} + release/* + --clobber "${{ github.ref_name }}" + --repo "${{ github.repository }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..3b93a1e0b0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,141 @@ +name: "CI: Release" + +description: Manually-triggered release workflow. Must have a release note in the draft state and the release commit tagged. + +on: + workflow_dispatch: + inputs: + component: + description: "Component to release" + required: true + type: choice + options: + - cuda-core + - cuda-bindings + - cuda-python + - all + git-tag: + description: "The release git tag" + required: true + type: string + run-id: + description: "The GHA run ID that generated validated artifacts" + required: true + type: string + build-ctk-ver: + type: string + required: true + wheel-dst: + description: "Which wheel index to publish to?" + required: true + type: choice + options: + - testpypi + - pypi + #print_tags: + # description: 'True to print to STDOUT' + # required: true + # type: boolean + +defaults: + run: + shell: bash --noprofile --norc -xeuo pipefail {0} + +jobs: + check-tag: + runs-on: ubuntu-latest + steps: + - name: Check if draft exists for the tag + env: + GH_TOKEN: ${{ github.token }} + run: | + tags= + for i in $(gh release list -R ${{ github.repository }} --json tagName --jq '.[]| .tagName'); do + tags+=( $i ) + done + is_draft= + for i in $(gh release list -R ${{ github.repository }} --json isDraft --jq '.[]| .isDraft'); do + is_draft+=( $i ) + done + + found=0 + for idx in ${!tags[@]}; do + if [[ "${tags[$idx]}" == "${{ inputs.git-tag }}" ]]; then + echo "found ${{ inputs.git-tag }}" + found=1 + if [[ "${is_draft[$idx]}" != "true" ]]; then + echo "the release note is not in draft state" + exit 1 + fi + break + fi + done + if [[ "$found" == 0 ]]; then + echo "the release is not yet tagged" + exit 1 + fi + + doc: + name: Build release docs + if: ${{ github.repository_owner == 'nvidia' }} + # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages + permissions: + id-token: write + contents: write + pull-requests: write + needs: + - check-tag + secrets: inherit + uses: + ./.github/workflows/build-docs.yml + with: + build-ctk-ver: ${{ inputs.build-ctk-ver }} + component: ${{ inputs.component }} + git-tag: ${{ inputs.git-tag }} + is-release: true + + upload-archive: + name: Upload source archive + permissions: + contents: write + needs: + - check-tag + secrets: inherit + uses: + ./.github/workflows/release-upload.yml + with: + git-tag: ${{ inputs.git-tag }} + + publish-wheels: + name: Publish wheels + runs-on: ubuntu-latest + needs: + - check-tag + environment: + name: ${{ inputs.wheel-dst }} + url: https://${{ (inputs.wheel-dst == 'testpypi' && 'test.') || '' }}pypi.org/p/${{ inputs.component }}/ + permissions: + id-token: write + steps: + - name: Download component wheels + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh run download ${{ inputs.run-id }} -p "${{ inputs.component }}*" -R ${{ github.repository }} + mkdir dist + for p in "${{ inputs.component }}*"; do + mv ${p}/*.whl dist/ + done + rmdir "${{ inputs.component }}*" + + - name: Publish package distributions to PyPI + if: ${{ inputs.wheel-dst == 'pypi' }} + uses: pypa/gh-action-pypi-publish@release/v1 + + - name: Publish package distributions to TestPyPI + if: ${{ inputs.wheel-dst == 'testpypi' }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + + # TODO: add another job to make the release leave the draft state?