Skip to content
Open
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
42 changes: 34 additions & 8 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,40 +140,66 @@ jobs:
check_integration_label:
runs-on: ubuntu-latest
needs: [build]
permissions:
pull-requests: read
outputs:
has_geos_integration_label: ${{ steps.set-label.outputs.has_label }}
steps:
- name: Check if PR has '${{ env.LABEL_TEST_GEOS_INTEGRATION }}' label
id: set-label
# Fetch labels live from the GitHub REST API rather than reading
# github.event.pull_request.labels. The event payload is a snapshot
# frozen at the time the workflow was first triggered, so labels
# added after that first run are invisible to re-runs.
env:
GITHUB_TOKEN: ${{ github.token }}
REQUIRED_LABEL: ${{ env.LABEL_TEST_GEOS_INTEGRATION }}
run: |
echo "Checking for label..."
LABEL_FOUND=false
LABELS='${{ toJson(github.event.pull_request.labels.*.name) }}'
PR_JSON=$(curl --fail --silent --show-error \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}")
LABELS=$(echo "${PR_JSON}" | jq -crM '[.labels[].name]')
echo "PR Labels: $LABELS"
if echo "$LABELS" | grep -q "${{ env.LABEL_TEST_GEOS_INTEGRATION }}"; then
if echo "$LABELS" | jq -e --arg label "${REQUIRED_LABEL}" 'index($label) != null' > /dev/null; then
LABEL_FOUND=true
echo "Label '${{ env.LABEL_TEST_GEOS_INTEGRATION }}' found"
echo "Label '${REQUIRED_LABEL}' found"
fi
echo "has_label=$LABEL_FOUND" >> $GITHUB_OUTPUT
echo "has_label=$LABEL_FOUND" >> "$GITHUB_OUTPUT"

check_force_integration_label:
runs-on: ubuntu-latest
# needs: [build]
permissions:
pull-requests: read
outputs:
has_geos_integration_force_label: ${{ steps.set-label.outputs.has_label }}
steps:
- name: Check if PR has '${{ env.LABEL_FORCE_GEOS_INTEGRATION }}' label
id: set-label
# Fetch labels live from the GitHub REST API rather than reading
# github.event.pull_request.labels. The event payload is a snapshot
# frozen at the time the workflow was first triggered, so labels
# added after that first run are invisible to re-runs.
env:
GITHUB_TOKEN: ${{ github.token }}
REQUIRED_LABEL: ${{ env.LABEL_FORCE_GEOS_INTEGRATION }}
run: |
echo "Checking for label..."
LABEL_FOUND=false
LABELS='${{ toJson(github.event.pull_request.labels.*.name) }}'
PR_JSON=$(curl --fail --silent --show-error \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}")
LABELS=$(echo "${PR_JSON}" | jq -crM '[.labels[].name]')
echo "PR Labels: $LABELS"
if echo "$LABELS" | grep -q "${{ env.LABEL_FORCE_GEOS_INTEGRATION }}"; then
if echo "$LABELS" | jq -e --arg label "${REQUIRED_LABEL}" 'index($label) != null' > /dev/null; then
LABEL_FOUND=true
echo "Label '${{ env.LABEL_FORCE_GEOS_INTEGRATION }}' found"
echo "Label '${REQUIRED_LABEL}' found"
fi
echo "has_label=$LABEL_FOUND" >> $GITHUB_OUTPUT
echo "has_label=$LABEL_FOUND" >> "$GITHUB_OUTPUT"

# Step 3: Check if GEOS integration is required based on changed files
check_geos_integration_required:
Expand Down
30 changes: 22 additions & 8 deletions geos-xml-tools/src/geos/xml_tools/attribute_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,30 @@
def parse_schema_element( root: ElementTree.Element,
node: ElementTree.Element,
xsd: str = '{http://www.w3.org/2001/XMLSchema}',
recursive_types: Iterable[ str ] = [ 'PeriodicEvent', 'SoloEvent', 'HaltEvent' ],
folders: Iterable[ str ] = [ 'src', 'examples' ] ) -> record_type:
folders: Iterable[ str ] = [ 'src', 'examples' ],
_seen: set | None = None ) -> record_type:
"""Parse the xml schema at the current level.

Args:
root (lxml.etree.Element): the root schema node
node (lxml.etree.Element): current schema node
xsd (str): the file namespace
recursive_types (list): node tags that allow recursive nesting
folders (list): folders to sort xml attribute usage into
_seen (set): complexType names visited on the current recursion
path, used to break cycles. Managed by recursive calls.

Returns:
dict: Dictionary of attributes and children for the current node
"""
element_type = node.get( 'type' )
element_name = node.get( 'name' )
if _seen is None:
_seen = set()
if element_type in _seen:
return { 'attributes': {}, 'children': {} }
_seen = _seen | { element_type }
element_def = root.find( "%scomplexType[@name='%s']" % ( xsd, element_type ) )
if element_def is None:
return { 'attributes': {}, 'children': {} }
local_types: record_type = { 'attributes': {}, 'children': {} }

# Parse attributes
Expand All @@ -41,8 +48,11 @@ def parse_schema_element( root: ElementTree.Element,
if choice_node:
for child in choice_node[ 0 ].findall( '%selement' % ( xsd ) ):
child_name = child.get( 'name' )
if not ( ( child_name in recursive_types ) and ( element_name in recursive_types ) ):
local_types[ 'children' ][ child_name ] = parse_schema_element( root, child )
local_types[ 'children' ][ child_name ] = parse_schema_element( root,
child,
xsd=xsd,
folders=folders,
_seen=_seen )

return local_types

Expand Down Expand Up @@ -71,10 +81,14 @@ def collect_xml_attributes_level( local_types: record_type, node: ElementTree.El
folder (str): the source folder for the current file
"""
for ka in node.attrib:
local_types[ 'attributes' ][ ka ][ folder ].append( node.get( ka ) )
# Skip attributes not present in the parsed schema (e.g. off-schema
# attributes in a deck, or truncated recursive complexTypes).
slot = local_types.get( 'attributes', {} ).get( ka )
if slot is not None and folder in slot:
slot[ folder ].append( node.get( ka ) )

for child in node:
if child.tag in local_types[ 'children' ]:
if isinstance( child.tag, str ) and child.tag in local_types.get( 'children', {} ):
collect_xml_attributes_level( local_types[ 'children' ][ child.tag ], child, folder )


Expand Down
Loading