Skip to content

Commit

Permalink
Merge pull request #113 from DSACMS/dev
Browse files Browse the repository at this point in the history
Merge Dev Into Main
  • Loading branch information
IsaacMilarky authored Jul 3, 2024
2 parents 5804a90 + 7c089f6 commit 74856e3
Show file tree
Hide file tree
Showing 23 changed files with 511 additions and 41 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ If you know what tier you need, you can run the cookiecutter for an individual t
cookiecutter https://github.com/DSACMS/repo-scaffolder --directory=tierX
```

## Add Repometrics to your Project
To integrate repometrics into your new project, navigate to your project's directory and run the following cookiecutter command:
```
cookiecutter . --directory=repometrics
```

## Existing Projects
You can update existing projects with the repo scaffolder. Using the `-s` flag on cookiecutter will not overwrite existing files. Follow these steps:
1. Create a new branch in your repo
Expand Down
3 changes: 2 additions & 1 deletion tier1/cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"__prompts__": {
"create_repo": "Would you like to create a repo on github.com?",
"receive_updates": "Would you like to receive updates from the DSACMS team via pull requests?"
}
},
"_copy_without_render": ["repometrics"]
}
18 changes: 18 additions & 0 deletions tier1/{{cookiecutter.project_slug}}/repometrics/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"project_type" : ["Package", "Website", "Standards", "Libraries", "Data", "Apps", "Tools", "APIs"],
"user_input": ["Yes", "No"],
"project_fisma_level": ["Low", "Moderate", "High"],
"group": "CMS/OA/DSAC",
"subset_in_healthcare": "Policy, Operational",
"user_type": "Providers, Patients, Government",
"repository_host": ["Github.com", "GitHub ENT", "GitHub Cloud", "GitLab.com", "GitLab ENT", "GitLab ENT CCSQ"],
"maturity_model_tier": ["1", "2", "3", "4"],
"__prompts__": {
"group": "Which group is the project part of?",
"subset_in_healthcare": "Which subset of healthcare does the project belong to?",
"user_type": "Who are the intended users?",
"user_input": "Does the project accept user input? (e.g. allows user to query a database, allows login by users, etc.)",
"repository_host": "Where is the repository hosted?",
"maturity_model_tier": "What maturity model tier is your project classified as?"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash

# Change to the parent directory
cd ..

# Define the repometrics directory to remove
dir_name="repometrics"

# Check if repometrics directory exists and remove it
if [ -d "$dir_name" ]; then
rm -rf "$dir_name"
fi

project_type="{{cookiecutter.project_type}}"
sub_project_dir="${project_type}"
repometrics_file="code.json"
parent_dir="./"

if [ -f "${sub_project_dir}/${repometrics_file}" ]; then
# Move code.json file to parent directory
mv "${sub_project_dir}/${repometrics_file}" "${parent_dir}"

# Check if the move was successful
if [ $? -eq 0 ]; then
# Remove the source directory
rm -rf "${sub_project_dir}"

# Check if the deletion was successful
if [ $? -eq 0 ]; then
echo "Successfully generated code.json file."
fi
fi
fi
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"project_type": "{{ cookiecutter.project_type }}",
"user_input": "{{ cookiecutter.user_input }}",
"project_fisma_level": "{{ cookiecutter.project_fisma_level }}",
"group": "{{ cookiecutter.group }}",
"subset_in_healthcare": "{{ cookiecutter.subset_in_healthcare }}",
"user_type": "{{ cookiecutter.user_type }}",
"repository_host": "{{ cookiecutter.repository_host }}",
"maturity_model_tier": "{{ cookiecutter.maturity_model_tier }}"
}
29 changes: 16 additions & 13 deletions tier2/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
{
"project_name": "My Project",
"project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_') }}",
"project_org": "DSACMS",
"project_repo_name": "{{ cookiecutter.project_name.lower().replace(' ', '-') }}",
"project_description": "This is the project description, could match github.com repo description.",
"code_owners": "Git usernames of code owners; separated by commas.",
"project_visibility": ["public", "internal", "private"],
"create_repo": [true, false],
"receive_updates": [true, false],
"__prompts__": {
"create_repo": "Would you like to create a repo on github.com?",
"receive_updates": "Would you like to receive updates from the DSACMS team via pull requests?"
}
"project_name": "My Project",
"project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_') }}",
"project_org": "DSACMS",
"project_repo_name": "{{ cookiecutter.project_name.lower().replace(' ', '-') }}",
"project_description": "This is the project description, could match github.com repo description.",
"code_owners": "Git usernames of code owners; separated by commas.",
"project_visibility": ["public", "internal", "private"],
"create_repo": [true, false],
"receive_updates": [true, false],
"add_maintainer": [true, false],
"__prompts__": {
"create_repo": "Would you like to create a repo on github.com?",
"receive_updates": "Would you like to receive updates from the DSACMS team via pull requests?",
"add_maintainer": "Would you like to add a maintainer?"
},
"_copy_without_render": ["repometrics"]
}
46 changes: 45 additions & 1 deletion tier2/hooks/post_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
DESCRIPTION = '{{cookiecutter.project_description}}'
CREATE_REPO = '{{cookiecutter.create_repo}}'
RECEIVE_UPDATES = '{{cookiecutter.receive_updates}}'
ADD_MAINTAINER = '{{cookiecutter.add_maintainer}}'

def createGithubRepo():
subprocess.call(["git", "init", "-b", "main"])
Expand All @@ -26,12 +27,55 @@ def addTopic():
gh_cli_command = [
"gh", "repo", "edit",
f"{ORG_NAME}/{REPO_NAME}",
"--add-topic=dsacms-tier0",
"--add-topic=dsacms-tier2",
]
subprocess.call(gh_cli_command)

def addMaintainer():
maintainers = []
add_maintainer = True
while add_maintainer:
maintainer = {}
maintainer["role"] = input("Maintainer's Role (Reviewer, Approver, Maintainer): ").strip()
maintainer["name"] = input("Maintainer's Name: ").strip()
github_username = input("Maintainer's GitHub Username: ").strip()
maintainer["github_username"] = github_username if github_username.startswith('@') else f'@{github_username}'
maintainer["affiliation"] = input("Maintainer's Affiliation (DSAC, CCSQ, CMMI, etc...): ").strip()
maintainers.append(maintainer)

while True:
add_maintainer_input = input("Would you like to add another maintainer? [Y/n]: ").strip().lower()
if add_maintainer_input in ("y", "yes", ""):
add_maintainer = True
break
elif add_maintainer_input in ("n", "no"):
add_maintainer = False
break
else:
print("\nInvalid response, please respond with: 'y', 'yes', 'n', 'no', or just press Enter for yes")

maintainers_table = ""
for maintainer in maintainers:
maintainers_table += f"| {maintainer["role"]} | {maintainer["name"]}| {maintainer["github_username"]} | {maintainer["affiliation"]} |\n"

proj_name = "{{ cookiecutter.project_name }}"
maintainers_file_path = f"../{proj_name}/MAINTAINERS.md"

with open(maintainers_file_path, "r") as f:
lines = f.readlines()

with open(maintainers_file_path, "w") as f:
for line in lines:
if "| {role} | {names} | {github usernames} | {affiliations}|" in line:
f.write(maintainers_table) # Replace placeholder line with new table of maintainers
else:
f.write(line)

if CREATE_REPO == "True":
createGithubRepo()

if RECEIVE_UPDATES == "True":
addTopic()

if ADD_MAINTAINER == "True":
addMaintainer()
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ jobs:
- name: Contribute List
uses: akhilmhdh/[email protected]
env:
{% raw %}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
{% endraw %}
with:
# https://github.com/marketplace/actions/contribute-list#optional-parameters
readme_path: MAINTAINERS.md
Expand All @@ -38,18 +40,22 @@ jobs:
# https://docs.github.com/en/graphql/guides/forming-calls-with-graphql#communicating-with-graphql
# CANNOT have newlines!
run: |
{% raw %}
OWNER=$(echo $GITHUB_REPOSITORY | cut -d'/' -f1)
REPO=$(echo $GITHUB_REPOSITORY | cut -d'/' -f2)
QUERY='query { repository(owner: \"'"$OWNER"'\", name: \"'"$REPO"'\") { collaborators { totalCount } } }'
CONTRIBUTORS=$(curl -s -X POST -H "Authorization: bearer ${{ secrets.GITHUB_TOKEN }}" -H "Content-Type: application/json" -d "{\"query\": \"$QUERY\"}" https://api.github.com/graphql | jq -r '.data.repository.collaborators.totalCount')
echo "Total contributors: $CONTRIBUTORS"
echo "contributors=$CONTRIBUTORS" >> $GITHUB_OUTPUT
{% endraw %}
- name: Replace slug in MAINTAINERS.md with number of contributors
# https://stackoverflow.com/questions/10613643/replace-a-unknown-string-between-two-known-strings-with-sed
run: |
{% raw %}
CONTRIBUTORS=${{ steps.get_contributors.outputs.contributors }}
sed -i 's/<!--CONTRIBUTOR COUNT START-->.*<!--CONTRIBUTOR COUNT END-->/<!--CONTRIBUTOR COUNT START--> '"$CONTRIBUTORS"' <!--CONTRIBUTOR COUNT END-->/g' MAINTAINERS.md
{% endraw %}
- name: Commit and push changes
# https://github.com/orgs/community/discussions/26560#discussioncomment-3531273
Expand Down
18 changes: 18 additions & 0 deletions tier2/{{cookiecutter.project_slug}}/repometrics/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"project_type" : ["Package", "Website", "Standards", "Libraries", "Data", "Apps", "Tools", "APIs"],
"user_input": ["Yes", "No"],
"project_fisma_level": ["Low", "Moderate", "High"],
"group": "CMS/OA/DSAC",
"subset_in_healthcare": "Policy, Operational",
"user_type": "Providers, Patients, Government",
"repository_host": ["Github.com", "GitHub ENT", "GitHub Cloud", "GitLab.com", "GitLab ENT", "GitLab ENT CCSQ"],
"maturity_model_tier": ["1", "2", "3", "4"],
"__prompts__": {
"group": "Which group is the project part of?",
"subset_in_healthcare": "Which subset of healthcare does the project belong to?",
"user_type": "Who are the intended users?",
"user_input": "Does the project accept user input? (e.g. allows user to query a database, allows login by users, etc.)",
"repository_host": "Where is the repository hosted?",
"maturity_model_tier": "What maturity model tier is your project classified as?"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash

# Change to the parent directory
cd ..

# Define the repometrics directory to remove
dir_name="repometrics"

# Check if repometrics directory exists and remove it
if [ -d "$dir_name" ]; then
rm -rf "$dir_name"
fi

project_type="{{cookiecutter.project_type}}"
sub_project_dir="${project_type}"
repometrics_file="code.json"
parent_dir="./"

if [ -f "${sub_project_dir}/${repometrics_file}" ]; then
# Move code.json file to parent directory
mv "${sub_project_dir}/${repometrics_file}" "${parent_dir}"

# Check if the move was successful
if [ $? -eq 0 ]; then
# Remove the source directory
rm -rf "${sub_project_dir}"

# Check if the deletion was successful
if [ $? -eq 0 ]; then
echo "Successfully generated code.json file."
fi
fi
fi
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"project_type": "{{ cookiecutter.project_type }}",
"user_input": "{{ cookiecutter.user_input }}",
"project_fisma_level": "{{ cookiecutter.project_fisma_level }}",
"group": "{{ cookiecutter.group }}",
"subset_in_healthcare": "{{ cookiecutter.subset_in_healthcare }}",
"user_type": "{{ cookiecutter.user_type }}",
"repository_host": "{{ cookiecutter.repository_host }}",
"maturity_model_tier": "{{ cookiecutter.maturity_model_tier }}"
}
29 changes: 16 additions & 13 deletions tier3/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
{
"project_name": "My Project",
"project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_') }}",
"project_org": "DSACMS",
"project_repo_name": "{{ cookiecutter.project_name.lower().replace(' ', '-') }}",
"project_description": "This is the project description, could match github.com repo description.",
"code_owners": "Git usernames of code owners; separated by commas.",
"project_visibility": ["public", "internal", "private"],
"create_repo": [true, false],
"receive_updates": [true, false],
"__prompts__": {
"create_repo": "Would you like to create a repo on github.com?",
"receive_updates": "Would you like to receive updates from the DSACMS team via pull requests?"
}
"project_name": "My Project",
"project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_') }}",
"project_org": "DSACMS",
"project_repo_name": "{{ cookiecutter.project_name.lower().replace(' ', '-') }}",
"project_description": "This is the project description, could match github.com repo description.",
"code_owners": "Git usernames of code owners; separated by commas.",
"project_visibility": ["public", "internal", "private"],
"create_repo": [true, false],
"receive_updates": [true, false],
"add_maintainer": [true, false],
"__prompts__": {
"create_repo": "Would you like to create a repo on github.com?",
"receive_updates": "Would you like to receive updates from the DSACMS team via pull requests?",
"add_maintainer": "Would you like to add maintainers, approvers, and/or reviewers?"
},
"_copy_without_render": ["repometrics"]
}
74 changes: 74 additions & 0 deletions tier3/hooks/post_gen_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import subprocess

REPO_NAME = '{{ cookiecutter.project_repo_name }}'
ORG_NAME = '{{ cookiecutter.project_org }}'
VISIBILITY = '{{cookiecutter.project_visibility}}'
DESCRIPTION = '{{cookiecutter.project_description}}'
CREATE_REPO = '{{cookiecutter.create_repo}}'
RECEIVE_UPDATES = '{{cookiecutter.receive_updates}}'
ADD_MAINTAINER = '{{cookiecutter.add_maintainer}}'

def createGithubRepo():
subprocess.call(["git", "init", "-b", "main"])
subprocess.call(["git", "add", "."])
subprocess.call(["git", "commit", "-m", "first commit"])
gh_cli_command = [
"gh", "repo", "create",
f"{ORG_NAME}/{REPO_NAME}",
"--source=.",
f"--{VISIBILITY}",
"--push",
f"--description={DESCRIPTION}",
]
subprocess.call(gh_cli_command)
subprocess.call(["git", "push", "--set-upstream", "origin", "main"])

def addTopic():
gh_cli_command = [
"gh", "repo", "edit",
f"{ORG_NAME}/{REPO_NAME}",
"--add-topic=dsacms-tier3",
]
subprocess.call(gh_cli_command)

# Helper function for addMaintainer() to get user input of usernames for Maintainer, Approver, and Reviewer
def getUsernames(role):
while True:
usernames = input(f"Enter the GitHub usernames of {role} (comma-separated): ").strip()
if usernames:
return [username.strip() for username in usernames.split(',')]
print("Please enter at least one username.")

# Helper function for addMaintainer() to format list of usernames
def formatUsernames(usernames):
return "".join(f"- @{username.lstrip('@')}\n" for username in usernames)

def addMaintainer():
maintainers = getUsernames("MAINTAINERS")
approvers = getUsernames("APPROVERS")
reviewers = getUsernames("REVIEWERS")

maintainers_file_path = "MAINTAINERS.md"

with open(maintainers_file_path, "r") as f:
lines = f.readlines()

for i, line in enumerate(lines):
if line.strip() == "## Maintainers:" and i + 2 < len(lines) and lines[i + 2].strip() == "-":
lines[i + 2] = formatUsernames(maintainers)
elif line.strip() == "## Approvers:" and i + 1 < len(lines) and lines[i + 1].strip() == "-":
lines[i + 1] = formatUsernames(approvers)
elif line.strip() == "## Reviewers:" and i + 1 < len(lines) and lines[i + 1].strip() == "-":
lines[i + 1] = formatUsernames(reviewers)

with open(maintainers_file_path, "w") as f:
f.writelines(lines)

if CREATE_REPO == "True":
createGithubRepo()

if RECEIVE_UPDATES == "True":
addTopic()

if ADD_MAINTAINER == "True":
addMaintainer()
Loading

0 comments on commit 74856e3

Please sign in to comment.