Skip to content

Commit 9a7aac8

Browse files
Merge pull request #345 from DSACMS/DSACMS/nat/codejson-cookiecutter-updates
Cookiecutter: Update code.json generation to reflect current schema
2 parents 1dd0c21 + da0e59f commit 9a7aac8

File tree

15 files changed

+287
-167
lines changed

15 files changed

+287
-167
lines changed

tier0/{{cookiecutter.project_slug}}/.github/codejson/hooks/post_gen_project.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,30 @@
22
import shutil
33
import json
44
import os
5-
import shutil
5+
from datetime import datetime, timezone
66

77
def get_date_fields():
88
# Run git commands and capture as string
99
output = subprocess.run(['git', 'log', '--date=iso', '--pretty=%cI', '--max-parents=0', '-n', '1'], capture_output=True, text=True)
10-
10+
1111
# Store string and strip of leading / trailing whitespace
1212
date = output.stdout.strip()
13+
14+
# Parse the git timestamp and convert to UTC
15+
git_date = datetime.fromisoformat(date)
16+
utc_date = git_date.astimezone(timezone.utc)
17+
created_date = utc_date.strftime('%Y-%m-%dT%H:%M:%SZ')
18+
19+
# Generate current UTC timestamps using the new recommended method
20+
current_utc = datetime.now(timezone.utc)
21+
current_timestamp = current_utc.strftime('%Y-%m-%dT%H:%M:%SZ')
1322

1423
# Create a dictionary for date information to be pushed to JSON
15-
date_information = {"created": f"{date}",
16-
"lastModified": "{% now 'utc', '%Y-%m-%dT%H:%M:%S%z' %}",
17-
"metadataLastUpdated": "{% now 'utc', '%Y-%m-%dT%H:%M:%S%z' %}"}
24+
date_information = {
25+
"created": created_date,
26+
"lastModified": current_timestamp,
27+
"metadataLastUpdated": current_timestamp
28+
}
1829

1930
return date_information
2031

@@ -77,20 +88,26 @@ def update_code_json(json_file_path):
7788
data['laborHours'] = None
7889

7990
# Check if usageType is an exemption
80-
if data['permissions']['usageType'].startswith('exempt'):
91+
contains_exempt = any("exempt" in item for item in data['permissions']['usageType'])
92+
if contains_exempt:
8193
exemption_text = prompt_exemption_text(data['permissions']['usageType'])
8294
data['permissions']['exemptionText'] = exemption_text
8395
else:
8496
del data['permissions']['exemptionText']
8597

8698
# Format multi-select options
87-
multi_select_fields = ["platforms", "categories", "languages", "tags", "feedbackMechanisms", "projects", "systems", "upstream", "subsetInHealthcare", "userType"]
99+
multi_select_fields = ["platforms", "categories", "languages", "contractNumber", "tags", "projects", "systems", "subsetInHealthcare", "userType"]
88100
for field in multi_select_fields:
89101
data[field] = format_multi_select_fields(data[field][0])
90102

91103
# Format integer fields
92104
if data['reuseFrequency']['forks'].isdigit():
93105
data['reuseFrequency']['forks'] = int(data['reuseFrequency']['forks'])
106+
if data['reuseFrequency']['clones'].isdigit():
107+
data['reuseFrequency']['clones'] = int(data['reuseFrequency']['clones'])
108+
109+
data['localisation'] = eval(data['localisation'])
110+
data['userInput'] = eval(data['userInput'])
94111

95112
# Update the JSON
96113
with open(json_file_path, 'w') as file:

