{"id":16976154,"url":"https://github.com/ashvardanian/tinysemver","last_synced_at":"2025-03-17T08:38:04.620Z","repository":{"id":242576163,"uuid":"809217799","full_name":"ashvardanian/tinysemver","owner":"ashvardanian","description":"Tiny Semantic Versioning (SemVer) library with LLMs and GitHub CI, that doesn't depend on 300K lines of JavaScript code and fits in a single Python file","archived":false,"fork":false,"pushed_at":"2025-01-13T19:53:11.000Z","size":103,"stargazers_count":21,"open_issues_count":3,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-15T15:49:59.674Z","etag":null,"topics":["devops","devops-tools","github-actions","llm","minimalist","openai-api","semantic-version","semantic-versioning"],"latest_commit_sha":null,"homepage":"https://github.com/marketplace/actions/tinysemver","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ashvardanian.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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":"2024-06-02T03:45:58.000Z","updated_at":"2025-02-01T17:24:06.000Z","dependencies_parsed_at":"2024-06-03T21:46:36.184Z","dependency_job_id":"41a99ba2-c4e0-4db4-83ee-bf192c6c68c5","html_url":"https://github.com/ashvardanian/tinysemver","commit_stats":null,"previous_names":["ashvardanian/tinysemver"],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashvardanian%2Ftinysemver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashvardanian%2Ftinysemver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashvardanian%2Ftinysemver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashvardanian%2Ftinysemver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ashvardanian","download_url":"https://codeload.github.com/ashvardanian/tinysemver/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243853668,"owners_count":20358455,"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","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":["devops","devops-tools","github-actions","llm","minimalist","openai-api","semantic-version","semantic-versioning"],"created_at":"2024-10-14T01:25:07.127Z","updated_at":"2025-03-17T08:38:04.605Z","avatar_url":"https://github.com/ashvardanian.png","language":"Python","readme":"![TinySemVer Banner](https://github.com/ashvardanian/ashvardanian/blob/master/repositories/TinySemVer.jpg)\n\n__TinySemVer__ is a minimalistic [Semantic Versioning](https://semver.org/) package for projects following [Conventional Commits](https://www.conventionalcommits.org/) in a single short Python file, capable of generating changelogs and release notes with the use of OpenAI-compatible LLM APIs, or without them.\nIn plain English, if your commit messages look like `feat: add new feature` or `fix: bugfix`, this package will automate releasing new \"GIT tags\" based on the commit messages.\nHere is how to integrate it into your project CI:\n\n```sh\n$ pip install tinysemver\n$ tinysemver --dry-run --verbose\n\u003e Current version: 1.2.2\n\u003e Next version: 1.3.0\n```\n\nThe `--dry-run` flag will only print the next version without changing any files.\nGreat for pre-release CI pipelines.\n\n## Usage Details for the Command Line Interface\n\nIf you need more control over the default specification, here are more options you can run against the files in this repository:\n\n```sh\n# This won't push\n$ tinysemver --verbose \\\n    --major-verbs 'breaking,break,major' \\\n    --minor-verbs 'feature,minor,add,new' \\\n    --patch-verbs 'fix,patch,bug,improve,docs,make' \\\n    --changelog-file 'CHANGELOG.md' \\\n    --version-file 'VERSION' \\\n    --update-version-in 'pyproject.toml' '^version = \"(\\d+\\.\\d+\\.\\d+)\"' \\\n    --github-repository 'ashvardanian/tinysemver'\n# Revert to the previous commit\n$ git reset --soft HEAD~1                         \n```\n\nIt's recommended to use strict version matching with `\\d+\\.\\d+\\.\\d+` instead of a generic wildcard like `.*`, but both would work.\nHere is an example of passing even more parameters for a project like `stringzilla`:\n\n```sh\n$ tinysemver --verbose \\\n    --major-verbs 'breaking,break,major' \\\n    --minor-verbs 'feature,minor,add,new' \\\n    --patch-verbs 'fix,patch,bug,improve,docs,make' \\\n    --changelog-file 'CHANGELOG.md' \\\n    --version-file 'VERSION' \\\n    --update-version-in 'pyproject.toml' '^version = \"(\\d+\\.\\d+\\.\\d+)\"' \\\n    --update-version-in 'package.json' '\"version\": \"(.*)\"' \\\n    --update-version-in 'CITATION.cff' '^version: (.*)' \\\n    --update-major-version-in 'include/stringzilla/stringzilla.h' '^#define STRINGZILLA_VERSION_MAJOR (.*)' \\\n    --update-minor-version-in 'include/stringzilla/stringzilla.h' '^#define STRINGZILLA_VERSION_MINOR (.*)' \\\n    --update-patch-version-in 'include/stringzilla/stringzilla.h' '^#define STRINGZILLA_VERSION_PATCH (.*)' \\\n    --github-repository 'ashvardanian/stringzilla' \\\n    --push\n\u003e Current version: 1.2.2\n\u003e ? Commits since last tag: 3                   # Only in verbose mode\n\u003e # 5579972: Improve: Log file patches          # Only in verbose mode\n\u003e # de645ea: Improve: Grouping CHANGELOG        # Only in verbose mode\n\u003e Next version: 1.3.0\n\u003e Will update file: VERSION:0\n\u003e - 1.2.2                                       # Only in verbose mode\n\u003e + 1.3.0                                       # Only in verbose mode\n\u003e Will update file: package.json:5\n\u003e - \"version\": \"1.2.2\"                          # Only in verbose mode\n\u003e + \"version\": \"1.3.0\"                          # Only in verbose mode\n\u003e Will update file: pyproject.toml:7\n\u003e - version = \"1.2.2\"                           # Only in verbose mode\n\u003e + version = \"1.3.0\"                           # Only in verbose mode\n\u003e Will update file: CITATION.cff:7\n\u003e - version: 1.2.2                              # Only in verbose mode\n\u003e + version: 1.3.0                              # Only in verbose mode\n\u003e Appending to changelog file: CHANGELOG.md\n\u003e = skipping 250 lines                          # Only in verbose mode\n\u003e + adding 30 lines                             # Only in verbose mode\n```\n\nAlternatively, you can just ask for `--help`:\n\n```sh\n$ tinysemver --help\n```\n\n## AI and Rock-n-Roll\n\nTinySemVer can leverage a language model to validate the commits and generate clean and infromative release notes.\n\n```sh\n$ tinysemver --verbose \\\n    --github-repository 'ashvardanian/tinysemver' \\\n    --openai-base-url 'https://api.groq.com/openai/v1' \\\n    --openai-api-key 'GET_YOURSELF_A_KEY' \\\n    --openai-model 'llama-3.2-11b-text-preview' \\\n    --dry-run\n```\n\n## Usage Details for the GitHub CI Action\n\nTinySemVer can be easily integrated into your GitHub Actions CI pipeline.\nAssuming the differences between YAML and shell notation, some arguments are passed in a different form, like `--update-version-in`.\n\n```yaml\nname: Release\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  semver:\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v4\n      with:\n        persist-credentials: false # Only if main branch if protected\n\n    - name: Run TinySemVer\n      uses: ashvardanian/tinysemver@v2.0.1\n      with:\n        major-verbs: 'breaking,break,major'\n        minor-verbs: 'feature,minor,add,new'\n        patch-verbs: 'fix,patch,bug,improve,docs,make'\n        changelog-file: 'CHANGELOG.md'\n        version-file: 'VERSION'\n        update-version-in: 'pyproject.toml:version = \"(.*)\"' # Use colon instead of space\n        git-user-name: 'GitHub Actions'\n        git-user-email: 'actions@github.com'\n        github-token: ${{ secrets.GITHUB_TOKEN }}\n        verbose: 'true'\n        push: 'true'\n        create-release: 'true'\n        dry-run: 'false'\n\n  publish:\n    needs: semver # Depends on the previous job\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: main # Take the most recent updated version\n```\n\nEvery team has a different workflow, but a common pattern is to have one `release.yml` for the `main` branch and another `prerelease.yml` for the `main-dev` branch used as a staging area.\nThe latter would run with `dry-run: 'true'` and `push: 'false'` to prevent pushing changes to the main repository.\nThe `create-release` flag is optional and can be set to `false` if you don't want to create a new release on GitHub.\nIf you need to update the version in multiple files, pass a multiline string with the `|` operator:\n\n```yaml\n        update-version-in: |\n          pyproject.toml:version = \"(.*)\"\n          package.json:\"version\": \"(.*)\"\n          CITATION.cff:version: \"(.*)\"\n```\n\nFor examples, consider checking StringZilla, USearch, and other libraries using TinySemVer.\n\n### Security Considerations\n\nIf your default branch is protected with a \"pull request before merging\" rule:\n\n1. A repository-scoped Personal Access Token (PAT) is required to push to the branch.\n2. Set `persist-credentials: false` in the `actions/checkout` step.\n\nAlso keep in mind:\n\n- The default `GITHUB_TOKEN` cannot be used with protected branches.\n- Using a PAT instead of `GITHUB_TOKEN` poses security risks:\n  - Workflows from any branch can access secret variables.\n  - This could allow non-protected branches to use elevated permissions.\n- Mitigation:\n  - Use a fine-grained PAT with minimal necessary permissions.\n  - Prefer the `pull_request` workflow trigger, which limits permissions.\n  - Be cautious: users with write access could still potentially exploit workflows to expose the PAT.\n\n\u003e [!TIP]\n\u003e Always follow the principle of least privilege when setting up tokens and permissions.\n\nFor more information on CI configurations and pushing changes in GitHub Actions, see the [semantic-release GitHub Actions guide](https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/ci-configurations/github-actions.md#pushing-packagejson-changes-to-a-master-branch).\n\n## Why Create Another SemVer Tool?\n\nIn the past I was using [semantic-release](https://github.com/semantic-release/semantic-release) for my 10+ projects.\nAt some point, a breaking change in the dependencies broke all my projects CI pipelines for a month, affecting dozens of tech companies using those libraries.\nI felt miserable trying to trace the issue and reluctant to go through __363K lines of low-quality JavaScript code__ to find the bug.\nYes, it's 363K lines of code:\n\n```sh\n$ .../node_modules$ cloc .\n   10751 text files.\n    7809 unique files.                                          \n    3498 files ignored.\n\ngithub.com/AlDanial/cloc v 1.90  T=2.96 s (2450.6 files/s, 300331.1 lines/s)\n--------------------------------------------------------------------------------\nLanguage                      files          blank        comment           code\n--------------------------------------------------------------------------------\nJavaScript                     4902          48080          81205         363424\nTypeScript                      732           7008          73034          79367\n...                             ...            ...            ...            ...\n--------------------------------------------------------------------------------\nSUM:                           7256          90782         164390         634071\n--------------------------------------------------------------------------------\n```\n\nHere is the `cloc` output for `tinysemver`:\n\n```sh\n$ tinysemver$ cloc .\n      17 text files.\n      13 unique files.                              \n       6 files ignored.\n\ngithub.com/AlDanial/cloc v 1.96  T=0.01 s (660.7 files/s, 44267.6 lines/s)\n-------------------------------------------------------------------------------\nLanguage                     files          blank        comment           code\n-------------------------------------------------------------------------------\nPython                           1             79             93            493\n...                            ...            ...            ...            ...\n-------------------------------------------------------------------------------\nSUM:                            13            227            107           1124\n-------------------------------------------------------------------------------\n```\n\n## What's Missing?\n\n- Optional commit scopes, like `feat(scope): add new feature`. Doesn't make sense for most projects.\n- Pre-release versions, like `1.2.3-alpha.1`. Not needed for most projects.\n- GenAI.\n\n\u003e For reference, according to SemVer 2.0, all [following versions](https://regex101.com/r/Ly7O1x/3/) are valid: `1.1.2-prerelease+meta`, `1.1.2+meta`, `1.1.2+meta-valid`, `1.0.0-alpha`, `1.0.0-beta`, `1.0.0-alpha.beta.1`, `1.0.0-alpha.1`, `1.0.0-alpha0.valid`, `1.0.0-alpha.0valid`, `1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay`, `1.0.0-rc.1+build.1`, `2.0.0-rc.1+build.123`, `1.2.3-beta`, `10.2.3-DEV-SNAPSHOT`, `1.2.3-SNAPSHOT-123`, `2.0.0+build.1848`, `2.0.1-alpha.1227`, `1.0.0-alpha+beta`, `1.2.3----RC-SNAPSHOT.12.9.1--.12+788`, `1.2.3----R-S.12.9.1--.12+meta`, `1.2.3----RC-SNAPSHOT.12.9.1--.12`, `1.0.0+0.build.1-rc.10000aaa-kk-0.1`, `1.0.0-0A.is.legal`.\n\n## Examples\n\nAssembling RegEx queries can be hard.\nLuckily, there aren't too many files to update in most projects.\nBelow is an example of a pipeline for the [USearch](https://github.com/unum-cloud/usearch) project, that has bindings to 10 programming languages.\nFeel free to add other sources and examples.\n\n```sh\n$ mkdir -p example\n\n$ wget https://github.com/unum-cloud/usearch/raw/main/VERSION -P example/\n$ wget https://github.com/unum-cloud/usearch/raw/main/CHANGELOG.md -P example/ # Missing\n$ wget https://github.com/unum-cloud/usearch/raw/main/CITATION.cff -P example/\n$ wget https://github.com/unum-cloud/usearch/raw/main/CMakeLists.txt -P example/\n$ wget https://github.com/unum-cloud/usearch/raw/main/Cargo.toml -P example/\n$ wget https://github.com/unum-cloud/usearch/raw/main/package.json -P example/\n$ wget https://github.com/unum-cloud/usearch/raw/main/conanfile.py -P example/\n$ wget https://github.com/unum-cloud/usearch/raw/main/README.md -P example/\n$ wget https://github.com/unum-cloud/usearch/raw/main/wasmer.toml -P example/\n$ wget https://github.com/unum-cloud/usearch/raw/main/csharp/nuget/nuget-package.props -P example/\n$ wget https://github.com/unum-cloud/usearch/raw/main/include/usearch/index.hpp -P example/\n\n# You can match the semantic version part with a generic wildcard like: .*\n# But it's recommended to stick to a stricter format: \\d+\\.\\d+\\.\\d+\n$ tinysemver --dry-run --verbose \\\n    --major-verbs 'breaking,break,major' \\\n    --minor-verbs 'feature,minor,add,new' \\\n    --patch-verbs 'fix,patch,bug,improve,docs,make' \\\n    --version-file 'example/VERSION' \\\n    --changelog-file 'example/CHANGELOG.md' \\\n    --update-version-in 'example/CITATION.cff' '^version: (\\d+\\.\\d+\\.\\d+)' \\\n    --update-version-in 'example/CMakeLists.txt' '\\sVERSION (\\d+\\.\\d+\\.\\d+)' \\\n    --update-version-in 'example/Cargo.toml' '^version = \"(\\d+\\.\\d+\\.\\d+)\"' \\\n    --update-version-in 'example/package.json' '\"version\": \"(\\d+\\.\\d+\\.\\d+)\"' \\\n    --update-version-in 'example/conanfile.py' '\\sversion = \"(\\d+\\.\\d+\\.\\d+)\"' \\\n    --update-version-in 'example/README.md' '^version = \\{(\\d+\\.\\d+\\.\\d+)\\}' \\\n    --update-version-in 'example/wasmer.toml' '^version = \"(\\d+\\.\\d+\\.\\d+)\"' \\\n    --update-version-in 'example/nuget-package.props' '(\\d+\\.\\d+\\.\\d+)\\\u003c\\/Version\\\u003e' \\\n    --update-major-version-in 'example/index.hpp' '^#define USEARCH_VERSION_MAJOR (\\d+)' \\\n    --update-minor-version-in 'example/index.hpp' '^#define USEARCH_VERSION_MINOR (\\d+)' \\\n    --update-patch-version-in 'example/index.hpp' '^#define USEARCH_VERSION_PATCH (\\d+)' \\\n    --path .\n```\n\n## Contributing\n\nFeel free to open an issue or a pull request.\nIf you need to bump the version of `tinysemver` itself:\n\n```sh\ntinysemver --verbose \\\n    --version-file 'VERSION' \\\n    --changelog-file 'CHANGELOG.md' \\\n    --update-version-in 'pyproject.toml' 'version = \"(.*)\"' \\\n    --github-repository 'ashvardanian/tinysemver' --push\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashvardanian%2Ftinysemver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fashvardanian%2Ftinysemver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashvardanian%2Ftinysemver/lists"}