-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Address minor TODOs #55
Changes from all commits
b32efc4
349e754
04fe507
b0ce931
cb13faa
dee086c
20aed4c
fc00e95
76a2807
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
type: improvement | ||
improvement: | ||
description: Address minor issues | ||
links: | ||
- https://github.com/palantir/osdk-ts/pull/55 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,70 +14,84 @@ | |
* limitations under the License. | ||
*/ | ||
|
||
import { execSync } from "node:child_process"; | ||
import { exec } from "node:child_process"; | ||
import { promisify } from "node:util"; | ||
import { describe, expect, it, vi } from "vitest"; | ||
import { autoVersion } from "./autoVersion.js"; | ||
|
||
vi.mock("node:child_process"); | ||
const execAsync = promisify(exec); | ||
|
||
describe("autoVersion", () => { | ||
const execSyncMock = vi.mocked(execSync); | ||
const execMock = vi.mocked(execAsync); | ||
const execReturnValue = (out: string) => ({ stdout: out, stderr: "" }); | ||
|
||
it("should return a valid SemVer version from git describe", async () => { | ||
const validGitVersion = "1.2.3"; | ||
execSyncMock.mockReturnValue(validGitVersion); | ||
execMock.mockResolvedValue(execReturnValue(validGitVersion)); | ||
|
||
const version = await autoVersion(); | ||
expect(version).toBe("1.2.3"); | ||
|
||
expect(execSyncMock).toHaveBeenCalledWith( | ||
"git describe --tags --first-parent --dirty", | ||
{ encoding: "utf8" }, | ||
); | ||
}); | ||
|
||
it("should replace default prefix v from git describe output", async () => { | ||
const validGitVersion = "v1.2.3"; | ||
execSyncMock.mockReturnValue(validGitVersion); | ||
const version = await autoVersion(); | ||
execMock.mockResolvedValue(execReturnValue(validGitVersion)); | ||
|
||
const version = await autoVersion(); | ||
expect(version).toBe("1.2.3"); | ||
expect(execSyncMock).toHaveBeenCalledWith( | ||
"git describe --tags --first-parent --dirty", | ||
{ encoding: "utf8" }, | ||
); | ||
}); | ||
|
||
it("should replace the prefix from the found git tag", async () => { | ||
const validGitVersion = "@[email protected]"; | ||
execSyncMock.mockReturnValue(validGitVersion); | ||
execMock.mockResolvedValue(execReturnValue(validGitVersion)); | ||
|
||
const version = await autoVersion("@package@"); | ||
|
||
expect(version).toBe("1.2.3"); | ||
expect(execSyncMock).toHaveBeenCalledWith( | ||
"git describe --tags --first-parent --dirty --match=\"@package@*\"", | ||
{ encoding: "utf8" }, | ||
); | ||
}); | ||
|
||
it("should only replace the prefix if found at the start of the tag only", async () => { | ||
const validGitVersion = "1.2.3-package"; | ||
execSyncMock.mockReturnValue(validGitVersion); | ||
execMock.mockResolvedValue(execReturnValue(validGitVersion)); | ||
|
||
const version = await autoVersion("-package"); | ||
|
||
expect(version).toBe("1.2.3-package"); | ||
expect(execSyncMock).toHaveBeenCalledWith( | ||
"git describe --tags --first-parent --dirty --match=\"-package*\"", | ||
{ encoding: "utf8" }, | ||
); | ||
}); | ||
|
||
it("should throw an error if git describe returns a non-SemVer string", async () => { | ||
const nonSemVerGitVersion = "not-semver"; | ||
execSyncMock.mockReturnValue(nonSemVerGitVersion); | ||
execMock.mockResolvedValue(execReturnValue(nonSemVerGitVersion)); | ||
|
||
await expect(autoVersion()).rejects.toThrowError(); | ||
}); | ||
|
||
await expect(autoVersion()).rejects.toThrow(); | ||
it("should throw an error if git isn't found", async () => { | ||
execMock.mockImplementation(() => { | ||
throw new Error("Command not found"); | ||
}); | ||
|
||
await expect(autoVersion()).rejects.toThrowError( | ||
"Unable to determine the version using git-describe as git is not installed", | ||
); | ||
}); | ||
|
||
it("should throw an error if the current directory is not a git repository", async () => { | ||
execMock.mockImplementation(() => { | ||
throw new Error("fatal: not a git repository"); | ||
}); | ||
|
||
await expect(autoVersion()).rejects.toThrowError( | ||
"Unable to determine the version using git-describe as the current directory is not a git repository", | ||
); | ||
}); | ||
|
||
it("should throw an error if no git tags are found", async () => { | ||
execMock.mockImplementation(() => { | ||
throw new Error("fatal: no names found, cannot describe anything."); | ||
}); | ||
|
||
await expect(autoVersion()).rejects.toThrowError( | ||
"Unable to determine the version using git-describe as no matching tags were found.", | ||
); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,8 @@ | |
* limitations under the License. | ||
*/ | ||
|
||
import { execSync } from "node:child_process"; | ||
import { exec } from "node:child_process"; | ||
import { promisify } from "node:util"; | ||
import { ExitProcessError } from "../ExitProcessError.js"; | ||
import { isValidSemver } from "./isValidSemver.js"; | ||
|
||
|
@@ -29,26 +30,71 @@ export async function autoVersion(tagPrefix: string = ""): Promise<string> { | |
const [matchPrefix, prefixRegex] = tagPrefix !== "" | ||
? [tagPrefix, new RegExp(`^${tagPrefix}`)] | ||
: [undefined, new RegExp(`^v?`)]; | ||
|
||
const gitVersion = await gitDescribe(matchPrefix); | ||
const version = gitVersion.trim().replace(prefixRegex, ""); | ||
if (!isValidSemver(version)) { | ||
throw new ExitProcessError( | ||
2, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From earlier comments we don't actually do anything with this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually think it doesn't add any value as well. So I could remove the passing of errorCode in a FLUP. Unless you foresee a usecase where we could benefit from it consistently? |
||
`The version string ${version} is not SemVer compliant.`, | ||
); | ||
} | ||
|
||
return version; | ||
} | ||
|
||
async function gitDescribe(matchPrefix: string | undefined): Promise<string> { | ||
let gitVersion; | ||
try { | ||
const gitVersion = execSync( | ||
const execAsync = promisify(exec); | ||
const { stdout } = await execAsync( | ||
`git describe --tags --first-parent --dirty${ | ||
matchPrefix != null ? ` --match="${matchPrefix}*"` : "" | ||
}`, | ||
{ encoding: "utf8" }, | ||
); | ||
const version = gitVersion.trim().replace(prefixRegex, ""); | ||
if (!isValidSemver(version)) { | ||
throw new ExitProcessError( | ||
2, | ||
`The version string ${version} is not SemVer compliant.`, | ||
); | ||
gitVersion = stdout; | ||
} catch (error: any) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, have you tested for this new execAsync change that it throws? If it does not throw on non-zero exit code is the error message on stderr instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tested and throws 👍 |
||
if (error instanceof Error) { | ||
const errorMessage: string = error.message.toLowerCase(); | ||
|
||
if ( | ||
errorMessage.includes("not recognized") | ||
|| errorMessage.includes("command not found") | ||
|| errorMessage.includes("no such file or directory") | ||
) { | ||
throw new ExitProcessError( | ||
2, | ||
`Unable to determine the version using git-describe as git is not installed or found in the PATH.\nPlease correctly configure git or supply a --version option.`, | ||
); | ||
} | ||
|
||
if ( | ||
errorMessage.includes("fatal: not a git repository") | ||
) { | ||
throw new ExitProcessError( | ||
2, | ||
`Unable to determine the version using git-describe as the current directory is not a git repository.\nPlease run the command in a git respository or supply a --version option.`, | ||
); | ||
} | ||
|
||
if ( | ||
errorMessage.includes( | ||
"fatal: no names found, cannot describe anything.", | ||
) | ||
) { | ||
throw new ExitProcessError( | ||
2, | ||
`Unable to determine the version using git-describe as no matching tags were found.\nPlease tag a matching version or supply a --version option.`, | ||
); | ||
} | ||
} | ||
|
||
return version; | ||
} catch (error) { | ||
throw new ExitProcessError( | ||
2, | ||
`Unable to determine the version automatically. Please supply a --version argument. ${error}`, | ||
`Unable to determine the version automatically: ${error}.\nPlease supply a --version option.`, | ||
); | ||
} | ||
|
||
return gitVersion; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably assume the versions are enforced semver given the timelines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think its better to leave it and I could clarify with a comment. I personally have few broken apps that have LOOSE versions stored
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I guess the point is that after a certain point in time in the future we're not going to have the control to filter this and it will be on the service layer to decide how to handle this instead