reci.recipe_checks¶
Whole-recipe checks that need the recipe text and the config, not the step graph.
Shared by the compiler (which refuses to emit a workflow with these problems) and the validation rules (which report them), so both always agree.
Module Attributes
The generated job that exports config values; recipe jobs may not use the id when config is supplied. |
Functions
|
An |
|
The config keys referenced in text's ``${{ . |
|
|
|
The body of each |
|
Problems that would make the compiled workflow invalid. |
|
A config value as the text of a |
|
Substitute every |
|
The uses of the |
Classes
|
One problem found by |
- class reci.recipe_checks.RecipeProblem(rule_id, message, location=None)[source]¶
Bases:
objectOne problem found by
find_recipe_problems().
- reci.recipe_checks.SETUP_JOB_ID = 'setup'¶
The generated job that exports config values; recipe jobs may not use the id when config is supplied.
- reci.recipe_checks.as_expression(text)[source]¶
An
if:value as a${{ }}expression: GitHub evaluates it either way.- Return type:
>>> as_expression("config.flag"), as_expression("${{ config.flag }}") ('${{ config.flag }}', '${{ config.flag }}')
- reci.recipe_checks.config_names(text)[source]¶
The config keys referenced in text’s
${{ ... }}expressions, in order.>>> config_names("${{ config.a }} ${{ !config.b && 'config.c' }} config.d") ['a', 'b']
- reci.recipe_checks.config_references(recipe)[source]¶
(location, key, needs_context_available)for each${{ config.key }}.Duplicates within one location are reported once.
- reci.recipe_checks.expression_texts(text)[source]¶
The body of each
${{ }}in text, string literals blanked.A literal survives only as the index of a bracket access (
steps['p']), so a name inside a message or comparison ('steps.p.outputs.v') is never taken for a reference.>>> list(expression_texts("${{ steps['p'].outputs.v == 'steps.q.outputs.w' }} x")) [" steps['p'].outputs.v == '' "]
- reci.recipe_checks.find_recipe_problems(recipe, config)[source]¶
Problems that would make the compiled workflow invalid.
CONF004—${{ config.X }}whereXis not a config key (the rewrittenneeds.setup.outputs.Xwould be empty or the setup job absent), or that sits where theneedscontext is unavailable.DAG006—needs:naming a job that does not exist (setupexists only when config is supplied).CONF005— a config key that is not a valid output id, or a string value holding characters the setup job cannot export unchanged.DAG007— a recipe job namedsetupwhile config is supplied: it would replace the generated setup job.
- Return type:
- reci.recipe_checks.serialize_config_value(value)[source]¶
A config value as the text of a
$GITHUB_OUTPUTentry.Lists, mappings and tuples become JSON (dates inside them as ISO text); a boolean
true/false; a number as the author wrote it (a TOML or YAML3.10stays3.10, not3.1).None, bytes and other objects have no faithful text and raiseTypeError.- Return type:
>>> serialize_config_value({"d": datetime.date(2024, 1, 2), "t": (1, 2)}) '{"d": "2024-01-02", "t": [1, 2]}' >>> serialize_config_value(True), serialize_config_value(7) ('true', '7') >>> serialize_config_value(None) Traceback (most recent call last): ... TypeError: None (null) has no text form; give the key a value or remove it
- reci.recipe_checks.sub_config_refs(text, repl)[source]¶
Substitute every
config.<key>inside a${{ ... }}in text.repl receives the match (
group(1)is the key). Only expression code is touched, never string literals inside an expression ('config.json') and never text outside${{ }}(cat config.json). An expression that changes is re-emitted as${{ <code> }}; the others are left verbatim.- Return type:
>>> sub_config_refs("${{ fromJson(config.v) }} cat config.json", ... lambda m: "NEEDS." + m.group(1)) '${{ fromJson(NEEDS.v) }} cat config.json'
- reci.recipe_checks.unsupported_config_refs(text)[source]¶
The uses of the
configcontext in text that reci cannot rewrite.Only
config.<key>maps to a setup-job output. Nested access (config.x.y), bracket access (config['x']) and the whole context (toJSON(config),config.*) have no counterpart, and would reach GitHub unrewritten, whereconfigis no context.>>> unsupported_config_refs("${{ config.a }} ${{ config.b.c }} ${{ config['d'] }}") ['config.b.c', 'config['] >>> unsupported_config_refs("${{ toJSON(config) }} ${{ 'config' }} ${{ config.a }}") ['config']