Skip to content

Commit

Permalink
Add git commit companion files rule
Browse files Browse the repository at this point in the history
See: #505
  • Loading branch information
ggodlewski committed Jan 27, 2025
1 parent 0008bcb commit 8083b5d
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 3 deletions.
5 changes: 5 additions & 0 deletions apps/ui/src/components/GitSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
<textarea class="form-control" rows="6" placeholder="Deploy key" readonly :value="public_key" @click="copyEmail"></textarea>
</div>
</div>

<div class="form-group">
<label>Git commit companion files rule</label>
<input class="form-control" v-model="user_config.companion_files_rule" />
</div>
</div>
<div class="card-footer">
<div class="btn-group">
Expand Down
16 changes: 14 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"website"
],
"dependencies": {
"@nyariv/sandboxjs": "0.8.23",
"@opentelemetry/core": "1.28.0",
"@opentelemetry/api": "1.3.0",
"@opentelemetry/context-zone": "1.8.0",
Expand Down
5 changes: 4 additions & 1 deletion src/containers/google_folder/UserConfigService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export class UserConfig {
fm_without_version?: boolean;
actions_yaml?: string;
rewrite_rules?: RewriteRule[];
companion_files_rule?: string;
}

const DEFAULT_CONFIG: UserConfig = {
Expand Down Expand Up @@ -90,7 +91,9 @@ export class UserConfigService {
if (!this.config.rewrite_rules || this.config.rewrite_rules.length === 0) {
this.config.rewrite_rules = DEFAULT_REWRITE_RULES;
}

if (!this.config.companion_files_rule) {
this.config.companion_files_rule = '(file.path == "content/navigation.md") || (file.path == "content/toc.md") || (commit.id && file.redirectTo == commit.id) || (commit.redirectTo == file.id && file.id)';
}
return this.config;
}

Expand Down
66 changes: 66 additions & 0 deletions src/containers/job/JobManagerContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import fs from 'node:fs';
import path from 'node:path';
import { randomUUID } from 'node:crypto';

import Sandbox from '@nyariv/sandboxjs';

import {Container, ContainerConfig, ContainerEngine} from '../../ContainerEngine.ts';
import {FileId} from '../../model/model.ts';
import {GoogleFolderContainer} from '../google_folder/GoogleFolderContainer.ts';
Expand Down Expand Up @@ -703,6 +705,70 @@ export class JobManagerContainer extends Container {
const gitScanner = new GitScanner(logger, transformedFileSystem.getRealPath(), '[email protected]');
await gitScanner.initialize();

const googleFileSystem = await this.filesService.getSubFileService(driveId, '');
const userConfigService = new UserConfigService(googleFileSystem);
const userConfig = await userConfigService.load();

const contentFileService = await getContentFileService(transformedFileSystem, userConfigService);
const markdownTreeProcessor = new MarkdownTreeProcessor(contentFileService);
await markdownTreeProcessor.load();

if (userConfig.companion_files_rule) {
gitScanner.setCompanionFileResolver(async (filePath: string) => {
if (!filePath.endsWith('.md')) {
return [];
}

let subdir = (userConfigService.config.transform_subdir || '')
.replace(/^\//, '')
.replace(/\/$/, '');
if (subdir.length > 0) {
subdir += '/';
}

filePath = filePath
.replace(/^\//, '')
.substring(subdir.length);

const tuple = await markdownTreeProcessor.findByPath('/' + filePath);

const treeItem = tuple[0];
if (!treeItem) {
return [];
}

const retVal: Set<string> = new Set();

const sandbox = new Sandbox.default();
const exec = sandbox.compile('return ' + (userConfig.companion_files_rule || 'false'));

await markdownTreeProcessor.walkTree((treeNode) => {
const commit = {
path: subdir + treeItem.path.replace(/^\//, ''),
id: treeItem.id,
fileName: treeItem.fileName,
mimeType: treeItem.mimeType,
redirectTo: treeItem.redirectTo
};
const file = {
path: subdir + treeNode.path.replace(/^\//, ''),
id: treeNode.id,
fileName: treeNode.fileName,
mimeType: treeNode.mimeType,
redirectTo: treeNode.redirectTo
};

const result = exec({ commit, file }).run();

if (result) {
retVal.add(file.path);
}
return false;
});
return Array.from(retVal);
});
}

await gitScanner.commit(message, filePaths, user);

await this.schedule(driveId, {
Expand Down
4 changes: 4 additions & 0 deletions src/containers/server/routes/ConfigController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface ConfigBody {
config_toml?: string;
transform_subdir?: string;
rewrite_rules_yaml?: string;
companion_files_rule?: string;
hugo_theme: HugoTheme;
auto_sync: boolean;
use_google_markdowns: boolean;
Expand Down Expand Up @@ -98,6 +99,9 @@ export class ConfigController extends Controller {
if (body.config?.rewrite_rules_yaml) {
userConfigService.config.rewrite_rules = yaml.load(body.config?.rewrite_rules_yaml);
}
if (body.config?.companion_files_rule) {
userConfigService.config.companion_files_rule = body.config?.companion_files_rule;
}
let modified = false;
if ('string' === typeof body.config?.transform_subdir) {
let trimmed = body.config?.transform_subdir.trim();
Expand Down
22 changes: 22 additions & 0 deletions src/git/GitScanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ interface ExecOpts {

export class GitScanner {
private logger: Logger;
private companionFileResolver: (filePath: string) => Promise<string[]> = async () => ([]);

constructor(logger: Logger, public readonly rootPath: string, private email: string) {
this.logger = logger.child({ filename: __filename });
Expand Down Expand Up @@ -201,10 +202,26 @@ export class GitScanner {
return retValArr;
}

async resolveCompanionFiles(filePaths: string[]): Promise<string[]> {
const retVal = [];
for (const filePath of filePaths) {
retVal.push(filePath);
try {
retVal.push(...(await this.companionFileResolver(filePath) || []));
} catch (err) {
this.logger.warn('Error evaluating companion files: ' + err.message);
break;
}
}
return retVal;
}

async commit(message: string, selectedFiles: string[], committer: Commiter): Promise<string> {
selectedFiles = selectedFiles.map(fileName => fileName.startsWith('/') ? fileName.substring(1) : fileName)
.filter(fileName => !!fileName);

selectedFiles = await this.resolveCompanionFiles(selectedFiles);

const addedFiles: string[] = [];
const removedFiles: string[] = [];

Expand Down Expand Up @@ -964,4 +981,9 @@ export class GitScanner {
async removeCached(filePath: string) {
await this.exec(`git rm --cached ${filePath}`);
}

setCompanionFileResolver(resolver: (filePath: string) => Promise<string[]>) {
this.companionFileResolver = resolver;
}

}
57 changes: 57 additions & 0 deletions test/git/SingleCommitTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {createTmpDir} from '../utils.ts';
import {GitScanner} from '../../src/git/GitScanner.ts';
import fs from 'node:fs';
import path from 'node:path';

import test from '../tester.ts';
import winston from 'winston';
import {instrumentLogger} from '../../src/utils/logger/logger.ts';
import Sandbox from '@nyariv/sandboxjs';

const COMMITER1 = {
name: 'John', email: '[email protected]'
};

const logger = winston.createLogger({
level: 'debug',
defaultMeta: {},
transports: [
new winston.transports.Console()
]
});
instrumentLogger(logger);

test('test single commit', async (t) => {
t.timeout(5000);

const localRepoDir: string = createTmpDir();

try {
const scannerLocal = new GitScanner(logger, localRepoDir, COMMITER1.email);
await scannerLocal.initialize();

fs.writeFileSync(path.join(scannerLocal.rootPath, 'test1.md'), 'test');
fs.writeFileSync(path.join(scannerLocal.rootPath, 'navigation.md'), 'nav');
fs.writeFileSync(path.join(scannerLocal.rootPath, 'toc.md'), 'toc');

{
const changes = await scannerLocal.changes();
t.is(changes.length, 4);
}

// console.log('Sandbox', Sandbox);
const sandbox = new Sandbox.default();
const exec = sandbox.compileExpression('return (filePath.endsWith(".md") && filePath == "test1.md" && ["navigation.md", "toc.md"]) || []');

scannerLocal.setCompanionFileResolver((filePath: string) => {
return exec({ filePath }).run();
});

await scannerLocal.commit('initial commit', ['.gitignore', 'test1.md'], COMMITER1);

const changes = await scannerLocal.changes();
t.is(changes.length, 0);
} finally {
fs.rmSync(localRepoDir, { recursive: true, force: true });
}
});

0 comments on commit 8083b5d

Please sign in to comment.