-
Notifications
You must be signed in to change notification settings - Fork 207
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce git utilities in the API (#422)
* Use isomorphic-git, initial commit and commit post packages install during app creation * Commit progress on git API on the web package * Add ability to fetch current version on the frontend
- Loading branch information
Showing
10 changed files
with
323 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import fs from 'node:fs/promises'; | ||
import Path from 'node:path'; | ||
import git, { type ReadCommitResult } from 'isomorphic-git'; | ||
import { pathToApp } from './disk.mjs'; | ||
import type { App as DBAppType } from '../db/schema.mjs'; | ||
|
||
// Initialize a git repository in the app directory | ||
export async function initRepo(app: DBAppType): Promise<void> { | ||
const dir = pathToApp(app.externalId); | ||
await git.init({ fs, dir }); | ||
await commitAllFiles(app, 'Initial commit'); | ||
} | ||
|
||
// Commit all current files in the app directory | ||
export async function commitAllFiles(app: DBAppType, message: string): Promise<string> { | ||
const dir = pathToApp(app.externalId); | ||
|
||
// Stage all files | ||
await git.add({ fs, dir, filepath: '.' }); | ||
|
||
// Create commit | ||
const sha = await git.commit({ | ||
fs, | ||
dir, | ||
message, | ||
author: { | ||
name: 'Srcbook', | ||
email: '[email protected]', | ||
}, | ||
}); | ||
|
||
return sha; | ||
} | ||
|
||
// Checkout to a specific commit | ||
// Use this to revert to a previous commit or "version" | ||
export async function checkoutCommit(app: DBAppType, commitSha: string): Promise<void> { | ||
const dir = pathToApp(app.externalId); | ||
|
||
await git.checkout({ | ||
fs, | ||
dir, | ||
ref: commitSha, | ||
force: true, | ||
}); | ||
} | ||
|
||
// Get commit history | ||
export async function getCommitHistory( | ||
app: DBAppType, | ||
limit: number = 100, | ||
): Promise<Array<ReadCommitResult>> { | ||
const dir = pathToApp(app.externalId); | ||
|
||
const commits = await git.log({ | ||
fs, | ||
dir, | ||
depth: limit, // Limit to specified number of commits, default 100 | ||
}); | ||
|
||
return commits; | ||
} | ||
|
||
// Helper function to ensure the repo exists, initializing it if necessary | ||
export async function ensureRepoExists(app: DBAppType): Promise<void> { | ||
const dir = pathToApp(app.externalId); | ||
try { | ||
await fs.access(Path.join(dir, '.git')); | ||
} catch (error) { | ||
// If .git directory doesn't exist, initialize the repo | ||
await initRepo(app); | ||
} | ||
} | ||
|
||
// Get the current commit SHA | ||
export async function getCurrentCommitSha(app: DBAppType): Promise<string> { | ||
const dir = pathToApp(app.externalId); | ||
const currentCommit = await git.resolveRef({ fs, dir, ref: 'HEAD' }); | ||
return currentCommit; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# typical gitignore for web apps | ||
node_modules | ||
dist | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import React, { createContext, useContext, useState, useCallback, useEffect } from 'react'; | ||
import { useApp } from './use-app'; | ||
import { commitVersion, getCurrentVersion } from '@/clients/http/apps'; | ||
|
||
interface Version { | ||
sha: string; | ||
message?: string; | ||
} | ||
|
||
interface VersionContextType { | ||
currentVersion: Version | null; | ||
commitFiles: (message: string) => Promise<void>; | ||
checkout: (sha: string) => Promise<void>; | ||
fetchVersions: () => Promise<void>; | ||
} | ||
|
||
const VersionContext = createContext<VersionContextType | undefined>(undefined); | ||
|
||
export const VersionProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { | ||
const { app } = useApp(); | ||
// TODO implement this | ||
// const { refreshFiles } = useFiles(); | ||
const [currentVersion, setCurrentVersion] = useState<Version | null>(null); | ||
|
||
const fetchVersion = useCallback(async () => { | ||
if (!app) return; | ||
|
||
try { | ||
const currentVersionResponse = await getCurrentVersion(app.id); | ||
setCurrentVersion({ sha: currentVersionResponse.sha }); | ||
} catch (error) { | ||
console.error('Error fetching current version:', error); | ||
} | ||
}, [app]); | ||
|
||
useEffect(() => { | ||
fetchVersion(); | ||
}, [fetchVersion]); | ||
|
||
const commitFiles = useCallback( | ||
async (message: string) => { | ||
if (!app) return; | ||
|
||
try { | ||
const response = await commitVersion(app.id, message); | ||
setCurrentVersion({ sha: response.sha, message }); | ||
} catch (error) { | ||
console.error('Error committing files:', error); | ||
} | ||
}, | ||
[app], | ||
); | ||
|
||
const checkout = useCallback( | ||
async (sha: string) => { | ||
if (!app) return; | ||
|
||
try { | ||
const response = await fetch(`/api/apps/${app.id}/checkout`, { | ||
method: 'POST', | ||
headers: { 'Content-Type': 'application/json' }, | ||
body: JSON.stringify({ sha }), | ||
}); | ||
if (!response.ok) throw new Error('Failed to checkout version'); | ||
await fetchVersion(); | ||
// await refreshFiles(); | ||
} catch (error) { | ||
console.error('Error checking out version:', error); | ||
} | ||
}, | ||
[app, fetchVersion], | ||
); | ||
|
||
return ( | ||
<VersionContext.Provider | ||
value={{ currentVersion, commitFiles, checkout, fetchVersions: fetchVersion }} | ||
> | ||
{children} | ||
</VersionContext.Provider> | ||
); | ||
}; | ||
|
||
export const useVersion = () => { | ||
const context = useContext(VersionContext); | ||
if (context === undefined) { | ||
throw new Error('useVersion must be used within a VersionProvider'); | ||
} | ||
return context; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.