diff --git a/build/version_archiver.py b/build/version_archiver.py new file mode 100644 index 0000000000..f8b095a31a --- /dev/null +++ b/build/version_archiver.py @@ -0,0 +1,219 @@ +import os, shutil, re, argparse + + +class VersionArchiver: + def __init__(self, product, version): + self.product = product + self.new_version = version + + if self.product in ("kubernetes", "rs"): + self.prefix = "operate" + else: + self.prefix = "integrate" + self.new_directory = os.path.join("content",self.prefix,self.product,self.new_version) + self.latest = os.path.join("content",self.prefix,self.product) + + def archive_version(self): + """Copy all files from latest in new versioned directory, excluding release-notes""" + + # Walk through the latest directory + for root, dirs, files in os.walk(self.latest): + # Exclude directories with numbers in their names (other releases) and 'release-notes' directory + dirs[:] = [ + d + for d in dirs + if not any(char.isdigit() for char in d) and d != "release-notes" + ] + + # Create the corresponding destination directory if it does not exist + relative_path = os.path.relpath(root, self.latest) + dest_dir = os.path.join(self.new_directory, relative_path) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + + for file in files: + src_file = os.path.join(root, file) + dest_file = os.path.join(dest_dir, file) + shutil.copy2(src_file, dest_file) + + def update_relrefs(self, file_path, version, product): + """Helper function for updating relrefs""" + + # Define a pattern to match relref links dynamically using product + pattern = ( + r'(\(\{\{< ?relref "/' + + self.prefix + + "/" + + re.escape(product) + + r'/([^"]+)" ?>\}\})' + ) + with open(file_path, "r") as file: + lines = file.readlines() + + modified = False + + # Process each line in the file + for i in range(len(lines)): + # Search for relref links + def replace_link(match): + full_match = match.group(0) # The entire match + link = match.group(1) # The actual relref link + + # Check if the link contains 'release-notes' and whether the replacement has already happened + if ( + "release-notes" not in link + and f"/{self.prefix}/{product}/{version}" not in link + ): + # Otherwise, replace it + new_link = link.replace( + f"/{self.prefix}/{product}/", + f"/{self.prefix}/{product}/{version}/", + ) + return f"{new_link}" + return full_match + + # Replace all relref links in the line + modified_line = re.sub(pattern, replace_link, lines[i]) + + # If the line was modified, update the lines list + if modified_line != lines[i]: + lines[i] = modified_line + modified = True + + # If any modification was made, write the updated content back to the file + if modified: + with open(file_path, "w") as file: + file.writelines(lines) + + def version_relrefs(self): + """Make all relrefs in a versioned directory versioned""" + + # Walk through the new directory and process all .md files + for root, _, files in os.walk(self.new_directory): + for file_name in files: + if file_name.endswith(".md"): + file_path = os.path.join(root, file_name) + self.update_relrefs(file_path, self.new_version, self.product) + + def inject_url_frontmatter(self): + """Inject url frontmatter property""" + + base_url = self.new_directory.strip("content").strip(f"/{self.new_version}") + + # Walk through the new directory + for root, dirs, files in os.walk(self.new_directory): + for file in files: + file_path = os.path.join(root, file) + + # Read the file line by line + with open(file_path, "r", encoding="utf-8") as f: + lines = f.readlines() + + # Find the positions of the first and second '---' markers + first_emdash_index = -1 + second_emdash_index = -1 + + # Search for the frontmatter markers + for i, line in enumerate(lines): + if line.strip() == "---": + if first_emdash_index == -1: + first_emdash_index = i + elif second_emdash_index == -1: + second_emdash_index = i + break + + if first_emdash_index != -1 and second_emdash_index != -1: + # Extract the frontmatter lines + frontmatter_lines = lines[ + first_emdash_index + 1 : second_emdash_index + ] + + # If the url property already exists, skip + if any("url" in f for f in frontmatter_lines): + break + + if file_path == os.path.join(self.new_directory,"_index.md"): + for idx, item in enumerate(frontmatter_lines): + if "linkTitle" in item: + frontmatter_lines[idx] = ( + f"linkTitle: {self.new_version}\n" + ) + frontmatter_lines.append( + f"bannerText: This documentation applies to version {self.new_version}.\n" + ) + frontmatter_lines.append(f"bannerChildren: true\n") + + # Add the 'url' field to the frontmatter + relative_path = os.path.relpath(root, self.new_directory) + if file == "_index.md": + + if relative_path == ".": + url = f"url: '/{base_url}/{self.new_version}/'" + else: + url = f"url: '/{base_url}/{self.new_version}/{relative_path}/'" + + else: + f = file.strip(".md") + if relative_path == ".": + url = f"url: '/{base_url}/{self.new_version}/{f}/'" + else: + url = f"url: '/{base_url}/{self.new_version}/{relative_path}/{f}/'" + + # Add url at the end of the frontmatter + frontmatter_lines.append(url + "\n") + + # Rebuild the content with the updated frontmatter + updated_lines = ( + lines[: first_emdash_index + 1] + + frontmatter_lines + + lines[second_emdash_index:] + ) + + # Write the updated content back to the file + with open(file_path, "w", encoding="utf-8") as f: + f.writelines(updated_lines) + else: + # skip files without frontmatter + pass + + +def validate_product(value): + """Custom validator for product argument to allow only 'rs' or 'kubernetes'""" + if value not in ["rs", "kubernetes", "redis-data-integration"]: + raise argparse.ArgumentTypeError( + "Product must be either 'rs' or 'kubernetes' or 'redis-data-integration'." + ) + return value + + +def validate_version(value): + """Custom validator for version argument to ensure it follows the version format (e.g., 7, 7.1, 7.1.11)""" + version_pattern = r"^\d+(\.\d+){0,2}(\.\d+)?$" + if not re.match(version_pattern, value): + raise argparse.ArgumentTypeError( + "Version must be in the format 'x', 'x.x', or 'x.x.x' (e.g., 7, 7.1, 7.1.11)." + ) + return value + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser( + description="Archive documentation for a specific version of a Redis product." + ) + parser.add_argument( + "product", + type=validate_product, + help="The name of the product (e.g., rs, kubernetes, redis-data-integration)", + ) + parser.add_argument( + "version", + type=validate_version, + help="The release version (e.g., 7, 7.1, 7.1.11)", + ) + args = parser.parse_args() + + r = VersionArchiver(args.product, args.version) + r.archive_version() + r.version_relrefs() + r.inject_url_frontmatter() diff --git a/version_frontmatter_helper.bash b/version_frontmatter_helper.bash deleted file mode 100755 index 66000814ea..0000000000 --- a/version_frontmatter_helper.bash +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# example usage ./version_frontmatter_helper.bash "content/operate/kubernetes/7.4.6" -# -dir="$1" -pages="$(find $dir -name "*.md")" - -# inject url frontmatter property in versioned folder -for page in $pages; do - if [[ "$page" =~ \/_index.md$ ]]; then - url=$(sed "s/_index.md$/'/; s/^content/'/"<<< $page) - else - url=$(sed "s/.md$/\/'/; s/^content/'/"<<< $page) - fi - # skip if url property is already present - if ! grep -q "$url" $page; then - awk -v url="$url" '$1 == "---" {delim++; if (delim==2){printf "%s\n", "url: "url}} {print}' $page > tmp.md - mv tmp.md $page - fi -done - -latest_dir="${dir%/*}" -pages="$(find "$latest_dir" -name "*.md" ! -path '*.*.*' ! -path '*release-notes*' | xargs -I {} grep -rl 'aliases:' {})" - -# remove aliases from latest version -for page in $pages; do - awk '$1 == "---" {delim++} /aliases/{f=1} {if(f==1 && delim!=2){}else {print}}' $page > tmp.md - mv tmp.md $page -done \ No newline at end of file