fix: Add releaseStage-aware version comparison logic (#8998)
* ✨ (AccountMenu/index.tsx): Add computeNonPrereleaseVersion function to calculate non-prerelease version for comparing versions 📝 (utils.ts): Add computeNonPrereleaseVersion function to extract non-prerelease version for version comparison in AccountMenu component * refactor: replace computeNonPrereleaseVersion with stripReleaseStageFromVersion for version comparison in AccountMenu component - Updated AccountMenu to utilize stripReleaseStageFromVersion for determining the latest version. - Removed computeNonPrereleaseVersion function from utils and replaced it with stripReleaseStageFromVersion for clarity and consistency in version handling. * ✅ (strip-release-fn.test.ts): add standalone test for stripReleaseStageFromVersion function to avoid dependency issues in test environment * 📝 (strip-release-fn.test.ts): add detailed documentation for the stripReleaseStageFromVersion function to explain its functionality and examples * 🐛 (python_code_structured_tool.py): fix issue with handling default values in function arguments to prevent potential errors * [autofix.ci] apply automated fixes --------- Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> Co-authored-by: Carlos Coelho <80289056+carlosrcoelho@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
169b687ed0
commit
264681bf32
5 changed files with 358 additions and 157 deletions
|
|
@ -298,7 +298,7 @@ class PythonCodeStructuredTool(LCToolComponent):
|
|||
if isinstance(default, ast.Name):
|
||||
func_arg["default"] = default.id
|
||||
elif isinstance(default, ast.Constant):
|
||||
func_arg["default"] = default.value
|
||||
func_arg["default"] = str(default.value) if default.value is not None else None
|
||||
|
||||
if arg.annotation:
|
||||
annotation_line = lines[arg.annotation.lineno - 1]
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { ENABLE_DATASTAX_LANGFLOW } from "@/customization/feature-flags";
|
|||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import { useDarkStore } from "@/stores/darkStore";
|
||||
import { cn } from "@/utils/utils";
|
||||
import { cn, stripReleaseStageFromVersion } from "@/utils/utils";
|
||||
import {
|
||||
HeaderMenu,
|
||||
HeaderMenuItemButton,
|
||||
|
|
@ -38,7 +38,14 @@ export const AccountMenu = () => {
|
|||
mutationLogout();
|
||||
};
|
||||
|
||||
const isLatestVersion = version === latestVersion;
|
||||
const isLatestVersion = (() => {
|
||||
if (!version || !latestVersion) return false;
|
||||
|
||||
const currentBaseVersion = stripReleaseStageFromVersion(version);
|
||||
const latestBaseVersion = stripReleaseStageFromVersion(latestVersion);
|
||||
|
||||
return currentBaseVersion === latestBaseVersion;
|
||||
})();
|
||||
|
||||
return (
|
||||
<HeaderMenu>
|
||||
|
|
|
|||
181
src/frontend/src/utils/__tests__/strip-release-fn.test.ts
Normal file
181
src/frontend/src/utils/__tests__/strip-release-fn.test.ts
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
// Standalone test for stripReleaseStageFromVersion function
|
||||
// This avoids importing from utils.ts which has dependency issues in test environment
|
||||
|
||||
/**
|
||||
* The stripReleaseStageFromVersion function removes release stage suffixes from version strings.
|
||||
*
|
||||
* How it works:
|
||||
* 1. Checks for keywords in order: ["a", "b", "rc", "dev", "post"]
|
||||
* 2. When a keyword is found, splits the version string on that keyword
|
||||
* 3. Takes the first part of the split
|
||||
* 4. Removes the last character using slice(0, -1)
|
||||
*
|
||||
* Examples:
|
||||
* - "1.2.3a1" → splits on "a" → ["1.2.3", "1"] → takes "1.2.3" → slice(0,-1) → "1.2."
|
||||
* - "1.2.3dev" → splits on "dev" → ["1.2.3", ""] → takes "1.2.3" → slice(0,-1) → "1.2."
|
||||
* - "1.a.3" → splits on "a" → ["1.", "3"] → takes "1." → slice(0,-1) → "1"
|
||||
* - "1.2.3" → no keywords found → returns "1.2.3" unchanged
|
||||
*
|
||||
* Note: The function finds the FIRST matching keyword in the order they appear in the array,
|
||||
* so "1.2.3ba1" finds "a" first and becomes "1.2.3" (not "b").
|
||||
*/
|
||||
const stripReleaseStageFromVersion = (version: string): string => {
|
||||
const releaseStageKeywords = ["a", "b", "rc", "dev", "post"];
|
||||
for (const keyword of releaseStageKeywords) {
|
||||
if (version.includes(keyword)) {
|
||||
return version.split(keyword)[0].slice(0, -1);
|
||||
}
|
||||
}
|
||||
return version;
|
||||
};
|
||||
|
||||
describe("stripReleaseStageFromVersion", () => {
|
||||
describe("Basic functionality", () => {
|
||||
it("should strip alpha release stage", () => {
|
||||
expect(stripReleaseStageFromVersion("1.2.3a1")).toBe("1.2.");
|
||||
expect(stripReleaseStageFromVersion("2.0.0a5")).toBe("2.0.");
|
||||
expect(stripReleaseStageFromVersion("0.1.0a1")).toBe("0.1.");
|
||||
});
|
||||
|
||||
it("should strip beta release stage", () => {
|
||||
expect(stripReleaseStageFromVersion("1.2.3b1")).toBe("1.2.");
|
||||
expect(stripReleaseStageFromVersion("2.0.0b2")).toBe("2.0.");
|
||||
expect(stripReleaseStageFromVersion("0.5.1b10")).toBe("0.5.");
|
||||
});
|
||||
|
||||
it("should strip release candidate stage", () => {
|
||||
expect(stripReleaseStageFromVersion("1.2.3rc1")).toBe("1.2.");
|
||||
expect(stripReleaseStageFromVersion("2.0.0rc5")).toBe("2.0.");
|
||||
expect(stripReleaseStageFromVersion("3.1.0rc2")).toBe("3.1.");
|
||||
});
|
||||
|
||||
it("should strip dev release stage", () => {
|
||||
expect(stripReleaseStageFromVersion("1.2.3dev")).toBe("1.2.");
|
||||
expect(stripReleaseStageFromVersion("2.0.0dev1")).toBe("2.0.");
|
||||
expect(stripReleaseStageFromVersion("0.1.0dev")).toBe("0.1.");
|
||||
});
|
||||
|
||||
it("should strip post release stage", () => {
|
||||
expect(stripReleaseStageFromVersion("1.2.3post1")).toBe("1.2.");
|
||||
expect(stripReleaseStageFromVersion("2.0.0post5")).toBe("2.0.");
|
||||
expect(stripReleaseStageFromVersion("1.5.2post")).toBe("1.5.");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Version strings without release stages", () => {
|
||||
it("should return version unchanged when no release stage keywords are present", () => {
|
||||
expect(stripReleaseStageFromVersion("1.2.3")).toBe("1.2.3");
|
||||
expect(stripReleaseStageFromVersion("2.0.0")).toBe("2.0.0");
|
||||
expect(stripReleaseStageFromVersion("0.1.0")).toBe("0.1.0");
|
||||
expect(stripReleaseStageFromVersion("10.15.20")).toBe("10.15.20");
|
||||
});
|
||||
|
||||
it("should handle semantic versioning without pre-release", () => {
|
||||
expect(stripReleaseStageFromVersion("1.0.0")).toBe("1.0.0");
|
||||
expect(stripReleaseStageFromVersion("2.1.5")).toBe("2.1.5");
|
||||
expect(stripReleaseStageFromVersion("0.0.1")).toBe("0.0.1");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Edge cases", () => {
|
||||
it("should handle empty string", () => {
|
||||
expect(stripReleaseStageFromVersion("")).toBe("");
|
||||
});
|
||||
|
||||
it("should handle single character versions", () => {
|
||||
expect(stripReleaseStageFromVersion("1")).toBe("1");
|
||||
expect(stripReleaseStageFromVersion("a")).toBe("");
|
||||
expect(stripReleaseStageFromVersion("b")).toBe("");
|
||||
});
|
||||
|
||||
it("should handle versions with keyword at the beginning", () => {
|
||||
expect(stripReleaseStageFromVersion("a1.2.3")).toBe("");
|
||||
expect(stripReleaseStageFromVersion("rc1.0.0")).toBe("");
|
||||
expect(stripReleaseStageFromVersion("dev2.0")).toBe("");
|
||||
});
|
||||
|
||||
it("should handle versions with multiple keywords (first match wins)", () => {
|
||||
expect(stripReleaseStageFromVersion("1.2.3a1b2")).toBe("1.2.");
|
||||
// For "1.0.0devrc1": finds "rc" before "dev", splits on "rc": ["1.0.0dev", "1"], slice(0,-1) = "1.0.0de"
|
||||
expect(stripReleaseStageFromVersion("1.0.0devrc1")).toBe("1.0.0de");
|
||||
// For "2.1.0postb1": finds "b" before "post", splits on "b": ["2.1.0post", "1"], slice(0,-1) = "2.1.0pos"
|
||||
expect(stripReleaseStageFromVersion("2.1.0postb1")).toBe("2.1.0pos");
|
||||
});
|
||||
|
||||
it("should handle versions where keyword appears in the middle", () => {
|
||||
expect(stripReleaseStageFromVersion("1.a.3")).toBe("1");
|
||||
expect(stripReleaseStageFromVersion("2.rc.0")).toBe("2");
|
||||
expect(stripReleaseStageFromVersion("1.dev.2")).toBe("1");
|
||||
});
|
||||
|
||||
it("should handle very short versions with release stages", () => {
|
||||
expect(stripReleaseStageFromVersion("1a")).toBe("");
|
||||
expect(stripReleaseStageFromVersion("2b1")).toBe("");
|
||||
expect(stripReleaseStageFromVersion("3rc")).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Real-world version formats", () => {
|
||||
it("should handle Python package versions", () => {
|
||||
expect(stripReleaseStageFromVersion("3.9.0a1")).toBe("3.9.");
|
||||
expect(stripReleaseStageFromVersion("3.8.0b4")).toBe("3.8.");
|
||||
expect(stripReleaseStageFromVersion("3.10.0rc2")).toBe("3.10.");
|
||||
});
|
||||
|
||||
it("should handle complex version numbers", () => {
|
||||
expect(stripReleaseStageFromVersion("2021.1.0a1")).toBe("2021.1.");
|
||||
expect(stripReleaseStageFromVersion("0.25.3dev")).toBe("0.25.");
|
||||
expect(stripReleaseStageFromVersion("1.0.0post1")).toBe("1.0.");
|
||||
});
|
||||
|
||||
it("should handle versions with build metadata that contains keywords", () => {
|
||||
// These should still work since the function looks for keywords anywhere
|
||||
// For "1.2.3-alpha", it finds "a" and splits on "a", then removes last char
|
||||
expect(stripReleaseStageFromVersion("1.2.3-alpha")).toBe("1.2.3");
|
||||
// For "1.2.3+beta.1": finds "a" first, splits on "a": ["1.2.3+bet", ".1"], slice(0,-1) = "1.2.3+be"
|
||||
expect(stripReleaseStageFromVersion("1.2.3+beta.1")).toBe("1.2.3+be");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Keyword priority", () => {
|
||||
it("should match keywords in order of appearance in the array", () => {
|
||||
// The function uses the first match it finds in the loop
|
||||
// For "1.2.3ba1": finds "a" first, splits on "a": ["1.2.3b", "1"], slice(0,-1) = "1.2.3"
|
||||
expect(stripReleaseStageFromVersion("1.2.3ba1")).toBe("1.2.3");
|
||||
expect(stripReleaseStageFromVersion("1.2.3ab1")).toBe("1.2."); // 'a' comes first in array, splits on 'a'
|
||||
});
|
||||
});
|
||||
|
||||
describe("Special characters and formats", () => {
|
||||
it("should handle versions with dots and dashes", () => {
|
||||
expect(stripReleaseStageFromVersion("1.2.3-a1")).toBe("1.2.3");
|
||||
expect(stripReleaseStageFromVersion("1.2.3.dev")).toBe("1.2.3");
|
||||
expect(stripReleaseStageFromVersion("1.2.3_rc1")).toBe("1.2.3");
|
||||
});
|
||||
|
||||
it("should handle versions with leading zeros", () => {
|
||||
expect(stripReleaseStageFromVersion("01.02.03a1")).toBe("01.02.0");
|
||||
expect(stripReleaseStageFromVersion("1.00.0b2")).toBe("1.00.");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Function behavior analysis", () => {
|
||||
it("should demonstrate the split and slice behavior", () => {
|
||||
// For "1.2.3a1": splits to ["1.2.3", "1"], takes first part "1.2.3", then slice(0, -1) = "1.2."
|
||||
expect(stripReleaseStageFromVersion("1.2.3a1")).toBe("1.2.");
|
||||
|
||||
// For "1.a.3": splits to ["1.", "3"], takes first part "1.", then slice(0, -1) = "1"
|
||||
expect(stripReleaseStageFromVersion("1.a.3")).toBe("1");
|
||||
|
||||
// For "1a": splits to ["1", ""], takes first part "1", then slice(0, -1) = ""
|
||||
expect(stripReleaseStageFromVersion("1a")).toBe("");
|
||||
});
|
||||
|
||||
it("should handle edge cases where slice removes important characters", () => {
|
||||
// When the keyword is at position where slice(0, -1) removes a version component
|
||||
expect(stripReleaseStageFromVersion("1.2a")).toBe("1.");
|
||||
expect(stripReleaseStageFromVersion("1a")).toBe("");
|
||||
expect(stripReleaseStageFromVersion("12a")).toBe("1");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -992,3 +992,13 @@ export function prepareSessionIdForAPI(session_id: string): string {
|
|||
const formatted = sessionIdFormatted(session_id);
|
||||
return encodeSessionId(formatted);
|
||||
}
|
||||
|
||||
export const stripReleaseStageFromVersion = (version: string): string => {
|
||||
const releaseStageKeywords = ["a", "b", "rc", "dev", "post"];
|
||||
for (const keyword of releaseStageKeywords) {
|
||||
if (version.includes(keyword)) {
|
||||
return version.split(keyword)[0].slice(0, -1);
|
||||
}
|
||||
}
|
||||
return version;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue