diff --git a/CHANGELOG.md b/CHANGELOG.md index 20bc2d8..aefb9d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how ## [Released] +##[1.8.0](#v1.8.0) (2022-03-30) + +### Added + +- Prompt Camper to update course, when update is detected +- Provide a button to automatically update course + ##[1.7.4](#v1.7.4) (2022-03-30) ### Updated diff --git a/README.md b/README.md index 201e12f..c808832 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,10 @@ This extension helps run the freeCodeCamp courses found here: [./resources/cours ## Published Courses +- [NEAR Curriculum](https://github.com/freeCodeCamp/near-curriculum/) - [Project Euler: Rust](https://github.com/freeCodeCamp/euler-rust/) +- [Solana Curriculum](https://github.com/freeCodeCamp/solana-curriculum/) +- [Web3 Curriculum](https://github.com/freeCodeCamp/web3-curriculum/) ## Course Config diff --git a/package-lock.json b/package-lock.json index 82dd941..c2c932d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "freecodecamp-courses", - "version": "1.7.4", + "version": "1.8.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "freecodecamp-courses", - "version": "1.7.4", + "version": "1.8.0", "license": "BSD-3-Clause", "dependencies": { "node-fetch": "3.3.1" @@ -25,7 +25,7 @@ }, "engines": { "node": ">=18.0.0", - "vscode": "^1.74.0" + "vscode": ">=1.76.0" } }, "node_modules/@discoveryjs/json-ext": { diff --git a/package.json b/package.json index 6b0b00b..0058813 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "freecodecamp-courses", "displayName": "freeCodeCamp - Courses", "description": "Provides tooling for quick and easy selection of courses offered by freeCodeCamp", - "version": "1.7.4", + "version": "1.8.0", "author": "freeCodeCamp", "publisher": "freeCodeCamp", "galleryBanner": { diff --git a/src/commands/create-new-course.ts b/src/commands/create-new-course.ts index 724f5ab..7ded35e 100644 --- a/src/commands/create-new-course.ts +++ b/src/commands/create-new-course.ts @@ -1,18 +1,13 @@ import { window } from "vscode"; import { handleConnection, handleEmptyDirectory } from "../handles"; -import { handleMessage } from "../flash"; import { createBackgroundTerminal } from "../handles"; import { showInputBox } from "../inputs"; -import { FlashTypes } from "../typings"; import { gitClone } from "../usefuls"; export default async function createNewCourse() { const course = await showInputBox(); if (!course) { - handleMessage({ - message: "No course name provided.", - type: FlashTypes.ERROR, - }); + window.showErrorMessage("No course name provided."); return Promise.reject(); } try { @@ -27,10 +22,7 @@ export default async function createNewCourse() { return Promise.resolve(); } catch (e) { console.error(e); - handleMessage({ - message: "Error cloning course. See console for details.", - type: FlashTypes.ERROR, - }); + window.showErrorMessage("Error cloning course. See console for details."); return Promise.reject(); } } diff --git a/src/commands/develop-course.ts b/src/commands/develop-course.ts index 146c7cd..78bd8ee 100644 --- a/src/commands/develop-course.ts +++ b/src/commands/develop-course.ts @@ -1,8 +1,8 @@ +import { window } from "vscode"; import { handleConfig } from "../handles"; -import { handleMessage } from "../flash"; -import { FlashTypes } from "../typings"; import { getConfig, getPackageJson } from "../usefuls"; import { checkForCourseUpdates } from "../updates"; +import { updateRepository } from "../update-repository"; export default async function developCourse() { try { @@ -11,18 +11,20 @@ export default async function developCourse() { const githubLink = rootPackage.repository.url; const isCourseUpdates = await checkForCourseUpdates(githubLink, config); if (isCourseUpdates) { - handleMessage({ - message: - "This course has been updated. It is recommended you re-clone the repository.", - type: FlashTypes.WARNING, - }); + const camperChoice = await window.showWarningMessage( + "This course has been updated. It is recommended you re-clone the repository.", + "Update", + "Dismiss" + ); + if (camperChoice === "Update") { + return updateRepository(); + } } handleConfig(config, "develop-course"); } catch (e) { console.error("freeCodeCamp > runCourse: ", e); - return handleMessage({ - message: "Unable to develop course. See dev console for more details.", - type: FlashTypes.ERROR, - }); + return window.showErrorMessage( + "Unable to develop course. See dev console for more details." + ); } } diff --git a/src/commands/run-course.ts b/src/commands/run-course.ts index e9ece1c..65d29d3 100644 --- a/src/commands/run-course.ts +++ b/src/commands/run-course.ts @@ -1,8 +1,8 @@ import { handleConfig } from "../handles"; -import { handleMessage } from "../flash"; -import { FlashTypes } from "../typings"; +import { window } from "vscode"; import { getConfig, getPackageJson } from "../usefuls"; import { checkForCourseUpdates } from "../updates"; +import { updateRepository } from "../update-repository"; export default async function runCourse() { try { @@ -11,18 +11,24 @@ export default async function runCourse() { const githubLink = rootPackage.repository.url; const isCourseUpdates = await checkForCourseUpdates(githubLink, config); if (isCourseUpdates) { - handleMessage({ - message: - "This course has been updated. It is recommended you re-clone the repository.", - type: FlashTypes.WARNING, - }); + /** + * There is an update to the curriculum, it is recommended that you update your local copy of the curriculum and rebuild the container. + * NOTE: You will lose any progress in your container. + */ + const camperChoice = await window.showWarningMessage( + "This course has been updated. It is recommended you update the repository.", + "Update", + "Dismiss" + ); + if (camperChoice === "Update") { + return updateRepository(); + } } handleConfig(config, "run-course"); } catch (e) { console.error("freeCodeCamp > runCourse: ", e); - return handleMessage({ - message: "Unable to run course. See dev console for more details.", - type: FlashTypes.ERROR, - }); + return window.showErrorMessage( + "Unable to run course. See dev console for more details." + ); } } diff --git a/src/components.ts b/src/components.ts index 1b2fecc..c48e027 100644 --- a/src/components.ts +++ b/src/components.ts @@ -1,7 +1,6 @@ import { commands, Uri, workspace, window } from "vscode"; import fetch from "node-fetch"; -import { Course, FlashTypes } from "./typings"; -import { handleMessage } from "./flash"; +import { Course } from "./typings"; export async function openTerminal() { const terminal = window.createTerminal("freeCodeCamp"); @@ -32,7 +31,7 @@ export async function currentDirectoryCourse(): Promise< return Promise.resolve(courseGithubLink); } catch (e) { console.error(e); - handleMessage({ message: e as string, type: FlashTypes.INFO }); + window.showInformationMessage(e as string); return Promise.resolve(null); } } @@ -43,7 +42,7 @@ export async function getRootWorkspaceDir() { return Promise.resolve(path.path); } catch (e) { console.error(e); - handleMessage({ message: e as string, type: FlashTypes.INFO }); + window.showInformationMessage(e as string); return Promise.resolve(null); } } diff --git a/src/flash.ts b/src/flash.ts deleted file mode 100644 index 1d5e714..0000000 --- a/src/flash.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { window } from "vscode"; -import { FlashTypes, Flash } from "./typings"; - -export function showMessage(shower: Function) { - return (s: string, opts: Flash["opts"]) => shower(s, opts); -} - -export const flasher = { - [FlashTypes.INFO]: showMessage(window.showInformationMessage), - [FlashTypes.WARNING]: showMessage(window.showWarningMessage), - [FlashTypes.ERROR]: showMessage(window.showErrorMessage), -}; - -export function handleMessage(flash: Flash) { - flasher[flash.type](flash.message, flash.opts); -} diff --git a/src/handles.ts b/src/handles.ts index 2eef2fa..6321cbe 100644 --- a/src/handles.ts +++ b/src/handles.ts @@ -1,9 +1,8 @@ -import { Bashrc, Config, FlashTypes, Test } from "./typings"; +import { Bashrc, Config, Test } from "./typings"; import { exampleConfig } from "./fixture"; import { commands, Terminal, TerminalExitStatus, window } from "vscode"; import { isConnectedToInternet, openSimpleBrowser } from "./components"; import { cd, checkIfURLIsAvailable, ensureDirectoryIsEmpty } from "./usefuls"; -import { handleMessage } from "./flash"; import { everythingButHandles } from "."; import { createLoaderWebView } from "./loader"; @@ -82,10 +81,9 @@ export function rebuildAndReopenInContainer() { export async function handleConnection() { const isConnected = await isConnectedToInternet(); if (!isConnected) { - handleMessage({ - message: "No connection found. Please check your internet connection", - type: FlashTypes.ERROR, - }); + window.showErrorMessage( + "No connection found. Please check your internet connection" + ); return Promise.reject(); } return Promise.resolve(); @@ -94,15 +92,7 @@ export async function handleConnection() { export async function handleEmptyDirectory() { const isEmpty = await ensureDirectoryIsEmpty(); if (!isEmpty) { - handleMessage({ - message: "Directory is not empty.", - type: FlashTypes.WARNING, - opts: { - detail: "Please empty working directory, and try again.", - modal: true, - }, - }); - + window.showWarningMessage("Directory is not empty."); return Promise.reject(); } return Promise.resolve(); @@ -148,10 +138,7 @@ export async function handleWorkspace( for (const preview of workspace!.previews) { const notSets = getNotSets(preview, compulsoryKeys); if (notSets.length) { - handleMessage({ - message: `Preview missing keys: ${notSets.join(", ")}`, - type: FlashTypes.ERROR, - }); + window.showErrorMessage(`Preview missing keys: ${notSets.join(", ")}`); return Promise.reject(); } if (preview.showLoader) { @@ -186,10 +173,9 @@ export async function handleWorkspace( for (const term of workspace!.terminals) { const notSets = getNotSets(term, compulsoryKeys); if (notSets.length) { - handleMessage({ - message: `Terminals missing keys: ${notSets.join(", ")}`, - type: FlashTypes.ERROR, - }); + window.showErrorMessage( + `Terminals missing keys: ${notSets.join(", ")}` + ); return Promise.reject(); } if (term?.name) { @@ -209,10 +195,7 @@ export async function handleWorkspace( for (const file of workspace!.files) { const notSets = getNotSets(file, compulsoryKeys); if (notSets.length) { - handleMessage({ - message: `Files missing keys: ${notSets.join(", ")}`, - type: FlashTypes.ERROR, - }); + window.showErrorMessage(`Files missing keys: ${notSets.join(", ")}`); return Promise.reject(); } // TODO: Open file @@ -240,10 +223,7 @@ export async function handleConfig( const notSets = getNotSets(config, compulsoryKeys); if (notSets.length) { - return handleMessage({ - type: FlashTypes.ERROR, - message: `${notSets.join(", and ")} not set.`, - }); + return window.showErrorMessage(`${notSets.join(", and ")} not set.`); } // Run prepare script @@ -307,9 +287,8 @@ export function ensureNoExtraKeys(obj: any, exampleObject: any) { console.log( "There are keys that are not recognised in the `freecodecamp.conf.json` file. Double-check the specification." ); - handleMessage({ - type: FlashTypes.WARNING, - message: `Unrecognised keys: ${unrecognisedKeys.join(", ")}`, - }); + window.showWarningMessage( + `Unrecognised keys: ${unrecognisedKeys.join(", ")}` + ); } } diff --git a/src/index.ts b/src/index.ts index 0a07ded..1663117 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,8 +13,6 @@ import { cd, } from "./usefuls"; -import { handleMessage, showMessage } from "./flash"; - export const everythingButHandles = { currentDirectoryCourse, ensureDirectoryIsEmpty, @@ -26,7 +24,5 @@ export const everythingButHandles = { openSimpleBrowser, openTerminal, showInputBox, - handleMessage, - showMessage, cd, }; diff --git a/src/typings.ts b/src/typings.ts index 8c93b79..9eea39c 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -1,19 +1,4 @@ /* eslint-disable @typescript-eslint/naming-convention */ -export enum FlashTypes { - ERROR = "error", - INFO = "info", - WARNING = "warning", -} - -export type Flash = { - message: string; - opts?: { - detail: string; - modal?: boolean; - }; - type: FlashTypes; -}; - export interface Course { githubLink: string; name: string; diff --git a/src/update-repository.ts b/src/update-repository.ts new file mode 100644 index 0000000..b7eba84 --- /dev/null +++ b/src/update-repository.ts @@ -0,0 +1,27 @@ +import { window } from "vscode"; +import { currentDirectoryCourse } from "./components"; +import { createBackgroundTerminal } from "./handles"; + +/** + * Pulls the latest changes from the remote repository. + */ +export async function updateRepository() { + const courseGitDownloaded = await currentDirectoryCourse(); + + // git checkout -b "" + // git commit -m "test" + // git checkout main + // git pull upstream main + // git reset --hard upstream/main + // Tell camper where to find history + const termStatus = await createBackgroundTerminal( + "freeCodeCamp: Git Pull", + `git pull ${courseGitDownloaded} main` + ); + + if (termStatus.code !== 0) { + window.showErrorMessage("Error updating course."); + } else { + window.showInformationMessage("Course updated successfully."); + } +} diff --git a/src/updates.ts b/src/updates.ts index e3ddd7b..48c5913 100644 --- a/src/updates.ts +++ b/src/updates.ts @@ -1,7 +1,7 @@ import { join } from "path"; +import { window } from "vscode"; import fetch from "node-fetch"; -import { Config, FlashTypes } from "./typings"; -import { handleMessage } from "./flash"; +import { Config } from "./typings"; export async function checkForCourseUpdates( githubLink: string, @@ -9,11 +9,9 @@ export async function checkForCourseUpdates( ): Promise { const currentVersion = config.version; if (!currentVersion) { - handleMessage({ - message: - "Unable to find curriculum version from `freecodecamp.conf.json` file", - type: FlashTypes.WARNING, - }); + window.showWarningMessage( + "Unable to find curriculum version from `freecodecamp.conf.json` file" + ); return false; } @@ -24,10 +22,7 @@ export async function checkForCourseUpdates( const repoVersion = repoConfig.version; if (!repoVersion) { - handleMessage({ - message: "Unable to get curriculum version from upstream", - type: FlashTypes.WARNING, - }); + window.showWarningMessage("Unable to get curriculum version from upstream"); return false; } @@ -58,14 +53,9 @@ async function getConfigFromGitHub(githubLink: string) { return config; } catch (e) { console.error(e); - handleMessage({ - message: `Unable to check for latest curriculum version: ${url.href}`, - type: FlashTypes.WARNING, - opts: { - detail: - "You might be running a version of the curriculum that does not have bug fixes or new features.", - }, - }); + window.showWarningMessage( + "Unable to check for latest curriculum version: " + url.href + ); } return null; } diff --git a/src/usefuls.ts b/src/usefuls.ts index dc14b65..039ac62 100644 --- a/src/usefuls.ts +++ b/src/usefuls.ts @@ -1,7 +1,6 @@ -import { workspace, Uri, FileType } from "vscode"; +import { workspace, Uri, FileType, window } from "vscode"; import fetch from "node-fetch"; -import { handleMessage } from "./flash"; -import { Config, FlashTypes } from "./typings"; +import { Config } from "./typings"; export const gitClone = (githubLink: string) => `git clone ${githubLink}.git .`; export const cd = (path: string, cmd: string) => `cd ${path} && ${cmd}`; @@ -81,10 +80,9 @@ export async function getConfig(): Promise { return Promise.resolve(fileData); } catch (e) { console.error("freeCodeCamp > getConfig: ", e); - handleMessage({ - message: "Unable to find a `freecodecamp.conf.json` file in workspace.", - type: FlashTypes.ERROR, - }); + window.showErrorMessage( + "Unable to find a `freecodecamp.conf.json` file in workspace." + ); return Promise.reject(e); } }