mirror of
https://github.com/HeyPuter/puter
synced 2024-11-15 06:15:47 +00:00
Implement git commit
This commit is contained in:
parent
32c172d145
commit
b4e2ba4544
@ -70,3 +70,15 @@ export const find_repo_root = async (fs, pwd) => {
|
|||||||
|
|
||||||
throw new Error('not a git repository (or any of the parent directories): .git');
|
throw new Error('not a git repository (or any of the parent directories): .git');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce a shortened version of the given hash, which is still unique within the repo.
|
||||||
|
* TODO: Ensure that whatever we produce is unique within the repo.
|
||||||
|
* For now this is just a convenience function, so there's one place to change later.
|
||||||
|
* @param hash
|
||||||
|
* @returns {String} The shortened hash
|
||||||
|
*/
|
||||||
|
export const shorten_hash = (hash) => {
|
||||||
|
// TODO: Ensure that whatever we produce is unique within the repo
|
||||||
|
return hash.slice(0, 7);
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
// Generated by /tools/gen.js
|
// Generated by /tools/gen.js
|
||||||
import module_add from './add.js'
|
import module_add from './add.js'
|
||||||
|
import module_commit from './commit.js'
|
||||||
import module_help from './help.js'
|
import module_help from './help.js'
|
||||||
import module_init from './init.js'
|
import module_init from './init.js'
|
||||||
import module_status from './status.js'
|
import module_status from './status.js'
|
||||||
@ -25,6 +26,7 @@ import module_version from './version.js'
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
"add": module_add,
|
"add": module_add,
|
||||||
|
"commit": module_commit,
|
||||||
"help": module_help,
|
"help": module_help,
|
||||||
"init": module_init,
|
"init": module_init,
|
||||||
"status": module_status,
|
"status": module_status,
|
||||||
|
114
packages/git/src/subcommands/commit.js
Normal file
114
packages/git/src/subcommands/commit.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Puter Technologies Inc.
|
||||||
|
*
|
||||||
|
* This file is part of Puter's Git client.
|
||||||
|
*
|
||||||
|
* Puter's Git client is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import git from 'isomorphic-git';
|
||||||
|
import path from 'path-browserify';
|
||||||
|
import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js';
|
||||||
|
import { find_repo_root, shorten_hash } from '../git-helpers.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'commit',
|
||||||
|
usage: 'git commit [-m|--message <message>] [-a|--author <author>]',
|
||||||
|
description: 'Commit staged changes to the repository.',
|
||||||
|
args: {
|
||||||
|
allowPositionals: false,
|
||||||
|
options: {
|
||||||
|
message: {
|
||||||
|
description: 'Specify the commit message',
|
||||||
|
type: 'string',
|
||||||
|
short: 'm',
|
||||||
|
},
|
||||||
|
author: {
|
||||||
|
description: 'Specify the commit author, as `A U Thor <author@example.com>`',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
execute: async (ctx) => {
|
||||||
|
const { io, fs, env, args } = ctx;
|
||||||
|
const { stdout, stderr } = io;
|
||||||
|
const { options, positionals } = args;
|
||||||
|
|
||||||
|
if (!options.message) {
|
||||||
|
// TODO: Support opening a temporary file in an editor,
|
||||||
|
// where the user can edit the commit message if it's not specified.
|
||||||
|
stderr('You must specify a commit message with --message or -m');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { repository_dir, git_dir } = await find_repo_root(fs, env.PWD);
|
||||||
|
|
||||||
|
let user_name;
|
||||||
|
let user_email;
|
||||||
|
|
||||||
|
if (options.author) {
|
||||||
|
const author_regex = /(.+?)\s+<(.+)>/;
|
||||||
|
const matches = options.author.match(author_regex);
|
||||||
|
if (!matches)
|
||||||
|
throw new Error('Failed to parse author string');
|
||||||
|
user_name = matches[1];
|
||||||
|
user_email = matches[2];
|
||||||
|
} else {
|
||||||
|
user_name = await git.getConfig({
|
||||||
|
fs,
|
||||||
|
dir: repository_dir,
|
||||||
|
gitdir: git_dir,
|
||||||
|
path: 'user.name',
|
||||||
|
});
|
||||||
|
user_email = await git.getConfig({
|
||||||
|
fs,
|
||||||
|
dir: repository_dir,
|
||||||
|
gitdir: git_dir,
|
||||||
|
path: 'user.email',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user_name || !user_email) {
|
||||||
|
throw new Error('Missing author information. Either provide --author="A <a@b.c>" or set user.name and user.email in the git config');
|
||||||
|
}
|
||||||
|
|
||||||
|
const commit_hash = await git.commit({
|
||||||
|
fs,
|
||||||
|
dir: repository_dir,
|
||||||
|
gitdir: git_dir,
|
||||||
|
message: options.message,
|
||||||
|
author: {
|
||||||
|
name: user_name,
|
||||||
|
email: user_email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const branch = await git.currentBranch({
|
||||||
|
fs,
|
||||||
|
dir: repository_dir,
|
||||||
|
gitdir: git_dir,
|
||||||
|
});
|
||||||
|
const commit_title = options.message.split('\n')[0];
|
||||||
|
const short_hash = shorten_hash(commit_hash);
|
||||||
|
let output = `[${branch} ${short_hash}] ${commit_title}\n`;
|
||||||
|
// TODO: --amend prints out the date of the original commit here, as:
|
||||||
|
// ` Date: Fri May 17 15:45:47 2024 +0100`
|
||||||
|
// TODO: Print out file change count, insertion count, and deletion count
|
||||||
|
// (Seems if insertions and deletions are both 0, we should print both.
|
||||||
|
// Otherwise we just print nonzero ones.)
|
||||||
|
// TODO: Print out each file created or deleted. eg:
|
||||||
|
// create mode 100644 bar
|
||||||
|
// delete mode 100644 foo.txt
|
||||||
|
stdout(output);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user