Skip to content

Commit

Permalink
Clean up PR previews (#1697)
Browse files Browse the repository at this point in the history
Adds a script and action to delete PR previews for closed PRs. See
3a29f15 for an example.

---------

Co-authored-by: Eric Arellano <[email protected]>
  • Loading branch information
frankharkins and Eric-Arellano authored Jul 13, 2024
1 parent 149c265 commit 1ae2ef3
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 26 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/pr-cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This code is a Qiskit project.
#
# (C) Copyright IBM 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

name: PR preview cleanup
on:
workflow_dispatch:
push:
branches:
- "main"

jobs:
preview-cleanup:
name: PR preview cleanup
runs-on: ubuntu-latest
if: github.repository_owner == 'Qiskit'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Clean up PR previews
run: scripts/pr_previews/cleanup.py
env:
GH_TOKEN: ${{ github.token }}
2 changes: 0 additions & 2 deletions .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ jobs:
- name: Deploy to GitHub Pages
run: scripts/pr_previews/deploy.py ${{ env.PR_PREVIEW_PATH }}
- name: Switch back to original branch
uses: actions/checkout@v4

- name: Determine deployment result
run: scripts/pr_previews/poll_deployment.py ${{ env.PR_PREVIEW_URL }}
Expand Down
64 changes: 64 additions & 0 deletions scripts/pr_previews/cleanup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3

# This code is a Qiskit project.
#
# (C) Copyright IBM 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

import json
import logging
import shutil
from pathlib import Path

logger = logging.getLogger(__name__)

from utils import (
configure_logging,
run_subprocess,
setup_git_account,
switch_branch,
changed_files,
commit_all_and_push,
)


def main() -> None:
setup_git_account()

with switch_branch("gh-pages"):
delete_closed_pr_folders()

if not changed_files():
logger.info("No changed files detected, so no push made to gh-pages")
return

commit_all_and_push("Clean up PR previews")
logger.info("Pushed updates to gh-pages branch")


def get_active_pr_folders() -> set[str]:
raw = run_subprocess(
["gh", "pr", "list", "--state", "open", "--json", "number", "--limit", "1000"]
).stdout
# `raw` is JSON string of form: { number: int }[]
return {f"pr-{obj['number']}" for obj in json.loads(raw)}


def delete_closed_pr_folders() -> None:
active_pr_folders = get_active_pr_folders()
for folder in Path(".").glob("pr-*"):
if folder.name not in active_pr_folders:
logger.info(f"Deleting {folder}")
shutil.rmtree(folder)


if __name__ == "__main__":
configure_logging()
main()
41 changes: 18 additions & 23 deletions scripts/pr_previews/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@

logger = logging.getLogger(__name__)

from utils import configure_logging, run_subprocess
from utils import (
configure_logging,
run_subprocess,
setup_git_account,
switch_branch,
changed_files,
commit_all_and_push,
)


def create_parser() -> ArgumentParser:
Expand All @@ -36,33 +43,21 @@ def main() -> None:
raise AssertionError(
f"Expected {folder} to have been created with the new content"
)

run_subprocess(["git", "config", "user.name", "github-actions[bot]"])
run_subprocess(
["git", "config", "user.email", "github-actions[bot]@users.noreply.github.com"]
)

run_subprocess(["git", "fetch", "origin", "gh-pages"])
setup_git_account()

# Handle if the content folder already exists on gh-pages branch.
run_subprocess(["git", "stash", "--include-untracked"])
run_subprocess(["git", "switch", "gh-pages"])
if folder.exists():
shutil.rmtree(folder)
run_subprocess(["git", "stash", "pop"])
with switch_branch("gh-pages"):
if folder.exists():
shutil.rmtree(folder)
run_subprocess(["git", "stash", "pop"])

changed_files = run_subprocess(["git", "status", "--porcelain"]).stdout.strip()
if changed_files:
run_subprocess(["git", "add", "."])
run_subprocess(["git", "commit", "-m", f"Deploy PR preview for {folder}"])
run_subprocess(["git", "push"])
logger.info("Pushed updates to gh-pages branch")
else:
logger.info("No changed files detected, so no push made to gh-pages")
if not changed_files():
logger.info("No changed files detected, so no push made to gh-pages")
return

logger.warning(
"The branch is set to gh-pages. You probably want to `git switch` back to your original branch"
)
commit_all_and_push(f"Deploy PR preview for {folder}")
logger.info("Pushed updates to gh-pages branch")


if __name__ == "__main__":
Expand Down
29 changes: 28 additions & 1 deletion scripts/pr_previews/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

import logging
import subprocess
from contextlib import contextmanager
from pathlib import Path
from typing import Iterator


logger = logging.getLogger(__name__)
Expand All @@ -28,6 +30,31 @@ def configure_logging() -> None:
)


def setup_git_account() -> None:
run_subprocess(["git", "config", "user.name", "github-actions[bot]"])
run_subprocess(
["git", "config", "user.email", "github-actions[bot]@users.noreply.github.com"]
)


def changed_files() -> str:
return run_subprocess(["git", "status", "--porcelain"]).stdout.strip()


def commit_all_and_push(commit_message: str) -> None:
run_subprocess(["git", "add", "."])
run_subprocess(["git", "commit", "-m", commit_message])
run_subprocess(["git", "push"])


@contextmanager
def switch_branch(branchname: str) -> Iterator[None]:
run_subprocess(["git", "fetch", "origin", branchname])
run_subprocess(["git", "switch", branchname])
yield
run_subprocess(["git", "checkout", "-"])


def run_subprocess(
cmd: list[str],
*,
Expand All @@ -52,4 +79,4 @@ def run_subprocess(
if not stream_output:
logger.error(f"stdout: {result.stdout}")
logger.error(f"stderr: {result.stderr}")
raise SystemExit()
raise SystemExit(1)

0 comments on commit 1ae2ef3

Please sign in to comment.