tier0/{{cookiecutter.project_slug}}/.github/codejson/{{cookiecutter.project_name}}/code.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
"permissions": {
77
"licenses": [
88
{
9-
"URL": "LICENSE",
10-
"name": "{{ cookiecutter.license }}"
9+
"name": "{{ cookiecutter.license }}",
10+
"URL": "{{cookiecutter.license_url}}"
11+
1112
}
1213
],
13-
"usageType": "{{ cookiecutter.usage_type }}",
14+
"usageType": [ "{{ cookiecutter.usage_type }}" ],
1415
"exemptionText": ""
1516
},
1617
"organization": "Centers for Medicare & Medicaid Services",
@@ -20,29 +21,31 @@
2021
"vcs": "{{ cookiecutter.vcs }}",
2122
"laborHours": [""],
2223
"reuseFrequency": {
23-
"forks": "{{ cookiecutter.forks }}"
24+
"forks": "{{ cookiecutter.forks }}",
25+
"clones": "{{ cookiecutter.clones }}"
2426
},
2527
"platforms": [ "{{ cookiecutter.platforms }}" ],
2628
"categories": [ "{{ cookiecutter.categories }}" ],
2729
"softwareType": "{{ cookiecutter.software_type }}",
2830
"languages": [ "{{ cookiecutter.languages }}" ],
2931
"maintenance": "{{ cookiecutter.maintenance }}",
30-
"contractNumber": "{{ cookiecutter.contract_number }}",
32+
"contractNumber": [ "{{ cookiecutter.contract_number }}" ],
33+
"SBOM": "{{ cookiecutter.sbom }}",
3134
"date": [""],
3235
"tags": [ "{{ cookiecutter.tags }}" ],
3336
"contact": {
3437
"email": "{{ cookiecutter.contact_email }}",
3538
"name": "{{ cookiecutter.contact_name }}"
3639
},
37-
"feedbackMechanisms": ["{{ cookiecutter.feedback_mechanisms }}"],
40+
"feedbackMechanism": "https://github.com/{{ cookiecutter.project_org }}/{{ cookiecutter.project_repo_name }}/issues",
41+
"AIUseCaseID": "{{ cookiecutter.ai_use_case_id }}",
3842
"localisation": "{{ cookiecutter.localisation }}",
3943
"repositoryType": "{{ cookiecutter.repository_type }}",
4044
"userInput": "{{ cookiecutter.user_input }}",
4145
"fismaLevel": "{{ cookiecutter.fisma_level }}",
4246
"group": "{{ cookiecutter.group }}",
4347
"projects": ["{{ cookiecutter.projects }}"],
4448
"systems": ["{{ cookiecutter.systems }}"],
45-
"upstream": ["{{ cookiecutter.upstream }}"],
4649
"subsetInHealthcare": ["{{ cookiecutter.subset_in_healthcare }}"],
4750
"userType": ["{{ cookiecutter.user_type }}"],
4851
"maturityModelTier": 0

