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
182 changes: 95 additions & 87 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,131 +2,139 @@ name: Release

on:
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., 1.0.0)'
required: true
type: string

concurrency: release

jobs:
test-python:
name: Python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true

- name: Install dependencies
working-directory: python
run: uv pip install --system -e ".[dev]"

- name: Run tests
working-directory: python
run: pytest tests/ -v --cov=jentic.problem_details --cov-report=term-missing

test-typescript:
name: TypeScript
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: typescript/package-lock.json

- name: Install dependencies
working-directory: typescript
run: npm ci

- name: Build
working-directory: typescript
run: npm run build

- name: Run tests
working-directory: typescript
run: npm test

- name: Type check
working-directory: typescript
run: npm run typecheck

release:
name: Release packages
needs: [test-python, test-typescript]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment:
name: npm-release
url: https://www.npmjs.com/org/jentic
name: release
url: https://github.com/jentic/api-problem-details/releases
permissions:
contents: write
id-token: write # Required for PyPI OIDC and NPM provenance
issues: write
pull-requests: write
id-token: write
attestations: write

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Update Python package version
working-directory: python
run: |
sed -i 's/^version = .*/version = "${{ inputs.version }}"/' pyproject.toml

- name: Update TypeScript package version
working-directory: typescript
run: |
npm version ${{ inputs.version }} --no-git-tag-version

- name: Commit version changes and create tag
- name: Install semantic-release
run: >
npm install -g
semantic-release
@semantic-release/commit-analyzer
@semantic-release/release-notes-generator
@semantic-release/github
@semantic-release/npm
@semantic-release/exec
@semantic-release/git

- name: Run semantic-release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git add python/pyproject.toml typescript/package.json typescript/package-lock.json
git commit -m "chore: release v${{ inputs.version }}"
git tag -a "v${{ inputs.version }}" -m "Release v${{ inputs.version }}"
git push origin main --tags

- name: Install Python dependencies and build
working-directory: python
run: |
uv pip install --system build
python -m build
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release

- name: Build TypeScript package
working-directory: typescript
run: |
npm ci
npm run build

- name: Prepare release artifacts
run: |
mkdir -p release-assets
cp python/dist/* release-assets/
cp ../LICENSE ../NOTICE .
npm pack
rm -f LICENSE NOTICE

echo "📦 Release artifacts:"
ls -la release-assets/
- name: Attest npm tarball
uses: actions/attest-build-provenance@v4
with:
subject-path: typescript/*.tgz

- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish TypeScript package to npm (OIDC)
working-directory: typescript
run: |
echo "🚀 Creating GitHub release..."
VERSION="${{ inputs.version }}"
set -euo pipefail
TARBALL="$(ls -1 *.tgz | head -n 1)"
echo "Publishing $TARBALL"
npm publish "file:./$TARBALL" --provenance --access public

# Try to extract changelog for this version
CHANGELOG_CONTENT="$(sed -n '/^## v'$VERSION'/,/^## /p' CHANGELOG.md 2>/dev/null | sed '$d')"

if [ -z "$CHANGELOG_CONTENT" ]; then
CHANGELOG_CONTENT="Release v$VERSION"
fi

gh release create "v$VERSION" \
--title "v$VERSION" \
--notes "$CHANGELOG_CONTENT" \
release-assets/*

- name: Publish Python package to PyPI
id: pypi_publish
continue-on-error: true # TODO: Remove after Trusted Publisher is configured on PyPI
- name: Publish Python package to PyPI (OIDC)
if: hashFiles('python/dist/*.whl') != ''
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: python/dist/
attestations: false

- name: Publish TypeScript package to NPM
id: npm_publish
working-directory: typescript
run: npm publish --access public --provenance

- name: Release Summary
run: |
echo "🎉 RELEASE COMPLETED"
echo "Released version: ${{ inputs.version }}"
echo ""
if [ "${{ steps.pypi_publish.outcome }}" == "success" ]; then
echo "Published to PyPI: ✓"
else
echo "Published to PyPI: ⚠️ SKIPPED (Trusted Publisher not configured yet)"
fi
echo "Published to NPM: ✓"
echo "GitHub release created: ✓"
47 changes: 47 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"branches": ["main"],
"tagFormat": "v${version}",
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/exec",
{
"prepareCmd": "cp LICENSE NOTICE python/ && cd python && sed -i 's/^version = .*/version = \"${nextRelease.version}\"/' pyproject.toml && pip install build && python -m build && rm -f LICENSE NOTICE"
}
],
[
"@semantic-release/npm",
{
"npmPublish": false,
"pkgRoot": "typescript"
}
],
[
"@semantic-release/github",
{
"assets": [
{
"path": "python/dist/*.tar.gz",
"label": "Python sdist"
},
{
"path": "python/dist/*.whl",
"label": "Python wheel"
}
]
}
],
[
"@semantic-release/git",
{
"assets": [
"python/pyproject.toml",
"typescript/package.json",
"typescript/package-lock.json"
],
"message": "chore(release): cut the v${nextRelease.version} release [ci skip]"
}
]
]
}
6 changes: 6 additions & 0 deletions python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ description = "RFC 9457 Problem Details models for Jentic APIs"
readme = "README.md"
requires-python = ">=3.11"
license = {text = "Apache-2.0"}
license-files = ["LICENSE", "NOTICE"]
authors = [
{name = "Jentic", email = "hello@jentic.com"}
]
Expand Down Expand Up @@ -47,6 +48,11 @@ Issues = "https://github.com/jentic/api-problem-details/issues"
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build]
exclude = [
"tests/",
]

[tool.hatch.build.targets.wheel]
packages = ["src/jentic"]

Expand Down
9 changes: 8 additions & 1 deletion typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
"license": "Apache-2.0",
"author": "Jentic <hello@jentic.com>",
"homepage": "https://github.com/jentic/api-problem-details#readme",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org",
"provenance": true
},
"repository": {
"type": "git",
"url": "https://github.com/jentic/api-problem-details.git",
Expand Down Expand Up @@ -32,7 +37,9 @@
},
"files": [
"dist",
"README.md"
"README.md",
"LICENSE",
"NOTICE"
],
"scripts": {
"build": "tsc",
Expand Down
Loading