Skip to content

Commit

Permalink
feat(templates): add the possibility to select a specific git branch …
Browse files Browse the repository at this point in the history
…on the template repo

Feature/select branch
  • Loading branch information
sebsto authored Jun 22, 2024
2 parents 82a28ae + 1ff334a commit 35a825c
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe("TemplateService", () => {

const data = await getTemplateTitles(
"https://example.com/templates.json",
"main",
);

expect(data.list.length).toBe(2);
Expand All @@ -53,14 +54,16 @@ describe("TemplateService", () => {
expect(data.list[1].name).toBe("sqsToLambda");
expect(data.list[1].path).toBe("some/path/to/sqs.png");
expect(axios.get).toHaveBeenCalledWith(
"https://example.com/templates.json",
"https://example.com/templates.json/main/cookiecutter.json",
);

axiosGetSpy.mockRestore();
});

it("should throw TemplateFetchError when URL is not defined", async () => {
await expect(getTemplateTitles("")).rejects.toThrow(TemplateFetchError);
await expect(getTemplateTitles("", "")).rejects.toThrow(
TemplateFetchError,
);
});

it("should throw TemplateFetchError when request fails", async () => {
Expand All @@ -70,7 +73,7 @@ describe("TemplateService", () => {
.mockRejectedValueOnce(new Error(errorMessage));

await expect(
getTemplateTitles("https://example.com/templates.json"),
getTemplateTitles("https://example.com/templates.json", "main"),
).rejects.toThrow(TemplateFetchError);

axiosGetSpy.mockRestore();
Expand Down
8 changes: 4 additions & 4 deletions vscode-extension/packages/core-lib/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
//===----------------------------------------------------------------------===//

export const config = {
TEMPLATES_JSON_URL:
process.env.TEMPLATES_JSON_URL ||
"https://raw.githubusercontent.com/swift-server-community/aws-lambda-swift-sam-template/main/cookiecutter.json",
RAW_TEMPLATES_REPO_URL:
process.env.RAW_TEMPLATES_REPO_URL ||
"https://raw.githubusercontent.com/swift-server-community/aws-lambda-swift-sam-template",
TEMPLATES_REPO_URL:
process.env.TEMPLATES_REPO_URL ||
"https://github.com/swift-server-community/aws-lambda-swift-sam-template.git",
"https://github.com/swift-server-community/aws-lambda-swift-sam-template",
CLONED_TEMPLATES_DIR:
process.env.CLONED_TEMPLATES_DIR || "/tmp/template-repo",
EVENTS_DIR: process.env.EVENTS_DIR || "/events",
Expand Down
30 changes: 25 additions & 5 deletions vscode-extension/packages/core-lib/src/facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
//===----------------------------------------------------------------------===//

/* eslint-disable no-unused-vars */
import { getTemplateTitles } from "./services/templateServices";
import {
getTemplateTitles,
getTemplateBranches,
} from "./services/templateServices";
import logger from "./logger";
import { config } from "./config/config";
import * as Sam from "./sam/sam";
Expand Down Expand Up @@ -43,6 +46,20 @@ export async function getFunctions(path: string): Promise<string[]> {
return await Sam.getFunctions(path);
}

/**
* Gets all the branches from the template repository
* @async
* @example
* const branches = await getBranches();
* console.log("Branches:", branches);
* @throws {Error} If the branches cannot be fetched
* @returns {Promise<string[]>} A list of branches
*/
export async function getBranches(): Promise<string[]> {
logger.debug("Getting branches...");
return await getTemplateBranches(config.TEMPLATES_REPO_URL);
}

/**
* Gets all the events
* @param {string} path The path to the project to get the events from
Expand Down Expand Up @@ -150,9 +167,11 @@ export function unsubscribeFromStderr(listener: (data: string) => void) {
* @throws {Error} If the templates cannot be retrieved
* @returns {Promise<string[]>} A list of available template titles
*/
export async function getTemplates(): Promise<TemplatesResult> {
export async function getTemplates(
branch: string = "main",
): Promise<TemplatesResult> {
logger.debug("Getting templates...");
return await getTemplateTitles(config.TEMPLATES_JSON_URL);
return await getTemplateTitles(config.RAW_TEMPLATES_REPO_URL, branch);
}

/**
Expand All @@ -170,11 +189,12 @@ export async function initializeProject(
name: string,
template: string,
path: string,
branch: string = "main",
): Promise<CommandResult> {
logger.debug(
`Initializing project with template ${template} and name ${name} in directory ${path}...`,
`Initializing project with template ${template} and name ${name} in directory ${path}... from branch ${branch}`,
);
return await Sam.runInitializeProject(name, template, path);
return await Sam.runInitializeProject(name, template, path, branch);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion vscode-extension/packages/core-lib/src/sam/sam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export async function runInitializeProject(
name: string,
template: string,
path: string,
branch: string,
): Promise<CommandResult> {
try {
if (!name) {
Expand Down Expand Up @@ -181,7 +182,7 @@ export async function runInitializeProject(
const exitCode = 0;

await cleanupTempDirectory();
const cloneResult = await cloneTemplate();
const cloneResult = await cloneTemplate(branch);
output.stdout += cloneResult.output.stdout;
output.stderr += cloneResult.output.stderr;
if (cloneResult.exitCode !== 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,30 @@ import { TemplatesResult } from "../utils/types";

/** Get the titles of the templates from the JSON file.
* @param {string} URL The URL of the JSON file
* @param {string} branch The branch of the repository
* @throws {Error} If the URL is not defined in the environment
* @async
* @example
* const titles = await getTemplateTitles("https://example.com/templates.json");
* const titles = await getTemplateTitles("https://example.com/templates.json", "main");
* console.log("Template titles:", titles);
* @returns {Promise<TemplatesResult>} The titles of the templates with their images
*/
export async function getTemplateTitles(URL: string): Promise<TemplatesResult> {
export async function getTemplateTitles(
URL: string,
branch: string,
): Promise<TemplatesResult> {
if (!URL || URL === "") {
throw new TemplateFetchError(
"TEMPLATES_JSON_URL is not defined in the environment.",
);
}

if (!branch || branch === "") {
throw new TemplateFetchError("Branch is not defined.");
}

try {
const response = await axios.get(URL);
const response = await axios.get(`${URL}/${branch}/cookiecutter.json`);

const result = Object.entries(response.data.templates).map(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -52,3 +60,38 @@ export async function getTemplateTitles(URL: string): Promise<TemplatesResult> {
);
}
}

/**
* Get the branches of the template repository.
* @param {string} repoUrl The URL of the GitHub repository
* @throws {Error} If the URL is not defined or if there's an error fetching the branches
* @async
* @example
* const branches = await getTemplateBranches("https://github.com/username/repository");
* console.log("Branches:", branches);
* @returns {Promise<string[]>} The branches of the repository
*/
export async function getTemplateBranches(repoUrl: string): Promise<string[]> {
if (!repoUrl || repoUrl === "") {
throw new TemplateFetchError("Repository URL is not defined.");
}

const apiUrl = `${repoUrl}/branches/all`;

try {
const response = await axios.get(apiUrl, {
headers: {
Accept: "application/json",
},
});
return response.data.payload.branches.map(
(branch: { name: string }) => branch.name,
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
throw new TemplateFetchError(
`Error fetching template branches: ${error.message}`,
error,
);
}
}
5 changes: 4 additions & 1 deletion vscode-extension/packages/core-lib/src/utils/initUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ const commandRunner = CommandRunner.getInstance();
* @throws {GitCloneFailedError} If the template repository cannot be cloned
* @returns {Promise<CommandResult>}
*/
export async function cloneTemplate(): Promise<CommandResult> {
export async function cloneTemplate(branch: string): Promise<CommandResult> {
const cloneArgs: string[] = [
"clone",
"--single-branch",
"--branch",
branch,
"--depth",
"1",
config.TEMPLATES_REPO_URL,
Expand Down
30 changes: 28 additions & 2 deletions vscode-extension/src/commands/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ export async function getEvents(data: any) {
return { events, success: true };
}

/**
* Fetches templates from the specified branch.
* @param {any} data - Branch information.
* @returns {Promise<{ templates: { list: [{ name: string, path: string }] }, success: boolean }>} An object containing fetched templates and success status.
* @async
* @example
* const templates = await getTemplates({ branch: "main" });
* console.log("Templates:", templates);
*/
export async function getTemplates(data: any) {
try {
const branch = data.branch;
const templates = await Sam.getTemplates(branch);
return { templates, success: true };
} catch (error: any) {
window.showErrorMessage(error.message);
}
}

/**
* Fetches necessary data to initialize the project.
* @returns {Promise<{ templates: any[], path: string, regions: any[], locale: string, theme: string }>} Object with templates, path, regions, locale, and theme.
Expand Down Expand Up @@ -82,7 +101,8 @@ export async function getReady() {
}
const locale = env.language || "en";
const theme = window.activeColorTheme.kind || "dark";
return { templates, path, regions, locale, theme };
const branches = await Sam.getBranches();
return { templates, path, regions, locale, theme, branches };
} catch (error: any) {
window.showErrorMessage(error.message);
}
Expand Down Expand Up @@ -137,13 +157,19 @@ export async function initializeProject(data: any) {
const name = data.name;
const selectedTemplate = data.template;
let path = data.path;
const branch = data.branch;

if (!path) {
const workspaceFolders = workspace.workspaceFolders;
path = workspaceFolders?.[0]?.uri.fsPath;
}

const result = await Sam.initializeProject(name, selectedTemplate, path);
const result = await Sam.initializeProject(
name,
selectedTemplate,
path,
branch || "main",
);
return { success: result.exitCode === 0 };
} catch (error: any) {
window.showErrorMessage(error.message);
Expand Down
13 changes: 13 additions & 0 deletions vscode-extension/src/panels/MainPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
getEvents,
getFunctions,
checkFolderExists,
getTemplates,
} from "../commands/Commands";

/**
Expand Down Expand Up @@ -211,6 +212,18 @@ export class MainPanel {
const data = message.data;

switch (command) {
case "templates":
getTemplates(data)
.then((response) => {
webview.postMessage({ command: "templates", data: response });
})
.catch((error) => {
webview.postMessage({
command: "templates",
data: { success: false, error },
});
});
return;
case "checkExists":
checkFolderExists(data)
.then((response) => {
Expand Down
9 changes: 6 additions & 3 deletions vscode-extension/webview-ui/src/api/markdownApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@
// This file contains the API for fetching Markdown files from the specified template repository.
const GITHUB_API_URL =
process.env.GITHUB_API_URL ||
"https://raw.githubusercontent.com/swift-server-community/aws-lambda-swift-sam-template/main/";
"https://raw.githubusercontent.com/swift-server-community/aws-lambda-swift-sam-template";

/**
* Fetches a Markdown file from the specified template repository.
* @param {string} template - The name of the template repository.
* @returns {Promise<string>} - A promise that resolves to the content of the Markdown file.
* @throws {Error} - If fetching the Markdown file fails.
*/
export async function fetchMarkdownFile(template: string): Promise<string> {
export async function fetchMarkdownFile(
template: string,
branch: string = "main",
): Promise<string> {
// Constructing the URL of the Markdown file
const url = `${GITHUB_API_URL}/${template}/doc/INFO.md`;
const url = `${GITHUB_API_URL}/${branch}/${template}/doc/INFO.md`;

try {
// Fetching the Markdown file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
*
*===----------------------------------------------------------------------===//
*/

.loading-ring-container, .loading-ring {
height: 100%;
}

.markdown-container {
display: flex;
Expand Down
Loading

0 comments on commit 35a825c

Please sign in to comment.