tier0/{{cookiecutter.project_slug}}/.github/cookiecutter.json

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,35 @@
44
"project_org": "{{ cookiecutter.project_org }}",
55
"description": "A short description of the project.",
66
"long_description": "A longer description of the project.",
7-
"status": ["ideation", "development", "alpha", "beta", "release candidate", "production", "archival"],
8-
"license": ["CC0-1.0", "Apache-2.0", "MIT", "MPL-2.0", "GPL-2.0-only", "GPL-3.0-only", "GPL-3.0-or-later", "LGPL-2.1-only", "LGPL-3.0-only", "BSD-2-Clause", "BSD-3-Clause", "EPL-2.0", "Other"],
9-
"usage_type" : ["openSource", "governmentWideReuse", "exemptByLaw", "exemptByNationalSecurity", "exemptByAgencySystem", "exemptByAgencyMission", "exemptByCIO", "exemptByPolicyDate"],
10-
"repository_host": ["github.com/CMSgov", "github.com/CMS-Enterprise", "github.com/DSACMS", "github.cms.gov", "CCSQ GitHub"],
7+
"status": ["Ideation", "Development", "Alpha", "Beta", "Release Candidate", "Production", "Archival"],
8+
"license": ["CC0-1.0", "Apache-2.0", "MIT", "MPL-2.0", "GPL-2.0-only", "GPL-3.0-only", "GPL-3.0-or-later", "LGPL-2.1-only", "LGPL-3.0-only", "BSD-2-Clause", "BSD-3-Clause", "EPL-2.0", "Other", "None"],
9+
"license_url": "https://github.com/{{ cookiecutter.project_org }}/{{ cookiecutter.project_repo_name }}/blob/main/LICENSE",
10+
"usage_type" : ["openSource", "governmentWideReuse", "exemptByNationalSecurity", "exemptByNationalIntelligence", "exemptByFOIA", "exemptByEAR", "exemptByITAR", "exemptByTSA", "exemptByClassifiedInformation", "exemptByPrivacyRisk", "exemptByIPRestriction", "exemptByAgencySystem", "exemptByAgencyMission", "exemptByCIO", "exemptByPolicyDate"],
11+
"repository_host": ["github.com/CMSgov", "github.com/CMS-Enterprise", "github.com/Enterprise-CMCS", "github.com/DSACMS", "github.cms.gov", "CCSQ GitHub"],
1112
"repository_visibility": ["public", "private"],
1213
"vcs": ["git", "hg", "svn", "rcs", "bzr"],
1314
"forks": 0,
15+
"clones": 0,
1416
"platforms": "web, windows, mac, linux, ios, android, other",
1517
"categories": "healthcare",
1618
"software_type":["standalone/mobile", "standalone/iot", "standalone/desktop", "standalone/web", "standalone/backend", "standalone/other", "addon", "library", "configurationFiles"],
1719
"languages": "",
1820
"maintenance": ["internal", "contract", "community", "none"],
19-
"contract_number": 0,
21+
"contract_number": "",
22+
"sbom": "https://github.com/{{ cookiecutter.project_org }}/{{ cookiecutter.project_repo_name }}/network/dependencies",
2023
"tags": "dsacms-tier0",
2124
"contact_email": "[email protected]",
2225
"contact_name": "CMS Open Source Program Office",
23-
"feedback_mechanisms": "https://github.com/{{ cookiecutter.project_org }}/{{ cookiecutter.project_repo_name }}/issues",
24-
"localisation": ["true", "false"],
25-
"repository_type" : ["Package", "Website", "Standards", "Libraries", "Data", "Apps", "Tools", "APIs", "Docs"],
26-
"user_input": ["Yes", "No"],
27-
"fisma_level": ["Low", "Moderate", "High"],
26+
"ai_use_case_id": "0",
27+
"localisation": [true, false],
28+
"repository_type" : ["package", "website", "standards", "libraries", "data", "apps", "tools", "APIs"],
29+
"user_input": [true, false],
30+
"fisma_level": ["low", "moderate", "high"],
2831
"group": "CMS/OA/DSAC",
2932
"projects": "",
3033
"systems": "",
31-
"upstream": "",
32-
"subset_in_healthcare": "Policy, Operational, Medicare, Medicaid",
33-
"user_type": "Providers, Patients, Government",
34+
"subset_in_healthcare": "policy, operational, medicare, medicaid",
35+
"user_type": "providers, patients, government",
3436
"__prompts__": {
3537
"project_name": "What is the name of the project or software?",
3638
"project_repo_name": "What is the name of the repository?",
@@ -39,29 +41,31 @@
3941
"long_description": "Provide longer description of the software, between 150 and 10000 chars. It is meant to provide an overview of the capabilities of the software for a potential user.",
4042
"status": "What is the status of the project?",
4143
"license": "What license is the project under?",
44+
"license_url": "What is the URL to the license?",
4245
"usage_type": "What is the usage type for this project? For more information on each option, visit github.com/DSACMS/gov-codejson",
4346
"repository_host": "Where is the repository hosted?",
4447
"vcs": "What version control system is used?",
4548
"forks": "How many forks does the repository have?",
49+
"clones": "How many clones does the repository have?",
4650
"platforms": "What platform does the software runs on? Separate items by commas.",
4751
"categories": "What categories best describes the project? Separate items by commas. List of categories here: https://yml.publiccode.tools/categories-list.html?highlight=categories",
4852
"software_type": "What type of software is the project?",
4953
"languages": "What programming language(s) is the software written in? Separate items by commas.",
5054
"maintenance": "How is the software maintained?",
51-
"contract_number": "What is the contractor number of the project?",
55+
"contract_number": "What is the contractor number(s) of the project? Separate items by commas.",
56+
"sbom": "Provide a link to the SBOM of the repository. If the software does not have a SBOM, enter 'None'.",
5257
"tags": "Provide a list of tags to describe the software for search. Separate items by commas.",
5358
"contact_name": "A point of contact is needed for the project. What is the name of the point of contact?",
5459
"contact_email": "What is email address of the point of contact?",
55-
"feedback_mechanisms": "What are methods a repository receives feedback from the community (e.g. URL to GitHub repository issues page, website, email)",
60+
"ai_use_case_id": "What is the software's ID in the AI Use Case Inventory? If the software is not listed in the inventory, enter '0'.",
5661
"localisation": "Does the software support multiple spoken languages?",
5762
"repository_type": "What type of repository is this project?",
5863
"user_input": "Does the project accept user input? (e.g. allows user to query a database, allows login by users, upload files, etc.)",
5964
"fisma_level": "What FISMA level is this project classified as? Learn more: https://security.cms.gov/learn/federal-information-security-modernization-act-fisma#perform-system-risk-categorization",
6065
"group": "Which group at CMS is the project part of?",
6166
"projects": "What project is the repository associated with? Separate items by commas.",
6267
"systems": "What systems does the repository use or interface with? Separate items by commas.",
63-
"upstream": "What upstream dependencies does the repository use? Separate items by commas.",
64-
"subset_in_healthcare": "Which subset of healthcare does the project belong to?",
65-
"user_type": "Who are the intended users?"
68+
"subset_in_healthcare": "Which subset of healthcare does the project belong to? Separate items by commas.",
69+
"user_type": "Who are the intended users? Separate items by commas."
6670
}
6771
}

