Skip to content

Commit ca7d0a2

Browse files
committed
create script tooling to create all redirects
for redirect to work, all the pages you want to redirect will need objects in same folder we server from assume docs_preview is the 'final' place we will serve from - all the redirect files will also have to be created in that folder to work do first 10 redirects for testing. remove the --start --end to do all. we wont want to run it all the time - so comment it out once all redirects are in place. we can figure a more robust check if this becomes an issue. llm: o3
1 parent 3deb3d2 commit ca7d0a2

File tree

4 files changed

+140
-41
lines changed

4 files changed

+140
-41
lines changed

.circleci/config.yml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ executors:
1515
- image: cimg/node:22.15.1
1616
working_directory: ~/project
1717

18+
python_executor:
19+
docker:
20+
- image: cimg/python:3.12.11
21+
working_directory: ~/project
22+
1823
ruby_executor:
1924
docker:
2025
- image: cimg/ruby:3.4
@@ -185,7 +190,7 @@ jobs:
185190
message: "Deploy preview job failed for branch ${CIRCLE_BRANCH}"
186191

187192
deploy-production:
188-
executor: node_executor
193+
executor: python_executor
189194
parameters:
190195
bucket_name:
191196
description: The name of the s3 bucket where static assets are stored.
@@ -208,13 +213,19 @@ jobs:
208213
echo "[INFO] Deploying production site..."
209214
aws s3 sync "$BUILD_DIRECTORY" "s3://$AWS_S3_BUCKET/"
210215
- run:
211-
name: Deploy Single Test Redirect to S3
216+
name: install pyyaml
217+
command: |
218+
set -e
219+
echo "[INFO] Installing pyyaml..."
220+
pip install pyyaml
221+
- run:
222+
name: Deploy Redirects to S3
212223
command: |
213224
AWS_S3_BUCKET=<< parameters.bucket_name >>
214225
215226
set -e
216-
echo "[INFO] Deploying single test redirect..."
217-
bash scripts/test-single-redirect.sh "$AWS_S3_BUCKET"
227+
echo "[INFO] Deploying redirects..."
228+
python scripts/create-redirects.py $AWS_S3_BUCKET --start 0 --end 10
218229
- notify_error:
219230
message: "Production deployment job failed for branch ${CIRCLE_BRANCH}"
220231

@@ -299,7 +310,7 @@ workflows:
299310
web-ui-npm,
300311
web-ui-datadog,
301312
]
302-
bucket_name: "circleci-docs-platform-assets/docs-preview"
313+
bucket_name: "circleci-docs-platform-assets"
303314
build_dir: "build"
304315
cleanup_preview:
305316
when: pipeline.parameters.cleanup_preview_branch != ""

scripts/create-redirect.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Validate parameters
5+
if [ "$#" -ne 3 ]; then
6+
echo "Usage: $0 <bucket_name> <old_path> <new_path>"
7+
echo "Example: $0 circleci-docs-platform-assets /about-circleci/ /docs-preview/guides/about-circleci/index.html"
8+
exit 1
9+
fi
10+
11+
BUCKET_NAME="$1"
12+
OLD_PATH="$2" # must include leading and trailing slash e.g. /about-circleci/
13+
NEW_PATH="$3" # full target path e.g. /docs-preview/guide/about-circleci/index.html
14+
15+
echo "[INFO] Deploying redirect to bucket: s3://$BUCKET_NAME"
16+
echo "[INFO] Redirect: $OLD_PATH -> $NEW_PATH"
17+
18+
# Convert old path to S3 key (no leading slash before key!)
19+
S3_KEY="docs-preview${OLD_PATH}index.html"
20+
21+
echo "[INFO] Creating S3 object: $S3_KEY"
22+
23+
# Create the redirect object in S3
24+
aws s3api put-object \
25+
--bucket "$BUCKET_NAME" \
26+
--key "$S3_KEY" \
27+
--website-redirect-location "$NEW_PATH" \
28+
--content-type "text/html" \
29+
--content-length "0"
30+
31+
echo "[INFO] ✅ Redirect created successfully!"

