Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up PR previews #1697

Merged
merged 13 commits into from
Jul 13, 2024
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 @@ -48,8 +48,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
frankharkins marked this conversation as resolved.
Show resolved Hide resolved

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", "-"])
frankharkins marked this conversation as resolved.
Show resolved Hide resolved


def run_subprocess(
cmd: list[str],
*,
Expand All @@ -50,4 +77,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)