Skip to content

fix: preserve async exception stack trace frames (#303) #69

fix: preserve async exception stack trace frames (#303)

fix: preserve async exception stack trace frames (#303) #69

Workflow file for this run

name: Release
on:
push:
branches: [main]
paths:
- '.changeset/*.md'
workflow_dispatch:
permissions:
contents: read
# Concurrency control: only one release process can run at a time.
# This prevents race conditions if multiple releasable changesets merge simultaneously.
concurrency:
group: release
cancel-in-progress: false
jobs:
check-changesets:
name: Check for changesets
runs-on: ubuntu-latest
outputs:
has-changesets: ${{ steps.check.outputs.has-changesets }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: main
fetch-depth: 0
- name: Check for changesets
id: check
run: |
changeset_count=$(find .changeset -name '*.md' ! -name 'README.md' 2>/dev/null | wc -l)
if [ "$changeset_count" -gt 0 ]; then
echo "has-changesets=true" >> "$GITHUB_OUTPUT"
echo "Found $changeset_count changeset(s), ready to release"
else
echo "has-changesets=false" >> "$GITHUB_OUTPUT"
echo "No changesets to release"
fi
notify-approval-needed:
name: Notify Slack - Approval Needed
needs: check-changesets
if: needs.check-changesets.outputs.has-changesets == 'true'
uses: posthog/.github/.github/workflows/notify-approval-needed.yml@5fc4680761e8ac29a61b212756230eba0e276d8c
with:
slack_channel_id: ${{ vars.SLACK_APPROVALS_CLIENT_LIBRARIES_CHANNEL_ID }}
slack_user_group_id: ${{ vars.GROUP_CLIENT_LIBRARIES_SLACK_GROUP_ID }}
secrets:
slack_bot_token: ${{ secrets.SLACK_CLIENT_LIBRARIES_BOT_TOKEN }}
posthog_project_api_key: ${{ secrets.POSTHOG_PROJECT_API_KEY }}
version-bump:
name: Bump versions and commit to main
needs: [check-changesets, notify-approval-needed]
runs-on: ubuntu-latest
if: always() && needs.check-changesets.outputs.has-changesets == 'true'
environment: Release
permissions:
contents: write
actions: write
id-token: write
outputs:
committed: ${{ steps.version-bump-outputs.outputs.committed }}
commit-sha: ${{ steps.version-bump-outputs.outputs.commit-sha }}
env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: true
DOTNET_VERSION: "9.0.102"
steps:
- name: Notify Slack - Approved
if: needs.notify-approval-needed.outputs.slack_ts != ''
uses: posthog/.github/.github/actions/slack-thread-reply@cb0979b67dcd585828b61ac45927eef4da8f6287 # main
with:
slack_bot_token: ${{ secrets.SLACK_CLIENT_LIBRARIES_BOT_TOKEN }}
slack_channel_id: ${{ vars.SLACK_APPROVALS_CLIENT_LIBRARIES_CHANNEL_ID }}
thread_ts: ${{ needs.notify-approval-needed.outputs.slack_ts }}
message: "✅ Release approved! Version bump in progress..."
emoji_reaction: "white_check_mark"
- name: Get GitHub App token
id: releaser
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ secrets.GH_APP_POSTHOG_DOTNET_RELEASER_APP_ID }}
private-key: ${{ secrets.GH_APP_POSTHOG_DOTNET_RELEASER_PRIVATE_KEY }}
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: main
fetch-depth: 0
token: ${{ steps.releaser.outputs.token }}
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Setup pnpm and Node.js
uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2
with:
# TODO: pnpm/setup does not read .nvmrc yet. Keep this in sync with .nvmrc
# until https://github.com/jasongin/nvs/pull/315 lands.
# pnpm/setup installs runtimes via pnpm runtime, which requires pnpm >=11.1.0.
version: 11.7.0
runtime: node@24
cache: true
install: false
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup .NET
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Apply changesets
run: pnpm changeset version
- name: Sync package versions to project files
run: |
set -euo pipefail
set_version() {
local project_file="$1"
local version="$2"
perl -0pi -e 's/<Version>[^<]+<\/Version>/<Version>'"$version"'<\/Version>/' "$project_file"
}
POSTHOG_VERSION=$(node -p "require('./src/PostHog/package.json').version")
ASPNETCORE_VERSION=$(node -p "require('./src/PostHog.AspNetCore/package.json').version")
AI_VERSION=$(node -p "require('./src/PostHog.AI/package.json').version")
set_version "src/PostHog/PostHog.csproj" "$POSTHOG_VERSION"
set_version "src/PostHog.AspNetCore/PostHog.AspNetCore.csproj" "$ASPNETCORE_VERSION"
set_version "src/PostHog.AI/PostHog.AI.csproj" "$AI_VERSION"
- name: Restore NuGet packages
run: dotnet restore --locked-mode
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --configuration Release --no-build
- name: Check for version bump changes
id: check-changes
run: |
if [ -z "$(git status --porcelain)" ]; then
echo "No changes to commit"
echo "has-changes=false" >> "$GITHUB_OUTPUT"
else
echo "has-changes=true" >> "$GITHUB_OUTPUT"
fi
- name: Commit version bump
id: commit-version-bump
if: steps.check-changes.outputs.has-changes == 'true'
uses: planetscale/ghcommit-action@a6b150b81dca5dd027baa898604418eec9e11465 # v0.2.22
with:
commit_message: "chore: update package versions [version bump] [skip ci]"
repo: ${{ github.repository }}
branch: main
env:
GITHUB_TOKEN: ${{ steps.releaser.outputs.token }}
- name: Set version bump outputs
id: version-bump-outputs
env:
HAS_CHANGES: ${{ steps.check-changes.outputs.has-changes }}
COMMIT_HASH: ${{ steps.commit-version-bump.outputs.commit-hash }}
run: |
if [ "$HAS_CHANGES" = "true" ]; then
echo "committed=true" >> "$GITHUB_OUTPUT"
echo "commit-sha=$COMMIT_HASH" >> "$GITHUB_OUTPUT"
else
echo "committed=false" >> "$GITHUB_OUTPUT"
echo "commit-sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
fi
- name: Resolve release failure metadata
id: release-failure-metadata
if: failure()
run: |
set -euo pipefail
package_name=""
package_version=""
separator=""
for package_json in src/PostHog/package.json src/PostHog.AspNetCore/package.json src/PostHog.AI/package.json; do
if [ -f "$package_json" ]; then
package_name_part=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("name", ""))' "$package_json")
version=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("version", ""))' "$package_json")
if [ -n "$package_name_part" ] && [ -n "$version" ]; then
package_name="${package_name}${separator}${package_name_part}"
package_version="${package_version}${separator}${package_name_part}@v${version}"
separator=", "
fi
fi
done
echo "package_name=$package_name" >> "$GITHUB_OUTPUT"
echo "package_version=$package_version" >> "$GITHUB_OUTPUT"
- name: Send failure event to PostHog
if: failure()
continue-on-error: true
uses: PostHog/posthog-github-action@9a6a19d360820ab4d95ecc4a5a7564062c895f84 # v1.3.0
with:
posthog-token: "${{ secrets.POSTHOG_PROJECT_API_KEY }}"
event: "posthog-sdk-github-release-workflow-failure"
properties: >-
{
"commitSha": "${{ github.sha }}",
"jobStatus": "${{ job.status }}",
"ref": "${{ github.ref }}",
"repository": "${{ github.repository }}",
"sdk": "posthog-dotnet",
"jobName": "version-bump",
"packageName": "${{ steps.release-failure-metadata.outputs.package_name || 'unknown' }}",
"packageVersion": "${{ steps.release-failure-metadata.outputs.package_version || 'unknown' }}",
"actionUrl": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"alertText": ":rotating_light: Failed to prepare release for posthog-dotnet :rotating_light:",
"alertContext": "The version bump/changelog step failed before packages were published."
}
- name: Notify Slack - Failed
if: failure() && needs.notify-approval-needed.outputs.slack_ts != ''
uses: posthog/.github/.github/actions/slack-thread-reply@cb0979b67dcd585828b61ac45927eef4da8f6287 # main
with:
slack_bot_token: ${{ secrets.SLACK_CLIENT_LIBRARIES_BOT_TOKEN }}
slack_channel_id: ${{ vars.SLACK_APPROVALS_CLIENT_LIBRARIES_CHANNEL_ID }}
thread_ts: ${{ needs.notify-approval-needed.outputs.slack_ts }}
message: "❌ Failed to bump versions for `posthog-dotnet`! <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View logs>"
emoji_reaction: "x"
publish:
name: Publish packages
needs: [version-bump, notify-approval-needed]
runs-on: ubuntu-latest
if: always() && needs.version-bump.outputs.committed == 'true'
permissions:
contents: write
actions: write
id-token: write
env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: true
DOTNET_VERSION: "9.0.102"
PackageDirectory: ${{ github.workspace }}/build/packages/Release
strategy:
# If any package fails to publish, stop immediately. PostHog must publish before dependents.
fail-fast: true
max-parallel: 1
matrix:
package:
- name: PostHog
path: src/PostHog
project: src/PostHog/PostHog.csproj
changelog: src/PostHog/CHANGELOG.md
- name: PostHog.AspNetCore
path: src/PostHog.AspNetCore
project: src/PostHog.AspNetCore/PostHog.AspNetCore.csproj
changelog: src/PostHog.AspNetCore/CHANGELOG.md
- name: PostHog.AI
path: src/PostHog.AI
project: src/PostHog.AI/PostHog.AI.csproj
changelog: src/PostHog.AI/CHANGELOG.md
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.version-bump.outputs.commit-sha }}
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Fetch tags
run: git fetch --tags --force
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
- name: Setup .NET
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Detect version change for ${{ matrix.package.name }}
id: detect-version
run: |
set -euo pipefail
PACKAGE_JSON="${{ matrix.package.path }}/package.json"
CURRENT_VERSION=$(node -p "require('./${PACKAGE_JSON}').version")
RELEASE_TAG="${{ matrix.package.name }}-v${CURRENT_VERSION}"
if git diff --quiet HEAD^ HEAD -- "$PACKAGE_JSON"; then
echo "${{ matrix.package.name }} version did not change in the version-bump commit"
echo "has-new-version=false" >> "$GITHUB_OUTPUT"
elif git rev-parse "$RELEASE_TAG" >/dev/null 2>&1; then
echo "Tag $RELEASE_TAG already exists - no new version to release"
echo "has-new-version=false" >> "$GITHUB_OUTPUT"
else
echo "New ${{ matrix.package.name }} version detected: $CURRENT_VERSION"
echo "has-new-version=true" >> "$GITHUB_OUTPUT"
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
fi
- name: Restore NuGet packages
if: steps.detect-version.outputs.has-new-version == 'true'
run: dotnet restore --locked-mode
- name: Build and pack ${{ matrix.package.name }}
if: steps.detect-version.outputs.has-new-version == 'true'
run: dotnet build "${{ matrix.package.project }}" --configuration Release --no-restore
- name: NuGet login
if: steps.detect-version.outputs.has-new-version == 'true'
uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0
id: login
with:
user: PostHog-Engineering
- name: Publish ${{ matrix.package.name }} to NuGet
if: steps.detect-version.outputs.has-new-version == 'true'
env:
NUGET_API_KEY: ${{ steps.login.outputs.NUGET_API_KEY }}
PACKAGE_NAME: ${{ matrix.package.name }}
PACKAGE_VERSION: ${{ steps.detect-version.outputs.version }}
run: |
package_file="${{ env.PackageDirectory }}/${PACKAGE_NAME}.${PACKAGE_VERSION}.nupkg"
if [ ! -f "$package_file" ]; then
echo "Package file not found: $package_file" >&2
find "${{ env.PackageDirectory }}" -type f -name '*.nupkg' -print >&2 || true
exit 1
fi
dotnet nuget push "$package_file" --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Tag and push ${{ matrix.package.name }}
if: steps.detect-version.outputs.has-new-version == 'true'
env:
RELEASE_TAG: ${{ steps.detect-version.outputs.tag }}
RELEASE_VERSION: ${{ steps.detect-version.outputs.version }}
PACKAGE_NAME: ${{ matrix.package.name }}
run: |
git tag -a "$RELEASE_TAG" -m "$PACKAGE_NAME $RELEASE_VERSION"
git push origin "$RELEASE_TAG"
- name: Create GitHub release for ${{ matrix.package.name }}
if: steps.detect-version.outputs.has-new-version == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ steps.detect-version.outputs.tag }}
CHANGELOG_FILE: ${{ matrix.package.changelog }}
run: |
if [ -f "$CHANGELOG_FILE" ]; then
awk -v defText="See $CHANGELOG_FILE" '
/^## / { if (found_version) exit; found_version=1; next }
found_version { print }
END { if (!found_version) print defText }
' "$CHANGELOG_FILE" | sed '/[^[:space:]]/,$!d' | tac | sed '/[^[:space:]]/,$!d' | tac > release-notes.md
else
echo "See $CHANGELOG_FILE" > release-notes.md
fi
gh release create "$RELEASE_TAG" \
--target "${{ needs.version-bump.outputs.commit-sha }}" \
--title "$RELEASE_TAG" \
--notes-file release-notes.md
- name: Send failure event to PostHog
if: failure()
continue-on-error: true
uses: PostHog/posthog-github-action@9a6a19d360820ab4d95ecc4a5a7564062c895f84 # v1.3.0
with:
posthog-token: "${{ secrets.POSTHOG_PROJECT_API_KEY }}"
event: "posthog-sdk-github-release-workflow-failure"
properties: >-
{
"commitSha": "${{ github.sha }}",
"jobStatus": "${{ job.status }}",
"ref": "${{ github.ref }}",
"repository": "${{ github.repository }}",
"sdk": "posthog-dotnet",
"jobName": "publish",
"packageName": "${{ matrix.package.name }}",
"packageVersion": "${{ steps.detect-version.outputs.version || 'unknown' }}",
"actionUrl": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"alertText": ":rotating_light: Failed to release ${{ matrix.package.name }}@${{ steps.detect-version.outputs.version }} :rotating_light:",
"alertContext": "The package publish step failed."
}
- name: Notify Slack - Failed
if: failure() && needs.notify-approval-needed.outputs.slack_ts != ''
uses: posthog/.github/.github/actions/slack-thread-reply@cb0979b67dcd585828b61ac45927eef4da8f6287 # main
with:
slack_bot_token: ${{ secrets.SLACK_CLIENT_LIBRARIES_BOT_TOKEN }}
slack_channel_id: ${{ vars.SLACK_APPROVALS_CLIENT_LIBRARIES_CHANNEL_ID }}
thread_ts: ${{ needs.notify-approval-needed.outputs.slack_ts }}
message: "❌ Failed to release `${{ matrix.package.name }}@${{ steps.detect-version.outputs.version }}`! <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View logs>"
emoji_reaction: "x"
notify-rejected:
name: Notify Slack - Rejected
needs: [version-bump, notify-approval-needed]
runs-on: ubuntu-latest
if: always() && (needs.version-bump.result == 'failure' || needs.version-bump.result == 'skipped') && needs.notify-approval-needed.outputs.slack_ts != ''
steps:
- name: Check for rejection
id: check-rejection
env:
GH_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY_NAME: ${{ github.repository }}
GITHUB_RUN_ID_VALUE: ${{ github.run_id }}
run: |
RESPONSE=$(gh api "/repos/$GITHUB_REPOSITORY_NAME/actions/runs/$GITHUB_RUN_ID_VALUE/approvals")
REJECTED=$(echo "$RESPONSE" | jq '[.[] | select(.state == "rejected")] | length')
if [ "$REJECTED" -gt 0 ]; then
echo "was_rejected=true" >> "$GITHUB_OUTPUT"
COMMENT=$(echo "$RESPONSE" | jq -r '.[] | select(.state == "rejected") | .comment // empty' | head -1)
if [ -n "$COMMENT" ]; then
{
echo 'message<<EOF'
echo "🚫 Release was rejected: $COMMENT"
echo 'EOF'
} >> "$GITHUB_OUTPUT"
else
echo "message=🚫 Release was rejected." >> "$GITHUB_OUTPUT"
fi
else
echo "was_rejected=false" >> "$GITHUB_OUTPUT"
fi
- name: Notify Slack - Rejected
if: steps.check-rejection.outputs.was_rejected == 'true'
continue-on-error: true
uses: posthog/.github/.github/actions/slack-thread-reply@cb0979b67dcd585828b61ac45927eef4da8f6287 # main
with:
slack_bot_token: ${{ secrets.SLACK_CLIENT_LIBRARIES_BOT_TOKEN }}
slack_channel_id: ${{ vars.SLACK_APPROVALS_CLIENT_LIBRARIES_CHANNEL_ID }}
thread_ts: ${{ needs.notify-approval-needed.outputs.slack_ts }}
message: '${{ steps.check-rejection.outputs.message }}'
emoji_reaction: 'no_entry_sign'
notify-released:
name: Notify Slack - Released
needs: [notify-approval-needed, publish]
runs-on: ubuntu-latest
if: always() && needs.publish.result == 'success' && needs.notify-approval-needed.outputs.slack_ts != ''
steps:
- name: Notify Slack - Released
uses: posthog/.github/.github/actions/slack-thread-reply@cb0979b67dcd585828b61ac45927eef4da8f6287 # main
with:
slack_bot_token: ${{ secrets.SLACK_CLIENT_LIBRARIES_BOT_TOKEN }}
slack_channel_id: ${{ vars.SLACK_APPROVALS_CLIENT_LIBRARIES_CHANNEL_ID }}
thread_ts: ${{ needs.notify-approval-needed.outputs.slack_ts }}
message: "🚀 Released updated posthog-dotnet packages successfully!"
emoji_reaction: "rocket"