Skip to content

Commit 7ecd58c

Browse files
chaliyclaude
andauthored
chore(release): prepare v0.1.0 (#14)
## What Prepare fetchkit v0.1.0 for first crates.io release, adopting bashkit's release process conventions. ## Why First public release. Aligning release process with bashkit for consistency across everruns projects. ## How - Add crates.io metadata (keywords, categories, readme) to all crate Cargo.toml files - Reformat CHANGELOG.md with Highlights section, `*` bullets, Full Changelog link - Create `[0.1.0]` release section from `[Unreleased]` - Switch release.yml to `softprops/action-gh-release@v2` with `workflow_dispatch` support - Simplify publish.yml (remove pre-publish test job, add tag version verification) - Add `publish = false` to fetchkit-python - Update release process docs and AGENTS.md ## Risk - Low - CI workflows changed but follow proven bashkit patterns ### Checklist - [x] Unit tests passed - [x] Clippy clean (`-D warnings`) - [x] Formatting clean (`cargo fmt`) - [x] `cargo package -p fetchkit` succeeds - [x] Documentation updated (docs/release-process.md, AGENTS.md) https://claude.ai/code/session_01FESDz9faJVnHYQfZ1LEXeM Co-authored-by: Claude <noreply@anthropic.com>
1 parent 959708a commit 7ecd58c

9 files changed

Lines changed: 132 additions & 168 deletions

File tree

.github/workflows/publish.yml

Lines changed: 17 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,53 @@
1-
name: Publish to crates.io
1+
name: Publish
22

33
on:
44
release:
55
types: [published]
66
workflow_dispatch:
7-
inputs:
8-
dry_run:
9-
description: 'Dry run (no actual publish)'
10-
required: false
11-
default: 'true'
12-
type: boolean
13-
crate:
14-
description: 'Crate to publish (all, fetchkit, fetchkit-cli)'
15-
required: false
16-
default: 'all'
17-
type: choice
18-
options:
19-
- all
20-
- fetchkit
21-
- fetchkit-cli
227

238
permissions:
249
contents: read
2510

2611
env:
2712
CARGO_TERM_COLOR: always
28-
RUST_BACKTRACE: 1
2913

3014
jobs:
31-
test:
32-
name: Test before publish
33-
runs-on: ubuntu-latest
34-
steps:
35-
- uses: actions/checkout@v4
36-
- uses: dtolnay/rust-toolchain@stable
37-
- uses: Swatinem/rust-cache@v2
38-
- name: Run tests
39-
run: cargo test --workspace
40-
- name: Check formatting
41-
run: cargo fmt --all -- --check
42-
- name: Clippy
43-
run: cargo clippy --workspace --all-targets -- -D warnings
44-
4515
publish-fetchkit:
4616
name: Publish fetchkit
47-
needs: test
4817
runs-on: ubuntu-latest
49-
if: >-
50-
github.event_name == 'release' ||
51-
(github.event_name == 'workflow_dispatch' &&
52-
(github.event.inputs.crate == 'all' || github.event.inputs.crate == 'fetchkit'))
5318
steps:
5419
- uses: actions/checkout@v4
5520
- uses: dtolnay/rust-toolchain@stable
56-
- uses: Swatinem/rust-cache@v2
5721

58-
- name: Verify crate can be packaged
59-
run: cargo package -p fetchkit --allow-dirty
60-
61-
- name: Publish fetchkit (dry run)
62-
if: github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true'
63-
run: cargo publish -p fetchkit --dry-run
64-
65-
- name: Publish fetchkit
66-
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'false')
22+
- name: Verify version matches tag
23+
run: |
24+
TAG_VERSION="${{ github.event.release.tag_name }}"
25+
if [ -n "$TAG_VERSION" ]; then
26+
TAG_VERSION="${TAG_VERSION#v}"
27+
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
28+
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
29+
echo "Error: Tag version does not match Cargo.toml version"
30+
exit 1
31+
fi
32+
fi
33+
34+
- name: Publish fetchkit to crates.io
6735
run: cargo publish -p fetchkit
6836
env:
6937
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
7038

