commit 54ec2336968986b96ad46ff3adc73d9677bc25c0
parent 32a1bea865af0764895473525f0a514d7eee640e
Author: brookjeynes <me@brookjeynes.dev>
Date: Thu, 25 Jun 2026 07:19:20 +1000
refactor: move related commits to 'commits' subcommand
Task-id: nrqnlxvtksoyytvz
Signed-off-by: brookjeynes <me@brookjeynes.dev>
Diffstat:
2 files changed, 110 insertions(+), 129 deletions(-)
diff --git a/task.c b/task.c
@@ -23,16 +23,20 @@ struct options {
};
static void print_help(const char *program) {
- printf("usage: %s [--priority A|-p A] <title> [properties...]\n", program);
+ printf("usage: %s <command> [options]\n",
+ program);
printf("\n");
printf("create a new task.\n");
printf("\n");
+ printf("commands:\n");
+ printf(" commits <task-id> list all commits tied <task-id>.\n");
+ printf(" new [--priority A|-p A] <title> [properties...] create a new task.\n");
+ printf("\n");
printf("options:\n");
printf(" -h, --help show this help\n");
printf(" -p, --priority A set priority A-Z\n");
printf(" --context list all known contexts\n");
printf(" --projects list all known projects\n");
- printf(" --related-commits <task-id> list all commits tied <task-id>.\n");
}
static int has_txt_extension(const char *name) {
@@ -350,77 +354,6 @@ cleanup:
}
}
-static void print_related_commits(char *task_id) {
- int error;
-
- git_libgit2_init();
-
- git_repository *repo = NULL;
- if ((error = git_repository_open(&repo, ".")) < 0) {
- const git_error *e = git_error_last();
- fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
- exit(error);
- }
-
- git_object *obj = NULL;
- if ((error = git_revparse_single(&obj, repo, "HEAD")) < 0) {
- const git_error *e = git_error_last();
- fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
- exit(error);
- }
-
- const git_oid *head = NULL;
- head = git_object_id(obj);
- git_object_free(obj);
-
- git_revwalk *walker = NULL;
- if ((error = git_revwalk_new(&walker, repo)) < 0) {
- const git_error *e = git_error_last();
- fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
- exit(error);
- }
-
- if ((error = git_revwalk_push(walker, head)) < 0) {
- const git_error *e = git_error_last();
- fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
- exit(error);
- }
-
- git_oid id;
- while (!git_revwalk_next(&id, walker)) {
- git_commit *commit;
- if ((error = git_commit_lookup(&commit, repo, &id)) < 0) {
- const git_error *e = git_error_last();
- fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
- exit(error);
- }
-
- const char *summary = git_commit_summary(commit);
- const char *message = git_commit_message(commit);
- const char *git_header = git_commit_raw_header(commit);
-
- git_message_trailer_array *trailers =
- malloc(sizeof(git_message_trailer_array));
- if ((error = git_message_trailers(trailers, message)) < 0) {
- const git_error *e = git_error_last();
- fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
- exit(error);
- }
-
- for (size_t i = 0; i < trailers->count; i++) {
- if (strcmp(trailers->trailers[i].key, "Task-id") == 0) {
- if (strcmp(trailers->trailers[i].value, task_id) == 0) {
- char oid_str[GIT_OID_HEXSZ + 1];
- git_oid_tostr(oid_str, sizeof(oid_str), &id);
- printf("%s: %s\n", oid_str, summary);
- }
- }
- }
- }
-
- git_libgit2_shutdown();
-}
-
int new_command(int argc, char *argv[], struct options *cli_args) {
if (argc == 1) {
fprintf(stderr, "err: title required\n");
@@ -514,18 +447,19 @@ int new_command(int argc, char *argv[], struct options *cli_args) {
int write_failed = 0;
int write_errno = 0;
+
if (cli_args->priority != '\0') {
if (fprintf(f, "(%c) ", cli_args->priority) < 0) {
- write_failed = 1;
- write_errno = errno;
+ fclose(f);
+ fprintf(stderr, "err: failed to write file: %s\n", strerror(errno));
+ return 1;
}
}
if (fprintf(f, "%s", cli_args->title) < 0) {
- if (!write_failed) {
- write_failed = 1;
- write_errno = errno;
- }
+ fclose(f);
+ fprintf(stderr, "err: failed to write file: %s\n", strerror(errno));
+ return 1;
}
int seen_title = 0;
@@ -541,64 +475,122 @@ int new_command(int argc, char *argv[], struct options *cli_args) {
}
if (fprintf(f, " %s", argv[idx]) < 0) {
- if (!write_failed) {
- write_failed = 1;
- write_errno = errno;
- }
+ fclose(f);
+ fprintf(stderr, "err: failed to write file: %s\n", strerror(errno));
+ return 1;
}
}
if (fprintf(f, "\n") < 0) {
- if (!write_failed) {
- write_failed = 1;
- write_errno = errno;
- }
+ fclose(f);
+ fprintf(stderr, "err: failed to write file: %s\n", strerror(errno));
+ return 1;
}
if (fprintf(f, "id: %s\n", id) < 0) {
- if (!write_failed) {
- write_failed = 1;
- write_errno = errno;
- }
+ fclose(f);
+ fprintf(stderr, "err: failed to write file: %s\n", strerror(errno));
+ return 1;
}
- int close_failed = 0;
- int close_errno = 0;
- if (fclose(f) != 0) {
- close_failed = 1;
- close_errno = errno;
+ char *editor = getenv("VISUAL");
+ if (editor != NULL && strcmp(editor, "") == 0) {
+ editor = NULL;
+ }
+ if (editor == NULL) {
+ editor = getenv("EDITOR");
}
- if (write_failed) {
- fprintf(stderr, "err: failed to write file: %s\n", strerror(write_errno));
+ if (editor == NULL || strcmp(editor, "") == 0) {
+ return 0;
+ }
+
+ execlp("sh", "sh", "-c", "exec $1 \"$2\"", "task", editor, title_to_file,
+ NULL);
+ fprintf(stderr, "err: failed to open editor: %s", strerror(errno));
+
+ return 1;
+}
+
+int related_commits_command(int argc, char *argv[], struct options *cli_args) {
+ if (argc != 2) {
+ fprintf(stderr, "err: task id required\n");
return 1;
}
- if (close_failed) {
- fprintf(stderr, "err: failed to close file: %s\n", strerror(close_errno));
+ if (strcmp(argv[1], "") == 0) {
+ fprintf(stderr, "err: task id can not be empty\n");
return 1;
}
- char *editor = getenv("VISUAL");
- if (editor != NULL && strcmp(editor, "") == 0) {
- editor = NULL;
+ char *task_id = argv[1];
+
+ int error;
+ git_libgit2_init();
+
+ git_repository *repo = NULL;
+ if ((error = git_repository_open(&repo, ".")) < 0) {
+ const git_error *e = git_error_last();
+ fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
+ return 1;
}
- if (editor == NULL) {
- editor = getenv("EDITOR");
+ git_object *obj = NULL;
+ if ((error = git_revparse_single(&obj, repo, "HEAD")) < 0) {
+ const git_error *e = git_error_last();
+ fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
+ return 1;
}
- if (editor != NULL && strcmp(editor, "") == 0) {
- editor = NULL;
+ const git_oid *head = NULL;
+ head = git_object_id(obj);
+ git_object_free(obj);
+
+ git_revwalk *walker = NULL;
+ if ((error = git_revwalk_new(&walker, repo)) < 0) {
+ const git_error *e = git_error_last();
+ fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
+ return 1;
}
- if (editor == NULL) {
- return 0;
+ if ((error = git_revwalk_push(walker, head)) < 0) {
+ const git_error *e = git_error_last();
+ fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
+ return 1;
}
- execlp("sh", "sh", "-c", "exec $1 \"$2\"", "task", editor, title_to_file,
- NULL);
- perror("err: failed to open editor");
+ git_oid id;
+ while (!git_revwalk_next(&id, walker)) {
+ git_commit *commit;
+ if ((error = git_commit_lookup(&commit, repo, &id)) < 0) {
+ const git_error *e = git_error_last();
+ fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
+ return 1;
+ }
+
+ const char *summary = git_commit_summary(commit);
+ const char *message = git_commit_message(commit);
+
+ git_message_trailer_array *trailers =
+ malloc(sizeof(git_message_trailer_array));
+ if ((error = git_message_trailers(trailers, message)) < 0) {
+ const git_error *e = git_error_last();
+ fprintf(stderr, "err: %d/%d: %s\n", error, e->klass, e->message);
+ return 1;
+ }
+
+ for (size_t i = 0; i < trailers->count; i++) {
+ if (strcmp(trailers->trailers[i].key, "Task-id") == 0) {
+ if (strcmp(trailers->trailers[i].value, task_id) == 0) {
+ char oid_str[GIT_OID_HEXSZ + 1];
+ git_oid_tostr(oid_str, sizeof(oid_str), &id);
+ printf("%s: %s\n", oid_str, summary);
+ }
+ }
+ }
+ }
+
+ git_libgit2_shutdown();
return 0;
}
@@ -623,25 +615,14 @@ int main(int argc, char *argv[]) {
return 0;
}
- if (argc > 1 && (strcmp(argv[1], "--related-commits") == 0)) {
- if (argc != 3) {
- fprintf(stderr, "err: task id required\n");
- exit(1);
- }
-
- if (strcmp(argv[2], "") == 0) {
- fprintf(stderr, "err: task id can not be empty\n");
- exit(1);
+ if (argc > 1 && strcmp(argv[1], "new") == 0) {
+ if (new_command(argc - 1, argv + 1, &cli_args) != 0) {
+ return 1;
}
-
- char *task_id = argv[2];
- print_related_commits(task_id);
-
- return 0;
}
- if (argc > 1 && strcmp(argv[1], "new") == 0) {
- if (new_command(argc - 1, argv + 1, &cli_args) != 0) {
+ if (argc > 1 && strcmp(argv[1], "commits") == 0) {
+ if (related_commits_command(argc - 1, argv + 1, &cli_args) != 0) {
return 1;
}
}
diff --git a/tasks/add_subcommands.txt b/tasks/add_subcommands.txt
@@ -5,5 +5,5 @@ task doesnt have subcommands. this is a little painful when adding new features
as they are forced behind flags.
[x] new
-[ ] related-commits
+[x] related-commits
[ ] contexts / projects