Sync GitHub Release Downloads to PostHog #156
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Sync GitHub Release Downloads to PostHog | |
| on: | |
| schedule: | |
| # 每天 UTC 2:00 执行(北京时间 10:00) | |
| - cron: '0 2 * * *' | |
| workflow_dispatch: # 支持手动触发 | |
| jobs: | |
| sync: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Restore previous sync state | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: .sync-state.json | |
| key: posthog-sync-state-${{ github.repository_id }} | |
| restore-keys: | | |
| posthog-sync-state- | |
| - name: Fetch release data and sync to PostHog | |
| env: | |
| POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} | |
| POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # 调试:检查环境变量(不显示完整 key) | |
| echo "POSTHOG_HOST: ${POSTHOG_HOST}" | |
| echo "POSTHOG_API_KEY length: ${#POSTHOG_API_KEY}" | |
| echo "POSTHOG_API_KEY prefix: ${POSTHOG_API_KEY:0:5}..." | |
| # 如果 POSTHOG_HOST 没有设置,使用默认值 | |
| if [ -z "$POSTHOG_HOST" ]; then | |
| POSTHOG_HOST="https://us.i.posthog.com" | |
| echo "Using default POSTHOG_HOST: ${POSTHOG_HOST}" | |
| fi | |
| # 获取当前同步时间(ISO 8601 格式) | |
| sync_timestamp=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") | |
| echo "Sync timestamp: ${sync_timestamp}" | |
| # 加载上次同步的状态(用于计算增量) | |
| if [ -f .sync-state.json ] && [ "$(cat .sync-state.json)" != "{}" ]; then | |
| echo "Loaded previous sync state" | |
| echo "true" > .has-previous-state | |
| else | |
| echo '{}' > .sync-state.json | |
| echo "false" > .has-previous-state | |
| echo "No previous sync state, starting fresh" | |
| fi | |
| # 获取所有 releases | |
| releases=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ | |
| "https://api.github.com/repos/mantra-hq/mantra-releases/releases?per_page=100") | |
| echo "Found $(echo "$releases" | jq 'length') releases" | |
| # 遍历每个 release | |
| echo "$releases" | jq -c '.[]' | while read -r release; do | |
| version=$(echo "$release" | jq -r '.tag_name') | |
| published_at=$(echo "$release" | jq -r '.published_at') | |
| echo "Processing release: ${version}" | |
| # 遍历每个 asset | |
| echo "$release" | jq -c '.assets[]' | while read -r asset; do | |
| asset_name=$(echo "$asset" | jq -r '.name') | |
| download_count=$(echo "$asset" | jq -r '.download_count') | |
| # 跳过签名文件 | |
| if [[ "$asset_name" == *.sig ]]; then | |
| continue | |
| fi | |
| # 判断平台和架构 | |
| platform="unknown" | |
| arch="unknown" | |
| if [[ "$asset_name" == *macos* ]] || [[ "$asset_name" == *app.tar.gz* ]]; then | |
| platform="macos" | |
| if [[ "$asset_name" == *arm64* ]] || [[ "$asset_name" == *aarch64* ]]; then | |
| arch="arm64" | |
| else | |
| arch="x64" | |
| fi | |
| elif [[ "$asset_name" == *windows* ]] || [[ "$asset_name" == *.exe ]] || [[ "$asset_name" == *.msi ]]; then | |
| platform="windows" | |
| arch="x64" | |
| elif [[ "$asset_name" == *linux* ]] || [[ "$asset_name" == *AppImage* ]] || [[ "$asset_name" == *.deb ]] || [[ "$asset_name" == *.rpm ]]; then | |
| platform="linux" | |
| arch="x64" | |
| fi | |
| # 计算增量下载数 | |
| asset_key="${version}:${asset_name}" | |
| previous_count=$(jq -r --arg key "$asset_key" '.[$key] // 0' .sync-state.json) | |
| download_delta=$((download_count - previous_count)) | |
| # 更新状态文件 | |
| jq --arg key "$asset_key" --argjson val "$download_count" \ | |
| '.[$key] = $val' .sync-state.json > .sync-state.tmp && mv .sync-state.tmp .sync-state.json | |
| # 跳过无增量的记录(首次同步除外) | |
| has_previous=$(cat .has-previous-state) | |
| if [ "$download_delta" -le 0 ] && [ "$has_previous" = "true" ]; then | |
| echo " - ${asset_name}: no new downloads (total: ${download_count})" | |
| continue | |
| fi | |
| # 发送到 PostHog(使用当前同步时间) | |
| response=$(curl -s -w "\n%{http_code}" -X POST "${POSTHOG_HOST}/capture/" \ | |
| -H "Content-Type: application/json" \ | |
| -d "{ | |
| \"api_key\": \"${POSTHOG_API_KEY}\", | |
| \"event\": \"github_release_download\", | |
| \"distinct_id\": \"github-release-sync\", | |
| \"timestamp\": \"${sync_timestamp}\", | |
| \"properties\": { | |
| \"version\": \"${version}\", | |
| \"asset_name\": \"${asset_name}\", | |
| \"platform\": \"${platform}\", | |
| \"arch\": \"${arch}\", | |
| \"download_count\": ${download_count}, | |
| \"download_delta\": ${download_delta}, | |
| \"published_at\": \"${published_at}\" | |
| } | |
| }") | |
| http_code=$(echo "$response" | tail -1) | |
| response_body=$(echo "$response" | head -n -1) | |
| if [ "$http_code" = "200" ]; then | |
| echo " ✓ ${asset_name}: +${download_delta} new downloads (total: ${download_count}) (${platform}/${arch})" | |
| else | |
| echo " ✗ Failed: ${asset_name} (HTTP ${http_code})" | |
| echo " Response: ${response_body}" | |
| fi | |
| done | |
| done | |
| echo "" | |
| echo "Sync completed!" | |
| - name: Save sync state | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: .sync-state.json | |
| key: posthog-sync-state-${{ github.repository_id }} |