Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/check_workflow_template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Check Workflow Templates

on:
pull_request:
paths:
- .github/workflows/**
- github_rest_api/scripts/github/workflows/**

jobs:
check_workflow_template:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Check workflow templates use .yaml extension
run: |
yml_files=$(find .github/workflows/ -name '*.yml')
if [ -n "$yml_files" ]; then
echo "The following workflow templates must use the .yaml extension instead of .yml:"
echo "$yml_files"
exit 1
fi
- name: Check bundled workflow templates are in sync with .github/workflows
run: |
# github_rest_api/scripts/github/workflows/ is the set of templates copied
# into repos created by create_github_repo. It must mirror .github/workflows/
# exactly, except for workflows that only make sense for this repo itself.
repo_only=(check_workflow_template.yaml)
status=0
for f in .github/workflows/*.yaml; do
name=$(basename "$f")
skip=false
for r in "${repo_only[@]}"; do
[ "$name" = "$r" ] && skip=true
done
[ "$skip" = true ] && continue
if ! diff -u "$f" "github_rest_api/scripts/github/workflows/$name"; then
echo "::error::github_rest_api/scripts/github/workflows/$name is out of sync with $f"
status=1
fi
done
for f in github_rest_api/scripts/github/workflows/*; do
name=$(basename "$f")
if [ ! -f ".github/workflows/$name" ]; then
echo "::error::github_rest_api/scripts/github/workflows/$name has no corresponding .github/workflows/$name"
status=1
fi
done
exit "$status"
18 changes: 0 additions & 18 deletions .github/workflows/check_workflow_template_extensions.yaml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,10 @@ jobs:
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
permissions:
actions: read
issues: read
pull-requests: read
id-token: write
uses: legendu-net/.github/.github/workflows/claude.yml@main
secrets: inherit
9 changes: 9 additions & 0 deletions .github/workflows/create_pr_dev_to_main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: Create PR From dev To main
on:
push:
branches:
- dev
jobs:
create_pr_dev_to_main:
uses: legendu-net/.github/.github/workflows/create_pr_dev_to_main.yaml@main
secrets: inherit
11 changes: 11 additions & 0 deletions .github/workflows/create_pr_to_dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: Create PR to dev
on:
push:
branches-ignore:
- main
- dev
- gh-pages*
jobs:
create_pr_to_dev:
uses: legendu-net/.github/.github/workflows/create_pr_to_dev.yaml@main
secrets: inherit
5 changes: 1 addition & 4 deletions .github/workflows/pr-workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@ jobs:
uses: legendu-net/.github/.github/workflows/test.yaml@main
secrets: inherit

check_workflow_template_extensions:
uses: ./.github/workflows/check_workflow_template_extensions.yaml

claude-review:
needs: [lint_code, test_code, check_workflow_template_extensions]
needs: [lint_code, test_code]
permissions:
contents: read
issues: write
Expand Down
20 changes: 3 additions & 17 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,6 @@ on:
release:
types: [published]
jobs:
release-github_rest_api:
name: Release github_rest_api
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
contents: write
steps:
- uses: actions/checkout@v6
- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sudo env UV_INSTALL_DIR="/usr/local/bin" sh
- name: Build and Publish Package to PyPI
run: |
uv build
ls -lha dist/
uv publish -u __token__ -p ${{ secrets.PYPI_GITHUB_REST_API }}
release:
uses: legendu-net/.github/.github/workflows/release.yaml@main
secrets: inherit
40 changes: 14 additions & 26 deletions github_rest_api/scripts/github/create_github_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

logger = logging.getLogger(__name__)

# Workflows that configure this repository itself rather than the repositories
# created from these templates.
_REPO_ONLY_WORKFLOWS = frozenset({"check_workflow_template.yaml"})


def _create_remote_repo(
repo: str, private: bool, token: str, is_owner_user: bool
Expand Down Expand Up @@ -73,7 +77,6 @@ def _head_and_branches(path: Path) -> tuple[str | None, set[str]]:

def _init_local_repo(
repo: str,
language: str,
dir_: str,
token: str,
protocol: str,
Expand Down Expand Up @@ -147,13 +150,12 @@ def _init_local_repo(
logger.info("Successfully pushed branch '%s'.", branch)
else:
logger.info("Skipping push (pass --push to push branches to the remote).")
_add_workflow(path, language)
_add_workflow(path)


def create_github_repo(
repo: str,
private: bool,
language: str,
is_owner_user: bool,
dir_: str,
token: str,
Expand All @@ -170,7 +172,6 @@ def create_github_repo(
)
_init_local_repo(
repo=repo,
language=language,
dir_=dir_,
token=token,
branches=branches,
Expand All @@ -179,26 +180,22 @@ def create_github_repo(
)


def _add_workflow(path: Path, language: str, workflow_dir: Path | None = None) -> None:
def _add_workflow(path: Path, workflow_dir: Path | None = None) -> None:
if workflow_dir is None:
workflow_dir = Path(__file__).parent / "workflows"
templates = [
yaml
for yaml in workflow_dir.glob("*.yaml")
if yaml.name not in _REPO_ONLY_WORKFLOWS
]
if not templates:
raise FileNotFoundError(f"No workflow templates found in '{workflow_dir}'.")
dir_dest = path / ".github" / "workflows"
dir_dest.mkdir(parents=True, exist_ok=True)
for yaml in workflow_dir.glob("*.yaml"):
for yaml in templates:
if not (dir_dest / yaml.name).exists():
shutil.copy2(yaml, dir_dest)
logger.info("Copied workflow %s to %s", yaml.name, dir_dest)
if not language:
return
lang_dir = workflow_dir / language
if not lang_dir.exists():
return
for yaml in lang_dir.glob("*.yaml"):
if not (dir_dest / yaml.name).exists():
shutil.copy2(yaml, dir_dest)
logger.info(
"Copied %s specific workflow %s to %s", language, yaml.name, dir_dest
)


def parse_args(args=None, namespace=None):
Expand Down Expand Up @@ -237,14 +234,6 @@ def parse_args(args=None, namespace=None):
action="store_false",
help="Whether to create the repository as public.",
)
parser.add_argument(
"-l",
"--lang",
"--language",
dest="language",
default="",
help="The language of the GitHub repository.",
)
parser.add_argument(
"-d",
"--dir",
Expand Down Expand Up @@ -291,7 +280,6 @@ def main() -> int:
create_github_repo(
repo=args.repo,
private=args.private,
language=args.language,
is_owner_user=args.is_owner_user,
dir_=args.dir,
token=args.token,
Expand Down
5 changes: 5 additions & 0 deletions github_rest_api/scripts/github/workflows/claude.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,10 @@ jobs:
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
permissions:
actions: read
issues: read
pull-requests: read
id-token: write
uses: legendu-net/.github/.github/workflows/claude.yml@main
secrets: inherit
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,5 @@ on:
- dev
jobs:
create_pr_dev_to_main:
runs-on: ubuntu-latest
steps:
- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sudo env UV_INSTALL_DIR="/usr/local/bin" sh
- name: Create PR From dev To main
run: |
uvx --from github-rest-api@latest create_pull_request \
--head-branch dev \
--base-branch main \
--token ${{ secrets.GITHUBACTIONS }}

uses: legendu-net/.github/.github/workflows/create_pr_dev_to_main.yaml@main
secrets: inherit
14 changes: 2 additions & 12 deletions github_rest_api/scripts/github/workflows/create_pr_to_dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,5 @@ on:
- gh-pages*
jobs:
create_pr_to_dev:
runs-on: ubuntu-latest
steps:
- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sudo env UV_INSTALL_DIR="/usr/local/bin" sh
- name: Create PR to dev
run: |
uvx --from github-rest-api@latest create_pull_request \
--head-branch ${{ github.ref_name }} \
--base-branch dev \
--token ${{ secrets.GITHUBACTIONS }}

uses: legendu-net/.github/.github/workflows/create_pr_to_dev.yaml@main
secrets: inherit
8 changes: 8 additions & 0 deletions github_rest_api/scripts/github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: Release
on:
release:
types: [published]
jobs:
release:
uses: legendu-net/.github/.github/workflows/release.yaml@main
secrets: inherit
13 changes: 2 additions & 11 deletions github_rest_api/scripts/github/workflows/remove_branch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,5 @@ on:
timezone: 'America/Los_Angeles'
jobs:
remove_branch:
runs-on: ubuntu-latest
steps:
- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sudo env UV_INSTALL_DIR="/usr/local/bin" sh
- name: Remove Branches
run: |
uvx --from github-rest-api@latest remove_branch \
--repo ${{ github.repository }} \
--pattern '^(?!(main|dev)$)' \
--token ${{ secrets.ACTIONS_TOKEN }}
uses: legendu-net/.github/.github/workflows/remove_branch.yaml@main
secrets: inherit
53 changes: 51 additions & 2 deletions tests/test_create_github_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from dulwich import porcelain
from dulwich.refs import HEADREF

from github_rest_api.scripts.github.create_github_repo import _init_local_repo
from github_rest_api.scripts.github.create_github_repo import (
_add_workflow,
_init_local_repo,
)

KEPT_BRANCH = "kept"

Expand All @@ -22,7 +25,6 @@ def isolated_git_config(tmp_path, monkeypatch):
def _init_local(dir_: Path, branches=("main",)) -> None:
_init_local_repo(
repo="owner/name",
language="",
dir_=str(dir_),
token="",
protocol="git",
Expand Down Expand Up @@ -126,3 +128,50 @@ def test_init_local_repo_with_unborn_head_and_nothing_to_create(tmp_path):
_init_local(dir_, branches=(KEPT_BRANCH,))

assert _branches(dir_) == {KEPT_BRANCH}


def test_add_workflow_copies_templates_and_skips_repo_only_ones(tmp_path):
workflow_dir = tmp_path / "templates"
workflow_dir.mkdir()
(workflow_dir / "lint.yaml").write_text("name: lint\n")
(workflow_dir / "check_workflow_template.yaml").write_text("name: repo-only\n")
dest = tmp_path / "repo"
dest.mkdir()

_add_workflow(dest, workflow_dir=workflow_dir)

copied = {p.name for p in (dest / ".github" / "workflows").iterdir()}
assert copied == {"lint.yaml"}


def test_add_workflow_does_not_overwrite_existing_file(tmp_path):
workflow_dir = tmp_path / "templates"
workflow_dir.mkdir()
(workflow_dir / "lint.yaml").write_text("name: new\n")
dest = tmp_path / "repo"
dest_workflows = dest / ".github" / "workflows"
dest_workflows.mkdir(parents=True)
(dest_workflows / "lint.yaml").write_text("name: customized\n")

_add_workflow(dest, workflow_dir=workflow_dir)

assert (dest_workflows / "lint.yaml").read_text() == "name: customized\n"


def test_add_workflow_raises_when_template_dir_missing(tmp_path):
dest = tmp_path / "repo"
dest.mkdir()

with pytest.raises(FileNotFoundError):
_add_workflow(dest, workflow_dir=tmp_path / "does-not-exist")


def test_add_workflow_raises_when_template_dir_has_only_repo_only_workflows(tmp_path):
workflow_dir = tmp_path / "templates"
workflow_dir.mkdir()
(workflow_dir / "check_workflow_template.yaml").write_text("name: repo-only\n")
dest = tmp_path / "repo"
dest.mkdir()

with pytest.raises(FileNotFoundError):
_add_workflow(dest, workflow_dir=workflow_dir)