7139
publish-fetchkit-cli:
7240
name: Publish fetchkit-cli
73-
needs: [test, publish-fetchkit]
7441
runs-on: ubuntu-latest
75-
if: >-
76-
github.event_name == 'release' ||
77-
(github.event_name == 'workflow_dispatch' &&
78-
(github.event.inputs.crate == 'all' || github.event.inputs.crate == 'fetchkit-cli'))
42+
needs: publish-fetchkit
7943
steps:
8044
- uses: actions/checkout@v4
8145
- uses: dtolnay/rust-toolchain@stable
82-
- uses: Swatinem/rust-cache@v2
8346

84-
# Wait for crates.io index to update after fetchkit publish
85-
- name: Wait for crates.io index
86-
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'false')
47+
- name: Wait for crates.io index update
8748
run: sleep 30
8849

89-
- name: Verify crate can be packaged
90-
run: cargo package -p fetchkit-cli --allow-dirty
91-
92-
- name: Publish fetchkit-cli (dry run)
93-
if: github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true'
94-
run: cargo publish -p fetchkit-cli --dry-run
95-
96-
- name: Publish fetchkit-cli
97-
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'false')
50+
- name: Publish fetchkit-cli to crates.io
9851
run: cargo publish -p fetchkit-cli
9952
env:
10053
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

.github/workflows/release.yml

Lines changed: 31 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,87 +4,63 @@ on:
44
push:
55
branches:
66
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
actions: write
712

813
jobs:
914
release:
15+
name: Create Release
1016
runs-on: ubuntu-latest
11-
# Only run if commit message matches release pattern
12-
if: ${{ startsWith(github.event.head_commit.message, 'chore(release): prepare v') }}
13-
14-
permissions:
15-
contents: write
17+
if: "${{ github.event_name == 'workflow_dispatch' || startsWith(github.event.head_commit.message, 'chore(release): prepare v') }}"
1618

1719
steps:
1820
- name: Checkout
1921
uses: actions/checkout@v4
20-
with:
21-
fetch-depth: 0
2222

23-
- name: Extract version from commit message
23+
- name: Extract version
2424
id: version
2525
run: |
26-
# Extract version from commit message like "chore(release): prepare v0.1.0"
27-
VERSION=$(echo "${{ github.event.head_commit.message }}" | grep -oP 'prepare v\K[0-9]+\.[0-9]+\.[0-9]+')
26+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
27+
VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
28+
else
29+
COMMIT_MSG="${{ github.event.head_commit.message }}"
30+
VERSION=$(echo "$COMMIT_MSG" | sed -n 's/.*prepare v\([0-9]*\.[0-9]*\.[0-9]*\).*/\1/p')
31+
fi
2832
if [ -z "$VERSION" ]; then
29-
echo "::error::Could not extract version from commit message"
33+
echo "Error: Could not determine version"
3034
exit 1
3135
fi
3236
echo "version=$VERSION" >> $GITHUB_OUTPUT
3337
echo "tag=v$VERSION" >> $GITHUB_OUTPUT
34-
echo "Extracted version: $VERSION"
35-
36-
- name: Check if tag already exists
37-
id: check_tag
38-
run: |
39-
if git rev-parse "v${{ steps.version.outputs.version }}" >/dev/null 2>&1; then
40-
echo "::error::Tag v${{ steps.version.outputs.version }} already exists"
41-
exit 1
42-
fi
43-
echo "Tag does not exist, proceeding..."
4438
45-
- name: Verify Cargo.toml version matches
39+
- name: Verify version matches Cargo.toml
4640
run: |
47-
CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
48-
if [ "$CARGO_VERSION" != "${{ steps.version.outputs.version }}" ]; then
49-
echo "::error::Cargo.toml version ($CARGO_VERSION) does not match release version (${{ steps.version.outputs.version }})"
41+
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
42+
if [ "${{ steps.version.outputs.version }}" != "$CARGO_VERSION" ]; then
43+
echo "Error: Commit version does not match Cargo.toml version"
5044
exit 1
5145
fi
52-
echo "Cargo.toml version matches: $CARGO_VERSION"
5346
54-
- name: Extract release notes from CHANGELOG.md
47+
- name: Extract release notes from CHANGELOG
5548
id: changelog
5649
run: |
5750
VERSION="${{ steps.version.outputs.version }}"
58-
59-
# Extract the section for this version from CHANGELOG.md
60-
# Matches from "## [X.Y.Z]" until the next "## [" or end of significant content
61-
NOTES=$(awk -v ver="$VERSION" '
62-
/^## \[/ {
63-
if (found) exit
64-
if (index($0, "[" ver "]")) found=1
65-
next
66-
}
67-
found && /^## \[/ { exit }
68-
found { print }
69-
' CHANGELOG.md)
70-
71-
if [ -z "$NOTES" ]; then
72-
echo "::warning::No changelog entry found for version $VERSION"
73-
NOTES="Release v$VERSION"
74-
fi
75-
76-
# Write to file to preserve formatting
51+
NOTES=$(awk "/^## \[$VERSION\]/{found=1; next} /^## \[/{if(found) exit} found{print}" CHANGELOG.md)
7752
echo "$NOTES" > release_notes.md
78-
echo "Release notes extracted:"
79-
cat release_notes.md
8053
8154
- name: Create GitHub Release
55+
uses: softprops/action-gh-release@v2
56+
with:
57+
tag_name: ${{ steps.version.outputs.tag }}
58+
name: Release ${{ steps.version.outputs.tag }}
59+
body_path: release_notes.md
60+
draft: false
61+
prerelease: false
62+
63+
- name: Trigger publish workflow
64+
run: gh workflow run publish.yml
8265
env:
8366
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
84-
run: |
85-
gh release create "v${{ steps.version.outputs.version }}" \
86-
--title "v${{ steps.version.outputs.version }}" \
87-
--notes-file release_notes.md \
88-
--target "${{ github.sha }}"
89-
90-
echo "Created release v${{ steps.version.outputs.version }}"

