Skip to content

Commit 41a9ad4

Browse files
committed
Implement git commit
1 parent fe683b1 commit 41a9ad4

File tree

3 files changed

+127
-0
lines changed

3 files changed

+127
-0
lines changed

packages/git/src/git-helpers.js

+13
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,16 @@ export const find_repo_root = async (fs, pwd) => {
7070

7171
throw new Error('not a git repository (or any of the parent directories): .git');
7272
}
73+
74+
/**
75+
* Produce a shortened version of the given hash, which is still unique within the repo.
76+
* @param hash
77+
* @param fs
78+
* @param repository_dir
79+
* @param git_dir
80+
* @returns {Promise<String>} The shortened hash
81+
*/
82+
export const shorten_hash = async (hash, { fs, repository_dir, git_dir }) => {
83+
// TODO: Ensure that whatever we produce is unique within the repo
84+
return hash.slice(0, 7);
85+
}

packages/git/src/subcommands/__exports__.js

+2
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
*/
1919
// Generated by /tools/gen.js
2020
import module_add from './add.js'
21+
import module_commit from './commit.js'
2122
import module_init from './init.js'
2223
import module_status from './status.js'
2324

2425
export default {
2526
"add": module_add,
27+
"commit": module_commit,
2628
"init": module_init,
2729
"status": module_status,
2830
};
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (C) 2024 Puter Technologies Inc.
3+
*
4+
* This file is part of Puter's Git client.
5+
*
6+
* Puter's Git client is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as published
8+
* by the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
import git from 'isomorphic-git';
20+
import path from 'path-browserify';
21+
import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js';
22+
import { find_repo_root, shorten_hash } from '../git-helpers.js';
23+
24+
export default {
25+
name: 'commit',
26+
args: {
27+
allowPositionals: false,
28+
options: {
29+
message: {
30+
description: 'Specify the commit message',
31+
type: 'string',
32+
short: 'm',
33+
},
34+
author: {
35+
description: 'Specify the commit author, as `A U Thor <[email protected]>`',
36+
type: 'string',
37+
},
38+
},
39+
},
40+
execute: async (ctx) => {
41+
const { io, fs, env, args } = ctx;
42+
const { stdout, stderr } = io;
43+
const { options, positionals } = args;
44+
45+
if (!options.message) {
46+
// TODO: Support opening a temporary file in an editor,
47+
// where the user can edit the commit message if it's not specified.
48+
stderr('You must specify a commit message with --message or -m');
49+
return 1;
50+
}
51+
52+
const { repository_dir, git_dir } = await find_repo_root(fs, env.PWD);
53+
54+
let user_name;
55+
let user_email;
56+
57+
if (options.author) {
58+
const author_regex = /(.+?)\s+<(.+)>/;
59+
const matches = options.author.match(author_regex);
60+
if (!matches)
61+
throw new Error('Failed to parse author string');
62+
user_name = matches[1];
63+
user_email = matches[2];
64+
} else {
65+
user_name = await git.getConfig({
66+
fs,
67+
dir: repository_dir,
68+
gitdir: git_dir,
69+
path: 'user.name',
70+
});
71+
user_email = await git.getConfig({
72+
fs,
73+
dir: repository_dir,
74+
gitdir: git_dir,
75+
path: 'user.email',
76+
});
77+
}
78+
79+
if (!user_name || !user_email) {
80+
throw new Error('Missing author information. Either provide --author="A <[email protected]>" or set user.name and user.email in the git config');
81+
}
82+
83+
const commit_hash = await git.commit({
84+
fs,
85+
dir: repository_dir,
86+
gitdir: git_dir,
87+
message: options.message,
88+
author: {
89+
name: user_name,
90+
email: user_email,
91+
},
92+
});
93+
94+
const branch = await git.currentBranch({
95+
fs,
96+
dir: repository_dir,
97+
gitdir: git_dir,
98+
});
99+
const commit_title = options.message.split('\n')[0];
100+
const short_hash = await shorten_hash(commit_hash, {fs, repository_dir, git_dir});
101+
let output = `[${branch} ${short_hash}] ${commit_title}\n`;
102+
// TODO: --amend prints out the date of the original commit here, as:
103+
// ` Date: Fri May 17 15:45:47 2024 +0100`
104+
// TODO: Print out file change count, insertion count, and deletion count
105+
// (Seems if insertions and deletions are both 0, we should print both.
106+
// Otherwise we just print nonzero ones.)
107+
// TODO: Print out each file created or deleted. eg:
108+
// create mode 100644 bar
109+
// delete mode 100644 foo.txt
110+
stdout(output);
111+
}
112+
}

0 commit comments

Comments
 (0)