tier1/{{cookiecutter.project_slug}}/.github/codejson/hooks/post_gen_project.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,30 @@
22
import shutil
33
import json
44
import os
5-
import shutil
5+
from datetime import datetime, timezone
66

77
def get_date_fields():
88
# Run git commands and capture as string
99
output = subprocess.run(['git', 'log', '--date=iso', '--pretty=%cI', '--max-parents=0', '-n', '1'], capture_output=True, text=True)
10-
10+
1111
# Store string and strip of leading / trailing whitespace
1212
date = output.stdout.strip()
13+
14+
# Parse the git timestamp and convert to UTC
15+
git_date = datetime.fromisoformat(date)
16+
utc_date = git_date.astimezone(timezone.utc)
17+
created_date = utc_date.strftime('%Y-%m-%dT%H:%M:%SZ')
18+
19+
# Generate current UTC timestamps using the new recommended method
20+
current_utc = datetime.now(timezone.utc)
21+
current_timestamp = current_utc.strftime('%Y-%m-%dT%H:%M:%SZ')
1322

1423
# Create a dictionary for date information to be pushed to JSON
15-
date_information = {"created": f"{date}",
16-
"lastModified": "{% now 'utc', '%Y-%m-%dT%H:%M:%S%z' %}",
17-
"metadataLastUpdated": "{% now 'utc', '%Y-%m-%dT%H:%M:%S%z' %}"}
24+
date_information = {
25+
"created": created_date,
26+
"lastModified": current_timestamp,
27+
"metadataLastUpdated": current_timestamp
28+
}
1829

1930
return date_information
2031

@@ -77,20 +88,26 @@ def update_code_json(json_file_path):
7788
data['laborHours'] = None
7889

7990
# Check if usageType is an exemption
80-
if data['permissions']['usageType'].startswith('exempt'):
91+
contains_exempt = any("exempt" in item for item in data['permissions']['usageType'])
92+
if contains_exempt:
8193
exemption_text = prompt_exemption_text(data['permissions']['usageType'])
8294
data['permissions']['exemptionText'] = exemption_text
8395
else:
8496
del data['permissions']['exemptionText']
8597

