From e6bbd759fdf28129556aa648234482fe3915fada Mon Sep 17 00:00:00 2001 From: chfw Date: Fri, 8 Mar 2019 18:13:22 +0000 Subject: [PATCH 1/8] :fire: remove this tests because its static asset prevent package creation in macos --- .../symbolic-link-gets-junk/.moban.yml | 6 --- .../symbolic-link-gets-junk/sym-link-to-file | 1 - .../symbolic-link-gets-junk/symbolic-link | 1 - tests/test_regression_pack.py | 52 ------------------- 4 files changed, 60 deletions(-) delete mode 100644 tests/regression-pack/symbolic-link-gets-junk/.moban.yml delete mode 120000 tests/regression-pack/symbolic-link-gets-junk/sym-link-to-file delete mode 120000 tests/regression-pack/symbolic-link-gets-junk/symbolic-link delete mode 100644 tests/test_regression_pack.py diff --git a/tests/regression-pack/symbolic-link-gets-junk/.moban.yml b/tests/regression-pack/symbolic-link-gets-junk/.moban.yml deleted file mode 100644 index 8d8613b5..00000000 --- a/tests/regression-pack/symbolic-link-gets-junk/.moban.yml +++ /dev/null @@ -1,6 +0,0 @@ -configuration: - template_dir: - - . -targets: - - a.output: symbolic-link - - b.output: sym-link-to-file diff --git a/tests/regression-pack/symbolic-link-gets-junk/sym-link-to-file b/tests/regression-pack/symbolic-link-gets-junk/sym-link-to-file deleted file mode 120000 index ce03d0af..00000000 --- a/tests/regression-pack/symbolic-link-gets-junk/sym-link-to-file +++ /dev/null @@ -1 +0,0 @@ -/tmp/adobegc.log \ No newline at end of file diff --git a/tests/regression-pack/symbolic-link-gets-junk/symbolic-link b/tests/regression-pack/symbolic-link-gets-junk/symbolic-link deleted file mode 120000 index cad23091..00000000 --- a/tests/regression-pack/symbolic-link-gets-junk/symbolic-link +++ /dev/null @@ -1 +0,0 @@ -/tmp \ No newline at end of file diff --git a/tests/test_regression_pack.py b/tests/test_regression_pack.py deleted file mode 100644 index b4e978be..00000000 --- a/tests/test_regression_pack.py +++ /dev/null @@ -1,52 +0,0 @@ -import os -import sys -from textwrap import dedent - -from mock import patch -from nose import SkipTest -from nose.tools import eq_ - -from moban.main import main - - -def custom_dedent(long_texts): - refined = dedent(long_texts) - if refined.startswith("\n"): - refined = refined[1:] - return refined - - -class TestTutorial: - def setUp(self): - self.current = os.getcwd() - - def test_symbolic_link_on_windows(self): - if sys.platform != "win32": - raise SkipTest("No need to test on linux nor macos") - - expected = "/tmp" - - folder = "symbolic-link-gets-junk" - self._raw_moban(["moban"], folder, expected, "a.output") - - def _moban(self, folder, expected): - args = ["moban", "-c", "data.yml", "-t", "a.template"] - self._raw_moban(args, folder, expected, "moban.output") - - def _raw_moban(self, args, folder, expected, output): - os.chdir(os.path.join("tests", "regression-pack", folder)) - with patch.object(sys, "argv", args): - main() - _verify_content(output, expected) - os.unlink(output) - - def tearDown(self): - if os.path.exists(".moban.hashes"): - os.unlink(".moban.hashes") - os.chdir(self.current) - - -def _verify_content(file_name, expected): - with open(file_name, "r") as f: - content = f.read() - eq_(content, expected) From 44f8317c2a61e74dfa720f5ee53b4ef7e69a70c1 Mon Sep 17 00:00:00 2001 From: chfw Date: Fri, 8 Mar 2019 18:16:49 +0000 Subject: [PATCH 2/8] :books: update change log --- .moban.cd/changelog.yml | 12 ++++++++++-- .moban.cd/moban.yml | 4 ++-- CHANGELOG.rst | 19 ++++++++++++++++--- docs/conf.py | 2 +- moban/_version.py | 2 +- setup.py | 2 +- 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/.moban.cd/changelog.yml b/.moban.cd/changelog.yml index a776e582..24d27822 100644 --- a/.moban.cd/changelog.yml +++ b/.moban.cd/changelog.yml @@ -1,12 +1,20 @@ name: moban organisation: moremoban releases: +- changes: + - action: Removed + details: + - "`#253`: symbolic link in regression pack causes python setup.py to do recursive include" + date: unreleased + version: 0.4.3 - changes: - action: Added details: - "`#234`: Define template parameters on the fly inside `targets` section" - - "`#180`: No longer two statistics will be shown in v0.4.x. legacy copy targets are injected into a normal targets. cli target is made a clear priority." - "`#62`: select a group target to run" + - action: Updated + details: + - "`#180`: No longer two statistics will be shown in v0.4.x. legacy copy targets are injected into a normal targets. cli target is made a clear priority." - "`#244`: version 0.4.2 is first version which would work perfectly on windows since 17 Nov 2018. Note that: file permissions are not used on windows. Why the date? because samefile is not avaiable on windows, causing unit tests to fail hence it lead to my conclusion that moban version between 17 Nov 2018 and March 2019 wont work well on Windows." date: 08.03.2019 version: 0.4.2 @@ -21,7 +29,7 @@ releases: - action: Added details: - "`#165`: Copy as plugins" - - action: Added + - action: Updated details: - "`#219`: git clone depth set to 2" - "`#186`: lowest dependecy on ruamel.yaml is 0.15.5, Jun 2017" diff --git a/.moban.cd/moban.yml b/.moban.cd/moban.yml index 5218515c..d8f5d578 100644 --- a/.moban.cd/moban.yml +++ b/.moban.cd/moban.yml @@ -4,8 +4,8 @@ organisation: moremoban author: C. W. contact: wangc_2011@hotmail.com license: MIT -version: 0.4.2 -current_version: 0.4.2 +version: 0.4.3 +current_version: 0.4.3 release: 0.4.2 branch: master master: index diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9f88d3ad..d458e558 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,15 @@ Change log ================================================================================ +0.4.3 - unreleased +-------------------------------------------------------------------------------- + +Removed +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +#. `#253 `_: symbolic link in + regression pack causes python setup.py to do recursive include + 0.4.2 - 08.03.2019 -------------------------------------------------------------------------------- @@ -9,11 +18,15 @@ Added #. `#234 `_: Define template parameters on the fly inside `targets` section +#. `#62 `_: select a group target + to run + +Updated +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + #. `#180 `_: No longer two statistics will be shown in v0.4.x. legacy copy targets are injected into a normal targets. cli target is made a clear priority. -#. `#62 `_: select a group target - to run #. `#244 `_: version 0.4.2 is first version which would work perfectly on windows since 17 Nov 2018. Note that: file permissions are not used on windows. Why the date? because @@ -42,7 +55,7 @@ Added #. `#165 `_: Copy as plugins -Added +Updated ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #. `#219 `_: git clone depth set diff --git a/docs/conf.py b/docs/conf.py index 5a711f36..00ac05ce 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -25,7 +25,7 @@ copyright = '2017-2019 Onni Software Ltd. and its contributors' author = 'Onni Software Ltd.' # The short X.Y version -version = '0.4.2' +version = '0.4.3' # The full version, including alpha/beta/rc tags release = '0.4.2' diff --git a/moban/_version.py b/moban/_version.py index 557698b6..1a806ddf 100644 --- a/moban/_version.py +++ b/moban/_version.py @@ -1,2 +1,2 @@ -__version__ = "0.4.2" +__version__ = "0.4.3" __author__ = "C. W." diff --git a/setup.py b/setup.py index 813daf15..e8040d58 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ NAME = 'moban' AUTHOR = 'C. W.' -VERSION = '0.4.2' +VERSION = '0.4.3' EMAIL = 'wangc_2011@hotmail.com' LICENSE = 'MIT' ENTRY_POINTS = { From aa08103c289ccc398785b0116514b32ee1dfad3f Mon Sep 17 00:00:00 2001 From: chfw Date: Fri, 8 Mar 2019 20:10:53 +0000 Subject: [PATCH 3/8] :books: update our vision --- README.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 76ecd037..dfd13714 100644 --- a/README.rst +++ b/README.rst @@ -25,9 +25,13 @@ moban - 模板 Yet another jinja2 cli command for static text generation **moban** brings the high performance template engine (JINJA2) for web into -static text generation. It is used in pyexcel project to keep documentation +static text generation. It is used in `pyexcel` and `coala` project to keep documentation consistent across the documentations of individual libraries. +Our vision is: any template, any data. Our current architecture enables moban +to plugin any python template engine: mako, handlebars, velocity, haml, slim and tornado +and to plugin any data format: json and yaml. Please look at our issues. We have many +more template engines and data format on the road map. Installation ================================================================================ From 84afbafb4989fa2810f9b347f64ec5e4db7d0414 Mon Sep 17 00:00:00 2001 From: jaska Date: Fri, 8 Mar 2019 22:23:15 +0000 Subject: [PATCH 4/8] check if git is available on non-win32 platform (#255) * :wheel_chair: tell user that you will need to have git for repo related features. fix #209 * :books: update change log --- .moban.cd/changelog.yml | 1 + CHANGELOG.rst | 2 ++ moban/exceptions.py | 4 ++++ moban/repo.py | 17 ++++++++++++++++- tests/mobanfile/test_targets.py | 2 +- tests/test_repo.py | 16 ++++++++++++++-- 6 files changed, 38 insertions(+), 4 deletions(-) diff --git a/.moban.cd/changelog.yml b/.moban.cd/changelog.yml index 24d27822..9c726859 100644 --- a/.moban.cd/changelog.yml +++ b/.moban.cd/changelog.yml @@ -5,6 +5,7 @@ releases: - action: Removed details: - "`#253`: symbolic link in regression pack causes python setup.py to do recursive include" + - "`#209`: Alert moban user when `git` is not available and is used." date: unreleased version: 0.4.3 - changes: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d458e558..58502302 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,8 @@ Removed #. `#253 `_: symbolic link in regression pack causes python setup.py to do recursive include +#. `#209 `_: Alert moban user + when `git` is not available and is used. 0.4.2 - 08.03.2019 -------------------------------------------------------------------------------- diff --git a/moban/exceptions.py b/moban/exceptions.py index c0ab48b9..f214acba 100644 --- a/moban/exceptions.py +++ b/moban/exceptions.py @@ -24,3 +24,7 @@ class IncorrectDataInput(Exception): class GroupTargetNotFound(Exception): pass + + +class NoGitCommand(Exception): + pass diff --git a/moban/repo.py b/moban/repo.py index 36da0582..615a2a5a 100644 --- a/moban/repo.py +++ b/moban/repo.py @@ -1,12 +1,20 @@ import os +import sys +import subprocess -from moban import reporter, constants +from moban import reporter, constants, exceptions from moban.utils import mkdir_p def git_clone(requires): from git import Repo + if sys.platform != "win32": + # Unfortunately for windows user, the following function + # needs shell=True, which expose security risk. I would + # rather not to trade it with its marginal benefit + make_sure_git_is_available() + moban_home = get_moban_home() mkdir_p(moban_home) @@ -51,3 +59,10 @@ def get_moban_home(): home_dir = user_cache_dir(appname=constants.PROGRAM_NAME) return os.path.join(home_dir, constants.MOBAN_REPOS_DIR_NAME) + + +def make_sure_git_is_available(): + try: + subprocess.check_output(["git", "--help"]) + except Exception: + raise exceptions.NoGitCommand("Please install git command") diff --git a/tests/mobanfile/test_targets.py b/tests/mobanfile/test_targets.py index e239ea83..81dd1139 100644 --- a/tests/mobanfile/test_targets.py +++ b/tests/mobanfile/test_targets.py @@ -37,7 +37,7 @@ def test_handling_group_target(): def test_extract_group_targets(): test_targets = [ {"output": "a.output", "template": "a.template.jj2"}, - {"copy": [{"output": "source"}], "copy1": [{"output1": "source1"}]} + {"copy": [{"output": "source"}], "copy1": [{"output1": "source1"}]}, ] actual = targets.extract_group_targets("copy1", test_targets) expected = [{"copy1": [{"output1": "source1"}]}] diff --git a/tests/test_repo.py b/tests/test_repo.py index c180c18f..4d219d3a 100644 --- a/tests/test_repo.py +++ b/tests/test_repo.py @@ -1,9 +1,15 @@ import os from mock import patch -from nose.tools import eq_ +from nose.tools import eq_, raises -from moban.repo import git_clone, get_repo_name, get_moban_home +from moban.repo import ( + git_clone, + get_repo_name, + get_moban_home, + make_sure_git_is_available, +) +from moban.exceptions import NoGitCommand from moban.definitions import GitRequire @@ -112,3 +118,9 @@ def test_get_repo_name_can_handle_invalid_url(fake_reporter): def test_get_moban_home(_): actual = get_moban_home() eq_(os.path.join("root", "repos"), actual) + + +@raises(NoGitCommand) +@patch("subprocess.check_output", side_effect=Exception) +def test_make_git_is_available(_): + make_sure_git_is_available() From a133fd286f42c4a714c14b2a78145eed5a3a934b Mon Sep 17 00:00:00 2001 From: chfw Date: Sat, 9 Mar 2019 18:37:10 +0000 Subject: [PATCH 5/8] :fire: remove deprecated copy syntax --- docs/index.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index f95acb7c..ace1fb1b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -35,13 +35,6 @@ examples folder. level-18-user-defined-template-types/README.rst level-19-moban-a-sub-group-in-targets/README.rst -In pratice, the following use cases were found interesting to go along with. - -.. toctree:: - :maxdepth: 1 - - misc-1-copying-templates/README.rst - For more complex use case, please look at `its usage in pyexcel project `_ From 5b319c7f192205283bf66ae70f1f37334de20e32 Mon Sep 17 00:00:00 2001 From: jaska Date: Mon, 11 Mar 2019 18:03:14 +0000 Subject: [PATCH 6/8] Only the template engine sequence (#262) * :sparkles: respect appearance sequence * :microscope: test the sequence * :newspaper: add missing file * :books: update change log. #261 --- .moban.cd/changelog.yml | 1 + CHANGELOG.rst | 3 ++ moban/mobanfile/__init__.py | 7 +++- tests/fixtures/mobanfile/a.template.jj2 | 0 tests/fixtures/mobanfile/filterme.handlebars | 0 tests/mobanfile/test_mobanfile.py | 42 ++++++++++++++++++++ 6 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/mobanfile/a.template.jj2 create mode 100644 tests/fixtures/mobanfile/filterme.handlebars diff --git a/.moban.cd/changelog.yml b/.moban.cd/changelog.yml index 9c726859..b05c6e39 100644 --- a/.moban.cd/changelog.yml +++ b/.moban.cd/changelog.yml @@ -6,6 +6,7 @@ releases: details: - "`#253`: symbolic link in regression pack causes python setup.py to do recursive include" - "`#209`: Alert moban user when `git` is not available and is used." + - "`#261`: since moban group template files per template type, this fill use first come first register to order moban group" date: unreleased version: 0.4.3 - changes: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 58502302..ead5bd11 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,9 @@ Removed regression pack causes python setup.py to do recursive include #. `#209 `_: Alert moban user when `git` is not available and is used. +#. `#261 `_: since moban group + template files per template type, this fill use first come first register to + order moban group 0.4.2 - 08.03.2019 -------------------------------------------------------------------------------- diff --git a/moban/mobanfile/__init__.py b/moban/mobanfile/__init__.py index e788eaf9..dd3a33a7 100644 --- a/moban/mobanfile/__init__.py +++ b/moban/mobanfile/__init__.py @@ -1,7 +1,7 @@ import os import re import sys -from collections import defaultdict +from collections import OrderedDict from lml.utils import do_import @@ -112,7 +112,7 @@ def _iterate_list_of_dicts(list_of_dict): def handle_targets(merged_options, targets): list_of_templating_parameters = parse_targets(merged_options, targets) - jobs_for_each_engine = defaultdict(list) + jobs_for_each_engine = OrderedDict() for target in list_of_templating_parameters: forced_template_type = merged_options.get( @@ -129,6 +129,9 @@ def handle_targets(merged_options, targets): ] target.set_template_type(primary_template_type) + if primary_template_type not in jobs_for_each_engine: + jobs_for_each_engine[primary_template_type] = [] + jobs_for_each_engine[primary_template_type].append(target) count = 0 diff --git a/tests/fixtures/mobanfile/a.template.jj2 b/tests/fixtures/mobanfile/a.template.jj2 new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/mobanfile/filterme.handlebars b/tests/fixtures/mobanfile/filterme.handlebars new file mode 100644 index 00000000..e69de29b diff --git a/tests/mobanfile/test_mobanfile.py b/tests/mobanfile/test_mobanfile.py index 0786108d..d30f79d1 100644 --- a/tests/mobanfile/test_mobanfile.py +++ b/tests/mobanfile/test_mobanfile.py @@ -143,3 +143,45 @@ def test_handle_targets(fake_renderer): ) ], ) + + +@patch("moban.plugins.template.MobanEngine.render_to_files") +def test_handle_targets_sequence(fake_renderer): + from moban.mobanfile import handle_targets + + TEMPLATE1 = "a.template.jj2" + OUTPUT1 = "filterme.handlebars" # in the future, this could dynamic output + OUTPUT2 = "filtered_output.txt" + CONFIGURATION = "child.yaml" + TEMPLATE_DIRS = [os.path.join("tests", "fixtures", "mobanfile")] + DEFAULT_TEMPLATE_TYPE = "jinja2" + + options = dict( + configuration=CONFIGURATION, + template_type=DEFAULT_TEMPLATE_TYPE, + template_dir=TEMPLATE_DIRS, + configuration_dir=os.path.join("tests", "fixtures"), + ) + short_hand_targets = [{OUTPUT1: TEMPLATE1}, {OUTPUT2: OUTPUT1}] + handle_targets(options, short_hand_targets) + + call_args = list(fake_renderer.call_args_list) + + eq_( + call_args[0][0][0][0], + TemplateTarget( + "a.template.jj2", + "child.yaml", + "filterme.handlebars", + template_type="jj2", + ), + ) + eq_( + call_args[1][0][0][0], + TemplateTarget( + "filterme.handlebars", + "child.yaml", + "filtered_output.txt", + template_type="handlebars", + ), + ) From 9cdcbc4d563ed5062d16fe0b6d8f06dc80eabd67 Mon Sep 17 00:00:00 2001 From: chfw Date: Fri, 15 Mar 2019 18:08:11 +0000 Subject: [PATCH 7/8] :egg: :ferris_wheel: release 0.4.3 --- .moban.cd/changelog.yml | 2 +- .moban.cd/moban.yml | 2 +- CHANGELOG.rst | 2 +- docs/conf.py | 2 +- setup.py | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.moban.cd/changelog.yml b/.moban.cd/changelog.yml index b05c6e39..8ac66abc 100644 --- a/.moban.cd/changelog.yml +++ b/.moban.cd/changelog.yml @@ -7,7 +7,7 @@ releases: - "`#253`: symbolic link in regression pack causes python setup.py to do recursive include" - "`#209`: Alert moban user when `git` is not available and is used." - "`#261`: since moban group template files per template type, this fill use first come first register to order moban group" - date: unreleased + date: 16.03.2019 version: 0.4.3 - changes: - action: Added diff --git a/.moban.cd/moban.yml b/.moban.cd/moban.yml index d8f5d578..83db1971 100644 --- a/.moban.cd/moban.yml +++ b/.moban.cd/moban.yml @@ -6,7 +6,7 @@ contact: wangc_2011@hotmail.com license: MIT version: 0.4.3 current_version: 0.4.3 -release: 0.4.2 +release: 0.4.3 branch: master master: index command_line_interface: "moban" diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ead5bd11..649aaa33 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,7 @@ Change log ================================================================================ -0.4.3 - unreleased +0.4.3 - 16.03.2019 -------------------------------------------------------------------------------- Removed diff --git a/docs/conf.py b/docs/conf.py index 00ac05ce..125a3cbe 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,7 +27,7 @@ # The short X.Y version version = '0.4.3' # The full version, including alpha/beta/rc tags -release = '0.4.2' +release = '0.4.3' # -- General configuration --------------------------------------------------- diff --git a/setup.py b/setup.py index e8040d58..18a73dd6 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ 'Yet another jinja2 cli command for static text generation' ) URL = 'https://github.com/moremoban/moban' -DOWNLOAD_URL = '%s/archive/0.4.2.tar.gz' % URL +DOWNLOAD_URL = '%s/archive/0.4.3.tar.gz' % URL FILES = ['README.rst', 'CONTRIBUTORS.rst', 'CHANGELOG.rst'] KEYWORDS = [ 'python', @@ -79,8 +79,8 @@ # You do not need to read beyond this line PUBLISH_COMMAND = '{0} setup.py sdist bdist_wheel upload -r pypi'.format( sys.executable) -GS_COMMAND = ('gs moban v0.4.2 ' + - "Find 0.4.2 in changelog for more details") +GS_COMMAND = ('gs moban v0.4.3 ' + + "Find 0.4.3 in changelog for more details") NO_GS_MESSAGE = ('Automatic github release is disabled. ' + 'Please install gease to enable it.') UPLOAD_FAILED_MSG = ( From 01599bad43946fc624e1d3bd05e09079cf21d9fe Mon Sep 17 00:00:00 2001 From: chfw Date: Fri, 15 Mar 2019 18:25:31 +0000 Subject: [PATCH 8/8] :books: update change log --- .moban.cd/changelog.yml | 4 ++++ CHANGELOG.rst | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/.moban.cd/changelog.yml b/.moban.cd/changelog.yml index 8ac66abc..89e2e37f 100644 --- a/.moban.cd/changelog.yml +++ b/.moban.cd/changelog.yml @@ -5,7 +5,11 @@ releases: - action: Removed details: - "`#253`: symbolic link in regression pack causes python setup.py to do recursive include" + - action: Added + details: - "`#209`: Alert moban user when `git` is not available and is used." + - action: Updated + details: - "`#261`: since moban group template files per template type, this fill use first come first register to order moban group" date: 16.03.2019 version: 0.4.3 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 649aaa33..a29335ca 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,8 +9,16 @@ Removed #. `#253 `_: symbolic link in regression pack causes python setup.py to do recursive include + +Added +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + #. `#209 `_: Alert moban user when `git` is not available and is used. + +Updated +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + #. `#261 `_: since moban group template files per template type, this fill use first come first register to order moban group