AGENTS.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,20 @@ See `docs/release-process.md` for full release process documentation.
9898

9999
Quick summary:
100100
1. Human asks agent: "Create release v0.2.0"
101-
2. Agent updates CHANGELOG.md, Cargo.toml version, creates PR
101+
2. Agent updates CHANGELOG.md (with Highlights + What's Changed), Cargo.toml version, creates PR
102102
3. Human reviews and merges PR to main
103-
4. CI creates GitHub Release (release.yml)
104-
5. CI publishes to crates.io (publish.yml)
103+
4. CI creates GitHub Release via `softprops/action-gh-release` (release.yml)
104+
5. release.yml triggers publish.yml
105+
6. CI publishes `fetchkit` then `fetchkit-cli` to crates.io (publish.yml)
105106

106107
Workflows:
107-
- `.github/workflows/release.yml` - Creates GitHub Release on merge
108-
- `.github/workflows/publish.yml` - Publishes to crates.io on GitHub Release
108+
- `.github/workflows/release.yml` - Creates GitHub Release on merge or manual dispatch
109+
- `.github/workflows/publish.yml` - Publishes to crates.io on GitHub Release or manual dispatch
109110

110111
Requirements:
111112
- `CARGO_REGISTRY_TOKEN` secret must be configured in repo settings
112113

113-
Note: `fetchkit-python` is not published to crates.io (uses PyPI distribution instead).
114+
Note: `fetchkit-python` is not published to crates.io (`publish = false`). Uses PyPI distribution instead.
114115

115116
### Cloud Agent environments
116117

CHANGELOG.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.1.0] - 2026-02-12
11+
12+
### Highlights
13+
14+
- AI-friendly web content fetching with HTML-to-Markdown and HTML-to-Text conversion
15+
- CLI and MCP server for AI tool integration
16+
- Pluggable fetcher system for URL-specific handling
17+
- Python bindings via PyO3
18+
1019
### What's Changed
1120