scripts/create-redirects.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/usr/bin/env python3
2+
"""Bulk S3 redirect creator.
3+
4+
Reads redirects from scripts/redirects_v2.yml (expects list of mapping with
5+
`old` and `new` keys) and calls `scripts/create-redirect.sh` for each redirect.
6+
7+
Usage:
8+
python scripts/create-redirect.py <bucket_name> [--start N] [--end M]
9+
10+
Options:
11+
--start N Start index (inclusive) in redirects list to process. Default 0.
12+
--end M End index (exclusive). Default len(list).
13+
14+
The slice options are useful for testing a subset.
15+
"""
16+
from __future__ import annotations
17+
18+
import argparse
19+
import subprocess
20+
import sys
21+
from pathlib import Path
22+
23+
try:
24+
import yaml # type: ignore
25+
except ImportError: # pragma: no cover
26+
sys.stderr.write("[ERROR] PyYAML is required. Install with: pip install pyyaml\n")
27+
sys.exit(1)
28+
29+
ROOT_DIR = Path(__file__).resolve().parent.parent # repo root (circleci-docs-static)
30+
REDIRECTS_FILE = ROOT_DIR / "scripts" / "redirects_v2.yml"
31+
SH_SCRIPT = ROOT_DIR / "scripts" / "create-redirect.sh"
32+
33+
34+
def load_redirects(path: Path) -> list[dict[str, str]]:
35+
"""Load redirects YAML file into list of dicts with 'old' and 'new'."""
36+
if not path.exists():
37+
raise FileNotFoundError(f"Redirects YAML not found: {path}")
38+
39+
with path.open("r", encoding="utf-8") as fh:
40+
data = yaml.safe_load(fh)
41+
42+
if not isinstance(data, list):
43+
raise ValueError("Redirects YAML should be a list of mappings.")
44+
45+
redirects: list[dict[str, str]] = []
46+
for item in data:
47+
if not isinstance(item, dict):
48+
continue
49+
old = item.get("old")
50+
new = item.get("new")
51+
if old and new:
52+
redirects.append({"old": str(old), "new": str(new)})
53+
return redirects
54+
55+
56+
def create_redirect(bucket: str, old_path: str, new_path: str) -> None:
57+
"""Call the shell script to create a single redirect."""
58+
cmd = [
59+
"bash",
60+
str(SH_SCRIPT),
61+
bucket,
62+
old_path,
63+
new_path,
64+
]
65+
subprocess.run(cmd, check=True)
66+
67+
68+
def main() -> None:
69+
parser = argparse.ArgumentParser(description="Bulk S3 redirect creator")
70+
parser.add_argument("bucket", help="Target S3 bucket name")
71+
parser.add_argument("--start", type=int, default=0, help="Start index (inclusive)")
72+
parser.add_argument("--end", type=int, default=None, help="End index (exclusive)")
73+
args = parser.parse_args()
74+
75+
redirects = load_redirects(REDIRECTS_FILE)
76+
end = args.end if args.end is not None else len(redirects)
77+
78+
slice_redirects = redirects[args.start : end]
79+
total = len(slice_redirects)
80+
print(f"[INFO] Processing {total} redirects (indexes {args.start}-{end-1})...")
81+
82+
for idx, entry in enumerate(slice_redirects, start=args.start):
83+
old = entry["old"]
84+
new = entry["new"]
85+
try:
86+
print(f"[INFO] ({idx}) Creating redirect {old} -> {new}")
87+
create_redirect(args.bucket, old, new)
88+
except subprocess.CalledProcessError as exc:
89+
print(f"[ERROR] Failed to create redirect for {old}: {exc}", file=sys.stderr)
90+
91+
92+
if __name__ == "__main__":
93+
main()

scripts/test-single-redirect.sh

Lines changed: 0 additions & 36 deletions
This file was deleted.

0 commit comments

Comments
 (0)