Skip to content

Commit 62f81e3

Browse files
committed
fix(python adapter): skip _generated dirs in readVersion to avoid stale versions
1 parent 89e6c98 commit 62f81e3

2 files changed

Lines changed: 142 additions & 41 deletions

File tree

scripts/api_md_workflow/adapters/python.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ function readVersion(packageDir) {
8383
for (const file of walkFiles(packageDir)) {
8484
const name = path.basename(file);
8585
if (name === "_version.py" || name === "version.py") {
86+
// Skip generated code directories — they often contain stale versions
87+
const relative = path.relative(packageDir, file);
88+
if (relative.includes("_generated") || relative.includes("generated_")) {
89+
continue;
90+
}
8691
candidates.push(file);
8792
}
8893
}

scripts/api_md_workflow/create_api_review_pr.js

Lines changed: 137 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,40 @@ function run(cmd, args, options = {}) {
8989
return result;
9090
}
9191

92+
let cachedGitExecutable = undefined;
93+
let cachedGitAwareEnv = undefined;
94+
95+
function resolveGitExecutable() {
96+
if (cachedGitExecutable !== undefined) {
97+
return cachedGitExecutable;
98+
}
99+
100+
if (process.platform !== "win32") {
101+
const resolved = spawnSync("git", ["--exec-path"], {
102+
cwd: REPO_ROOT,
103+
encoding: "utf-8",
104+
env: process.env,
105+
});
106+
cachedGitExecutable = resolved.status === 0 ? "git" : "git";
107+
return cachedGitExecutable;
108+
}
109+
110+
cachedGitExecutable = findPreferredGitExecutable() || "git";
111+
return cachedGitExecutable;
112+
}
113+
92114
function git(args, options = {}) {
93-
return run("git", args, options);
115+
return run(resolveGitExecutable(), args, {
116+
...options,
117+
env: buildGitAwareEnv(options.env),
118+
});
119+
}
120+
121+
function gh(args, options = {}) {
122+
return run("gh", args, {
123+
...options,
124+
env: buildGitAwareEnv(options.env),
125+
});
94126
}
95127

96128
function gitOut(args) {
@@ -181,49 +213,117 @@ function metadataRel(packageDir) {
181213
return `${packageRelDir(packageDir)}/API.metadata.yml`;
182214
}
183215

184-
function findRealGitExe() {
216+
function apiReviewBranchName(kind, packageName, version) {
217+
return `apireview/${kind}_${packageName}_${version}`;
218+
}
219+
220+
function scoreGitCandidate(candidate) {
221+
const normalized = candidate.replace(/\//g, "\\").toLowerCase();
222+
if (normalized.includes("\\program files\\git\\cmd\\git.exe")) {
223+
return 0;
224+
}
225+
226+
if (normalized.includes("\\program files\\git\\bin\\git.exe")) {
227+
return 1;
228+
}
229+
230+
if (normalized.includes("\\git\\cmd\\git.exe")) {
231+
return 2;
232+
}
233+
234+
if (normalized.includes("\\git\\bin\\git.exe")) {
235+
return 3;
236+
}
237+
238+
if (normalized.includes("\\windows\\")) {
239+
return 100;
240+
}
241+
242+
return 10;
243+
}
244+
245+
function findPreferredGitExecutable() {
185246
if (process.platform !== "win32") {
186247
return null;
187248
}
188249

189-
const seen = new Set();
190-
const entries = (process.env.PATH || "").split(path.delimiter);
191-
for (const rawEntry of entries) {
192-
const entry = rawEntry.replace(/^"|"$/g, "");
193-
if (!entry) {
250+
const candidates = new Set();
251+
const roots = [process.env.ProgramW6432, process.env.ProgramFiles, process.env["ProgramFiles(x86)"], process.env.LocalAppData];
252+
for (const root of roots) {
253+
if (!root) {
194254
continue;
195255
}
196256

197-
const key = entry.toLowerCase();
198-
if (seen.has(key)) {
257+
candidates.add(path.join(root, "Git", "cmd", "git.exe"));
258+
candidates.add(path.join(root, "Git", "bin", "git.exe"));
259+
candidates.add(path.join(root, "Programs", "Git", "cmd", "git.exe"));
260+
candidates.add(path.join(root, "Programs", "Git", "bin", "git.exe"));
261+
}
262+
263+
for (const rawEntry of (process.env.PATH || "").split(path.delimiter)) {
264+
const entry = rawEntry.replace(/^"|"$/g, "");
265+
if (!entry) {
199266
continue;
200267
}
201-
seen.add(key);
202268

203-
const candidate = path.join(entry, "git.exe");
204-
if (fs.existsSync(candidate)) {
205-
return candidate;
206-
}
269+
candidates.add(path.join(entry, "git.exe"));
207270
}
208271

209-
const fallback = "C:\\Program Files\\Git\\cmd\\git.exe";
210-
return fs.existsSync(fallback) ? fallback : null;
272+
const existing = [...candidates].filter((candidate) => fs.existsSync(candidate));
273+
existing.sort((left, right) => scoreGitCandidate(left) - scoreGitCandidate(right) || left.localeCompare(right));
274+
return existing[0] || null;
211275
}
212276

213-
function envWithRealGit() {
214-
const env = { ...process.env };
215-
const realGit = findRealGitExe();
216-
if (!realGit) {
217-
return env;
277+
function getGitExecPath(gitExecutable) {
278+
if (process.platform === "win32" && !path.isAbsolute(gitExecutable)) {
279+
return null;
280+
}
281+
282+
const result = spawnSync(gitExecutable, ["--exec-path"], {
283+
cwd: REPO_ROOT,
284+
encoding: "utf-8",
285+
});
286+
287+
if (result.status !== 0) {
288+
return null;
289+
}
290+
291+
return result.stdout.trim() || null;
292+
}
293+
294+
function samePathEntry(left, right) {
295+
if (process.platform === "win32") {
296+
return left.replace(/\\+$/, "").toLowerCase() === right.replace(/\\+$/, "").toLowerCase();
297+
}
298+
299+
return left === right;
300+
}
301+
302+
function buildGitAwareEnv(baseEnv = process.env) {
303+
if (baseEnv === process.env && cachedGitAwareEnv) {
304+
return cachedGitAwareEnv;
305+
}
306+
307+
const env = { ...baseEnv };
308+
const gitExecutable = resolveGitExecutable();
309+
const gitExecPath = getGitExecPath(gitExecutable);
310+
311+
if (path.isAbsolute(gitExecutable)) {
312+
const gitDir = path.dirname(gitExecutable);
313+
const currentEntries = (env.PATH || "").split(path.delimiter).filter(Boolean);
314+
const first = currentEntries[0] || "";
315+
if (!first || !samePathEntry(first, gitDir)) {
316+
env.PATH = [gitDir, ...currentEntries].join(path.delimiter);
317+
logInfo(`(using resolved git executable: ${gitExecutable})`);
318+
}
319+
}
320+
321+
if (gitExecPath) {
322+
env.GIT_EXEC_PATH = gitExecPath;
218323
}
219324

220-
const gitDir = path.dirname(realGit);
221-
const current = env.PATH || "";
222-
const parts = current.split(path.delimiter);
223-
const first = parts[0] || "";
224-
if (first.replace(/\\+$/, "").toLowerCase() !== gitDir.replace(/\\+$/, "").toLowerCase()) {
225-
env.PATH = `${gitDir}${path.delimiter}${current}`;
226-
logInfo(`(prepending real git to PATH for gh: ${gitDir})`);
325+
if (baseEnv === process.env) {
326+
cachedGitAwareEnv = env;
227327
}
228328

229329
return env;
@@ -253,7 +353,6 @@ function selectBestPr(prs) {
253353
}
254354

255355
function findOpenPrForHead(headSelector) {
256-
const env = envWithRealGit();
257356
const selectors = [headSelector];
258357
if (headSelector.includes(":")) {
259358
const branchOnly = headSelector.split(":", 2)[1];
@@ -264,8 +363,7 @@ function findOpenPrForHead(headSelector) {
264363

265364
const allPrs = [];
266365
for (const selector of selectors) {
267-
const direct = run(
268-
"gh",
366+
const direct = gh(
269367
[
270368
"pr",
271369
"list",
@@ -280,7 +378,7 @@ function findOpenPrForHead(headSelector) {
280378
"--limit",
281379
"50",
282380
],
283-
{ check: false, capture: true, env },
381+
{ check: false, capture: true },
284382
);
285383

286384
if (direct.status === 0) {
@@ -293,8 +391,7 @@ function findOpenPrForHead(headSelector) {
293391

294392
for (const selector of selectors) {
295393
const searchQuery = `repo:Azure/azure-sdk-for-python head:${selector}`;
296-
const search = run(
297-
"gh",
394+
const search = gh(
298395
[
299396
"pr",
300397
"list",
@@ -309,7 +406,7 @@ function findOpenPrForHead(headSelector) {
309406
"--limit",
310407
"50",
311408
],
312-
{ check: false, capture: true, env },
409+
{ check: false, capture: true },
313410
);
314411

315412
if (search.status === 0) {
@@ -399,7 +496,7 @@ function generateApiBytesForRef({
399496
// Restore the package directory to the current branch state
400497
git(["checkout", "HEAD", "--", packageRelative]);
401498
// Clean any untracked files that the generation may have left behind
402-
run("git", ["clean", "-fd", "--", packageRelative], { check: false });
499+
git(["clean", "-fd", "--", packageRelative], { check: false });
403500
}
404501
}
405502

@@ -454,8 +551,8 @@ function main() {
454551
});
455552
const targetVersion = targetResult.version;
456553

457-
const baseBranch = `base_${args.packageName}_${baseVersion}`;
458-
const reviewBranch = `review_${args.packageName}_${targetVersion}`;
554+
const baseBranch = apiReviewBranchName("base", args.packageName, baseVersion);
555+
const reviewBranch = apiReviewBranchName("review", args.packageName, targetVersion);
459556

460557
logInfo(`\n=== Creating base branch ${baseBranch} ===`);
461558
git(["checkout", "-B", baseBranch, MAIN_REF]);
@@ -548,8 +645,7 @@ function main() {
548645

549646
logInfo("\n=== Opening PR ===");
550647
const compareUrl = `https://github.com/Azure/azure-sdk-for-python/compare/${baseBranch}...${reviewBranch}?expand=1`;
551-
const prCreate = run(
552-
"gh",
648+
const prCreate = gh(
553649
[
554650
"pr",
555651
"create",
@@ -565,7 +661,7 @@ function main() {
565661
body,
566662
"--draft",
567663
],
568-
{ check: false, env: envWithRealGit() },
664+
{ check: false },
569665
);
570666

571667
if (prCreate.status !== 0) {

0 commit comments

Comments
 (0)