Skip to content

Commit

Permalink
CI: Update workflows and templates to expect json files
Browse files Browse the repository at this point in the history
Update GitHub and CircleCI settings to check for json files.

Update `check_description_files` CLI to parse json files:
* Remove `parse_s4ext` and introduce `parse_json` function along with
  `ExtensionParseError` exception.
* Update list of supported URL schemes. Only `https` and `git` are supported
* Remove obsolete `check_scm_notlocal` check
  • Loading branch information
jcfr committed Mar 12, 2024
1 parent 00784ff commit 31fcc37
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 43 deletions.
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- run:
name: Check description files
command: |
python ./scripts/check_description_files.py --check-dependencies . $(find . -name "*.s4ext")
python ./scripts/check_description_files.py --check-dependencies . $(find . -maxdepth 1 -name "*.json")
check-new-description-files:
docker:
Expand Down Expand Up @@ -50,8 +50,8 @@ jobs:
echo "BASE_BRANCH is [$BASE_BRANCH]"
echo "CIRCLE_BRANCH is [$CIRCLE_BRANCH]"
# Collect list of new *.s4ext files
added=$(git diff $BASE_BRANCH --diff-filter=A --name-only | grep -E "^[^\/]+\.s4ext$")
# Collect list of new *.json files
added=$(git diff $BASE_BRANCH --diff-filter=A --name-only | grep -E "^[^\/]+\.json$")
echo "added [$added]"
# Run checks
Expand Down
4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!--
Thank you for contributing to 3D Slicer!
- To add a new extension with this pull request: Please keep content of "New extension" section and put an 'x' in the brackets for each todo item to indicate that you have accomplished that prerequisite.
- To update an existing extension with this pull request: Please delete all text in this template and just describe which extension is updated and optionally tell us in a sentence what has been changed. To make extension updates easier in the future you may consider replacing specific git hash in your s4ext file by a branch name (for example: `main` for Slicer Preview Releases; `(majorVersion).(minorVersion)` such as `4.10` for Slicer Stable Releases).
- To update an existing extension with this pull request: Please delete all text in this template and just describe which extension is updated and optionally tell us in a sentence what has been changed. To make extension updates easier in the future you may consider replacing specific git hash in your json file by a branch name (for example: `main` for Slicer Preview Releases; `(majorVersion).(minorVersion)` such as `5.6` for Slicer Stable Releases).
-->