12-
- feat: add pluggable fetcher system for URL-specific handling ([#9](https://github.com/everruns/fetchkit/pull/9)) by @chaliy
13-
- docs: add LangChain example for MCP integration ([#8](https://github.com/everruns/fetchkit/pull/8)) by @chaliy
14-
- refactor(cli): unified md-first output format ([#7](https://github.com/everruns/fetchkit/pull/7)) by @chaliy
15-
- docs: clarify test classification in AGENTS.md ([#6](https://github.com/everruns/fetchkit/pull/6)) by @chaliy
16-
- docs: add cloud agent env and complete AGENTS.md placeholders ([#5](https://github.com/everruns/fetchkit/pull/5)) by @chaliy
17-
- refactor: rename project from webfetch to fetchkit ([#4](https://github.com/everruns/fetchkit/pull/4)) by @chaliy
18-
- docs: add comprehensive README with installation and usage guide ([#3](https://github.com/everruns/fetchkit/pull/3)) by @chaliy
19-
- feat: implement webfetch library, CLI, MCP server, and Python bindings ([#1](https://github.com/everruns/fetchkit/pull/1)) by @chaliy
20-
- feat: add initial webfetch spec and guidance by @chaliy
21-
22-
[Unreleased]: https://github.com/everruns/fetchkit/compare/HEAD...HEAD
21+
* feat: add pluggable fetcher system for URL-specific handling ([#9](https://github.com/everruns/fetchkit/pull/9)) by @chaliy
22+
* docs: add LangChain example for MCP integration ([#8](https://github.com/everruns/fetchkit/pull/8)) by @chaliy
23+
* refactor(cli): unified md-first output format ([#7](https://github.com/everruns/fetchkit/pull/7)) by @chaliy
24+
* docs: clarify test classification in AGENTS.md ([#6](https://github.com/everruns/fetchkit/pull/6)) by @chaliy
25+
* docs: add cloud agent env and complete AGENTS.md placeholders ([#5](https://github.com/everruns/fetchkit/pull/5)) by @chaliy
26+
* refactor: rename project from webfetch to fetchkit ([#4](https://github.com/everruns/fetchkit/pull/4)) by @chaliy
27+
* docs: add comprehensive README with installation and usage guide ([#3](https://github.com/everruns/fetchkit/pull/3)) by @chaliy
28+
* feat: implement webfetch library, CLI, MCP server, and Python bindings ([#1](https://github.com/everruns/fetchkit/pull/1)) by @chaliy
29+
* feat: add initial webfetch spec and guidance by @chaliy
30+
31+
**Full Changelog**: https://github.com/everruns/fetchkit/commits/v0.1.0
32+
33+
[Unreleased]: https://github.com/everruns/fetchkit/compare/v0.1.0...HEAD
34+
[0.1.0]: https://github.com/everruns/fetchkit/releases/tag/v0.1.0

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ edition = "2021"
88
license = "MIT"
99
authors = ["Everruns"]
1010
repository = "https://github.com/everruns/fetchkit"
11-
description = "AI-friendly fetchkit tool, CLI, MCP server, and library"
11+
description = "AI-friendly web content fetching and HTML-to-Markdown conversion library"
12+
keywords = ["fetch", "web", "markdown", "llm", "ai"]
13+
categories = ["web-programming", "text-processing"]
1214

1315
[workspace.dependencies]
1416
# Async runtime

crates/fetchkit-cli/Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ edition.workspace = true
55
license.workspace = true
66
authors.workspace = true
77
repository.workspace = true
8-
description = "CLI for the FetchKit tool"
8+
description = "Command line interface for FetchKit web content fetching tool"
9+
keywords.workspace = true
10+
categories.workspace = true
11+
readme = "../../README.md"
912

1013
[[bin]]
1114
name = "fetchkit"
1215
path = "src/main.rs"
1316

1417
[dependencies]
15-
fetchkit = { version = "0.1.0", path = "../fetchkit" }
18+
fetchkit = { path = "../fetchkit", version = "0.1.0" }
1619
tokio = { workspace = true }
1720
clap = { workspace = true }
1821
serde = { workspace = true }

crates/fetchkit-python/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ license.workspace = true
66
authors.workspace = true
77
repository.workspace = true
88
description = "Python bindings for the FetchKit library"
9+
publish = false
910

1011
[lib]
1112
name = "fetchkit_py"

crates/fetchkit/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ edition.workspace = true
55
license.workspace = true
66
authors.workspace = true
77
repository.workspace = true
8-
description = "AI-friendly fetchkit library for fetching and converting web content"
8+
description.workspace = true
9+
keywords.workspace = true
10+
categories.workspace = true
11+
readme = "../../README.md"
912

1013
[dependencies]
1114
tokio = { workspace = true }

0 commit comments

Comments
 (0)