Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 51 additions & 28 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
# at this workflow file (publish.yml) for repo fqueis/openapi-contract.
#
# Gate: skip if package.json version is already on the registry.
# Otherwise: lint + test + build, create GitHub Release (notes since previous tag),
# then pnpm publish. workflow_dispatch retries a failed publish without a new bump.
# Otherwise: lint + test + build, create GitHub Release, then pnpm publish.
# Release notes prefer the matching ## [version] section from CHANGELOG.md;
# otherwise fall back to gh --generate-notes from the previous v* tag (or an
# initial-release stub when no prior tag exists).
# workflow_dispatch retries a failed publish without a new bump.
#
# Bootstrap: the first package version must exist on npm (local publish + 2FA) before
# Trusted Publisher can be configured; after that, CI owns subsequent publishes.
Expand Down Expand Up @@ -92,41 +95,61 @@ jobs:
exit 0
fi

PREV_TAG="$(git describe --tags --abbrev=0 2>/dev/null || true)"
NOTES_FILE="$(mktemp)"
PREV_TAG="$(git tag -l 'v*' --sort=-v:refname | grep -vxF "$TAG" | head -n1 || true)"

if [ -z "$PREV_TAG" ]; then
{
echo "## ${TAG}"
echo
echo "Initial release of \`@fqueis/openapi-contract\`."
} > "$NOTES_FILE"
extract_changelog_section() {
local ver="$1"
local out="$2"
if [ ! -f CHANGELOG.md ]; then
return 1
fi
awk -v ver="$ver" '
BEGIN {
ver_re = ver
gsub(/\./, "\\.", ver_re)
}
$0 ~ ("^## \\[" ver_re "\\]( |$)") {
found = 1
print
next
}
found && /^## / { exit }
found { print }
' CHANGELOG.md > "$out"
# Require at least the heading line
if [ ! -s "$out" ] || ! grep -qF "## [${ver}]" "$out"; then
return 1
fi
return 0
}

if extract_changelog_section "$VERSION" "$NOTES_FILE"; then
echo "Using CHANGELOG.md section for ${VERSION}."
gh release create "$TAG" \
--title "$TAG" \
--notes-file "$NOTES_FILE" \
--target "${{ github.sha }}"
elif [ -n "$PREV_TAG" ]; then
echo "No CHANGELOG section for ${VERSION}; generating notes since ${PREV_TAG}."
gh release create "$TAG" \
--title "$TAG" \
--generate-notes \
--notes-start-tag "$PREV_TAG" \
--target "${{ github.sha }}"
else
echo "No CHANGELOG section and no previous v* tag; writing initial stub."
{
echo "## ${TAG}"
echo
echo "Changes since ${PREV_TAG}:"
echo
git log "${PREV_TAG}..HEAD" --pretty=format:"- %s (%h)" --no-merges
echo
echo "Initial release of \`@fqueis/openapi-contract\`."
} > "$NOTES_FILE"

if ! grep -q '^- ' "$NOTES_FILE"; then
{
echo "## ${TAG}"
echo
echo "Changes since ${PREV_TAG}:"
echo
echo "- No non-merge commits since ${PREV_TAG}."
} > "$NOTES_FILE"
fi
gh release create "$TAG" \
--title "$TAG" \
--notes-file "$NOTES_FILE" \
--target "${{ github.sha }}"
fi

gh release create "$TAG" \
--title "$TAG" \
--notes-file "$NOTES_FILE" \
--target "${{ github.sha }}"

- name: Publish to npm
if: steps.version.outputs.already_published == 'false'
run: pnpm publish --access public --no-git-checks
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Changelog

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.0] - 2026-07-23

Optional HTTP execution for registered backends, while keeping the default MCP surface read-only.

### Added

- Tool `call_endpoint` (opt-in): execute an OpenAPI operation against a registered backend
- Env `OPENAPI_MCP_ENABLE_CALLS` (`"1"` / `"true"` / `"yes"`): registers `call_endpoint` only when set
- Env `OPENAPI_MCP_CALL_TIMEOUT_MS` (default `30000`): abort timeout for calls
- Env `OPENAPI_MCP_CALL_MAX_BODY_BYTES` (default `102400`): truncates oversized response bodies
- Auth per call via `headers` and/or `headerEnv` (env wins on conflict; nothing stored in the registry)
- URL assembly from registry `baseUrl` + relative/same-origin OpenAPI `servers[0]` + path template / query

### Changed

- Default behavior remains contract inspection only; HTTP execution is off unless enabled
- PR Checks run `pnpm test:coverage` (thresholds from `vitest.config.ts`)
- Docs (README, ARCHITECT, roadmap) updated for opt-in calls and client-agnostic MCP setup

## 1.0.0 - 2026-07-23

### Added

- Initial public release of `@fqueis/openapi-contract`
- Read-only OpenAPI contract MCP tools (`use_backend`, overview, operations, schemas, security)
- On-demand backend registry with dual TTL (spec cache + disk registry)
- npm publish via Trusted Publishing (OIDC) and `npx -y @fqueis/openapi-contract` install path

[1.1.0]: https://github.com/fqueis/openapi-contract/releases/tag/v1.1.0
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ MCP client configs (`mcp.json` and equivalents) pass `env` into the server proce

For the communication flow between the MCP client, the service layer, the registry/cache, and the OpenAPI backend (including Mermaid diagrams), see [ARCHITECT.md](ARCHITECT.md).

Release history lives in [CHANGELOG.md](CHANGELOG.md). GitHub Release notes are taken from the matching version section when present.

---

## License
Expand Down