Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package gcil for openSUSE:Factory checked in at 2026-11-09 16:07:38 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/gcil (Old) and /work/SRC/openSUSE:Factory/.gcil.new.3759290 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "gcil" Mon Nov 9 16:07:38 2026 rev:5 rq:1396283 version:13.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/gcil/gcil.changes 2026-09-21 12:24:12.822785388 +0200 +++ /work/SRC/openSUSE:Factory/.gcil.new.3759290/gcil.changes 2026-11-09 16:08:44.514115784 +0100 @@ -1,0 +2,34 @@ +Sun Nov 8 09:45:06 UTC 2026 - Johannes Kastl <[email protected]> + +- update to 13.3.0: + * Features + - cli, menus: implement '--presets' to preselect jobs in menu + (e2928df) + - mise: avoid '--path' if already the default 'mise use' + configuration (3e152f0) + - updates: show 'mise use' update command if running from + 'mise' (117b2ab) + - updates: show 'mise use' update in the 'mise' configuration + of the tool (255cf86) + * Bug Fixes + - themes: resolve yellow color support on light theme UI + (4e0d170) + * Documentation + - mkdocs: exclude generated pages from + 'git-revision-date-localized' (6dd18c8) + - readme, prepare: link 'pipeline' badges to GitLab CI + pipelines page (330fe4a) + * Cleanups + - cliff: migrate 'cliff.toml' to 'conf/git-cliff/' folder + (60c051e) + - mise: create 'menu:gcil' task for 'gcil' use cases (45dfb35) + - mise: update 'changelog' task to generate with 'git-cliff' + (56c9af6) + - mise: remove 'gcil' task in favor of 'menu:gcil' (c0c0a91) + - pre-commit: migrate to 'pre-commit-crocodile' 8.4.0 (43fa2e7) + - pre-commit: migrate to 'pre-commit-crocodile' 9.0.0 (e5e136b) + * Build + - pages: install 'git-cliff' 2.14.1 through 'mise' from + 'extrepo' (7918741) + +------------------------------------------------------------------- Old: ---- gitlabci_local-13.2.0.tar.gz New: ---- gitlabci_local-13.3.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ gcil.spec ++++++ --- /var/tmp/diff_new_pack.JbDJDh/_old 2026-11-09 16:08:45.349150762 +0100 +++ /var/tmp/diff_new_pack.JbDJDh/_new 2026-11-09 16:08:45.351150846 +0100 @@ -17,7 +17,7 @@ Name: gcil -Version: 13.2.0 +Version: 13.3.0 Release: 0 Summary: Launch .gitlab-ci.yml jobs locally License: Apache-2.0 ++++++ gitlabci_local-13.2.0.tar.gz -> gitlabci_local-13.3.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/.gitlab-ci.yml new/gitlabci_local-13.3.0/.gitlab-ci.yml --- old/gitlabci_local-13.2.0/.gitlab-ci.yml 2026-09-19 19:10:29.335961300 +0200 +++ new/gitlabci_local-13.3.0/.gitlab-ci.yml 2026-11-08 01:01:01.307126500 +0100 @@ -1,5 +1,5 @@ include: - - component: gitlab.com/RadianDevCore/tools/pre-commit-crocodile/[email protected] + - component: gitlab.com/RadianDevCore/tools/pre-commit-crocodile/[email protected] inputs: stage: prepare - project: RadianDevCore/gitlab-ci/components @@ -100,7 +100,7 @@ stage: deploy image: registry.gitlab.com/radiandevcore/tools/gcil/gcil:pages pdf: gcil - watch: ./config/* ./docs/.* ./docs/* ./mkdocs.yml ./README.md + watch: ./conf/git-cliff/* ./docs/.* ./docs/* ./mkdocs.yml ./README.md stages: - development diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/.mise/tasks/gcil new/gitlabci_local-13.3.0/.mise/tasks/gcil --- old/gitlabci_local-13.2.0/.mise/tasks/gcil 2026-09-19 19:10:29.335961300 +0200 +++ new/gitlabci_local-13.3.0/.mise/tasks/gcil 1970-01-01 01:00:00.000000000 +0100 @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -# Mise -#MISE alias=["interactive"] -#MISE description="Interactive menu with gcil" - -# Action -gcil "${@}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/.mise/tasks/menu/gcil new/gitlabci_local-13.3.0/.mise/tasks/menu/gcil --- old/gitlabci_local-13.2.0/.mise/tasks/menu/gcil 1970-01-01 01:00:00.000000000 +0100 +++ new/gitlabci_local-13.3.0/.mise/tasks/menu/gcil 2026-11-08 01:01:01.307126500 +0100 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# Mise +#MISE alias=["interactive", "gcil"] +#MISE description="Interactive menu with gcil" + +# Action +gcil "${@}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/.mise/tasks/sources/changelog new/gitlabci_local-13.3.0/.mise/tasks/sources/changelog --- old/gitlabci_local-13.2.0/.mise/tasks/sources/changelog 2026-09-19 19:10:29.335961300 +0200 +++ new/gitlabci_local-13.3.0/.mise/tasks/sources/changelog 2026-11-08 01:01:01.307126500 +0100 @@ -15,18 +15,40 @@ if [ ! -z "${release_tag:-}" ]; then tag="${release_tag}" else - read -p ' > Release tag : ' -r tag + read -p ' > Release tag [ENTER to skip tag]: ' -r tag fi echo ' ' +# Prepare release tag +if [ ! -z "${tag}" ]; then + git tag -f -m "${tag}" "${tag}" +fi + +# Detect configuration +config='./conf/git-cliff/cliff.toml' +for path in ./conf/git-cliff/cliff.toml ./config/cliff.toml ./conf/cliff.toml; do + if [ -e "${path}" ]; then + config="${path}" + break + fi +done + # Generate changelog -git tag -f -m "${tag}" "${tag}" -git-cliff --no-exec --config ./config/cliff.toml --output ./CHANGELOG.md -sed -i "s#raw/[^/]*/docs#raw/${tag}/docs#g" ./README.md +git-cliff --no-exec --config "${config}" --output ./CHANGELOG.md +if [ ! -z "${tag}" ]; then + sed -i "s#raw/[^/]*/docs#raw/${tag}/docs#g" ./README.md +fi git add -v ./CHANGELOG.md ./README.md echo ' ' -git commit -m "docs(changelog): release version ${tag} and refresh changes history" -s +if [ ! -z "${tag}" ]; then + git commit -m "docs(changelog): release version ${tag} and refresh changes history" -s +else + version=$(git describe --abbrev=7 --always --long --tags) + git commit -m "docs(changelog): update to ${version} and refresh changes history" -s +fi echo ' ' # Create release tag -git tag -f -m "${tag}" "${tag}" +if [ ! -z "${tag}" ]; then + git tag -f -m "${tag}" "${tag}" +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/.pre-commit-config.yaml new/gitlabci_local-13.3.0/.pre-commit-config.yaml --- old/gitlabci_local-13.2.0/.pre-commit-config.yaml 2026-09-19 19:10:29.335961300 +0200 +++ new/gitlabci_local-13.3.0/.pre-commit-config.yaml 2026-11-08 01:01:01.307126500 +0100 @@ -9,8 +9,8 @@ - pre-commit - pre-push - prepare-commit-msg -minimum_pre_commit_version: 3.8.0 -minimum_prek_version: 0.2.1 +minimum_pre_commit_version: 4.6.2 +minimum_prek_version: 0.5.2 # pre-commit exclusions exclude: > @@ -45,6 +45,12 @@ hooks: - id: check-added-large-files args: ['--maxkb=500'] + # exclude: > + # (?x)( + # package-lock\.json$| + # pnpm-lock\.yaml$| + # yarn\.lock$ + # ) - id: check-case-conflict # exclude: > # (?x)( @@ -79,7 +85,7 @@ # Repository: commitizen - repo: https://github.com/commitizen-tools/commitizen - rev: v4.9.1 + rev: v4.19.3 hooks: - id: commitizen stages: @@ -92,7 +98,7 @@ # Repository: pre-commit-crocodile - repo: https://gitlab.com/RadianDevCore/tools/pre-commit-crocodile - rev: 8.2.0 + rev: 9.0.0 hooks: - id: check-yaml-ruamel-pure - id: prepare-commit-message diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/CHANGELOG.md new/gitlabci_local-13.3.0/CHANGELOG.md --- old/gitlabci_local-13.2.0/CHANGELOG.md 2026-09-19 19:10:29.336961300 +0200 +++ new/gitlabci_local-13.3.0/CHANGELOG.md 2026-11-08 01:01:01.309126400 +0100 @@ -1,5 +1,38 @@ # Changelog +<a name="13.3.0"></a> +## [13.3.0](https://gitlab.com/RadianDevCore/tools/gcil/compare/13.2.0...13.3.0) (2026-11-07) + +### โจ Features + +- **cli, menus:** implement '--presets' to preselect jobs in menu ([e2928df](https://gitlab.com/RadianDevCore/tools/gcil/commit/e2928dfb3cb21f008659e8c4a218bcf505c27667)) +- **mise:** avoid '--path' if already the default 'mise use' configuration ([3e152f0](https://gitlab.com/RadianDevCore/tools/gcil/commit/3e152f08c72a05165c9b0cefc7e1d5a40ce25222)) +- **updates:** show 'mise use' update command if running from 'mise' ([117b2ab](https://gitlab.com/RadianDevCore/tools/gcil/commit/117b2ab8c849a5fddc7b298cd02af8280559d92b)) +- **updates:** show 'mise use' update in the 'mise' configuration of the tool ([255cf86](https://gitlab.com/RadianDevCore/tools/gcil/commit/255cf86efbbe30a57de77200ad27e992d3d0318b)) + +### ๐ Bug Fixes + +- **themes:** resolve yellow color support on light theme UI ([4e0d170](https://gitlab.com/RadianDevCore/tools/gcil/commit/4e0d1702307609965b362707aacf829cdc31ea27)) + +### ๐ Documentation + +- **mkdocs:** exclude generated pages from 'git-revision-date-localized' ([6dd18c8](https://gitlab.com/RadianDevCore/tools/gcil/commit/6dd18c8d859450552ebfe7664cbf5a41293ed12d)) +- **readme, prepare:** link 'pipeline' badges to GitLab CI pipelines page ([330fe4a](https://gitlab.com/RadianDevCore/tools/gcil/commit/330fe4afcf9a5afe39ba01acb91bd65ece4928d1)) + +### โ๏ธ Cleanups + +- **cliff:** migrate 'cliff.toml' to 'conf/git-cliff/' folder ([60c051e](https://gitlab.com/RadianDevCore/tools/gcil/commit/60c051e2ce61c55e399be4739c129de398a93abd)) +- **mise:** create 'menu:gcil' task for 'gcil' use cases ([45dfb35](https://gitlab.com/RadianDevCore/tools/gcil/commit/45dfb3596163e84985882bc6ca4a55199199ea4b)) +- **mise:** update 'changelog' task to generate with 'git-cliff' ([56c9af6](https://gitlab.com/RadianDevCore/tools/gcil/commit/56c9af6bfb1416da2cb0d106605ef8b1b612daa5)) +- **mise:** remove 'gcil' task in favor of 'menu:gcil' ([c0c0a91](https://gitlab.com/RadianDevCore/tools/gcil/commit/c0c0a91cad477c2cbb5eddc0a9bc468f467bcccb)) +- **pre-commit:** migrate to 'pre-commit-crocodile' 8.4.0 ([43fa2e7](https://gitlab.com/RadianDevCore/tools/gcil/commit/43fa2e7c32c3c9da94579d863d71c40947055dcb)) +- **pre-commit:** migrate to 'pre-commit-crocodile' 9.0.0 ([e5e136b](https://gitlab.com/RadianDevCore/tools/gcil/commit/e5e136be51b0ed66ef7f83bc6c54a2a916e28b41)) + +### ๐ฆ Build + +- **pages:** install 'git-cliff' 2.14.1 through 'mise' from 'extrepo' ([7918741](https://gitlab.com/RadianDevCore/tools/gcil/commit/7918741ad411616b0916de5e67c5945f354d56d5)) + + <a name="13.2.0"></a> ## [13.2.0](https://gitlab.com/RadianDevCore/tools/gcil/compare/13.1.0...13.2.0) (2026-09-19) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/PKG-INFO new/gitlabci_local-13.3.0/PKG-INFO --- old/gitlabci_local-13.2.0/PKG-INFO 2026-09-19 19:10:32.325950100 +0200 +++ new/gitlabci_local-13.3.0/PKG-INFO 2026-11-08 01:01:05.387138000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: gitlabci-local -Version: 13.2.0 +Version: 13.3.0 Summary: Launch .gitlab-ci.yml jobs locally Home-page: https://gitlab.com/RadianDevCore/tools/gcil Author: Adrian DC @@ -61,7 +61,7 @@ [](https://pypi.org/project/gitlabci-local) [](https://gitlab.com/RadianDevCore/tools/gcil/-/blob/main/LICENSE) <br /> -[](https://gitlab.com/RadianDevCore/tools/gcil/-/commits/main/) +[](https://gitlab.com/RadianDevCore/tools/gcil/-/pipelines?ref=main) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) @@ -97,7 +97,7 @@ ## Preview - + --- @@ -111,6 +111,7 @@ gcil # Launch the jobs choices interactive menu gcil -p # Launch the jobs pipeline automatically gcil -l # Launch the job selection interactive menu +gcil -P 'Job 1' # Launch the jobs choices menu with 'Job 1' preselected gcil 'Dev' # Launch jobs where the name contains a given string gcil --debug 'Job 1' # Hold a finishing specific job for debugging gcil --bash 'Job 1' # Prepare a bash environment for a specific job @@ -132,7 +133,7 @@ [--privileged [BOOL]] [--random-paths] [-r] [-S] [--ssh [SSH_USER]] [-v VOLUME] [-w WORKDIR] [--bash | --debug] [--display] [--shell SHELL] [--all] [--configure] [--input KEY=VAL] [-f] [-i] [-m] [--no-console] [--no-git-safeties] [--no-script-fail] [-R] [--no-verbose] [--scripts] [-t TAGS] - [-d | -s | -l | --pull | --rmi] [--] + [-d | -s | -P | -l | --pull | --rmi] [--] [names ...] gcil: Launch .gitlab-ci.yml jobs locally (aliases: gitlabci-local) @@ -199,6 +200,7 @@ features arguments: -d, --dump # Dump parsed .gitlab-ci.yml configuration -s, --select # Force jobs selection from enumerated names + -P, --presets # Select jobs with preset names -l, --list # Select one job to run (implies --manual) --pull # Pull container images from jobs --rmi # Delete container images from jobs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/README.md new/gitlabci_local-13.3.0/README.md --- old/gitlabci_local-13.2.0/README.md 2026-09-19 19:10:29.336961300 +0200 +++ new/gitlabci_local-13.3.0/README.md 2026-11-08 01:01:01.309126400 +0100 @@ -7,7 +7,7 @@ [](https://pypi.org/project/gitlabci-local) [](https://gitlab.com/RadianDevCore/tools/gcil/-/blob/main/LICENSE) <br /> -[](https://gitlab.com/RadianDevCore/tools/gcil/-/commits/main/) +[](https://gitlab.com/RadianDevCore/tools/gcil/-/pipelines?ref=main) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) @@ -43,7 +43,7 @@ ## Preview - + --- @@ -57,6 +57,7 @@ gcil # Launch the jobs choices interactive menu gcil -p # Launch the jobs pipeline automatically gcil -l # Launch the job selection interactive menu +gcil -P 'Job 1' # Launch the jobs choices menu with 'Job 1' preselected gcil 'Dev' # Launch jobs where the name contains a given string gcil --debug 'Job 1' # Hold a finishing specific job for debugging gcil --bash 'Job 1' # Prepare a bash environment for a specific job @@ -78,7 +79,7 @@ [--privileged [BOOL]] [--random-paths] [-r] [-S] [--ssh [SSH_USER]] [-v VOLUME] [-w WORKDIR] [--bash | --debug] [--display] [--shell SHELL] [--all] [--configure] [--input KEY=VAL] [-f] [-i] [-m] [--no-console] [--no-git-safeties] [--no-script-fail] [-R] [--no-verbose] [--scripts] [-t TAGS] - [-d | -s | -l | --pull | --rmi] [--] + [-d | -s | -P | -l | --pull | --rmi] [--] [names ...] gcil: Launch .gitlab-ci.yml jobs locally (aliases: gitlabci-local) @@ -145,6 +146,7 @@ features arguments: -d, --dump # Dump parsed .gitlab-ci.yml configuration -s, --select # Force jobs selection from enumerated names + -P, --presets # Select jobs with preset names -l, --list # Select one job to run (implies --manual) --pull # Pull container images from jobs --rmi # Delete container images from jobs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/conf/git-cliff/cliff.toml new/gitlabci_local-13.3.0/conf/git-cliff/cliff.toml --- old/gitlabci_local-13.2.0/conf/git-cliff/cliff.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/gitlabci_local-13.3.0/conf/git-cliff/cliff.toml 2026-11-08 01:01:01.309126400 +0100 @@ -0,0 +1,100 @@ +# git-cliff ~ default configuration file +# https://git-cliff.org/docs/configuration + +[changelog] +# template for the changelog footer +header = """# Changelog""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +{% raw %}\n{% endraw %}\ +{% if version %}\ + <a name="{{version}}"></a> + {% if previous.version %}\ + ## [{{ version }}](<REPO>/compare/{{ previous.version }}...{{ version }}) ({{ timestamp | date(format="%Y-%m-%d") }}) + {% else %}\ + ## [{{ version }}](<REPO>/commits/{{ version }}) ({{ timestamp | date(format="%Y-%m-%d") }}) + {% endif %}\ +{% else %}\ + ## [Development](<REPO>/commits/main) ({{ commits | last | get(key='committer') | get(key='timestamp') | date(format="%Y-%m-%d") }}) +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits + | filter(attribute="scope") + | sort(attribute="scope") %} + - {% if commit.breaking %}**๐จ BREAKING CHANGE ๐จ |** {% endif %}\ + **{{commit.scope}}:** \ + {{ commit.message }} \ + ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }})) + {%- endfor -%} + {% raw %}\n{% endraw %}\ + {%- for commit in commits %} + {%- if commit.scope -%} + {% else -%} + - {% if commit.breaking %}**๐จ BREAKING CHANGE ๐จ |** {% endif %}\ + {{ commit.message }} \ + ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }})) + {% endif -%} + {% endfor -%} +{% endfor -%} +{% raw %}\n{% endraw %}\ +""" +# template for the changelog footer +footer = """""" +# remove the leading and trailing s +trim = true +# postprocessors +postprocessors = [ + { pattern = '<REPO>', replace = "https://gitlab.com/RadianDevCore/tools/gcil" }, # replace repository URL +] + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = true +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [ + # Replace issue numbers + #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"}, + # Check spelling of the commit with https://github.com/crate-ci/typos + # If the spelling is incorrect, it will be automatically fixed. + #{ pattern = '.*', replace_command = 'typos --write-changes -' }, +] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^security", group = "<!-- 01 -->๐ก๏ธ Security" }, + { body = ".*security", group = "<!-- 01 -->๐ก๏ธ Security" }, + { message = "^feat", group = "<!-- 02 -->โจ Features" }, + { message = "^fix", group = "<!-- 03 -->๐ Bug Fixes" }, + { message = "^refactor", group = "<!-- 04 -->๐ Code Refactoring" }, + { message = "^docs\\(changelog\\)", skip = true }, + { message = "^doc", group = "<!-- 05 -->๐ Documentation" }, + { message = "^perf", group = "<!-- 06 -->โก Performance Improvements" }, + { message = "^style", group = "<!-- 07 -->๐จ Styling" }, + { message = "^test", group = "<!-- 08 -->๐งช Test" }, + { message = "^chore", group = "<!-- 09 -->โ๏ธ Cleanups" }, + { message = "^ci", group = "<!-- 10 -->๐ CI" }, + { message = "^build", group = "<!-- 11 -->๐ฆ Build" }, + { message = "^revert", group = "<!-- 12 -->โ๏ธ Revert" }, + { message = "^wip", group = "<!-- 13 -->๐ง WIP" }, +] +# protect breaking changes from being skipped due to matching a skipping commit_parser +protect_breaking_commits = false +# filter out the commits that are not matched by commit parsers +filter_commits = false +# regex for matching git tags +# tag_pattern = "[0-9].*" +# regex for skipping tags +# skip_tags = "" +# regex for ignoring tags +ignore_tags = "" +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" +# limit the number of commits included in the changelog. +# limit_commits = 42 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/config/cliff.toml new/gitlabci_local-13.3.0/config/cliff.toml --- old/gitlabci_local-13.2.0/config/cliff.toml 2026-09-19 19:10:29.336961300 +0200 +++ new/gitlabci_local-13.3.0/config/cliff.toml 1970-01-01 01:00:00.000000000 +0100 @@ -1,100 +0,0 @@ -# git-cliff ~ default configuration file -# https://git-cliff.org/docs/configuration - -[changelog] -# template for the changelog footer -header = """# Changelog""" -# template for the changelog body -# https://keats.github.io/tera/docs/#introduction -body = """ -{% raw %}\n{% endraw %}\ -{% if version %}\ - <a name="{{version}}"></a> - {% if previous.version %}\ - ## [{{ version }}](<REPO>/compare/{{ previous.version }}...{{ version }}) ({{ timestamp | date(format="%Y-%m-%d") }}) - {% else %}\ - ## [{{ version }}](<REPO>/commits/{{ version }}) ({{ timestamp | date(format="%Y-%m-%d") }}) - {% endif %}\ -{% else %}\ - ## [Development](<REPO>/commits/main) ({{ commits | last | get(key='committer') | get(key='timestamp') | date(format="%Y-%m-%d") }}) -{% endif %}\ -{% for group, commits in commits | group_by(attribute="group") %} - ### {{ group | striptags | trim | upper_first }} - {% for commit in commits - | filter(attribute="scope") - | sort(attribute="scope") %} - - {% if commit.breaking %}**๐จ BREAKING CHANGE ๐จ |** {% endif %}\ - **{{commit.scope}}:** \ - {{ commit.message }} \ - ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }})) - {%- endfor -%} - {% raw %}\n{% endraw %}\ - {%- for commit in commits %} - {%- if commit.scope -%} - {% else -%} - - {% if commit.breaking %}**๐จ BREAKING CHANGE ๐จ |** {% endif %}\ - {{ commit.message }} \ - ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }})) - {% endif -%} - {% endfor -%} -{% endfor -%} -{% raw %}\n{% endraw %}\ -""" -# template for the changelog footer -footer = """""" -# remove the leading and trailing s -trim = true -# postprocessors -postprocessors = [ - { pattern = '<REPO>', replace = "https://gitlab.com/RadianDevCore/tools/gcil" }, # replace repository URL -] - -[git] -# parse the commits based on https://www.conventionalcommits.org -conventional_commits = true -# filter out the commits that are not conventional -filter_unconventional = true -# process each line of a commit as an individual commit -split_commits = false -# regex for preprocessing the commit messages -commit_preprocessors = [ - # Replace issue numbers - #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"}, - # Check spelling of the commit with https://github.com/crate-ci/typos - # If the spelling is incorrect, it will be automatically fixed. - #{ pattern = '.*', replace_command = 'typos --write-changes -' }, -] -# regex for parsing and grouping commits -commit_parsers = [ - { message = "^security", group = "<!-- 01 -->๐ก๏ธ Security" }, - { body = ".*security", group = "<!-- 01 -->๐ก๏ธ Security" }, - { message = "^feat", group = "<!-- 02 -->โจ Features" }, - { message = "^fix", group = "<!-- 03 -->๐ Bug Fixes" }, - { message = "^refactor", group = "<!-- 04 -->๐ Code Refactoring" }, - { message = "^docs\\(changelog\\)", skip = true }, - { message = "^doc", group = "<!-- 05 -->๐ Documentation" }, - { message = "^perf", group = "<!-- 06 -->โก Performance Improvements" }, - { message = "^style", group = "<!-- 07 -->๐จ Styling" }, - { message = "^test", group = "<!-- 08 -->๐งช Test" }, - { message = "^chore", group = "<!-- 09 -->โ๏ธ Cleanups" }, - { message = "^ci", group = "<!-- 10 -->๐ CI" }, - { message = "^build", group = "<!-- 11 -->๐ฆ Build" }, - { message = "^revert", group = "<!-- 12 -->โ๏ธ Revert" }, - { message = "^wip", group = "<!-- 13 -->๐ง WIP" }, -] -# protect breaking changes from being skipped due to matching a skipping commit_parser -protect_breaking_commits = false -# filter out the commits that are not matched by commit parsers -filter_commits = false -# regex for matching git tags -# tag_pattern = "[0-9].*" -# regex for skipping tags -# skip_tags = "" -# regex for ignoring tags -ignore_tags = "" -# sort the tags topologically -topo_order = false -# sort the commits inside sections by oldest/newest order -sort_commits = "oldest" -# limit the number of commits included in the changelog. -# limit_commits = 42 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/containers/pages/Dockerfile new/gitlabci_local-13.3.0/containers/pages/Dockerfile --- old/gitlabci_local-13.2.0/containers/pages/Dockerfile 2026-09-19 19:10:29.336961300 +0200 +++ new/gitlabci_local-13.3.0/containers/pages/Dockerfile 2026-11-08 01:01:01.309126400 +0100 @@ -4,12 +4,17 @@ # Install dependencies RUN apt update \ && apt install -y --no-install-recommends \ + extrepo \ + && extrepo enable mise \ + && apt update \ + && apt install -y --no-install-recommends \ entr \ git \ + mise \ wget \ - && wget -O ./git-cliff.deb -q https://github.com/orhun/git-cliff/releases/download/v2.5.0/git-cliff-2.5.0.deb \ - && apt install -y --no-install-recommends ./git-cliff.deb \ - && rm -f ./git-cliff.deb \ + && export MISE_DATA_DIR=/opt/mise \ + && mise use --global [email protected] \ + && ln -s "$(mise which git-cliff)" /usr/local/bin/git-cliff \ && rm -rf /var/lib/apt/lists/* # Install requirements diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/docs/deprecations.md new/gitlabci_local-13.3.0/docs/deprecations.md --- old/gitlabci_local-13.2.0/docs/deprecations.md 2026-09-19 19:10:29.337961200 +0200 +++ new/gitlabci_local-13.3.0/docs/deprecations.md 2026-11-08 01:01:01.310126500 +0100 @@ -12,7 +12,7 @@ [](https://pypi.org/project/gitlabci-local) [](https://gitlab.com/RadianDevCore/tools/gcil/-/blob/main/LICENSE) <br /> -[](https://gitlab.com/RadianDevCore/tools/gcil/-/commits/main/) +[](https://gitlab.com/RadianDevCore/tools/gcil/-/pipelines?ref=main) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/docs/gitlab-ci.md new/gitlabci_local-13.3.0/docs/gitlab-ci.md --- old/gitlabci_local-13.2.0/docs/gitlab-ci.md 2026-09-19 19:10:29.337961200 +0200 +++ new/gitlabci_local-13.3.0/docs/gitlab-ci.md 2026-11-08 01:01:01.310126500 +0100 @@ -7,7 +7,7 @@ [](https://pypi.org/project/gitlabci-local) [](https://gitlab.com/RadianDevCore/tools/gcil/-/blob/main/LICENSE) <br /> -[](https://gitlab.com/RadianDevCore/tools/gcil/-/commits/main/) +[](https://gitlab.com/RadianDevCore/tools/gcil/-/pipelines?ref=main) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/docs/hooks.md new/gitlabci_local-13.3.0/docs/hooks.md --- old/gitlabci_local-13.2.0/docs/hooks.md 2026-09-19 19:10:29.337961200 +0200 +++ new/gitlabci_local-13.3.0/docs/hooks.md 2026-11-08 01:01:01.310126500 +0100 @@ -7,7 +7,7 @@ [](https://pypi.org/project/gitlabci-local) [](https://gitlab.com/RadianDevCore/tools/gcil/-/blob/main/LICENSE) <br /> -[](https://gitlab.com/RadianDevCore/tools/gcil/-/commits/main/) +[](https://gitlab.com/RadianDevCore/tools/gcil/-/pipelines?ref=main) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/docs/prepare.sh new/gitlabci_local-13.3.0/docs/prepare.sh --- old/gitlabci_local-13.2.0/docs/prepare.sh 2026-09-19 19:10:29.337961200 +0200 +++ new/gitlabci_local-13.3.0/docs/prepare.sh 2026-11-08 01:01:01.310126500 +0100 @@ -94,7 +94,7 @@ echo 'pdf: false' echo '---' echo '' - git-cliff --no-exec --config "${root_path}/config/cliff.toml" \ + git-cliff --no-exec --config "${root_path}/conf/git-cliff/cliff.toml" \ | sed '/^- /{ s/</\</g; s/>/\>/g; }' } >"${docs_path}/about/changelog.md" diff -u "${root_path}/CHANGELOG.md" "${docs_path}/about/changelog.md" || true @@ -189,7 +189,7 @@ echo ' <b>GitLab</b>' echo ' </td>' echo ' <td>' - echo " <a href=\"${projectUrl}/-/commits/${branch}/\">" + echo " <a href=\"${projectUrl}/-/pipelines?ref=${branch}\">" echo " <img src=\"${projectUrl}/badges/${branch}/pipeline.svg\" alt=\"Build\" style=\"max-width: 100%;\">" echo ' </a>' echo " <a href=\"${projectUrl}/-/network/${branch}/\">" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/gitlabci_local.egg-info/PKG-INFO new/gitlabci_local-13.3.0/gitlabci_local.egg-info/PKG-INFO --- old/gitlabci_local-13.2.0/gitlabci_local.egg-info/PKG-INFO 2026-09-19 19:10:32.258950500 +0200 +++ new/gitlabci_local-13.3.0/gitlabci_local.egg-info/PKG-INFO 2026-11-08 01:01:05.263137600 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: gitlabci-local -Version: 13.2.0 +Version: 13.3.0 Summary: Launch .gitlab-ci.yml jobs locally Home-page: https://gitlab.com/RadianDevCore/tools/gcil Author: Adrian DC @@ -61,7 +61,7 @@ [](https://pypi.org/project/gitlabci-local) [](https://gitlab.com/RadianDevCore/tools/gcil/-/blob/main/LICENSE) <br /> -[](https://gitlab.com/RadianDevCore/tools/gcil/-/commits/main/) +[](https://gitlab.com/RadianDevCore/tools/gcil/-/pipelines?ref=main) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) [](https://sonarcloud.io/dashboard?id=RadianDevCore_gcil) @@ -97,7 +97,7 @@ ## Preview - + --- @@ -111,6 +111,7 @@ gcil # Launch the jobs choices interactive menu gcil -p # Launch the jobs pipeline automatically gcil -l # Launch the job selection interactive menu +gcil -P 'Job 1' # Launch the jobs choices menu with 'Job 1' preselected gcil 'Dev' # Launch jobs where the name contains a given string gcil --debug 'Job 1' # Hold a finishing specific job for debugging gcil --bash 'Job 1' # Prepare a bash environment for a specific job @@ -132,7 +133,7 @@ [--privileged [BOOL]] [--random-paths] [-r] [-S] [--ssh [SSH_USER]] [-v VOLUME] [-w WORKDIR] [--bash | --debug] [--display] [--shell SHELL] [--all] [--configure] [--input KEY=VAL] [-f] [-i] [-m] [--no-console] [--no-git-safeties] [--no-script-fail] [-R] [--no-verbose] [--scripts] [-t TAGS] - [-d | -s | -l | --pull | --rmi] [--] + [-d | -s | -P | -l | --pull | --rmi] [--] [names ...] gcil: Launch .gitlab-ci.yml jobs locally (aliases: gitlabci-local) @@ -199,6 +200,7 @@ features arguments: -d, --dump # Dump parsed .gitlab-ci.yml configuration -s, --select # Force jobs selection from enumerated names + -P, --presets # Select jobs with preset names -l, --list # Select one job to run (implies --manual) --pull # Pull container images from jobs --rmi # Delete container images from jobs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/gitlabci_local.egg-info/SOURCES.txt new/gitlabci_local-13.3.0/gitlabci_local.egg-info/SOURCES.txt --- old/gitlabci_local-13.2.0/gitlabci_local.egg-info/SOURCES.txt 2026-09-19 19:10:32.280950300 +0200 +++ new/gitlabci_local-13.3.0/gitlabci_local.egg-info/SOURCES.txt 2026-11-08 01:01:05.297137700 +0100 @@ -18,12 +18,12 @@ run.sh setup.py sonar-project.properties -.mise/tasks/gcil +.mise/tasks/menu/gcil .mise/tasks/sources/changelog .mise/tasks/sources/pull .vscode/extensions.json .vscode/settings.json -config/cliff.toml +conf/git-cliff/cliff.toml containers/build/Dockerfile containers/codestyle/Dockerfile containers/deploy/Dockerfile @@ -82,6 +82,7 @@ src/features/configurations.py src/features/images.py src/features/menus.py +src/features/mise.py src/features/pipelines.py src/jobs/__init__.py src/jobs/outputs.py @@ -113,6 +114,7 @@ src/prints/histories.py src/prints/themes.py src/system/__init__.py +src/system/commands.py src/system/git.py src/system/notify.py src/system/platform.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/gitlabci_local.egg-info/scm_file_list.json new/gitlabci_local-13.3.0/gitlabci_local.egg-info/scm_file_list.json --- old/gitlabci_local-13.2.0/gitlabci_local.egg-info/scm_file_list.json 2026-09-19 19:10:32.257950300 +0200 +++ new/gitlabci_local-13.3.0/gitlabci_local.egg-info/scm_file_list.json 2026-11-08 01:01:05.261137700 +0100 @@ -7,7 +7,7 @@ ".gitlab-ci.yml", ".gitmodules", ".markdownlint.json", - ".mise/tasks/gcil", + ".mise/tasks/menu/gcil", ".mise/tasks/sources/changelog", ".mise/tasks/sources/pull", ".pre-commit-config.yaml", @@ -19,7 +19,7 @@ "LICENSE", "README.md", "TEST.md", - "config/cliff.toml", + "conf/git-cliff/cliff.toml", "containers/build/Dockerfile", "containers/codestyle/Dockerfile", "containers/deploy/Dockerfile", @@ -76,6 +76,7 @@ "src/features/configurations.py", "src/features/images.py", "src/features/menus.py", + "src/features/mise.py", "src/features/pipelines.py", "src/jobs/__init__.py", "src/jobs/outputs.py", @@ -107,6 +108,7 @@ "src/prints/histories.py", "src/prints/themes.py", "src/system/__init__.py", + "src/system/commands.py", "src/system/git.py", "src/system/notify.py", "src/system/platform.py", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/gitlabci_local.egg-info/scm_version.json new/gitlabci_local-13.3.0/gitlabci_local.egg-info/scm_version.json --- old/gitlabci_local-13.2.0/gitlabci_local.egg-info/scm_version.json 2026-09-19 19:10:32.237950600 +0200 +++ new/gitlabci_local-13.3.0/gitlabci_local.egg-info/scm_version.json 2026-11-08 01:01:05.234137500 +0100 @@ -1,8 +1,8 @@ { - "tag": "13.2.0", + "tag": "13.3.0", "distance": 0, - "node": "g139222ce3c119b44d2a3ad34df2b017f569deb7a", + "node": "gf2db60f756ea3205325799db93794026c9c6a37c", "dirty": false, "branch": "HEAD", - "node_date": "2026-09-19" + "node_date": "2026-11-07" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/mkdocs.yml new/gitlabci_local-13.3.0/mkdocs.yml --- old/gitlabci_local-13.2.0/mkdocs.yml 2026-09-19 19:10:29.337961200 +0200 +++ new/gitlabci_local-13.3.0/mkdocs.yml 2026-11-08 01:01:01.311126500 +0100 @@ -82,6 +82,9 @@ html_report_dir: coverage-reports/html - git-revision-date-localized: enable_creation_date: true + exclude: + - about/* + - index.md fallback_to_build_date: true strict: false type: timeago diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/src/cli/entrypoint.py new/gitlabci_local-13.3.0/src/cli/entrypoint.py --- old/gitlabci_local-13.2.0/src/cli/entrypoint.py 2026-09-19 19:10:29.338961400 +0200 +++ new/gitlabci_local-13.3.0/src/cli/entrypoint.py 2026-11-08 01:01:01.312126400 +0100 @@ -147,6 +147,13 @@ options=options, ).select() + # Select jobs with presets + elif options.presets and interactive: + result = MenusFeature( + pipeline=pipeline, + options=options, + ).select() + # Launch pipeline or jobs elif options.pipeline or options.names: result = PipelinesFeature( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/src/cli/main.py new/gitlabci_local-13.3.0/src/cli/main.py --- old/gitlabci_local-13.2.0/src/cli/main.py 2026-09-19 19:10:29.338961400 +0200 +++ new/gitlabci_local-13.3.0/src/cli/main.py 2026-11-08 01:01:01.312126400 +0100 @@ -353,6 +353,13 @@ help='Force jobs selection from enumerated names', ) subgroup.add_argument( + '-P', + '--presets', + dest='presets', + action='store_true', + help='Select jobs with preset names', + ) + subgroup.add_argument( '-l', '--list', dest='list', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/src/features/menus.py new/gitlabci_local-13.3.0/src/features/menus.py --- old/gitlabci_local-13.2.0/src/features/menus.py 2026-09-19 19:10:29.338961400 +0200 +++ new/gitlabci_local-13.3.0/src/features/menus.py 2026-11-08 01:01:01.312126400 +0100 @@ -213,8 +213,20 @@ assert self.__pipeline is not None for job in self.__pipeline.jobs: + # Preset names + job_preset: bool = False + if self.__options.presets: + if self.__options.names and Lists.match( + self.__options.names, + self.__pipeline.jobs[job].stage + if self.__options.pipeline else job, + ignore_case=self.__options.ignore_case, + no_regex=self.__options.no_regex, + ): + job_preset = True + # Filter names - if self.__options.names: + elif self.__options.names: # Filter jobs list, pylint: disable=duplicate-code if not self.__options.pipeline and not Lists.match( @@ -283,7 +295,7 @@ title=f'{self.__pipeline.jobs[job].name}{tags}{job_details_string}', value=job, disabled=disabled, - checked=default_check, + checked=default_check or (job_preset and not disabled), shortcut_key=True, ) ] @@ -337,6 +349,9 @@ # Drop pipeline mode for jobs self.__options.pipeline = False + # Launch selected jobs only + self.__options.no_regex = True + # Footer print(' ') print(' ') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/src/features/mise.py new/gitlabci_local-13.3.0/src/features/mise.py --- old/gitlabci_local-13.2.0/src/features/mise.py 1970-01-01 01:00:00.000000000 +0100 +++ new/gitlabci_local-13.3.0/src/features/mise.py 2026-11-08 01:01:01.312126400 +0100 @@ -0,0 +1,244 @@ +#!/usr/bin/env python3 + +# Standard libraries +from json import loads +from os import environ +from pathlib import Path +from re import MULTILINE, search, sub +from typing import Any, Dict, List, Optional, Tuple + +# Components +from ..package.version import Version +from ..system.commands import Commands + +# Mise class +class Mise: + + # Constants + BACKEND_DEFAULT: str = 'pipx' + BACKENDS_PYTHON: List[str] = ['pipx', 'pypi'] + BINARY: str = 'mise' + CONFIG_FILE: str = 'config.toml' + ENV_CONFIG_DIR: str = 'MISE_CONFIG_DIR' + ENV_DATA_DIR: str = 'MISE_DATA_DIR' + ENV_GLOBAL_CONFIG_FILE: str = 'MISE_GLOBAL_CONFIG_FILE' + ENV_XDG_CONFIG_HOME: str = 'XDG_CONFIG_HOME' + INSTALLS: str = 'installs' + VERSION_LATEST: str = 'latest' + + # Arguments + @staticmethod + def arguments(config: str, specification: str = '') -> List[str]: + + # Use default configuration + if config and specification \ + and Path(config).expanduser().resolve() == Mise.target(specification): + return [] + + # Use global configuration + if config and Path(config).expanduser().resolve() == Mise.config_global(): + return [ + '--global', + ] + + # Use configuration file + if config: + return [ + '--path', + config, + ] + + # Use local configuration + return [] + + # Dependencies + @staticmethod + def dependencies( + binary: str, + package: str, + version: str = VERSION_LATEST, + ) -> Optional[bool]: + + # Variables + config: str + provided: str + tool: Optional[Tuple[str, str]] + + # Ignore missing mise + if not Mise.exists(): + return None + + # Detect packages + provided = Commands.output(Mise.BINARY, [ + 'which', + binary, + ], quiet=True) + tool = Mise.tool(provided) if provided else None # pragma: no cover + + # Upgrade packages + if provided and version == Mise.VERSION_LATEST: # pragma: no cover + return Commands.mise([ + 'upgrade', + tool[0] if tool else package, + ]) + + # Detect configuration file + if Mise.managed(): # pragma: no cover + config = Mise.config() + elif provided: # pragma: no cover + config = tool[1] if tool else '' + else: # pragma: no cover + return None + + # Install packages in the configuration file + specification: str = f'{package}@{version}' # pragma: no cover + return Commands.mise( # pragma: no cover + ['use'] + Mise.arguments(config, specification) + [specification]) + + # Configuration + @staticmethod + def config() -> str: + + # Detect configuration file + tool: Optional[Tuple[str, str]] = Mise.tool(Version.path()) + if tool: # pragma: no cover + return tool[1] + + # Fallback + return '' + + # Configuration global + @staticmethod + def config_global() -> Path: + + # Detect custom global configuration file + config_file: str = environ.get(Mise.ENV_GLOBAL_CONFIG_FILE, '') + if config_file: + return Path(config_file).expanduser().resolve() + + # Detect global configuration folder + config_dir: str = environ.get(Mise.ENV_CONFIG_DIR, '') + if not config_dir: + config_dir = str( + Path(environ.get(Mise.ENV_XDG_CONFIG_HOME, '~/.config')) / Mise.BINARY) + + # Result + return (Path(config_dir) / Mise.CONFIG_FILE).expanduser().resolve() + + # Exists + @staticmethod + def exists() -> bool: + + # Check if binary exists + return Commands.exists(Mise.BINARY) + + # Installation + @staticmethod + def installation() -> str: + + # Variables + parts = Path(Version.path()).parts + + # Detect custom mise installs + data_dir: str = environ.get(Mise.ENV_DATA_DIR, '') + if data_dir: + installs = Path(data_dir).expanduser().parts + (Mise.INSTALLS, ) + if parts[0:len(installs)] == installs and len(parts) > len(installs): + return parts[len(installs)] # pragma: no cover + + # Detect default mise installs + for index in range(len(parts) - 2): + if parts[index] == Mise.BINARY and parts[index + 1] == Mise.INSTALLS: + return parts[index + 2] # pragma: no cover + + # Fallback + return '' + + # Managed + @staticmethod + def managed() -> bool: + + # Check if running from mise + return bool(Mise.installation()) + + # Target + @staticmethod + def target(specification: str) -> Optional[Path]: + + # Detect default configuration file + output: str = Commands.output(Mise.BINARY, [ + 'use', + '--dry-run', + specification, + ], errors=True) + match = search( + r'^mise would \w+ (.+) \(', + sub(r'\x1b\[[0-9;]*m', '', output), + MULTILINE, + ) + if match: # pragma: no cover + return Path(match.group(1)).expanduser().resolve() + + # Fallback + return None + + # Tool + @staticmethod + def tool(path: str) -> Optional[Tuple[str, str]]: + + # Variables + resolved: Path = Path(path).resolve() + + # Find mise tool + for name, entries in Mise.tools().items(): # pragma: no cover + for entry in entries: + install: str = entry.get('install_path', '') + if not install: + continue + install_path: Path = Path(install).resolve() + if resolved == install_path or install_path in resolved.parents: + return name, str(entry.get('source', {}).get('path', '')) + + # Fallback + return None + + # Tools + @staticmethod + def tools() -> Dict[str, List[Dict[str, Any]]]: + + # Ignore missing mise + if not Mise.exists(): + return {} + + # Get current mise tools + try: + tools = loads( + Commands.output(Mise.BINARY, [ + 'ls', + '--current', + '--json', + ], quiet=True)) + if isinstance(tools, dict): # pragma: no cover + return tools + except ValueError: # pragma: no cover + pass + + # Fallback + return {} # pragma: no cover + + # Package + @staticmethod + def package(name: str) -> str: + + # Detect mise tool + tool: Optional[Tuple[str, str]] = Mise.tool(Version.path()) + if tool: # pragma: no cover + return tool[0] + + # Detect mise backend + backend: str = Mise.installation().split('-', maxsplit=1)[0] + if backend not in Mise.BACKENDS_PYTHON: + backend = Mise.BACKEND_DEFAULT + + # Result + return f'{backend}:{name}' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/src/package/updates.py new/gitlabci_local-13.3.0/src/package/updates.py --- old/gitlabci_local-13.2.0/src/package/updates.py 2026-09-19 19:10:29.339961300 +0200 +++ new/gitlabci_local-13.3.0/src/package/updates.py 2026-11-08 01:01:01.313126600 +0100 @@ -3,13 +3,15 @@ # Standard libraries from datetime import datetime from os import access, environ, W_OK +from shlex import quote from time import localtime, strftime, time -from typing import Optional +from typing import Optional, Tuple # Modules libraries from packaging.version import Version as PackageVersion # Components +from ..features.mise import Mise from ..prints.boxes import Boxes from ..prints.colors import Colors from ..system.platform import Platform @@ -145,6 +147,42 @@ def enabled(self) -> bool: return self.__enabled + # Installer + @staticmethod + def installer(name: str, available: Optional[str]) -> Tuple[str, str]: + + # Detect package installer + package_install: str = '' + if Mise.managed(): + package_install = ' '.join(['mise', 'use'] + [ # pragma: no cover + quote(argument) for argument in Mise.arguments( + Mise.config(), + f'{Mise.package(name)}@latest', + ) + ]) + elif Platform.PATH_SEPARATOR + 'pipx' + Platform.PATH_SEPARATOR in Version.path(): + package_install = 'pipx upgrade' # pragma: no cover + else: + package_install = 'pip3 install -U' # pragma: no cover + + # Detect package ownership + writable = access(__file__, W_OK) + if not package_install.startswith('mise') and (Platform.IS_USER_SUDO + or not writable): + package_install = 'sudo ' + package_install # pragma: no cover + + # Prepare package specification + package_specification: str = '' + if package_install.startswith('mise'): + package_specification = f'{Mise.package(name)}@latest' # pragma: no cover + elif 'pipx' in package_install: + package_specification = f'{name}' # pragma: no cover + else: + package_specification = f'{name}>={available}' # pragma: no cover + + # Result + return package_install, package_specification + # Message, pylint: disable=too-many-arguments,too-many-positional-arguments @staticmethod def message( @@ -166,23 +204,10 @@ version = Version.get() # Detect package installer - package_install: str = '' - if Platform.PATH_SEPARATOR + 'pipx' + Platform.PATH_SEPARATOR in Version.path(): - package_install = 'pipx upgrade' # pragma: no cover - else: - package_install = 'pip3 install -U' # pragma: no cover - - # Detect package ownership - writable = access(__file__, W_OK) - if Platform.IS_USER_SUDO or not writable: - package_install = 'sudo ' + package_install # pragma: no cover - - # Prepare package specification - package_specification: str = '' - if 'pipx' in package_install: - package_specification = f'{name}' # pragma: no cover - else: - package_specification = f'{name}>={available}' # pragma: no cover + package_install, package_specification = Updates.installer( + name, + available, + ) # Evaluate same version same = available and available == version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/src/prints/themes.py new/gitlabci_local-13.3.0/src/prints/themes.py --- old/gitlabci_local-13.2.0/src/prints/themes.py 2026-09-19 19:10:29.339961300 +0200 +++ new/gitlabci_local-13.3.0/src/prints/themes.py 2026-11-08 01:01:01.314126500 +0100 @@ -30,11 +30,11 @@ # Colors enabled if Colors.enabled(): Themes.__bold = 'bold' - Themes.__cyan = '#00FFFF bold' + Themes.__cyan = 'ansicyan bold' Themes.__disabled = 'italic' - Themes.__green = '#00FF00 bold noreverse' + Themes.__green = 'ansigreen bold noreverse' Themes.__selected = 'bold noreverse' - Themes.__yellow = '#FFFF00 bold' + Themes.__yellow = 'ansiyellow bold' # Colors disabled else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/src/system/commands.py new/gitlabci_local-13.3.0/src/system/commands.py --- old/gitlabci_local-13.2.0/src/system/commands.py 1970-01-01 01:00:00.000000000 +0100 +++ new/gitlabci_local-13.3.0/src/system/commands.py 2026-11-08 01:01:01.314126500 +0100 @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 + +# Standard libraries +from pathlib import Path +from shutil import which +import subprocess +from typing import List, Optional + +# Commands +class Commands: + + # Exec + @staticmethod + def exec(binary: str, arguments: List[str]) -> int: + + # Run system command + try: + process = subprocess.run( + args=[binary] + arguments, + cwd=None, + check=False, + shell=False, + ) + return process.returncode + except subprocess.CalledProcessError as e: + print(f"Error executing command: {e}") + return 1 + + # Exists + @staticmethod + def exists(binary: str) -> bool: + + # Check system binary exists + return which(binary) is not None + + # Grep + @staticmethod + def grep(file: Path, string: str) -> bool: + + # Ignore missing file + if not file.exists(): + return False + + # Check file contains string + with open( + file, + encoding='utf8', + mode='r', + ) as f: + for line in f.readlines(): + + # Find string in line + if string in line: + return True + + # Fallback + return False # pragma: no cover + + # Mise + @staticmethod + def mise(arguments: List[str], check: bool = True) -> bool: + + # Run mise + return Commands.run( + 'mise', + arguments, + check, + ) + + # Output + @staticmethod + def output( + binary: str, + arguments: List[str], + quiet: bool = False, + errors: bool = False, + ) -> str: + + # Variables + stderr: Optional[int] = None + + # Redirect errors + if errors: + stderr = subprocess.STDOUT + elif quiet: + stderr = subprocess.DEVNULL + + # Get system output + try: + return subprocess.check_output( + args=[binary] + arguments, + cwd=None, + shell=False, + stderr=stderr, + ).strip().decode() + except subprocess.CalledProcessError as err: + return str(err.output.decode()) + except FileNotFoundError: + return '' + + # Pip + @staticmethod + def pip(arguments: List[str]) -> bool: + + # Run with pipx + if Commands.exists('pipx'): + return Commands.run( + 'pipx', + arguments, + ) + + # Run with pip # pragma: no cover + return Commands.run( + 'sudo', + ['pip'] + arguments, + ) + + # Run + @staticmethod + def run(binary: str, arguments: List[str], check: bool = True) -> bool: + + # Variables + stderr: Optional[int] = None if check else subprocess.DEVNULL + stdout: Optional[int] = None if check else subprocess.DEVNULL + + # Run system command + try: + process = subprocess.run( + args=[binary] + arguments, + cwd=None, + check=check, + shell=False, + stderr=stderr, + stdout=stdout, + ) + return process.returncode == 0 + except subprocess.CalledProcessError as e: + if check: + print(f"Error executing command: {e}") + return False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlabci_local-13.2.0/tests/menus/test.sh new/gitlabci_local-13.3.0/tests/menus/test.sh --- old/gitlabci_local-13.2.0/tests/menus/test.sh 2026-09-19 19:10:29.343961200 +0200 +++ new/gitlabci_local-13.3.0/tests/menus/test.sh 2026-11-08 01:01:01.320126500 +0100 @@ -16,6 +16,12 @@ pexpect-executor --press a --enter gcil pexpect-executor --press a --enter -- gcil -s 'Job 1' pexpect-executor --down --down --space --enter -- gcil -m +pexpect-executor --enter -- gcil -P 'Job 1' +pexpect-executor --enter -- gcil -m --presets 'Job 1' 'Job 3' +pexpect-executor --enter -- gcil -m -P 'Job.*[45]' +pexpect-executor --down --space --enter -- gcil -P -R 'Job 1' 'Job 2' +pexpect-executor --enter -- gcil -p -P menus-2 +pexpect-executor --space --enter -- gcil -P pexpect-executor --space --enter -- gcil -p -s pexpect-executor --space --enter -- gcil -p -s menus-1 pexpect-executor -- gcil -p -s menus-0
