-
Notifications
You must be signed in to change notification settings - Fork 54
/
Copy pathskeleton
executable file
·119 lines (101 loc) · 3.53 KB
/
skeleton
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env python
"""Helper tool to start a new github project from a skeleton github repository.
Usage:
skeleton (-h | --help)
skeleton list [--org=<name>]
skeleton clone [options] <parent-repo-name> <new-repo-name>
Options:
-c --change-dir=<dir> Create clone in this directory.
-h --help Show this message.
-o --org=<name> Organization to search [default: cisagov].
"""
# Standard Python Libraries
import os
from pathlib import Path
import subprocess # nosec
import sys
# Third-Party Libraries
import docopt
from github import Github
import yaml
LINEAGE_CONFIG = Path(".github/lineage.yml")
LINEAGE_CONFIG_VERSION = "1"
VERSION = "0.0.1"
def run(cmd, comment):
"""Run a command and display its output and return code."""
print("―" * 80)
if comment:
print(f"💬 {comment}")
print(f"➤ {cmd}")
proc = subprocess.run(cmd, shell=True) # nosec
if proc.returncode == 0:
print("✅ success")
else:
print(f"❌ ERROR! return code: {proc.returncode}")
sys.exit(proc.returncode)
def print_available_skeletons(org):
"""Print a list of skeleton repos available for cloning."""
g = Github()
skel_repos = g.search_repositories(query=f"org:{org} topic:skeleton archived:false")
print(f"Available skeletons in {org}:\n")
for repo in skel_repos:
print(f"{repo.name}\n\t{repo.description}\n")
def clone_repo(parent_repo, new_repo, org, dir=None):
"""Clone a repository to a new name and prepare it for publication."""
if dir:
os.chdir(dir)
run(
f"git clone --origin {parent_repo} git@github.com:{org}/{parent_repo}.git {new_repo}",
"Clone an existing remote repository to the new name locally.",
)
os.chdir(new_repo)
run(
f"git remote set-url --push {parent_repo} no_push",
"Disable pushing to the upstream (parent) repository.",
)
run(
f"git remote add origin git@github.com:{org}/{new_repo}.git",
"Add a new remote origin for the this repository.",
)
run("git tag -d $(git tag -l)", f"Delete all local git tags from {parent_repo}")
run(
rf"find . \( ! -regex '.*/\.git/.*' \) -type f -exec "
rf"perl -pi -e s/{parent_repo}/{new_repo}/g {{}} \;",
"Search and replace repository name in source files.",
)
lineage = {
"version": LINEAGE_CONFIG_VERSION,
"lineage": {
"skeleton": {"remote-url": f"https://github.com/{org}/{parent_repo}.git"}
},
}
with LINEAGE_CONFIG.open("w") as f:
yaml.dump(lineage, stream=f, explicit_start=True)
run("git add --verbose .", "Stage modified files.")
run(
'git commit --message "Rename repository references after clone."',
"Commit staged files to the new repository.",
)
print("―" * 80)
print(
f"""
The repository "{parent_repo}" has been cloned and renamed to "{new_repo}".
Use the following commands to push the new repository to github:
cd {os.path.join(dir, new_repo) if dir else new_repo}
git push --set-upstream origin develop
"""
)
def main():
"""Parse arguments and perform requested actions."""
args = docopt.docopt(__doc__, version=VERSION)
org = args["--org"]
if args["list"]:
print_available_skeletons(org)
elif args["clone"]:
parent_repo = args["<parent-repo-name>"]
new_repo = args["<new-repo-name>"]
dir = args["--change-dir"]
clone_repo(parent_repo, new_repo, org, dir)
return 0
if __name__ == "__main__":
sys.exit(main())