Skip to content

Commit

Permalink
Make sure we have pulled before reading LyraConfig
Browse files Browse the repository at this point in the history
Move all initializing git pull into RepoGit and make RepoGit shared for
each unique local git clone.

As the repository specific configuration file is potentially stale,
we need to do this initializing pull before any read of that
configuration file. To ensure that, I replace all direct reads with a
read through RepoGit. Since the factory always pulls, we know the config
will be fresh after a Lyra server start.

Note that the route for creating pull-requests can now theoretically
pull twice, if RepoGit was not initialzied first. That is however
extremely unlikely as button the create pull requests is on a page that
uses RepoGit to load its data. Anyway, I beleive we will resolve this
when we implement resyncing from the remotes.
  • Loading branch information
WULCAN committed Mar 17, 2024
1 parent fdb109e commit 47d9ea2
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 42 deletions.
6 changes: 5 additions & 1 deletion webapp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ projects:
github_token: << github token >>
```
also the project repository (client repository) needs to be cloned locally. and has in the root folder config
Multiple projects are supported, and multiple projects in the same local git repository
are supported, but configuring multiple porjects with different repo_path, resolving to
same local git repository, is _not_ supported.
The project repository (client repository) needs to be cloned locally. and has in the root folder config
file `lyra.yml` with the
example content:

Expand Down
34 changes: 5 additions & 29 deletions webapp/src/Cache.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
/* global globalThis */

import { debug } from '@/utils/log';
import { IGit } from '@/utils/git/IGit';
import { getRepoGit } from '@/RepoGit';
import { LanguageNotSupported } from '@/errors';
import { LyraProjectConfig } from '@/utils/lyraConfig';
import { ProjectStore } from '@/store/ProjectStore';
import { RepoGit } from '@/RepoGit';
import { SimpleGitWrapper } from '@/utils/git/SimpleGitWrapper';
import { ServerConfig } from '@/utils/serverConfig';
import { Store } from '@/store/Store';
import YamlTranslationAdapter from '@/utils/adapters/YamlTranslationAdapter';
import { LyraConfig, LyraProjectConfig } from '@/utils/lyraConfig';
import { ServerConfig, ServerProjectConfig } from '@/utils/serverConfig';

export class Cache {
private static hasPulled = new Set<string>();

public static async getLanguage(projectName: string, lang: string) {
const serverProjectConfig =
await ServerConfig.getProjectConfig(projectName);
await Cache.gitPullIfNeeded(serverProjectConfig);
const lyraConfig = await LyraConfig.readFromDir(
serverProjectConfig.repoPath,
);
const repo = await getRepoGit(serverProjectConfig);
const lyraConfig = await repo.getLyraConfig();
const lyraProjectConfig = lyraConfig.getProjectConfigByPath(
serverProjectConfig.projectPath,
);
Expand All @@ -47,21 +40,4 @@ export class Cache {

return globalThis.store.getProjectStore(lyraProjectConfig.absPath);
}

private static async gitPullIfNeeded(spConfig: ServerProjectConfig) {
const { repoPath, baseBranch } = spConfig;
if (Cache.hasPulled.has(repoPath)) {
debug(`repoPath: ${repoPath} is already pulled`);
return;
}
await RepoGit.cloneIfNotExist(spConfig);
debug(`prepare git options for path: ${repoPath}`);
const git: IGit = new SimpleGitWrapper(repoPath);
debug(`git checkout ${baseBranch} branch...`);
await git.checkout(baseBranch);
debug('git pull...');
await git.pull();
debug(`git done checkout ${baseBranch} branch and pull`);
Cache.hasPulled.add(repoPath);
}
}
28 changes: 26 additions & 2 deletions webapp/src/RepoGit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,31 @@ import { debug, info, warn } from '@/utils/log';
import { WriteLanguageFileError, WriteLanguageFileErrors } from '@/errors';

export class RepoGit {
private static repositories: {
[name: string]: Promise<RepoGit>;
} = {};

private readonly git: IGit;
private lyraConfig?: LyraConfig;

constructor(private readonly spConfig: ServerProjectConfig) {
private constructor(private readonly spConfig: ServerProjectConfig) {
this.git = new SimpleGitWrapper(spConfig.repoPath);
}

static async getRepoGit(config: ServerProjectConfig): Promise<RepoGit> {
const key = config.repoPath;
if (key in RepoGit.repositories) {
return RepoGit.repositories[key];
}
const { promise, resolve, reject } = Promise.withResolvers<RepoGit>();
RepoGit.repositories[key] = promise;

const repository = new RepoGit(config);
repository.checkoutBaseAndPull().then(() => resolve(repository), reject);

return promise;
}

public static async cloneIfNotExist(
spConfig: ServerProjectConfig,
): Promise<void> {
Expand Down Expand Up @@ -116,7 +134,7 @@ export class RepoGit {
return response.data.html_url;
}

private async getLyraConfig(): Promise<LyraConfig> {
async getLyraConfig(): Promise<LyraConfig> {
if (this.lyraConfig === undefined) {
await RepoGit.cloneIfNotExist(this.spConfig);
this.lyraConfig = await LyraConfig.readFromDir(this.spConfig.repoPath);
Expand Down Expand Up @@ -158,3 +176,9 @@ export class RepoGit {
return paths;
}
}

export async function getRepoGit(
config: ServerProjectConfig,
): Promise<RepoGit> {
return RepoGit.getRepoGit(config);
}
8 changes: 3 additions & 5 deletions webapp/src/app/api/messages/[projectName]/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { LyraConfig } from '@/utils/lyraConfig';
import MessageAdapterFactory from '@/utils/adapters/MessageAdapterFactory';
import { RepoGit } from '@/RepoGit';
import { ServerConfig } from '@/utils/serverConfig';
import { getRepoGit, RepoGit } from '@/RepoGit';
import {
LyraConfigReadingError,
ProjectNameNotFoundError,
Expand All @@ -18,9 +17,8 @@ export async function GET(
const serverProjectConfig =
await ServerConfig.getProjectConfig(projectName);
await RepoGit.cloneIfNotExist(serverProjectConfig);
const lyraConfig = await LyraConfig.readFromDir(
serverProjectConfig.repoPath,
);
const repo = await getRepoGit(serverProjectConfig);
const lyraConfig = await repo.getLyraConfig();
const projectConfig = lyraConfig.getProjectConfigByPath(
serverProjectConfig.projectPath,
);
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/app/api/pull-request/[projectName]/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getRepoGit } from '@/RepoGit';
import { ProjectNameNotFoundError } from '@/errors';
import { RepoGit } from '@/RepoGit';
import { NextRequest, NextResponse } from 'next/server';
import { ServerConfig, ServerProjectConfig } from '@/utils/serverConfig';

Expand Down Expand Up @@ -37,7 +37,7 @@ export async function POST(

try {
syncLock.set(repoPath, true);
const repoGit = new RepoGit(serverProjectConfig);
const repoGit = await getRepoGit(serverProjectConfig);
const baseBranch = await repoGit.checkoutBaseAndPull();
const langFilePaths = await repoGit.saveLanguageFiles(
serverProjectConfig.projectPath,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Cache } from '@/Cache';
import { LyraConfig } from '@/utils/lyraConfig';
import { RepoGit } from '@/RepoGit';
import { ServerConfig } from '@/utils/serverConfig';
import { getRepoGit, RepoGit } from '@/RepoGit';
import {
LanguageNotFound,
LanguageNotSupported,
Expand All @@ -27,7 +26,8 @@ export async function PUT(
// TODO: include getProjectConfig & readFromDir in a try/catch block and check for error to return a certain 500 error
const serverProjectConfig = await ServerConfig.getProjectConfig(projectName);
await RepoGit.cloneIfNotExist(serverProjectConfig);
const lyraConfig = await LyraConfig.readFromDir(serverProjectConfig.repoPath);
const repo = await getRepoGit(serverProjectConfig);
const lyraConfig = await repo.getLyraConfig();

try {
const projectConfig = lyraConfig.getProjectConfigByPath(
Expand Down

0 comments on commit 47d9ea2

Please sign in to comment.