# New extension
Expand All @@ -25,7 +25,7 @@ Thank you for contributing to 3D Slicer!
- [ ] Tutorial: step-by-step description of at least the most typical use case, include a few screenshots, provide download links to sample input data set
- [ ] Publication: link to publication and/or to PubMed reference (if available)
- [ ] License: We suggest you use a permissive license that includes patent and contribution clauses. This will help protect developers and ensure the code remains freely available. We suggest you use the [Slicer License](https://github.com/Slicer/Slicer/blob/main/License.txt) or the [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0). Always mention in your README file the license you have chosen. If you choose a different license, explain why to the extension maintainers. Depending on the license we may not be able to host your work. Read [here](https://opensource.guide/legal/#which-open-source-license-is-appropriate-for-my-project) to learn more about licenses.
- [ ] Content of submitted s4ext file is consistent with the top-level CMakeLists.txt file in the repository (description, URLs, dependencies, etc. are the same)
- [ ] Content of submitted json file is consistent with the top-level CMakeLists.txt file in the repository (dependencies, etc. are the same)
- Hide unused features in the repository to reduce noise/irrelevant information:
- [ ] Click `Settings` and in repository settings uncheck `Wiki`, `Projects`, and `Discussions` (if they are currently not used)
- [ ] Click the settings icon next to `About` in the top-right corner of the repository main page and uncheck `Releases` and `Packages` (if they are currently not used)
Expand Down
83 changes: 46 additions & 37 deletions scripts/check_description_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import argparse
import json
import os
import sys
import textwrap
Expand All @@ -13,6 +14,17 @@
from functools import wraps


class ExtensionParseError(RuntimeError):
"""Exception raised when a particular extension description file failed to be parsed.
"""
def __init__(self, extension_name, details):
self.extension_name = extension_name
self.details = details

def __str__(self):
return self.details


class ExtensionCheckError(RuntimeError):
"""Exception raised when a particular extension check failed.
"""
Expand Down Expand Up @@ -40,20 +52,21 @@ def wrapped(*args, **kwargs):
return dec


def parse_s4ext(ext_file_path):
def parse_json(ext_file_path):
"""Parse a Slicer extension description file.
:param ext_file_path: Path to a Slicer extension description file.
:param ext_file_path: Path to a Slicer extension description file (.json).
:return: Dictionary of extension metadata.
"""
ext_metadata = {}
with open(ext_file_path) as ext_file:
for line in ext_file:
if not line.strip() or line.startswith("#"):
continue
fields = [field.strip() for field in line.split(' ', 1)]
assert(len(fields) <= 2)
ext_metadata[fields[0]] = fields[1] if len(fields) == 2 else None
return ext_metadata
with open(ext_file_path) as input_file:
try:
return json.load(input_file)
except json.JSONDecodeError as exc:
extension_name = os.path.splitext(os.path.basename(ext_file_path))[0]
raise ExtensionParseError(
extension_name,
textwrap.dedent("""
Failed to parse '%s': %s
""" % (ext_file_path, exc)))


@require_metadata_key("scmurl")
Expand All @@ -63,29 +76,20 @@ def check_scmurl_syntax(extension_name, metadata):
if "://" not in metadata["scmurl"]:
raise ExtensionCheckError(extension_name, check_name, "scmurl do not match scheme://host/path")

supported_schemes = ["git", "https", "svn"]
supported_schemes = ["git", "https"]
scheme = urlparse.urlsplit(metadata["scmurl"]).scheme
if scheme not in supported_schemes:
raise ExtensionCheckError(
extension_name, check_name,
"scmurl scheme is '%s' but it should by any of %s" % (scheme, supported_schemes))

@require_metadata_key("scm")
def check_scm_notlocal(extension_name, metadata):
check_name = "check_scm_notlocal"
if metadata["scm"] == "local":
raise ExtensionCheckError(extension_name, check_name, "scm cannot be local")

@require_metadata_key("scmurl")
@require_metadata_key("scm")
def check_git_repository_name(extension_name, metadata):
"""See https://www.slicer.org/wiki/Documentation/Nightly/Developers/FAQ#Should_the_name_of_the_source_repository_match_the_name_of_the_extension_.3F
"""
check_name = "check_git_repository_name"

if metadata["scm"] != "git":
return

repo_name = os.path.splitext(urlparse.urlsplit(metadata["scmurl"]).path.split("/")[-1])[0]

if not repo_name.startswith("Slicer"):
Expand All @@ -106,18 +110,19 @@ def check_dependencies(directory):
available_extensions = []
for filename in os.listdir(directory):
f = os.path.join(directory, filename)
if not os.path.isfile(f):
if not os.path.isfile(f) or not filename.endswith(".json"):
continue
extension_name = os.path.splitext(os.path.basename(filename))[0]
available_extensions.append(extension_name)
extension_description = parse_s4ext(f)
try:
extension_description = parse_json(f)
except ExtensionParseError as exc:
print(exc)
continue
if 'depends' not in extension_description:
continue
dependencies = extension_description['depends'].split(' ')
dependencies = extension_description['depends']
for dependency in dependencies:
if dependency == 'NA':
# special value, just a placeholder that must be ignored
continue
if dependency in required_extensions:
required_extensions[dependency].append(extension_name)
else:
Expand All @@ -140,7 +145,7 @@ def main():
"--check-git-repository-name", action="store_true",
help="Check extension git repository name. Disabled by default.")
parser.add_argument("-d", "--check-dependencies", help="Check all extension dsecription files in the provided folder.")
parser.add_argument("/path/to/description.s4ext", nargs='*')
parser.add_argument("/path/to/extension_name.json", nargs='*')
args = parser.parse_args()

checks = []
Expand All @@ -151,27 +156,31 @@ def main():
if not checks:
checks = [
check_scmurl_syntax,
check_scm_notlocal,
]

total_failure_count = 0

file_paths = getattr(args, "/path/to/description.s4ext")
file_paths = getattr(args, "/path/to/extension_name.json")
for file_path in file_paths:
extension_name = os.path.splitext(os.path.basename(file_path))[0]

failures = []

metadata = parse_s4ext(file_path)
for check in checks:
try:
check(extension_name, metadata)
except ExtensionCheckError as exc:
failures.append(str(exc))
try:
metadata = parse_json(file_path)
except ExtensionParseError as exc:
failures.append(str(exc))

if not failures:
for check in checks:
try:
check(extension_name, metadata)
except ExtensionCheckError as exc:
failures.append(str(exc))

if failures:
total_failure_count += len(failures)
print("%s.s4ext" % extension_name)
print("%s.json" % extension_name)
for failure in set(failures):
print(" %s" % failure)

Expand Down
3 changes: 2 additions & 1 deletion scripts/check_filenames.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ unexpected_files=$(find . -mindepth 1 \( -type d \( \
-path ./.github -o \
-path ./.git -o \
-path ./ARCHIVE -o \
-path ./resources -o \
-path ./scripts \
\) -o -type f \( \
-name .pre-commit-config.yaml -o \
-name .git-blame-ignore-revs -o \
-name README.md -o \
-name "*.s4ext" \
-name "*.json" \
\) \) -prune -o -print)

for unexpected_file in $unexpected_files; do
Expand Down

0 comments on commit 31fcc37

Please sign in to comment.