Skip to content

Commit 03f471e

Browse files
committed
Fix lostintangent#59: Support auto-commiting changes to submodules
1 parent 383234c commit 03f471e

File tree

2 files changed

+133
-64
lines changed

2 files changed

+133
-64
lines changed

src/git.ts

+32
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as vscode from "vscode";
2+
import * as path from "path"; // P0470: Import path module
23

34
interface CommitOptions {
45
all?: boolean | "tracked";
@@ -19,6 +20,7 @@ interface RepositoryState {
1920

2021
export interface Change {
2122
readonly uri: vscode.Uri;
23+
readonly submodule?: string; // P0bdb: Add a submodule property to the Change interface
2224
}
2325

2426
export enum ForcePushMode {
@@ -66,3 +68,33 @@ export async function getGitApi(): Promise<GitAPI | undefined> {
6668

6769
return extension.exports.getAPI(1);
6870
}
71+
72+
// P321d: Add a getSubmodule function that returns the submodule name for a given file path, or null if none
73+
export function getSubmodule(filePath: string, repository: Repository): string | null {
74+
const submodules = repository.state.refs.filter((ref) => ref.name.startsWith("submodule"));
75+
for (const submodule of submodules) {
76+
const submodulePath = path.join(repository.rootUri.fsPath, submodule.name.replace("submodule/", ""));
77+
if (filePath.startsWith(submodulePath)) {
78+
return submodule.name;
79+
}
80+
}
81+
return null;
82+
}
83+
84+
// P92d2: Modify the getRepository function to use the getSubmodule function and return the submodule repository if applicable
85+
export function getRepository(uri: vscode.Uri, git: GitAPI): Repository | null {
86+
const repository = git.getRepository(uri);
87+
if (!repository) {
88+
return null;
89+
}
90+
91+
const submodule = getSubmodule(uri.fsPath, repository);
92+
if (submodule) {
93+
const submoduleRepository = git.repositories.find((repo) => repo.rootUri.fsPath.endsWith(submodule));
94+
if (submoduleRepository) {
95+
return submoduleRepository;
96+
}
97+
}
98+
99+
return repository;
100+
}

src/watcher.ts

+101-64
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { debounce } from "debounce";
22
import * as vscode from "vscode";
33
import config from "./config";
4-
import { ForcePushMode, GitAPI, Repository } from "./git";
4+
import { ForcePushMode, GitAPI, Repository, getSubmodule } from "./git"; // Import getSubmodule from src/git.ts
55
import { DateTime } from "luxon";
66
import { store } from "./store";
77
import { reaction } from "mobx";
@@ -11,16 +11,26 @@ const REMOTE_NAME = "origin";
1111

1212
async function pushRepository(
1313
repository: Repository,
14-
forcePush: boolean = false
14+
forcePush: boolean = false,
15+
submodule?: string // Add a submodule name as an optional parameter
1516
) {
1617
store.isPushing = true;
1718

1819
try {
1920
if (config.autoPull === "onPush") {
20-
await pullRepository(repository);
21+
await pullRepository(repository, submodule); // Pass the submodule name to pullRepository
2122
}
2223

23-
const pushArgs: any[] = [REMOTE_NAME, repository.state.HEAD?.name, false];
24+
const pushArgs: any[] = [REMOTE_NAME];
25+
26+
// If pushing a submodule, use the submodule name as the branch name
27+
if (submodule) {
28+
pushArgs.push(submodule);
29+
} else {
30+
pushArgs.push(repository.state.HEAD?.name);
31+
}
32+
33+
pushArgs.push(false);
2434

2535
if (forcePush) {
2636
pushArgs.push(ForcePushMode.Force);
@@ -45,15 +55,22 @@ async function pushRepository(
4555
"Force Push"
4656
)
4757
) {
48-
await pushRepository(repository, true);
58+
await pushRepository(repository, true, submodule); // Pass the submodule name to pushRepository
4959
}
5060
}
5161
}
5262

53-
async function pullRepository(repository: Repository) {
63+
async function pullRepository(repository: Repository, submodule?: string) { // Add a submodule name as an optional parameter
5464
store.isPulling = true;
5565

56-
await repository.pull();
66+
const pullArgs: any[] = [];
67+
68+
// If pulling a submodule, use the submodule name as the refspec
69+
if (submodule) {
70+
pullArgs.push(REMOTE_NAME, submodule);
71+
}
72+
73+
await repository.pull(...pullArgs);
5774

5875
store.isPulling = false;
5976
}
@@ -70,64 +87,73 @@ export async function commit(repository: Repository, message?: string) {
7087
];
7188

7289
if (changes.length > 0) {
73-
const changedUris = changes
74-
.filter((change) => matches(change.uri))
75-
.map((change) => change.uri);
76-
77-
if (changedUris.length > 0) {
78-
if (config.commitValidationLevel !== "none") {
79-
const diagnostics = vscode.languages
80-
.getDiagnostics()
81-
.filter(([uri, diagnostics]) => {
82-
const isChanged = changedUris.find(
83-
(changedUri) =>
84-
changedUri.toString().localeCompare(uri.toString()) === 0
85-
);
86-
87-
return isChanged
88-
? diagnostics.some(
89-
(diagnostic) =>
90-
diagnostic.severity === vscode.DiagnosticSeverity.Error ||
91-
(config.commitValidationLevel === "warning" &&
92-
diagnostic.severity === vscode.DiagnosticSeverity.Warning)
93-
)
94-
: false;
95-
});
96-
97-
if (diagnostics.length > 0) {
98-
return;
90+
// Group changes by submodule name, using null for the main repository
91+
const changesBySubmodule = new Map<string | null, vscode.Uri[]>();
92+
for (const change of changes) {
93+
const submodule = change.submodule || null; // Use the submodule property of the change
94+
const changedUris = changesBySubmodule.get(submodule) || [];
95+
changedUris.push(change.uri);
96+
changesBySubmodule.set(submodule, changedUris);
97+
}
98+
99+
// Filter the changes by the file pattern and commit them to each submodule first, then to the main repository
100+
for (const [submodule, changedUris] of changesBySubmodule) {
101+
const filteredUris = changedUris.filter((uri) => matches(uri));
102+
if (filteredUris.length > 0) {
103+
if (config.commitValidationLevel !== "none") {
104+
const diagnostics = vscode.languages
105+
.getDiagnostics()
106+
.filter(([uri, diagnostics]) => {
107+
const isChanged = filteredUris.find(
108+
(changedUri) =>
109+
changedUri.toString().localeCompare(uri.toString()) === 0
110+
);
111+
112+
return isChanged
113+
? diagnostics.some(
114+
(diagnostic) =>
115+
diagnostic.severity === vscode.DiagnosticSeverity.Error ||
116+
(config.commitValidationLevel === "warning" &&
117+
diagnostic.severity === vscode.DiagnosticSeverity.Warning)
118+
)
119+
: false;
120+
});
121+
122+
if (diagnostics.length > 0) {
123+
return;
124+
}
99125
}
100-
}
101126

102-
// @ts-ignore
103-
await repository.repository.add(changedUris);
104-
let currentTime = DateTime.now();
127+
// @ts-ignore
128+
await repository.repository.add(filteredUris);
129+
let currentTime = DateTime.now();
105130

106-
// Ensure that the commit dates are formatted
107-
// as UTC, so that other clients can properly
108-
// re-offset them based on the user's locale.
109-
const commitDate = currentTime.toUTC().toString();
110-
process.env.GIT_AUTHOR_DATE = commitDate;
111-
process.env.GIT_COMMITTER_DATE = commitDate;
131+
// Ensure that the commit dates are formatted
132+
// as UTC, so that other clients can properly
133+
// re-offset them based on the user's locale.
134+
const commitDate = currentTime.toUTC().toString();
135+
process.env.GIT_AUTHOR_DATE = commitDate;
136+
process.env.GIT_COMMITTER_DATE = commitDate;
112137

113-
if (config.timeZone) {
114-
currentTime = currentTime.setZone(config.timeZone);
115-
}
138+
if (config.timeZone) {
139+
currentTime = currentTime.setZone(config.timeZone);
140+
}
116141

117-
const commitMessage =
118-
message || currentTime.toFormat(config.commitMessageFormat);
142+
const commitMessage =
143+
message || currentTime.toFormat(config.commitMessageFormat);
119144

120-
await repository.commit(commitMessage);
145+
await repository.commit(commitMessage);
121146

122-
delete process.env.GIT_AUTHOR_DATE;
123-
delete process.env.GIT_COMMITTER_DATE;
147+
delete process.env.GIT_AUTHOR_DATE;
148+
delete process.env.GIT_COMMITTER_DATE;
124149

125-
if (config.autoPush === "onCommit") {
126-
await pushRepository(repository);
127-
}
150+
if (config.autoPush === "onCommit") {
151+
await pushRepository(repository, false, submodule); // Pass the submodule name to pushRepository
152+
}
128153

129-
if (config.autoPull === "onCommit") {
130-
await pullRepository(repository);
154+
if (config.autoPull === "onCommit") {
155+
await pullRepository(repository, submodule); // Pass the submodule name to pullRepository
156+
}
131157
}
132158
}
133159
}
@@ -165,8 +191,11 @@ export function ensureStatusBarItem() {
165191

166192
let disposables: vscode.Disposable[] = [];
167193
export function watchForChanges(git: GitAPI): vscode.Disposable {
168-
const commitAfterDelay = debouncedCommit(git.repositories[0]);
169-
disposables.push(git.repositories[0].state.onDidChange(commitAfterDelay));
194+
// Iterate over all repositories, not just the first one
195+
for (const repository of git.repositories) {
196+
const commitAfterDelay = debouncedCommit(repository);
197+
disposables.push(repository.state.onDidChange(commitAfterDelay));
198+
}
170199

171200
ensureStatusBarItem();
172201

@@ -198,7 +227,10 @@ export function watchForChanges(git: GitAPI): vscode.Disposable {
198227

199228
if (config.autoPush === "afterDelay") {
200229
const interval = setInterval(async () => {
201-
pushRepository(git.repositories[0]);
230+
// Push changes to each repository separately
231+
for (const repository of git.repositories) {
232+
await pushRepository(repository);
233+
}
202234
}, config.autoPushDelay);
203235

204236
disposables.push({
@@ -209,10 +241,12 @@ export function watchForChanges(git: GitAPI): vscode.Disposable {
209241
}
210242

211243
if (config.autoPull === "afterDelay") {
212-
const interval = setInterval(
213-
async () => pullRepository(git.repositories[0]),
214-
config.autoPullDelay
215-
);
244+
const interval = setInterval(async () => {
245+
// Pull changes from each repository separately
246+
for (const repository of git.repositories) {
247+
await pullRepository(repository);
248+
}
249+
}, config.autoPullDelay);
216250

217251
disposables.push({
218252
dispose: () => clearInterval(interval),
@@ -236,7 +270,10 @@ export function watchForChanges(git: GitAPI): vscode.Disposable {
236270
});
237271

238272
if (config.pullOnOpen) {
239-
pullRepository(git.repositories[0]);
273+
// Pull changes from each repository separately
274+
for (const repository of git.repositories) {
275+
pullRepository(repository);
276+
}
240277
}
241278

242279
return {

0 commit comments

Comments
 (0)