Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/__tests__/fixtures/ssh-gitmodules.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "ports/mdBook"]
path = ports/mdBook
url = git@github.com:catppuccin/mdBook.git
71 changes: 70 additions & 1 deletion src/__tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ import {
Submodule,
updateToLatestCommit,
updateToLatestTag,
getRemoteName,
} from "../main";
import { getExecOutput } from "@actions/exec";
import { mdBookSubmodule, nvimSubmodule, vscodeIconsSubmodule } from "./utils";
import {
mdBookSubmodule,
nvimSubmodule,
vscodeIconsSubmodule
} from "./utils";
import { getInput, setOutput } from "@actions/core";

vi.mock("@actions/core", async () => {
Expand Down Expand Up @@ -62,6 +67,37 @@ test("parse GitHub Action inputs with no input submodules", async () => {
expect(actual).toEqual(expected);
});

test.each([
["ssh://user@host.xz:port/path/to/repo.git/", "port/path/to/repo"],
["ssh://user@host.xz/path/to/repo.git/", "path/to/repo"],
["ssh://host.xz:port/path/to/repo.git/", "port/path/to/repo"],
["ssh://host.xz/path/to/repo.git/", "path/to/repo"],
["ssh://user@host.xz/path/to/repo.git/", "path/to/repo"],
["ssh://host.xz/path/to/repo.git/", "path/to/repo"],
["ssh://user@host.xz/~user/path/to/repo.git/", "user/path/to/repo"],
["ssh://host.xz/~user/path/to/repo.git/", "user/path/to/repo"],
["ssh://user@host.xz/~/path/to/repo.git", "path/to/repo"],
["ssh://host.xz/~/path/to/repo.git", "path/to/repo"],
["user@host.xz:/path/to/repo.git/", "path/to/repo"],
["host.xz:/path/to/repo.git/", "path/to/repo"],
["user@host.xz:~user/path/to/repo.git/", "user/path/to/repo"],
["host.xz:~user/path/to/repo.git/", "user/path/to/repo"],
["user@host.xz:path/to/repo.git", "path/to/repo"],
["host.xz:path/to/repo.git", "path/to/repo"],
["rsync://host.xz/path/to/repo.git/", "path/to/repo"],
["git://host.xz/path/to/repo.git/", "path/to/repo"],
["git://host.xz/~user/path/to/repo.git/", "user/path/to/repo"],
["http://host.xz/path/to/repo.git/", "path/to/repo"],
["https://host.xz/path/to/repo.git/", "path/to/repo"],
["/path/to/repo.git/", "path/to/repo"],
["path/to/repo.git/", "path/to/repo"],
["~/path/to/repo.git", "path/to/repo"],
["file:///path/to/repo.git/", "path/to/repo"],
["file://~/path/to/repo.git/", "path/to/repo"],
])('getRemoteName(%s) -> %s', (url, expected) => {
expect(getRemoteName(url)).toBe(expected)
})

test("extract single submodule from .gitmodules", async () => {
const input = await readFile("src/__tests__/fixtures/single-gitmodules.ini");
const expected = [mdBookSubmodule()];
Expand Down Expand Up @@ -93,6 +129,39 @@ test("extract single submodule from .gitmodules", async () => {
expect(actual).toEqual(expected);
});

test("extract single submodule from .gitmodules with ssh-style url", async () => {
const input = await readFile("src/__tests__/fixtures/ssh-gitmodules.ini");
const submodule = mdBookSubmodule()
submodule.url = "git@github.com:catppuccin/mdBook.git"
const expected = [submodule];

vi.mocked(getExecOutput)
.mockReturnValueOnce(
Promise.resolve({
exitCode: 0,
stdout: `\n${expected[0].previousCommitSha}`,
stderr: "",
})
)
.mockReturnValueOnce(
Promise.resolve({
exitCode: 0,
stdout: `\n${expected[0].previousTag}`,
stderr: "",
})
)
.mockReturnValueOnce(
Promise.resolve({
exitCode: 0,
stdout: `\n${expected[0].previousTag}`,
stderr: "",
})
);

const actual = await parseGitmodules(input);
expect(actual).toEqual(expected);
});

test("extract single submodule from .gitmodules that has no tags", async () => {
const input = await readFile("src/__tests__/fixtures/single-gitmodules.ini");
const expected = [mdBookSubmodule()];
Expand Down
35 changes: 31 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const gitmodulesSchema = z.record(
z.string(),
z.object({
path: z.string(),
url: z.string().url(),
})
url: z.string().regex(/[A-Za-z][A-Za-z0-9+.-]*/),
}),
);

export type Inputs = {
Expand Down Expand Up @@ -84,6 +84,34 @@ export const readFile = async (path: string): Promise<string> => {
});
};

export const getRemoteName = (url: string) => {
url = url.replace(/\.git\/?/, "")

let startIndex = url.length - 1;

// Scan backwards to find separator.
while (startIndex >= 0) {
if (url[startIndex] == "~" || url[startIndex] == ":") {
startIndex++;
break;
} else if (url[startIndex] == ".") {
break;
}

startIndex--;
}

// If we broke on a dot, we _probably_ hit a domain label, so
// scan forward until we hit a slash.
if (url[startIndex] == ".") {
while (url[startIndex] != "/") {
startIndex++;
}
}

return url.substring(startIndex).replace(/^\/+/, "");
}

export const parseGitmodules = async (
content: string
): Promise<Submodule[]> => {
Expand All @@ -94,8 +122,7 @@ export const parseGitmodules = async (
const name = key.split('"')[1].trim();
const path = values.path.replace(/"/g, "").trim();
const url = values.url.replace(/"/g, "").trim();
const urlParts = url.replace(".git", "").split("/");
const remoteName = `${urlParts[3]}/${urlParts[4]}`;
const remoteName = getRemoteName(url);
const [previousCommitSha, previousShortCommitSha] = await getCommit(path);
const previousCommitShaHasTag = await hasTag(path, previousCommitSha);
const previousTag = await getPreviousTag(path);
Expand Down