From 0bea5f0cc566cc5bd19fdf2e11a45b44356671e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Melissa=20Weber=20Mendon=C3=A7a?= Date: Tue, 22 Oct 2024 14:17:54 -0300 Subject: [PATCH] Add a release action (#23) * Add a release action This action will build and deploy docs for a new release, copying the built docs artifacts to both the dev and the {version} folders in napari.github.io. It will also update the stable symlink to point to the new version folder. This action will be triggered by a new release tag pushed to the repo or by manually trigerring the action with an input specifying the new version (any input different from the default dev will trigger the action.) * Fix release action execution condition * Add condition to filter out release candidates from release action * Add script to update version switcher * WIP: Testing on fork --- .circleci/config.yml | 4 +- .github/workflows/build_and_deploy.yml | 55 ++++++++++++++++++++++++-- docs/_scripts/update_switcher.py | 34 ++++++++++++++++ 3 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 docs/_scripts/update_switcher.py diff --git a/.circleci/config.yml b/.circleci/config.yml index f808dcd58..6500834e9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,12 +6,12 @@ version: 2.1 # Orbs are reusable packages of CircleCI configuration that you may share across projects. # See: https://circleci.com/docs/2.1/orb-intro/ orbs: - python: circleci/python@1.5.0 + python: circleci/python@2.1.1 jobs: build-docs: docker: # A list of available CircleCI Docker convenience images are available here: https://circleci.com/developer/images/image/cimg/python - - image: cimg/python:3.10.13 + - image: cimg/python:3.10 steps: - checkout: path: docs diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index fdcfd13e1..1d33e83a1 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -69,11 +69,18 @@ jobs: python -c 'import napari.layers; print(napari.layers.__doc__)' - name: Create fallback videos + # Only needed for deployment, so should **NOT** be in + # napari/napari/.github/workflows/build_docs.yml run: | sudo apt-get update && sudo apt-get install -y ffmpeg cd docs make fallback-videos + - name: Update version switcher (on new tag) + if: ((github.event_name == 'release' && !contains(github.event.release.tag_name, 'rc')) || (github.event_name == 'workflow_dispatch' && github.event.inputs.target_directory != 'dev')) + run: | + python docs/_scripts/update_version_switcher.py ${{ github.event.inputs.target_directory || github.event.release.tag_name }} + - name: Build Docs uses: aganders3/headless-gui@v2 env: @@ -109,13 +116,55 @@ jobs: # Downloads to '/home/runner/work/docs/docs/html' path: html - - name: Deploy Docs + - name: Deploy Dev Docs if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/main')) uses: peaceiris/actions-gh-pages@v3 with: + # Note that GITHUB_TOKEN has no permission to access to external repositories. + # When you use deploy_key, set your private key to the repository which + # includes this action as a secret, and set your public key to your external repository. deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} - external_repository: napari/napari.github.io + external_repository: melissawm/napari.github.io publish_dir: ./html publish_branch: gh-pages destination_dir: ${{ github.event.inputs.target_directory || 'dev' }} - cname: napari.org + #cname: napari.org + keep_files: true + + # Because we are using two deploy actions, we need to reset the ssh-agent + # to avoid the following error: + # unix_listener: cannot bind to path /tmp/ssh-auth.sock: Address already in use + # See https://github.com/peaceiris/actions-gh-pages/issues/909 + - name: Reset ssh agent + if: ((github.event_name == 'release' && !contains(github.event.release.tag_name, 'rc')) || (github.event_name == 'workflow_dispatch' && github.event.inputs.target_directory != 'dev')) + run: killall ssh-agent + + # Because the actions-gh-pages triggers a pages deployment, it can be some + # time before the repo is updated. We need to wait for the deployment to + # complete before we can create a second deployment, or we will have a git + # conflict. The 5m sleep is completely arbitrary. + - name: Wait for first deployment + if: ((github.event_name == 'release' && !contains(github.event.release.tag_name, 'rc')) || (github.event_name == 'workflow_dispatch' && github.event.inputs.target_directory != 'dev')) + run: sleep 5m + + - name: Deploy Release Docs + if: ((github.event_name == 'release' && !contains(github.event.release.tag_name, 'rc')) || (github.event_name == 'workflow_dispatch' && github.event.inputs.target_directory != 'dev')) + uses: peaceiris/actions-gh-pages@v3 + with: + deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} + external_repository: melissawm/napari.github.io + publish_dir: ./html + publish_branch: gh-pages + destination_dir: ${{ github.event.inputs.target_directory || github.event.release.tag_name }} + #cname: napari.org + keep_files: true + + - name: Set up stable symlink + if: ((github.event_name == 'release' && !contains(github.event.release.tag_name, 'rc')) || (github.event_name == 'workflow_dispatch' && github.event.inputs.target_directory != 'dev')) + uses: convictional/trigger-workflow-and-wait@v1.6.5 + with: + owner: melissawm + repo: napari.github.io + github_token: ${{ secrets.WORKFLOW_PAT }} + workflow_file_name: symlink-stable.yml + client_payload: '{"target_directory": "${{ github.event.inputs.target_directory || github.event.release.tag_name }}"}' diff --git a/docs/_scripts/update_switcher.py b/docs/_scripts/update_switcher.py new file mode 100644 index 000000000..b7d934ba6 --- /dev/null +++ b/docs/_scripts/update_switcher.py @@ -0,0 +1,34 @@ +import sys +import json + + +def update_version_switcher(new_version): + """Update version_switcher.json after a new release.""" + with open("docs/_static/version_switcher.json", "r") as f: + switcher = json.load(f) + oldstable = switcher[1] + + newstable = oldstable.copy() + newstable["version"] = new_version + newstable["name"] = f"stable ({new_version})" + + oldstable["name"] = f"{oldstable['version']}" + del oldstable["preferred"] + oldstable["url"] = oldstable["url"].replace("stable", oldstable["version"]) + + switcher[1] = oldstable + switcher.insert(1, newstable) + with open("docs/_static/version_switcher.json", "w") as f: + json.dump(switcher, f, indent=4) + + print(f"Version switcher updated to {new_version}") + print(f"Old stable version: {switcher[2]}") + print(f"New stable version: {switcher[1]}") + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python update_switcher.py ") + sys.exit() + new_version = sys.argv[1] + update_version_switcher(new_version)