8698
# Format multi-select options
87-
multi_select_fields = ["platforms", "categories", "languages", "tags", "feedbackMechanisms", "projects", "systems", "upstream", "subsetInHealthcare", "userType"]
99+
multi_select_fields = ["platforms", "categories", "languages", "contractNumber", "tags", "projects", "systems", "subsetInHealthcare", "userType"]
88100
for field in multi_select_fields:
89101
data[field] = format_multi_select_fields(data[field][0])
90102

91103
# Format integer fields
92104
if data['reuseFrequency']['forks'].isdigit():
93105
data['reuseFrequency']['forks'] = int(data['reuseFrequency']['forks'])
106+
if data['reuseFrequency']['clones'].isdigit():
107+
data['reuseFrequency']['clones'] = int(data['reuseFrequency']['clones'])
108+
109+
data['localisation'] = eval(data['localisation'])
110+
data['userInput'] = eval(data['userInput'])
94111

95112
# Update the JSON
96113
with open(json_file_path, 'w') as file:

tier1/{{cookiecutter.project_slug}}/.github/codejson/{{cookiecutter.project_name}}/code.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
"permissions": {
77
"licenses": [
88
{
9-
"URL": "LICENSE",
10-
"name": "{{ cookiecutter.license }}"
9+
"name": "{{ cookiecutter.license }}",
10+
"URL": "{{cookiecutter.license_url}}"
11+
1112
}
1213
],
13-
"usageType": "{{ cookiecutter.usage_type }}",
14+
"usageType": [ "{{ cookiecutter.usage_type }}" ],
1415
"exemptionText": ""
1516
},
1617
"organization": "Centers for Medicare & Medicaid Services",
@@ -20,29 +21,31 @@
2021
"vcs": "{{ cookiecutter.vcs }}",
2122
"laborHours": [""],
2223
"reuseFrequency": {
23-
"forks": "{{ cookiecutter.forks }}"
24+
"forks": "{{ cookiecutter.forks }}",
25+
"clones": "{{ cookiecutter.clones }}"
2426
},
2527
"platforms": [ "{{ cookiecutter.platforms }}" ],
2628
"categories": [ "{{ cookiecutter.categories }}" ],
2729
"softwareType": "{{ cookiecutter.software_type }}",
2830
"languages": [ "{{ cookiecutter.languages }}" ],
2931
"maintenance": "{{ cookiecutter.maintenance }}",
30-
"contractNumber": "{{ cookiecutter.contract_number }}",
32+
"contractNumber": [ "{{ cookiecutter.contract_number }}" ],
33+
"SBOM": "{{ cookiecutter.sbom }}",
3134
"date": [""],
3235
"tags": [ "{{ cookiecutter.tags }}" ],
3336
"contact": {
3437
"email": "{{ cookiecutter.contact_email }}",
3538
"name": "{{ cookiecutter.contact_name }}"
3639
},
37-
"feedbackMechanisms": ["{{ cookiecutter.feedback_mechanisms }}"],
40+
"feedbackMechanism": "https://github.com/{{ cookiecutter.project_org }}/{{ cookiecutter.project_repo_name }}/issues",
41+
"AIUseCaseID": "{{ cookiecutter.ai_use_case_id }}",
3842
"localisation": "{{ cookiecutter.localisation }}",
3943
"repositoryType": "{{ cookiecutter.repository_type }}",
4044
"userInput": "{{ cookiecutter.user_input }}",
4145
"fismaLevel": "{{ cookiecutter.fisma_level }}",
4246
"group": "{{ cookiecutter.group }}",
4347
"projects": ["{{ cookiecutter.projects }}"],
4448
"systems": ["{{ cookiecutter.systems }}"],
45-
"upstream": ["{{ cookiecutter.upstream }}"],
4649
"subsetInHealthcare": ["{{ cookiecutter.subset_in_healthcare }}"],
4750
"userType": ["{{ cookiecutter.user_type }}"],
4851
"maturityModelTier": 1

0 commit comments

Comments
 (0)