microsoft/typespec

Public

mirrored from https://github.com/microsoft/typespecAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/create-github-action-issue

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.github/workflows/python-check-spec-tests.yml

175lines · modecode

1name: "[Python] Check Spec Test Cases"
2
3on:
4 # schedule:
5 # - cron: "0 0 * * *" # Daily at midnight UTC
6 workflow_dispatch:
7
8permissions:
9 issues: write
10
11concurrency:
12 group: python-check-spec-tests
13 cancel-in-progress: true
14
15jobs:
16 check-and-create-issues:
17 runs-on: ubuntu-latest
18 steps:
19 - uses: actions/setup-node@v4
20 with:
21 node-version: "20"
22
23 - name: Check for new spec changes and create issues
24 env:
25 GH_TOKEN: ${{ secrets.ISSUE_CREATE_GITHUB_TOKEN }}
26 run: |
27 set -euo pipefail
28
29 PACKAGE_JSON_URL="https://raw.githubusercontent.com/microsoft/typespec/main/packages/http-client-python/package.json"
30 SKILL_URL="https://github.com/microsoft/typespec/blob/main/.github/skills/python-sdk-spector-mock-api-tests/SKILL.md"
31 ISSUE_REPO="microsoft/typespec"
32
33 # Fetch package.json from main branch once
34 PACKAGE_JSON_CONTENT=$(curl -fsSL "$PACKAGE_JSON_URL")
35 if [ -z "$PACKAGE_JSON_CONTENT" ]; then
36 echo "ERROR: Could not fetch package.json from main branch"
37 exit 1
38 fi
39
40 check_package() {
41 local pkg_name="$1"
42 local repo="$2"
43 local specs_path="$3"
44
45 echo "=============================="
46 echo "Checking package: $pkg_name"
47 echo "=============================="
48
49 # Step 1: Extract version A from package.json devDependencies (main branch)
50 local version_a
51 version_a=$(echo "$PACKAGE_JSON_CONTENT" | jq -r ".devDependencies[\"$pkg_name\"]")
52 if [ -z "$version_a" ] || [ "$version_a" = "null" ]; then
53 echo "WARNING: Could not find $pkg_name in devDependencies, skipping"
54 return
55 fi
56 echo "Version A (from main branch package.json): $version_a"
57
58 # Step 2: Get publish dates and find the most recently published version (including dev/prerelease)
59 local time_data
60 time_data=$(npm view "$pkg_name" time --json 2>/dev/null || true)
61 if [ -z "$time_data" ]; then
62 echo "WARNING: Could not get time data for $pkg_name from npm, skipping"
63 return
64 fi
65
66 # Find the most recently published version (excluding "created" and "modified" metadata keys)
67 local version_b
68 version_b=$(echo "$time_data" | jq -r 'to_entries | map(select(.key != "created" and .key != "modified")) | sort_by(.value) | last | .key')
69 if [ -z "$version_b" ] || [ "$version_b" = "null" ]; then
70 echo "WARNING: Could not determine latest version from npm time data, skipping"
71 return
72 fi
73 echo "Version B (most recently published): $version_b"
74
75 local date_a
76 date_a=$(echo "$time_data" | jq -r ".[\"$version_a\"]")
77 local date_b
78 date_b=$(echo "$time_data" | jq -r ".[\"$version_b\"]")
79
80 if [ "$date_a" = "null" ] || [ -z "$date_a" ]; then
81 echo "WARNING: Could not find publish date for version $version_a, skipping"
82 return
83 fi
84 if [ "$date_b" = "null" ] || [ -z "$date_b" ]; then
85 echo "WARNING: Could not find publish date for version $version_b, skipping"
86 return
87 fi
88
89 echo "Date A ($version_a): $date_a"
90 echo "Date B ($version_b): $date_b"
91
92 # Compare dates - if B (latest) is newer than A (pinned), there are new specs to check
93 if [[ "$date_b" > "$date_a" ]]; then
94 echo "Latest version is newer than pinned, proceeding to check for PRs..."
95 else
96 echo "Pinned version is up-to-date, skipping $pkg_name"
97 return
98 fi
99
100 # Step 3: Adjust since date using git commit time instead of npm publish time.
101 # npm publish dates lag behind actual commit times due to CI/CD pipeline delays,
102 # which can cause recently-merged commits to be missed when the GitHub Commits API
103 # filters by author date. We find the last commit on the specs path before version A
104 # was published, and use that commit's author date as the since boundary.
105 local last_commit_date
106 last_commit_date=$(gh api "repos/${repo}/commits" \
107 -f path="${specs_path}" \
108 -f until="${date_a}" \
109 -f per_page=1 \
110 --jq '.[0].commit.author.date' 2>/dev/null || true)
111 if [ -n "$last_commit_date" ] && [ "$last_commit_date" != "null" ]; then
112 echo "Adjusted since date from npm publish ($date_a) to last spec commit ($last_commit_date)"
113 date_a="$last_commit_date"
114 fi
115
116 # Step 4: Use GitHub commits API (supports path filtering, unlike gh search prs)
117 echo "Searching for commits between $date_a and $date_b in $repo affecting $specs_path"
118
119 local pr_numbers
120 pr_numbers=$(gh api "repos/${repo}/commits" \
121 --paginate \
122 -f path="${specs_path}" \
123 -f since="${date_a}" \
124 -f until="${date_b}" \
125 --jq '.[].commit.message' 2>/dev/null \
126 | grep -oP '\(#\K[0-9]+(?=\))' \
127 | sort -un || true)
128
129 if [ -z "$pr_numbers" ]; then
130 echo "No PRs found affecting specs path in date range, skipping"
131 return
132 fi
133
134 local pr_count
135 pr_count=$(echo "$pr_numbers" | wc -l | tr -d ' ')
136 echo "Found $pr_count PRs affecting specs in date range"
137
138 # Step 5: Fetch existing issues once (across all states) to avoid duplicate creation
139 local existing_issues
140 existing_issues=$(gh issue list --repo "$ISSUE_REPO" --state all --search "in:title [python] add test case" --json title --limit 200 2>/dev/null || echo "[]")
141
142 while IFS= read -r pr_number; do
143 [ -z "$pr_number" ] && continue
144 local pr_url="https://github.com/${repo}/pull/${pr_number}"
145
146 echo "PR #$pr_number affects specs: $pr_url"
147
148 local title="[python] add test case for ${pr_url}"
149 local body="follow skill ${SKILL_URL} to write test case for ${pr_url}"
150
151 # Check if an issue with the same title already exists (open or closed)
152 local has_match
153 has_match=$(echo "$existing_issues" | jq --arg t "$title" '[.[] | select(.title == $t)] | length')
154
155 if [ "$has_match" -gt 0 ]; then
156 echo "Issue already exists for PR $pr_url, skipping"
157 continue
158 fi
159
160 # Create the issue
161 gh issue create --repo "$ISSUE_REPO" \
162 --title "$title" \
163 --body "$body" \
164 --label "emitter:client:python" \
165 --assignee "copilot"
166
167 echo "Created issue for PR $pr_url"
168 done <<< "$pr_numbers"
169 }
170
171 # Check both packages
172 check_package "@typespec/http-specs" "microsoft/typespec" "packages/http-specs/specs"
173 check_package "@azure-tools/azure-http-specs" "Azure/typespec-azure" "packages/azure-http-specs/specs"
174
175 echo "Done!"
176