Skip to content

Commit 91020a4

Browse files
author
Martin Møldrup
committed
Add automation pipelines
1 parent 1905435 commit 91020a4

File tree

7 files changed

+420
-106
lines changed

7 files changed

+420
-106
lines changed

.github/workflows/release.yaml

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
name: release
2+
3+
on:
4+
push:
5+
tags:
6+
- "[0-9]+\\.[0-9]+\\.[0-9]+"
7+
- "[0-9]+\\.[0-9]+\\.[0-9]+a[0-9]+"
8+
- "[0-9]+\\.[0-9]+\\.[0-9]+b[0-9]+"
9+
- "[0-9]+\\.[0-9]+\\.[0-9]+rc[0-9]+"
10+
11+
env:
12+
PACKAGE_NAME: "toolit"
13+
UV_VERSION: 0.7.7
14+
15+
jobs:
16+
details:
17+
runs-on: ubuntu-latest
18+
outputs:
19+
new_version: ${{ steps.release.outputs.new_version }}
20+
suffix: ${{ steps.release.outputs.suffix }}
21+
tag_name: ${{ steps.release.outputs.tag_name }}
22+
steps:
23+
- uses: actions/checkout@v2
24+
25+
- name: Extract tag and Details
26+
id: release
27+
run: |
28+
if [ "${{ github.ref_type }}" = "tag" ]; then
29+
TAG_NAME=${GITHUB_REF#refs/tags/}
30+
NEW_VERSION=$(echo $TAG_NAME | awk -F'-' '{print $1}')
31+
SUFFIX=$(echo $TAG_NAME | grep -oP '[a-z]+[0-9]+' || echo "")
32+
echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
33+
echo "suffix=$SUFFIX" >> "$GITHUB_OUTPUT"
34+
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
35+
echo "Version is $NEW_VERSION"
36+
echo "Suffix is $SUFFIX"
37+
echo "Tag name is $TAG_NAME"
38+
else
39+
echo "No tag found"
40+
exit 1
41+
fi
42+
43+
check_pypi:
44+
needs: details
45+
runs-on: ubuntu-latest
46+
steps:
47+
- name: Fetch information from PyPI
48+
run: |
49+
response=$(curl -s https://pypi.org/pypi/${{ env.PACKAGE_NAME }}/json || echo "{}")
50+
latest_previous_version=$(echo $response | jq --raw-output "select(.releases != null) | .releases | keys_unsorted | last")
51+
if [ -z "$latest_previous_version" ]; then
52+
echo "Package not found on PyPI."
53+
latest_previous_version="0.0.0"
54+
fi
55+
echo "Latest version on PyPI: $latest_previous_version"
56+
echo "latest_previous_version=$latest_previous_version" >> $GITHUB_ENV
57+
58+
- name: Compare versions and exit if not newer
59+
run: |
60+
NEW_VERSION=${{ needs.details.outputs.new_version }}
61+
LATEST_VERSION=$latest_previous_version
62+
if [ "$(printf '%s\n' "$LATEST_VERSION" "$NEW_VERSION" | sort -rV | head -n 1)" != "$NEW_VERSION" ] || [ "$NEW_VERSION" == "$LATEST_VERSION" ]; then
63+
echo "The new version $NEW_VERSION is not greater than the latest version $LATEST_VERSION on PyPI."
64+
exit 1
65+
else
66+
echo "The new version $NEW_VERSION is greater than the latest version $LATEST_VERSION on PyPI."
67+
fi
68+
setup_and_build:
69+
needs: [details, check_pypi]
70+
runs-on: ubuntu-latest
71+
steps:
72+
- uses: actions/checkout@v2
73+
74+
- name: Set up Python
75+
uses: actions/setup-python@v4
76+
with:
77+
python-version: "3.12"
78+
79+
- name: Install UV
80+
run: |
81+
curl -LsSf "https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh" | sh
82+
83+
# - name: Set project version with Poetry
84+
# run: |
85+
# uv version ${{ needs.details.outputs.new_version }}
86+
87+
# - name: Install dependencies
88+
# run: uv
89+
90+
- name: Build source and wheel distribution
91+
run: |
92+
uv build
93+
94+
- name: Upload artifacts
95+
uses: actions/upload-artifact@v4
96+
with:
97+
name: dist
98+
path: dist/
99+
100+
github_release:
101+
name: Create GitHub Release
102+
needs: [setup_and_build, details]
103+
runs-on: ubuntu-latest
104+
permissions:
105+
contents: write
106+
steps:
107+
- name: Checkout Code
108+
uses: actions/checkout@v3
109+
with:
110+
fetch-depth: 0
111+
112+
- name: Download artifacts
113+
uses: actions/download-artifact@v4
114+
with:
115+
name: dist
116+
path: dist/
117+
118+
- name: Create GitHub Release
119+
id: create_release
120+
env:
121+
GH_TOKEN: ${{ github.token }}
122+
run: |
123+
python ./scripts/get_changelog.py ${{ needs.details.outputs.new_version }} > specific_changelog.md
124+
echo "Changelog for ${{ needs.details.outputs.new_version }}:"
125+
cat specific_changelog.md
126+
changelog=$(cat specific_changelog.md)
127+
gh release create ${{ needs.details.outputs.tag_name }} dist/* --title ${{ needs.details.outputs.tag_name }} --generate-notes --notes "$changelog"
128+
129+
pypi_publish:
130+
name: Upload release to PyPI
131+
needs: [setup_and_build, details, github_release]
132+
runs-on: ubuntu-latest
133+
environment:
134+
name: release
135+
permissions:
136+
id-token: write
137+
steps:
138+
- name: Download artifacts
139+
uses: actions/download-artifact@v4
140+
with:
141+
name: dist
142+
path: dist/
143+
144+
- name: Publish distribution to PyPI
145+
uses: pypa/gh-action-pypi-publish@release/v1

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Change log
2+
All notable changes to this project will be documented in this file.
3+
4+
*NOTE:* Version 0.X.X might have breaking changes in bumps of the minor version number. This is because the project is still in early development and the API is not yet stable. It will still be marked clearly in the release notes.
5+
6+
## [0.0.1] - 23-05-2025
7+
- Initial release of toolit
8+
- Basic functionality for creating tools that run for both MCP and typer cli

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,12 @@
11
# Toolit
22
MCP Server and Typer CLI in one, provides an easy way to configure your own DevTools in a project.
3+
4+
## Installation
5+
To get started with Toolit, install the package via pip:
6+
7+
```bash
8+
pip install toolit
9+
```
10+
11+
## Contributing
12+
We welcome contributions to ToolIt! If you have ideas for new features, improvements, or bug fixes, please open an issue or submit a pull request on our GitHub repository. We appreciate your feedback and support in making ToolIt even better for the community.

pyproject.toml

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,53 @@
1-
[project]
2-
name = "toolit"
3-
version = "0.1.0"
4-
description = "MCP Server and Typer CLI in one, provides an easy way to configure your own DevTools in a project."
1+
[project]
2+
name = "toolit"
3+
version = "0.0.1"
4+
description = "MCP Server and Typer CLI in one, provides an easy way to configure your own DevTools in a project."
55
readme = "README.md"
6-
requires-python = ">=3.11"
6+
requires-python = ">=3.10"
77
dependencies = []
8-
9-
[dependency-groups]
10-
dev = [
11-
"mcp[cli]>=1.6.0",
12-
"pytest>=8.3.5",
13-
"pytest-asyncio>=0.26.0",
14-
"typer>=0.15.2",
8+
classifiers = [
9+
"Framework :: Pytest",
10+
"Development Status :: 4 - Beta",
11+
"Intended Audience :: Developers",
12+
"Topic :: Software Development :: Testing",
13+
"Operating System :: OS Independent",
14+
"Programming Language :: Python",
15+
"Programming Language :: Python :: 3.9",
16+
"Programming Language :: Python :: 3.10",
17+
"Programming Language :: Python :: 3.11",
18+
"Programming Language :: Python :: 3.12",
19+
"Programming Language :: Python :: 3.13",
20+
"Programming Language :: Python :: 3 :: Only",
21+
"Programming Language :: Python :: Implementation :: CPython",
22+
"Programming Language :: Python :: Implementation :: PyPy",
23+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
24+
]
25+
keywords = ["mcp", "cli", "devtools", "typer"]
26+
authors = [
27+
{name = "Martin Møldrup"},
1528
]
1629

17-
[project.scripts]
18-
toolit = "src.cli:app"
19-
20-
[build-system]
21-
requires = ["setuptools>=61.0"]
22-
build-backend = "setuptools.build_meta"
30+
[project.urls]
31+
Homepage = "https://github.com/martinmoldrup/toolit"
32+
# Documentation = "https://readthedocs.org"
33+
Repository = "https://github.com/martinmoldrup/toolit"
34+
Issues = "https://github.com/martinmoldrup/toolit/issues"
35+
Changelog = "https://github.com/martinmoldrup/toolit/blob/master/CHANGELOG.md"
2336

24-
[tool.setuptools]
25-
packages = ["src"]
37+
[dependency-groups]
38+
dev = [
39+
"mcp[cli]>=1.6.0",
40+
"pytest>=8.3.5",
41+
"pytest-asyncio>=0.26.0",
42+
"typer>=0.15.2",
43+
]
44+
45+
[project.scripts]
46+
toolit = "toolit.cli:app"
47+
48+
[build-system]
49+
requires = ["setuptools>=61.0"]
50+
build-backend = "setuptools.build_meta"
51+
52+
[tool.setuptools]
53+
packages = ["toolit"]

scripts/get_changelog.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""Python script for getting the change log entry from the CHANGELOG.md file."""
2+
import pathlib
3+
import argparse
4+
5+
PATH = pathlib.Path(__file__).parent.parent / "CHANGELOG.md"
6+
7+
parser = argparse.ArgumentParser(description="Get the change log entry for a version.")
8+
parser.add_argument("version", help="The version to get the change log entry for.")
9+
args = parser.parse_args()
10+
11+
version = args.version
12+
if not version:
13+
raise ValueError("No version provided.")
14+
15+
16+
with PATH.open("r", encoding="utf-8") as file:
17+
lines = file.readlines()
18+
19+
version_str = f"## [{version}]"
20+
version_str_next = f"## ["
21+
change_log = []
22+
found = False
23+
for line in lines:
24+
if found:
25+
if line.startswith(version_str_next):
26+
break
27+
change_log.append(line)
28+
if line.startswith(version_str):
29+
found = True
30+
31+
if not change_log:
32+
raise ValueError(f"Version {version} not found in change log.")
33+
34+
print("".join(change_log))

scripts/readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This folder contains automation scripts for various development and deployment tasks.

0 commit comments

Comments
 (0)