Skip to content

Commit

Permalink
WIP dynamic matrix
Browse files Browse the repository at this point in the history
  • Loading branch information
nitzmahone committed May 13, 2024
1 parent c39f904 commit 5e646da
Show file tree
Hide file tree
Showing 3 changed files with 456 additions and 336 deletions.
22 changes: 22 additions & 0 deletions .github/actions/dynamatrix/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Create matrix
description: Create matrix
inputs:
matrix_yaml:
description: input yaml matrix as multiline string; any entry with a bool true `omit` key will be filtered from the output matrix
required: true
outputs:
matrix_json:
description: filtered matrix as JSON
value: ${{ steps.matrix_gen.outputs.matrix_json }}

runs:
using: "composite"

steps:
- id: matrix_gen
run: |
# FIXME: input sanity check to prevent shell injection
python3 $GITHUB_ACTION_PATH/matrix_yaml_to_json.py --from-stdin << EOF
${{ inputs.matrix_yaml }}
EOF
shell: bash
71 changes: 71 additions & 0 deletions .github/actions/dynamatrix/matrix_yaml_to_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from __future__ import annotations

import argparse
import json
import os
import pathlib
import sys
import typing as t
import yaml

from collections.abc import MutableMapping, Sequence

skipped_entries = []

def _filter_omit_entries(value):
if isinstance(value, MutableMapping):
if (omit_value := value.pop('omit', ...)) is not ...:
if omit_value is True:
print(f'omitting {value} from matrix')
skipped_entries.append(value)
return ...

return {k: v for k, v in ((k, _filter_omit_entries(v)) for k, v in value.items()) if v is not ...}

if isinstance(value, str):
return value

if isinstance(value, Sequence):
return [v for v in (_filter_omit_entries(v) for v in value) if v is not ...]

return value

def main():
p = argparse.ArgumentParser(description='GHA YAML matrix filter')
required_grp = p.add_mutually_exclusive_group(required=True)
required_grp.add_argument('--from-stdin', action='store_true', help='read input YAML from stdin')
required_grp.add_argument('--from-file', type=pathlib.Path, help='read input YAML from file path')

args = p.parse_args()

path: pathlib.Path | None

matrix_yaml: str

if path := args.from_file:
matrix_yaml = path.read_text()
elif args.from_stdin:
matrix_yaml = sys.stdin.read()
else:
raise Exception('no source provided for matrix yaml')

raw_matrix = yaml.safe_load(matrix_yaml)
filtered_matrix = _filter_omit_entries(raw_matrix)

output_matrix_json = json.dumps(filtered_matrix)
output_skipped_matrix_json = json.dumps(skipped_entries)

print(f'filtered matrix: {output_matrix_json}')
print(f'skipped entries: {output_skipped_matrix_json}')

if (gh_output := os.environ.get('GITHUB_OUTPUT')):
print('setting step output var matrix_json; skipped_matrix_json...')
with pathlib.Path(gh_output).open('a') as env_fd:
env_fd.write(f'matrix_json<<__MATRIX_EOF\n{output_matrix_json}\n__MATRIX_EOF\n')
env_fd.write(f'skipped_matrix_json<<__MATRIX_EOF\n{output_skipped_matrix_json}\n__MATRIX_EOF\n')
else:
print("GITHUB_OUTPUT not set; skipping variable output")


if __name__ == '__main__':
main()
Loading

0 comments on commit 5e646da

Please sign in to comment.