{"id":19713482,"url":"https://github.com/shalomb/inji","last_synced_at":"2025-10-05T22:18:04.840Z","repository":{"id":62571033,"uuid":"276085288","full_name":"shalomb/inji","owner":"shalomb","description":"inji renders jinja template files to support parametrized configuration","archived":false,"fork":false,"pushed_at":"2025-09-16T18:45:46.000Z","size":251,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-24T23:37:10.916Z","etag":null,"topics":["jinja","jinja-templates","jinja2","jinja2-templates","parametrization","python","templating-engine","templating-tool"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shalomb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-2.0.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-30T11:55:44.000Z","updated_at":"2025-09-16T18:35:43.000Z","dependencies_parsed_at":"2024-11-11T22:22:57.582Z","dependency_job_id":"468917b0-f681-4fa6-87d1-f4e296fe8f6b","html_url":"https://github.com/shalomb/inji","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/shalomb/inji","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shalomb%2Finji","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shalomb%2Finji/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shalomb%2Finji/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shalomb%2Finji/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shalomb","download_url":"https://codeload.github.com/shalomb/inji/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shalomb%2Finji/sbom","scorecard":{"id":815467,"data":{"date":"2025-08-11","repo":{"name":"github.com/shalomb/inji","commit":"88067254eccc5cc83f00c8f09f045d62ccd09658"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE-2.0.txt:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'develop'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"14 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2019-217 / GHSA-462w-v97r-4m45","Warn: Project is vulnerable to: PYSEC-2014-8 / GHSA-8r7q-cvjq-x353","Warn: Project is vulnerable to: GHSA-cpwx-vrp4-4pq7","Warn: Project is vulnerable to: PYSEC-2014-82 / GHSA-fqh9-2qgg-h84h","Warn: Project is vulnerable to: PYSEC-2021-66 / GHSA-g3rq-g295-4j3m","Warn: Project is vulnerable to: GHSA-h5c8-rqwp-cp95","Warn: Project is vulnerable to: GHSA-h75v-3vvj-5mfj","Warn: Project is vulnerable to: PYSEC-2019-220 / GHSA-hj2j-77xm-mc5v","Warn: Project is vulnerable to: GHSA-q2x7-8rv6-6q7h","Warn: Project is vulnerable to: PYSEC-2021-142 / GHSA-8q59-q68h-6hv4","Warn: Project is vulnerable to: PYSEC-2018-49 / GHSA-rprw-h62v-c2w7","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2023-74 / GHSA-j8r2-6x86-q33q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T14:11:15.610Z","repository_id":62571033,"created_at":"2025-08-23T14:11:15.611Z","updated_at":"2025-08-23T14:11:15.611Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278528854,"owners_count":26001806,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jinja","jinja-templates","jinja2","jinja2-templates","parametrization","python","templating-engine","templating-tool"],"created_at":"2024-11-11T22:22:51.249Z","updated_at":"2025-10-05T22:18:04.824Z","avatar_url":"https://github.com/shalomb.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Pythons](https://img.shields.io/badge/python-3.5%E2%80%933.9%20%7C%20pypy-blue.svg)](.travis.yml)\n[![Build Status](https://travis-ci.org/shalomb/inji.svg?branch=develop)](https://travis-ci.org/shalomb/inji)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/shalomb/inji/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/shalomb/inji/?branch=develop)\n[![Code Coverage](https://scrutinizer-ci.com/g/shalomb/inji/badges/coverage.png?b=develop)](https://scrutinizer-ci.com/g/shalomb/inji/?branch=develop)\n[![Code Intelligence Status](https://scrutinizer-ci.com/g/shalomb/inji/badges/code-intelligence.svg?b=develop)](https://scrutinizer-ci.com/code-intelligence)\n\n![inji](./inji-logo.png)\n\nInji renders static\n[jinja2](https://jinja.palletsprojects.com/en/2.11.x/)\ntemplates.\n\nTemplates may be parametrized in which case inji can be given one or more\nYAML vars files to source parameters used in the templates.\n\nUseful in CI/CD scenarios where\n[DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)\nconfiguration is necessary and templating/parametrization is a\nusable pattern.\n\n### Installation\n\n```\npython3 -m pip install inji   #  or use pip3/pip, requires python \u003e= 3.6 (may work on 3.5)\n```\n\n### Usage\n\n##### Render a Jinja2 template\n\n```\n$ system=$(\u003c /etc/hostname)\n$ startime=$(date +%FT%T%z)\n\n$ echo 'Reporting from {{ node }}, it is now {{ time }}' \\\n    | inji --k node=\"$system\" -k time=\"$startime\"\nReporting from leto, it is now 2021-03-29T09:54:56+0200\n\n```\n\nOr from a file\n\n```\n$ inji jello-star-motd.j2 -k ... \u003e /etc/motd\n```\n\n##### Render a template passing vars in a JSON object\n\nJSON allows you to pass configuration in complex/multi-dimensional objects.\n\n```\n$ echo '\nnode : {{ node.name }}\ntime : {{ node.time }}\n' \u003e template.j2\n\n$ inji template.j2 -j '{\n  \"node\":{\n    \"name\":\"'$(\u003c/etc/hostname)'\", // Note the \"interpolation\" of shell commands\n    \"time\":\"'$(date)'\"            // here with the quoting.\n  }\n}'\n```\n\n##### Render a template passing vars from a YAML file\n\n\n```\ninji motd.j2 --vars-file=production.yaml\n```\n\nvars files must contain valid\n[YAML documents](https://yaml.org/spec/1.2/spec.html#id2800132)\nand can hold either simple\n[scalars](https://yaml.org/spec/1.2/spec.html#id2760844)\nor\n[collections](https://yaml.org/spec/1.2/spec.html#id2759963).\nYour jinja templates can then reference parameters/variables inside these\nvarsfiles depending on your context.\n\n##### Multiple docker images from a single Dockerfile\n\nA trivial case is building multiple docker images from a base Dockerfile.\n\nAnyone who has maintained a project like this finds themselves having to\nmaintain multiple Dockerfiles, one-per-image even though the differences\nbetween each Dockerfile are trivial. Such a\n[WET approach](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself#DRY_vs_WET_solutions)\nwhere copy-paste duplication is rife knows of painful maintenance\nwhen the structure of the Dockerfile has to change, etc.\n\nInstead, to [DRY](https://wiki.c2.com/?DontRepeatYourself) things up, consider\nhow paramertrization or templating addresses the issue.\n\n```\n$ cat Dockerfile.j2\nFROM {{ distribution }}:{{ version }}    # These jinja2 vars are set by inji\n                                         # from travis' environment variables\n\nMAINTAINER http://my.org/PlatformOps\n\nENV container       docker\nENV distribution {{ distribution }}\nENV version      {{ version }}-{{ ref }} # `ref` is set at inji's CLI\n\n{% if distribution == 'centos' %}        # Conditional execution\nRUN yum -y update \u0026\u0026 yum clean all\n{% endif %}\n\n{% if distribution == 'debian' %}\nRUN apt update -qq \u0026\u0026 apt upgrade -y\n{% endif %}\n\n{% if distribution == 'fedora' %}\nRUN dnf -y update \u0026\u0026 dnf clean all\n{% endif %}\n\nRUN my-awesome-build-script {{ distribution }} {{ version }}\n\nENTRYPOINT [\"/opt/bin/myserv\"]\n```\n\nThen a CI build job (e.g. Travis CI) using inji would look like this.\n\n```\n$ cat .travis.yml\n---\nlanguage: python\nsudo: required\nservices:\n  - docker\n\nenv:\n\n  - distribution: centos\n    version: 7\n\n  - distribution: centos\n    version: 8\n\n  - distribution: debian\n    version: stretch\n\n  - distribution: debian\n    version: buster\n\n  - distribution: fedora\n    version: 28\n\n  - distribution: fedora\n    version: 29\n\nbefore_script:\n  - pip install inji\n\nscript:\n  - \u003e\n    inji Dockerfile.j2 --kv-config ref=\"$CI_COMMIT_REF_NAME\" |\n      docker build --pull --tag \"myimage:$distribution-$version\" -\n  - docker push --all-tags \"myimage\"\n...\n```\n\n##### Render a template using variables from multiple vars files\n\n```\n$ inji nginx.conf.j2             \\\n      --vars-file=web-tier.yaml  \\\n      --vars-file=eu-west-1.yaml \\\n      --vars-file=prod.yaml    \u003e /etc/nginx/sites-enabled/prod-eu-west-1.conf\n```\n\nHere, variables from files specified later on the command-line\nwill override those from files specified before\n(prod.yaml supercedes eu-west-1.yaml, etc).\n\nThis is especially useful in managing layered configuration where different\ntiers of a deployment enforce/provide different parameters.\n\n##### Using directory configuration overlays\n\nAn inevitable practice is using multiple smaller configuration files\nto avoid the growing pains of huge configuration files,\nto source configuration from different sources,\nimprove churn, reduce friction, etc, etc, etc.\nHere, explicitly naming configuration files for inji to use becomes\na new pain point.\n\nWith overlay directories, inji naively reads in all yaml files from a directory\nand compiles a combined configuration object before using that in rendering\na template.\n\n```\n$ tree conf/\nconf/\n├── dev\n│   ├── service-discovery.yaml\n│   ├── load-balancer-ip.yaml\n│   ├── modules.yaml\n│   └── sites.yaml\n├── prod\n│   ├── service-discovery.yaml\n│   ├── load-balancer-ip.yaml\n│   ├── modules.yaml\n│   └── sites.yaml\n└── stage\n    ├── service-discovery.yaml\n    ├── load-balancer-ip.yaml\n    ├── modules.yaml\n    └── sites.yaml\n3 directories, 9 files\n\n$ inji  nginx.conf.j2 \\  # here $CI_ENV is be some variable your CI system\n        --overlay=\"conf/$CI_ENV\" \\  # sets holding the name of the target deployment\n        \u003e nginx.conf                # e.g. dev, stage, prod\n```\n\n### Parameter sourcing and precedence order\n\nParameters  (configuration)  can  be   specified  and  sourced  from  multiple\nsources. The  order of parameters  sourced and their precedence  is [12-factor\nfriendly](https://12factor.net/config)  and  is done  as  set  out here  (from\nlowest-to-highest precedence).\n\n- Default configuration file (`.inji.y*ml` or `inji.y*ml`) in current directory.\n- Overlay directories - last file sorted alphabetically wins\n- Named configuration file - last one specified wins\n- Environmental variables - last one specified wins\n- CLI JSON strings - last one specified wins\n- CLI KV strings - last one specified wins\n- Template parameters - last one specified wins (Jinja2 order)\n\n### Examples\n\nThis is a very contrived example showing how to orient a `.gitlab-ci.yml`\ntowards business workflows -\na multi-stage CI/CD deployment pipeline expedited by Gitlab.\n\nNote the use of complex objects in the parameters.\n\n```\n$ cat .gitlab-ci.vars\n---\nproject:\n  name: snowmobile\n  id:   https://gitlab.com/snowslope/snowmobile.git\n  url:  https://snowmobile.example.com/\n\ndeployer:\n  image: snowmobile-deployer:latest\n\n# This serves as the more succinct business abstract\n\nenvironments:\n\n  - name: snowmobile-env_dev\n    type: dev\n    region: us-east-1\n    ci_url:  https://snowmobile-dev.env.example.com/\n    branches:\n      - /^[0-9]+\\-.*/  # Match feature branches that have\n                       # a ticket number at the start of the branch name\n\n  - name: snowmobile-env_stage\n    type: stage\n    region: eu-west-2\n    ci_url:  https://snowmobile-stage.env.example.com/\n    branches:\n      - master         # Deploy to stage only after merge request is complete\n\n  - name: snowmobile-env_prod\n    type: production\n    region: eu-west-1\n    ci_url:  https://snowmobile.env.example.com/\n    branches:\n      - tags           # Only deploy tagged releases to production\n\n...\n```\n\n```\n$ cat .gitlab-ci.j2\n---\n\n# \u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\n# \u003e\u003e WARNING \u003e\u003e   This file is autogenerated!!\n# \u003e\u003e !!!!!!! \u003e\u003e   Edit .gitlab-ci.{j2, vars} instead and `make gitlab-ci-yml`\n# \u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e   All edits will be lost on the next update\n\n# This template when rendered with parameters from the above varsfile\n# produces the actual fuller .gitlab-ci.yml file\n\nstages:\n{% for env in environments %}\n  - '{{ env.name }}:provision'\n  - '{{ env.name }}:validate'\n  - '{{ env.name }}:deploy'\n  - '{{ env.name }}:test'\n  - '{{ env.name }}:destroy'\n{% endfor %}\n  - 'docs:publish'\n\nvariables:\n  project:             {{  project.name }}\n  project_id:          '{{ project.id   }}'\n  project_url:         {{  project.url  }}\n\n{% for env in environments %}\n\n# {{ env.type }} Run infrastructure provisioning\n'provision:{{ env.name }}':\n  stage: '{{ env.name }}:provision'\n  environment:\n    name: {{ env.type }}/$SITE/$CI_COMMIT_REF_NAME\n    url:  {{ env.ci_url }}\n  variables:\n    SITE:                {{ env.name }}\n    CI_ENVIRONMENT_TYPE: {{ env.type }}\n    REGION:              {{ env.region }}\n    CI_URL:              {{ env.ci_url }}\n  image:  {{ deployer.image }}\n  script:\n    - snowmobile-ctl provision\n\n  {% if env.branches -%}\n  only: {{ env.branches }}\n  {% endif %}\n\n# {{ env.type }} Run application deployment\n'deploy:{{ env.name }}':\n  stage: '{{ env.name }}:deploy'\n  # ...\n  script:\n    - snowmobile-ctl deploy\n\n# {{ env.type }} Run smoke tests\n'test:{{ env.name }}':\n  stage: '{{ env.name }}:test'\n  # ...\n  script:\n    - snowmobile-ctl smoke-test\n\n{% endfor %}\n\n# vim:ft=yaml\n...\n```\n\nTo then update the `.gitlab-ci.yml`, run inji with the above.\n\n```\n$ inji .gitlab-ci.j2 \\\n       --vars-file .gitlab-ci.vars \u003e .gitlab-ci.yml\n```\n\nWARNING: Edits to the above files are not automatically reflected in\n`.gitlab-ci.yml` and some other mechanism using inji to render the latter needs\nto be run before Gitlab acts upon it. e.g. Using a\n[git commit hook](https://git-scm.com/docs/githooks#_pre_commit)\nor\n[gitattribute filter](https://www.bignerdranch.com/blog/git-smudge-and-clean-filters-making-changes-so-you-dont-have-to/)\n, etc.\n\n```\n$ cat .githooks/pre-commit\n#!/bin/sh\n\nset -e\n\nsource_update=0\nfile_update=0\n\n# NOTE: git diff --exit-code ... returns 1 if file has changed\ngit diff --exit-code .gitlab-ci.j2   || source_update=1\ngit diff --exit-code .gitlab-ci.vars || source_update=1\ngit diff --exit-code .gitlab-ci.yaml || file_update=1\n\nif [ \"$file_update\" = 1 ]; then\n  echo \u003e\u00262 \".gitlab-ci.yaml updated without updating templates (.gitlab-ci.{j2,vars})\"\n  exit 1\nfi\n\n[ \"$source_update\" = 0 ] \u0026\u0026 exit 0\n\ninji .gitlab-ci.j2 --vars-file .gitlab-ci.vars \u003e .gitlab-ci.yaml\n\ngit add .gitlab-ci.yaml \u0026\u0026\n  git commit --amend -C HEAD --no-verify\n```\n\n### Etymology\n\nWhy the name inji?\n\nApart from keeping to the UNIX tradition of short (memorable?)\n command names, _inji_ is a 4-letter near-anagram of _Jinja_.\n\n[_inji_](https://en.wikipedia.org/wiki/Ginger#Etymology) (_/ɪndʒi:/_)\nalso happens to be the Dravidian word and ostensibly the source of the\nEnglish word Ginger, of which jinja is a partial homophone.\n\n### TODO\n\nOnly potential ideas so far - No commitment is made.\n\n* [ ] Read config from JSON/TOML files?\n* [ ] Manage collections of templates e.g. `*.j2`\n* [ ] Dry-run syntax checking\n* [ ] Document patterns driving the design and refactor docs\n* [ ] Document use of macros\n* [ ] Document use of vars collections\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshalomb%2Finji","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshalomb%2Finji","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshalomb%2Finji/lists"}