/ .github / utils / promote_unstable_docs_docusaurus.py
promote_unstable_docs_docusaurus.py
  1  """
  2  This script promotes an unstable documentation version to a stable version at the time of a new Haystack release.
  3  
  4  To understand how unstable doc versions are created, see create_unstable_docs_docusaurus.py.
  5  """
  6  
  7  import argparse
  8  import json
  9  import os
 10  import re
 11  import shutil
 12  import sys
 13  
 14  VERSION_VALIDATOR = re.compile(r"^[0-9]+\.[0-9]+$")
 15  MAX_STABLE_VERSIONS = 5
 16  
 17  if __name__ == "__main__":
 18      parser = argparse.ArgumentParser()
 19      parser.add_argument("-v", "--version", help="The version to promote to stable (e.g. 2.20).", required=True)
 20      args = parser.parse_args()
 21  
 22      if VERSION_VALIDATOR.match(args.version) is None:
 23          sys.exit("Version must be formatted like so <major>.<minor>")
 24  
 25      target_version = f"{args.version}"  # e.g., "2.20" - the target release version
 26      major, minor = args.version.split(".")
 27  
 28      target_unstable = f"{target_version}-unstable"  # e.g., "2.20-unstable"
 29      previous_stable = f"{major}.{int(minor) - 1}"  # e.g., "2.19" - previous stable release
 30  
 31      versions = [
 32          folder.replace("version-", "")
 33          for folder in os.listdir("docs-website/versioned_docs")
 34          if os.path.isdir(os.path.join("docs-website/versioned_docs", folder))
 35      ]
 36  
 37      if target_version in versions:
 38          sys.exit(f"{target_version} already exists (already released). Aborting.")
 39      if target_unstable not in versions:
 40          sys.exit(f"Can't find version {target_unstable} to promote to {target_version}")
 41  
 42      print(f"Promoting unstable version {target_unstable} to stable version {target_version}")
 43  
 44      ### Docusaurus updates
 45  
 46      # move versioned_docs/version-target_unstable to versioned_docs/version-target_version
 47      shutil.move(
 48          f"docs-website/versioned_docs/version-{target_unstable}",
 49          f"docs-website/versioned_docs/version-{target_version}",
 50      )
 51  
 52      # move reference_versioned_docs/version-target_unstable to reference_versioned_docs/version-target_version
 53      shutil.move(
 54          f"docs-website/reference_versioned_docs/version-{target_unstable}",
 55          f"docs-website/reference_versioned_docs/version-{target_version}",
 56      )
 57  
 58      # move versioned_sidebars/version-target_unstable-sidebars.json
 59      # to versioned_sidebars/version-target_version-sidebars.json
 60      shutil.move(
 61          f"docs-website/versioned_sidebars/version-{target_unstable}-sidebars.json",
 62          f"docs-website/versioned_sidebars/version-{target_version}-sidebars.json",
 63      )
 64  
 65      # move reference_versioned_sidebars/version-target_unstable-sidebars.json
 66      # to reference_versioned_sidebars/version-target_version-sidebars.json
 67      shutil.move(
 68          f"docs-website/reference_versioned_sidebars/version-{target_unstable}-sidebars.json",
 69          f"docs-website/reference_versioned_sidebars/version-{target_version}-sidebars.json",
 70      )
 71  
 72      # replace unstable version with stable version in versions.json
 73      with open("docs-website/versions.json") as f:
 74          versions_list = json.load(f)
 75      versions_list[versions_list.index(target_unstable)] = target_version
 76      with open("docs-website/versions.json", "w") as f:
 77          json.dump(versions_list, f)
 78  
 79      # replace unstable version with stable version in reference_versions.json
 80      with open("docs-website/reference_versions.json") as f:
 81          reference_versions_list = json.load(f)
 82      reference_versions_list[reference_versions_list.index(target_unstable)] = target_version
 83      with open("docs-website/reference_versions.json", "w") as f:
 84          json.dump(reference_versions_list, f)
 85  
 86      # in docusaurus.config.js, replace previous stable version with the target version
 87      with open("docs-website/docusaurus.config.js") as f:
 88          config = f.read()
 89      config = config.replace(f"lastVersion: '{previous_stable}'", f"lastVersion: '{target_version}'")  # "2.19" -> "2.20"
 90      with open("docs-website/docusaurus.config.js", "w") as f:
 91          f.write(config)
 92  
 93      # regenerate vercel.json redirects for inactive versions (those beyond the top MAX_STABLE_VERSIONS)
 94      with open("docs-website/versions.json") as f:
 95          updated_versions = json.load(f)
 96      stable_versions = [v for v in updated_versions if not v.endswith("-unstable")]
 97      inactive_versions = stable_versions[MAX_STABLE_VERSIONS:]
 98      redirects = []
 99      for v in inactive_versions:
100          redirects.append({"source": f"/docs/{v}/:slug*", "destination": "/docs/:slug*", "permanent": True})
101          redirects.append({"source": f"/reference/{v}/:slug*", "destination": "/reference/:slug*", "permanent": True})
102  
103      with open("docs-website/vercel.json") as f:
104          vercel_config = json.load(f)
105  
106      existing_redirects = vercel_config.get("redirects", [])
107      existing_sources = {r.get("source") for r in existing_redirects}
108  
109      for r in redirects:
110          if r["source"] not in existing_sources:
111              existing_redirects.append(r)
112  
113      vercel_config["redirects"] = existing_redirects
114      with open("docs-website/vercel.json", "w") as f:
115          json.dump(vercel_config, f, indent=2)
116          f.write("\n")
117      print(f"Updated vercel.json with {len(redirects)} redirect(s) for inactive versions: {inactive_versions}")