From 6f86457ba23ad3f8257268b8897ea40b5be50d82 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Wed, 24 May 2023 19:24:54 +0200 Subject: [PATCH 01/49] configure: Fix bug when giving --with-libcurl by itself I didn't catch this case which causes the build system to behave strangely. Seen during a test on sparc64 Gentoo Linux. Signed-off-by: Nico Sonack --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 3a2dca8c..5904c14e 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,7 @@ OPT_LIBCURL=$withval AS_IF([test "x$OPT_LIBCURL" = "xno"], [AC_MSG_ERROR([--with-libcurl must not be disabled])]) -AS_IF([test "x$OPT_LIBCURL" = "xcheck"], +AS_IF([test "x$OPT_LIBCURL" = "xcheck" || test "x$OPT_LIBCURL" = "xyes"], [PKG_CHECK_MODULES([LIBCURL], [libcurl],,[AC_MSG_ERROR([Could not find libcurl])]) CFLAGS="$LIBCURL_CFLAGS $CFLAGS" LDFLAGS="$LIBCURL_LIBS $LDFLAGS"], From d0c680eb83ca9e4c73b3c086e9868d41c74d033a Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 12:54:24 +0200 Subject: [PATCH 02/49] fix: Set 'merged' flag on GitLab MRs properly This was missing as the GitLab API doesn't give us a separate flag. Fix by looking at the state and recognising the value. Signed-off-by: Nico Sonack --- src/gitlab/merge_requests.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/gitlab/merge_requests.c b/src/gitlab/merge_requests.c index 8af461f5..d52ce649 100644 --- a/src/gitlab/merge_requests.c +++ b/src/gitlab/merge_requests.c @@ -37,6 +37,16 @@ #include +/* Workaround because gitlab doesn't give us an explicit field for + * this. */ +static void +gitlab_mrs_fixup(gcli_pull_list *const list) +{ + for (size_t i = 0; i < list->pulls_size; ++i) { + list->pulls[i].merged = !strcmp(list->pulls[i].state, "merged"); + } +} + int gitlab_fetch_mrs(char *url, int const max, gcli_pull_list *const list) { @@ -56,6 +66,8 @@ gitlab_fetch_mrs(char *url, int const max, gcli_pull_list *const list) free(url); + gitlab_mrs_fixup(list); + return 0; } From 692bb87e0eb91f5453b03d09e4594c4d10ce5303 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 14:03:11 +0200 Subject: [PATCH 03/49] Bump to new devel version Signed-off-by: Nico Sonack --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5904c14e..3c18f7be 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([gcli],[1.0.4-devel],[nsonack@herrhotzenplotz.de],[gcli],[https://gitlab.com/herrhotzenplotz/gcli/]) +AC_INIT([gcli],[1.2.0-devel],[nsonack@herrhotzenplotz.de],[gcli],[https://gitlab.com/herrhotzenplotz/gcli/]) AM_INIT_AUTOMAKE([1.0 foreign subdir-objects dist-bzip2 dist-xz -Wall]) dnl Release Date. From 6bd59b48898776dd0de94dde2db245fd8154b94a Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 14:07:12 +0200 Subject: [PATCH 04/49] cmd: Add config subcommand Signed-off-by: Nico Sonack --- Makefile.am | 1 + include/gcli/cmd.h | 1 + src/cmd/config.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ src/gcli.c | 3 ++ 4 files changed, 80 insertions(+) create mode 100644 src/cmd/config.c diff --git a/Makefile.am b/Makefile.am index 03ced5bf..12bbedba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,6 +58,7 @@ gcli_SOURCES = \ src/cmd/api.c \ src/cmd/ci.c \ src/cmd/comment.c \ + src/cmd/config.c \ src/cmd/forks.c \ src/cmd/gists.c \ src/cmd/issues.c \ diff --git a/include/gcli/cmd.h b/include/gcli/cmd.h index 54ed75e6..bd8d9ee2 100644 --- a/include/gcli/cmd.h +++ b/include/gcli/cmd.h @@ -61,6 +61,7 @@ void delete_repo(bool always_yes, const char *owner, const char *repo); int subcommand_api(int argc, char *argv[]); int subcommand_ci(int argc, char *argv[]); int subcommand_comment(int argc, char *argv[]); +int subcommand_config(int argc, char *argv[]); int subcommand_forks(int argc, char *argv[]); int subcommand_gists(int argc, char *argv[]); int subcommand_issues(int argc, char *argv[]); diff --git a/src/cmd/config.c b/src/cmd/config.c new file mode 100644 index 00000000..0bb84143 --- /dev/null +++ b/src/cmd/config.c @@ -0,0 +1,75 @@ +/* + * Copyright 2023 Nico Sonack + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#ifdef HAVE_GETOPT_H +#include +#endif + +static void +usage(void) +{ + fprintf(stderr, "usage: gcli config ssh\n"); + fprintf(stderr, "\n"); + version(); + copyright(); +} + +int +subcommand_config(int argc, char *argv[]) +{ + int ch; + + struct option options[] = { + {0} + }; + + while ((ch = getopt_long(argc, argv, "+", options, NULL)) != -1) { + switch (ch) { + default: + usage(); + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + return EXIT_SUCCESS; +} diff --git a/src/gcli.c b/src/gcli.c index f45d52ff..e0d52d49 100644 --- a/src/gcli.c +++ b/src/gcli.c @@ -66,6 +66,9 @@ static struct subcommand { { .cmd_name = "comment", .fn = subcommand_comment, .docstring = "Comment under issues and PRs" }, + { .cmd_name = "config", + .fn = subcommand_config, + .docstring = "Configure forges" }, { .cmd_name = "forks", .fn = subcommand_forks, .docstring = "Create, delete and list repository forks" }, From 66fdec1f59bda9cdbbc9104fac24b1466a8c72ca Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 14:12:50 +0200 Subject: [PATCH 05/49] cmd: Add subcommands for config subcommand Signed-off-by: Nico Sonack --- src/cmd/config.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/cmd/config.c b/src/cmd/config.c index 0bb84143..e39679a3 100644 --- a/src/cmd/config.c +++ b/src/cmd/config.c @@ -51,6 +51,22 @@ usage(void) copyright(); } +static int +subcommand_ssh(int argc, char *argv[]) +{ + (void) argc; + (void) argv; + + return 0; +} + +struct subcommand { + char const *const name; + int (*fn)(int argc, char *argv[]); +} subcommands[] = { + { .name = "ssh", .fn = subcommand_ssh }, +}; + int subcommand_config(int argc, char *argv[]) { @@ -71,5 +87,22 @@ subcommand_config(int argc, char *argv[]) argc -= optind; argv += optind; - return EXIT_SUCCESS; + /* Check if the user gave us at least one option for this + * subcommand */ + if (argc == 0) { + fprintf(stderr, "error: missing subcommand for config\n"); + usage(); + return EXIT_FAILURE; + } + + for (size_t i = 0; i < ARRAY_SIZE(subcommands); ++i) { + if (strcmp(argv[0], subcommands[i].name) == 0) + return subcommands[i].fn(argc, argv); + } + + fprintf(stderr, "error: unrecognised config subcommand »%s«\n", + argv[0]); + usage(); + + return EXIT_FAILURE; } From ddca7b5ce84ed9467b419b90dc15a803359932bb Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 14:40:04 +0200 Subject: [PATCH 06/49] Add stubs for listing ssh keys Signed-off-by: Nico Sonack --- Makefile.am | 1 + include/gcli/forges.h | 5 ++++ include/gcli/sshkeys.h | 55 ++++++++++++++++++++++++++++++++++++++++ src/cmd/config.c | 20 +++++++++++++-- src/sshkeys.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 include/gcli/sshkeys.h create mode 100644 src/sshkeys.c diff --git a/Makefile.am b/Makefile.am index 12bbedba..6f0cb23c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,6 +126,7 @@ libgcli_la_SOURCES = \ src/review.c include/gcli/review.h \ src/gitlab/snippets.c include/gcli/gitlab/snippets.h \ src/status.c include/gcli/status.h \ + src/sshkeys.c include/gcli/sshkeys.h \ src/table.c include/gcli/table.h \ src/gitlab/api.c include/gcli/gitlab/api.h \ src/gitlab/comments.c include/gcli/gitlab/comments.h \ diff --git a/include/gcli/forges.h b/include/gcli/forges.h index 445fdfa0..0f0bb2a2 100644 --- a/include/gcli/forges.h +++ b/include/gcli/forges.h @@ -44,6 +44,7 @@ #include #include #include +#include #include typedef struct gcli_forge_descriptor gcli_forge_descriptor; @@ -416,6 +417,10 @@ struct gcli_forge_descriptor { * Get the user account name */ sn_sv (*get_account)(void); + /** + * Get list of SSH keys */ + int (*get_sshkeys)(gcli_sshkey_list *); + /** * Get the error string from the API */ char const *(*get_api_error_string)( diff --git a/include/gcli/sshkeys.h b/include/gcli/sshkeys.h new file mode 100644 index 00000000..0000cc52 --- /dev/null +++ b/include/gcli/sshkeys.h @@ -0,0 +1,55 @@ +/* + * Copyright 2023 Nico Sonack + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCLI_SSHKEYS_H +#define GCLI_SSHKEYS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +struct gcli_sshkey { + int id; + char *title; + char *key; + char *created_at; +}; + +struct gcli_sshkey_list { + struct gcli_sshkey *keys; + size_t keys_size; +}; + +typedef struct gcli_sshkey gcli_sshkey; +typedef struct gcli_sshkey_list gcli_sshkey_list; + +int gcli_sshkeys_get_keys(gcli_sshkey_list *out); +void gcli_sshkeys_free_keys(gcli_sshkey_list *list); + +#endif /* GCLI_SSHKEYS_H */ diff --git a/src/cmd/config.c b/src/cmd/config.c index e39679a3..12b86182 100644 --- a/src/cmd/config.c +++ b/src/cmd/config.c @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include @@ -54,9 +54,25 @@ usage(void) static int subcommand_ssh(int argc, char *argv[]) { - (void) argc; + gcli_sshkey_list list = {0}; + (void) argv; + --argc; /* TODO: Proper option parsing */ + + if (argc) { + fprintf(stderr, "error: stray arguments\n"); + usage(); + return EXIT_FAILURE; + } + + if (gcli_sshkeys_get_keys(&list) < 0) { + fprintf(stderr, "error: could not get list of SSH keys\n"); + return EXIT_FAILURE; + } + + gcli_sshkeys_free_keys(&list); + return 0; } diff --git a/src/sshkeys.c b/src/sshkeys.c new file mode 100644 index 00000000..01002cc4 --- /dev/null +++ b/src/sshkeys.c @@ -0,0 +1,57 @@ +/* + * Copyright 2023 Nico Sonack + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +int +gcli_sshkeys_get_keys(gcli_sshkey_list *out) +{ + return gcli_forge()->get_sshkeys(out); +} + +void +gcli_sshkeys_free_keys(gcli_sshkey_list *list) +{ + for (size_t i = 0; i < list->keys_size; ++i) { + free(list->keys[i].title); + free(list->keys[i].key); + free(list->keys[i].created_at); + } + + free(list->keys); + + list->keys = NULL; + list->keys_size = 0; +} From 1f743ed6954be278998aa2789a5dc3eadeb4cb29 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 14:49:45 +0200 Subject: [PATCH 07/49] sshkeys: Add stubs and files for gitlab Signed-off-by: Nico Sonack --- Makefile.am | 1 + include/gcli/gitlab/sshkeys.h | 41 +++++++++++++++++++++++++++++++++++ include/gcli/sshkeys.h | 2 ++ src/forges.c | 2 ++ src/gitlab/sshkeys.c | 41 +++++++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+) create mode 100644 include/gcli/gitlab/sshkeys.h create mode 100644 src/gitlab/sshkeys.c diff --git a/Makefile.am b/Makefile.am index 6f0cb23c..e54ab441 100644 --- a/Makefile.am +++ b/Makefile.am @@ -141,6 +141,7 @@ libgcli_la_SOURCES = \ src/gitlab/repos.c include/gcli/gitlab/repos.h \ src/gitlab/review.c include/gcli/gitlab/review.h \ src/gitlab/status.c include/gcli/gitlab/status.h \ + src/gitlab/sshkeys.c include/gcli/gitlab/sshkeys.h \ src/github/releases.c include/gcli/github/releases.h \ src/github/config.c include/gcli/github/config.h \ src/github/api.c include/gcli/github/api.h \ diff --git a/include/gcli/gitlab/sshkeys.h b/include/gcli/gitlab/sshkeys.h new file mode 100644 index 00000000..ddf8ad2f --- /dev/null +++ b/include/gcli/gitlab/sshkeys.h @@ -0,0 +1,41 @@ +/* + * Copyright 2023 Nico Sonack + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCLI_GITLAB_SSHKEYS_H +#define GCLI_GITLAB_SSHKEYS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +int gitlab_get_sshkeys(gcli_sshkey_list *list); + +#endif /* GCLI_GITLAB_SSHKEYS_H */ diff --git a/include/gcli/sshkeys.h b/include/gcli/sshkeys.h index 0000cc52..5247aa23 100644 --- a/include/gcli/sshkeys.h +++ b/include/gcli/sshkeys.h @@ -34,6 +34,8 @@ #include #endif +#include + struct gcli_sshkey { int id; char *title; diff --git a/src/forges.c b/src/forges.c index 3353de4a..a3ec86f5 100644 --- a/src/forges.c +++ b/src/forges.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include @@ -183,6 +184,7 @@ gitlab_forge_descriptor = .notification_mark_as_read = gitlab_notification_mark_as_read, .get_authheader = gitlab_get_authheader, .get_account = gitlab_get_account, + .get_sshkeys = gitlab_get_sshkeys, .get_api_error_string = gitlab_api_error_string, .user_object_key = "username", .html_url_key = "web_url", diff --git a/src/gitlab/sshkeys.c b/src/gitlab/sshkeys.c new file mode 100644 index 00000000..846bde2b --- /dev/null +++ b/src/gitlab/sshkeys.c @@ -0,0 +1,41 @@ +/* + * Copyright 2023 Nico Sonack + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include + +int +gitlab_get_sshkeys(gcli_sshkey_list *list) +{ + *list = (gcli_sshkey_list) {0}; + return 0; +} From af482c8111218e0ee824524218cdfe233470f1b9 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 14:56:34 +0200 Subject: [PATCH 08/49] sshkeys: Add routine for printing a list of ssh keys Also hooked it into the ssk subcommand. Signed-off-by: Nico Sonack --- include/gcli/sshkeys.h | 1 + src/cmd/config.c | 1 + src/sshkeys.c | 25 +++++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/include/gcli/sshkeys.h b/include/gcli/sshkeys.h index 5247aa23..94ef3271 100644 --- a/include/gcli/sshkeys.h +++ b/include/gcli/sshkeys.h @@ -52,6 +52,7 @@ typedef struct gcli_sshkey gcli_sshkey; typedef struct gcli_sshkey_list gcli_sshkey_list; int gcli_sshkeys_get_keys(gcli_sshkey_list *out); +void gcli_sshkeys_print_keys(gcli_sshkey_list const *list); void gcli_sshkeys_free_keys(gcli_sshkey_list *list); #endif /* GCLI_SSHKEYS_H */ diff --git a/src/cmd/config.c b/src/cmd/config.c index 12b86182..8a6ac185 100644 --- a/src/cmd/config.c +++ b/src/cmd/config.c @@ -71,6 +71,7 @@ subcommand_ssh(int argc, char *argv[]) return EXIT_FAILURE; } + gcli_sshkeys_print_keys(&list); gcli_sshkeys_free_keys(&list); return 0; diff --git a/src/sshkeys.c b/src/sshkeys.c index 01002cc4..423620de 100644 --- a/src/sshkeys.c +++ b/src/sshkeys.c @@ -34,6 +34,7 @@ #include #include #include +#include int gcli_sshkeys_get_keys(gcli_sshkey_list *out) @@ -41,6 +42,30 @@ gcli_sshkeys_get_keys(gcli_sshkey_list *out) return gcli_forge()->get_sshkeys(out); } +void +gcli_sshkeys_print_keys(gcli_sshkey_list const *list) +{ + gcli_tbl *tbl; + gcli_tblcoldef cols[] = { + { .name = "ID", .type = GCLI_TBLCOLTYPE_INT, .flags = 0 }, + { .name = "CREATED", .type = GCLI_TBLCOLTYPE_STRING, .flags = 0 }, + { .name = "TITLE", .type = GCLI_TBLCOLTYPE_STRING, .flags = 0 }, + }; + + if (list->keys_size == 0) { + printf("No SSH keys\n"); + return; + } + + tbl = gcli_tbl_begin(cols, ARRAY_SIZE(cols)); + + for (size_t i = 0; i < list->keys_size; ++i) { + gcli_tbl_add_row(tbl, list->keys[i].id, list->keys[i].created_at, list->keys[i].title); + } + + gcli_tbl_end(tbl); +} + void gcli_sshkeys_free_keys(gcli_sshkey_list *list) { From 819708b61d411b2f9ac862803e737f6497406b28 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 15:01:04 +0200 Subject: [PATCH 09/49] sshkeys: Perform request to gitlab api Signed-off-by: Nico Sonack --- src/gitlab/sshkeys.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/gitlab/sshkeys.c b/src/gitlab/sshkeys.c index 846bde2b..8e4bb00c 100644 --- a/src/gitlab/sshkeys.c +++ b/src/gitlab/sshkeys.c @@ -32,10 +32,26 @@ #endif /* HAVE_CONFIG_H */ #include +#include +#include + +#include +#include int gitlab_get_sshkeys(gcli_sshkey_list *list) { + char *url; + gcli_fetch_buffer buf = {0}; + json_stream str; + *list = (gcli_sshkey_list) {0}; + url = sn_asprintf("%s/user/keys", gcli_get_apibase()); + + gcli_fetch(url, NULL, &buf); + json_open_buffer(&str, buf.data, buf.length); + + free(buf.data); + return 0; } From 0b6712803bf7684598282fbed21c1b150402f7a9 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 15:05:35 +0200 Subject: [PATCH 10/49] sshkeys: Add JSON parser template Signed-off-by: Nico Sonack --- Makefile.am | 1 + templates/gitlab/sshkeys.t | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 templates/gitlab/sshkeys.t diff --git a/Makefile.am b/Makefile.am index e54ab441..636b0658 100644 --- a/Makefile.am +++ b/Makefile.am @@ -103,6 +103,7 @@ TEMPLATES = \ templates/gitlab/releases.t \ templates/gitlab/repos.t \ templates/gitlab/review.t \ + templates/gitlab/sshkeys.t \ templates/gitlab/status.t \ templates/gitlab/snippets.t \ templates/gitea/milestones.t diff --git a/templates/gitlab/sshkeys.t b/templates/gitlab/sshkeys.t new file mode 100644 index 00000000..73bf9d76 --- /dev/null +++ b/templates/gitlab/sshkeys.t @@ -0,0 +1,10 @@ +include "gcli/sshkeys.h"; + +parser gitlab_sshkey is +object of gcli_sshkey with + ("title" => title as string, + "id" => id as int, + "key" => key as string, + "created_at" => created_at as string); + +parser gitlab_sshkeys is array of gcli_sshkey use parse_gitlab_sshkey; From d6ac46bc2149b6a3422eb81f64b399a6ef2e9842 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 15:06:09 +0200 Subject: [PATCH 11/49] sshkeys: Hook up generated parser for Gitlab Signed-off-by: Nico Sonack --- src/gitlab/sshkeys.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gitlab/sshkeys.c b/src/gitlab/sshkeys.c index 8e4bb00c..153193ac 100644 --- a/src/gitlab/sshkeys.c +++ b/src/gitlab/sshkeys.c @@ -38,6 +38,8 @@ #include #include +#include + int gitlab_get_sshkeys(gcli_sshkey_list *list) { @@ -51,6 +53,9 @@ gitlab_get_sshkeys(gcli_sshkey_list *list) gcli_fetch(url, NULL, &buf); json_open_buffer(&str, buf.data, buf.length); + parse_gitlab_sshkeys(&str, &list->keys, &list->keys_size); + + json_close(&str); free(buf.data); return 0; From a26cbf256e528eb24f43dcce54d9c5702bbbabc2 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 15:07:07 +0200 Subject: [PATCH 12/49] sshkeys: fix leak of url string Signed-off-by: Nico Sonack --- src/gitlab/sshkeys.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gitlab/sshkeys.c b/src/gitlab/sshkeys.c index 153193ac..077cf6fc 100644 --- a/src/gitlab/sshkeys.c +++ b/src/gitlab/sshkeys.c @@ -57,6 +57,7 @@ gitlab_get_sshkeys(gcli_sshkey_list *list) json_close(&str); free(buf.data); + free(url); return 0; } From 43ca188a806a07b0100ddd5d74599b03bb19ab85 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 15:10:33 +0200 Subject: [PATCH 13/49] sshkeys: Allow for multiple pages of keys I doubt this will ever happen but hey. We'll just support it. Signed-off-by: Nico Sonack --- src/gitlab/sshkeys.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/gitlab/sshkeys.c b/src/gitlab/sshkeys.c index 077cf6fc..7945c5e0 100644 --- a/src/gitlab/sshkeys.c +++ b/src/gitlab/sshkeys.c @@ -43,21 +43,23 @@ int gitlab_get_sshkeys(gcli_sshkey_list *list) { - char *url; - gcli_fetch_buffer buf = {0}; - json_stream str; + char *url, *next_url = NULL; *list = (gcli_sshkey_list) {0}; url = sn_asprintf("%s/user/keys", gcli_get_apibase()); - gcli_fetch(url, NULL, &buf); - json_open_buffer(&str, buf.data, buf.length); + do { + gcli_fetch_buffer buf = {0}; + json_stream str; - parse_gitlab_sshkeys(&str, &list->keys, &list->keys_size); + gcli_fetch(url, &next_url, &buf); + json_open_buffer(&str, buf.data, buf.length); + parse_gitlab_sshkeys(&str, &list->keys, &list->keys_size); - json_close(&str); - free(buf.data); - free(url); + json_close(&str); + free(buf.data); + free(url); + } while ((url = next_url)); return 0; } From 3bbfaa01fc53b1ac401126b260e894e786080ccc Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 18:37:15 +0200 Subject: [PATCH 14/49] cmd: Add code path for adding ssh keys Signed-off-by: Nico Sonack --- src/cmd/config.c | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/cmd/config.c b/src/cmd/config.c index 8a6ac185..9ceb9f54 100644 --- a/src/cmd/config.c +++ b/src/cmd/config.c @@ -46,26 +46,17 @@ static void usage(void) { fprintf(stderr, "usage: gcli config ssh\n"); + fprintf(stderr, " gcli config ssh add --title some-title --key path/to/key.pub\n"); fprintf(stderr, "\n"); version(); copyright(); } static int -subcommand_ssh(int argc, char *argv[]) +list_sshkeys(void) { gcli_sshkey_list list = {0}; - (void) argv; - - --argc; /* TODO: Proper option parsing */ - - if (argc) { - fprintf(stderr, "error: stray arguments\n"); - usage(); - return EXIT_FAILURE; - } - if (gcli_sshkeys_get_keys(&list) < 0) { fprintf(stderr, "error: could not get list of SSH keys\n"); return EXIT_FAILURE; @@ -77,6 +68,35 @@ subcommand_ssh(int argc, char *argv[]) return 0; } +static int +add_sshkey(int argc, char *argv[]) +{ + (void) argc; + (void) argv; + + sn_unimplemented; + + return EXIT_FAILURE; +} + +static int +subcommand_ssh(int argc, char *argv[]) +{ + char *cmdname; + + if (--argc == 0) + return list_sshkeys(); + + cmdname = *(++argv); + + if (strcmp(cmdname, "add") == 0) + return add_sshkey(argc, argv); + + fprintf(stderr, "error: unrecognised subcommand »%s«.\n", cmdname); + usage(); + return EXIT_FAILURE; +} + struct subcommand { char const *const name; int (*fn)(int argc, char *argv[]); From 30563bea8ae9129a81885d591e2fb91cd437998b Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 22:09:27 +0200 Subject: [PATCH 15/49] cmd: Add command line option parsing for ssh add subcommand Signed-off-by: Nico Sonack --- include/gcli/forges.h | 6 +++++ include/gcli/sshkeys.h | 3 +++ src/cmd/config.c | 51 ++++++++++++++++++++++++++++++++++++++---- src/sshkeys.c | 31 +++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 4 deletions(-) diff --git a/include/gcli/forges.h b/include/gcli/forges.h index 0f0bb2a2..1ed08921 100644 --- a/include/gcli/forges.h +++ b/include/gcli/forges.h @@ -421,6 +421,12 @@ struct gcli_forge_descriptor { * Get list of SSH keys */ int (*get_sshkeys)(gcli_sshkey_list *); + /** + * Add an SSH public key */ + int (*add_sshkey)(char const *title, + char const *public_key_path, + gcli_sshkey *out); + /** * Get the error string from the API */ char const *(*get_api_error_string)( diff --git a/include/gcli/sshkeys.h b/include/gcli/sshkeys.h index 94ef3271..76ab1cd9 100644 --- a/include/gcli/sshkeys.h +++ b/include/gcli/sshkeys.h @@ -52,6 +52,9 @@ typedef struct gcli_sshkey gcli_sshkey; typedef struct gcli_sshkey_list gcli_sshkey_list; int gcli_sshkeys_get_keys(gcli_sshkey_list *out); +int gcli_sshkeys_add_key(char const *title, + char const *public_key_path, + gcli_sshkey *out); void gcli_sshkeys_print_keys(gcli_sshkey_list const *list); void gcli_sshkeys_free_keys(gcli_sshkey_list *list); diff --git a/src/cmd/config.c b/src/cmd/config.c index 9ceb9f54..6886459d 100644 --- a/src/cmd/config.c +++ b/src/cmd/config.c @@ -35,8 +35,10 @@ #include #include +#include #include #include +#include #ifdef HAVE_GETOPT_H #include @@ -71,12 +73,53 @@ list_sshkeys(void) static int add_sshkey(int argc, char *argv[]) { - (void) argc; - (void) argv; + char *title = NULL, *keypath = NULL; + gcli_sshkey key = {0}; + int ch; - sn_unimplemented; + struct option options[] = { + { .name = "title", .has_arg = required_argument, .flag = NULL, .val = 't' }, + { .name = "key", .has_arg = required_argument, .flag = NULL, .val = 'k' }, + { 0 }, + }; - return EXIT_FAILURE; + while ((ch = getopt_long(argc, argv, "+t:k:", options, NULL)) != -1) { + switch (ch) { + case 't': { + title = optarg; + } break; + case 'k': { + keypath = optarg; + + if (access(keypath, R_OK) < 0) { + fprintf(stderr, "error: cannot access %s: %s\n", + keypath, strerror(errno)); + return EXIT_FAILURE; + } + } break; + default: { + usage(); + return EXIT_FAILURE; + } break; + } + } + + if (title == NULL) { + fprintf(stderr, "error: missing title\n"); + usage(); + return EXIT_FAILURE; + } + + if (keypath == NULL) { + fprintf(stderr, "error: missing public key path\n"); + usage(); + return EXIT_FAILURE; + } + + if (gcli_sshkeys_add_key(title, keypath, &key) < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; } static int diff --git a/src/sshkeys.c b/src/sshkeys.c index 423620de..6b1e1cca 100644 --- a/src/sshkeys.c +++ b/src/sshkeys.c @@ -80,3 +80,34 @@ gcli_sshkeys_free_keys(gcli_sshkey_list *list) list->keys = NULL; list->keys_size = 0; } + +int +gcli_sshkeys_add_key(char const *title, + char const *public_key_path, + gcli_sshkey *out) +{ + FILE *f; + size_t len; + int rc; + char *buffer; + + /* open file and determine length */ + f = fopen(public_key_path, "r"); + if (!f) + return -1; + + fseek(f, 0, SEEK_END); + len = ftell(f); + rewind(f); + + /* TODO proper error handling */ + buffer = malloc(len + 1); + if (fread(buffer, 1, len, f) != len) + return -1; + + rc = gcli_forge()->add_sshkey(title, buffer, out); + + free(buffer); + fclose(f); + return rc; +} From 4a691548207ecb95ad1c90455fecc5e4ddf5b8b2 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 22:36:38 +0200 Subject: [PATCH 16/49] sshkeys: Add support for adding ssh keys on gitlab Signed-off-by: Nico Sonack --- include/gcli/gitlab/sshkeys.h | 3 +++ src/cmd/config.c | 3 +-- src/forges.c | 1 + src/gitlab/sshkeys.c | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/include/gcli/gitlab/sshkeys.h b/include/gcli/gitlab/sshkeys.h index ddf8ad2f..a5bd434b 100644 --- a/include/gcli/gitlab/sshkeys.h +++ b/include/gcli/gitlab/sshkeys.h @@ -37,5 +37,8 @@ #include int gitlab_get_sshkeys(gcli_sshkey_list *list); +int gitlab_add_sshkey(char const *const title, + char const *const pubkey, + gcli_sshkey *const out); #endif /* GCLI_GITLAB_SSHKEYS_H */ diff --git a/src/cmd/config.c b/src/cmd/config.c index 6886459d..14f45741 100644 --- a/src/cmd/config.c +++ b/src/cmd/config.c @@ -74,7 +74,6 @@ static int add_sshkey(int argc, char *argv[]) { char *title = NULL, *keypath = NULL; - gcli_sshkey key = {0}; int ch; struct option options[] = { @@ -116,7 +115,7 @@ add_sshkey(int argc, char *argv[]) return EXIT_FAILURE; } - if (gcli_sshkeys_add_key(title, keypath, &key) < 0) + if (gcli_sshkeys_add_key(title, keypath, NULL) < 0) return EXIT_FAILURE; return EXIT_SUCCESS; diff --git a/src/forges.c b/src/forges.c index a3ec86f5..bf36dc31 100644 --- a/src/forges.c +++ b/src/forges.c @@ -185,6 +185,7 @@ gitlab_forge_descriptor = .get_authheader = gitlab_get_authheader, .get_account = gitlab_get_account, .get_sshkeys = gitlab_get_sshkeys, + .add_sshkey = gitlab_add_sshkey, .get_api_error_string = gitlab_api_error_string, .user_object_key = "username", .html_url_key = "web_url", diff --git a/src/gitlab/sshkeys.c b/src/gitlab/sshkeys.c index 7945c5e0..128fe1fc 100644 --- a/src/gitlab/sshkeys.c +++ b/src/gitlab/sshkeys.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -63,3 +64,35 @@ gitlab_get_sshkeys(gcli_sshkey_list *list) return 0; } + +int +gitlab_add_sshkey(char const *const title, + char const *const pubkey, + gcli_sshkey *const out) +{ + char *url, *payload; + char *e_title, *e_key; + gcli_fetch_buffer buf = {0}; + + url = sn_asprintf("%s/user/keys", gcli_get_apibase()); + + /* Prepare payload */ + e_title = gcli_json_escape_cstr(title); + e_key = gcli_json_escape_cstr(pubkey); + payload = sn_asprintf( + "{ \"title\": \"%s\", \"key\": \"%s\" }", + e_title, e_key); + + gcli_fetch_with_method("POST", url, payload, NULL, &buf); + if (out) { + json_stream str; + + json_open_buffer(&str, buf.data, buf.length); + parse_gitlab_sshkey(&str, out); + json_close(&str); + } + + free(buf.data); + + return 0; +} From d2d331c27bd0516a233141931b18be472ea11df1 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 23:22:15 +0200 Subject: [PATCH 17/49] (#180) Implement deleting SSH Public Keys This only contains the implementation for Gitlab. Signed-off-by: Nico Sonack --- include/gcli/forges.h | 4 ++++ include/gcli/gitlab/sshkeys.h | 1 + include/gcli/sshkeys.h | 1 + src/cmd/config.c | 32 ++++++++++++++++++++++++++++++++ src/forges.c | 1 + src/gitlab/sshkeys.c | 13 +++++++++++++ src/sshkeys.c | 6 ++++++ 7 files changed, 58 insertions(+) diff --git a/include/gcli/forges.h b/include/gcli/forges.h index 1ed08921..8f8d23e6 100644 --- a/include/gcli/forges.h +++ b/include/gcli/forges.h @@ -427,6 +427,10 @@ struct gcli_forge_descriptor { char const *public_key_path, gcli_sshkey *out); + /** + * Delete an SSH public key by its ID */ + int (*delete_sshkey)(int id); + /** * Get the error string from the API */ char const *(*get_api_error_string)( diff --git a/include/gcli/gitlab/sshkeys.h b/include/gcli/gitlab/sshkeys.h index a5bd434b..a0e78521 100644 --- a/include/gcli/gitlab/sshkeys.h +++ b/include/gcli/gitlab/sshkeys.h @@ -40,5 +40,6 @@ int gitlab_get_sshkeys(gcli_sshkey_list *list); int gitlab_add_sshkey(char const *const title, char const *const pubkey, gcli_sshkey *const out); +int gitlab_delete_sshkey(int id); #endif /* GCLI_GITLAB_SSHKEYS_H */ diff --git a/include/gcli/sshkeys.h b/include/gcli/sshkeys.h index 76ab1cd9..d594b26a 100644 --- a/include/gcli/sshkeys.h +++ b/include/gcli/sshkeys.h @@ -55,6 +55,7 @@ int gcli_sshkeys_get_keys(gcli_sshkey_list *out); int gcli_sshkeys_add_key(char const *title, char const *public_key_path, gcli_sshkey *out); +int gcli_sshkeys_delete_key(int id); void gcli_sshkeys_print_keys(gcli_sshkey_list const *list); void gcli_sshkeys_free_keys(gcli_sshkey_list *list); diff --git a/src/cmd/config.c b/src/cmd/config.c index 14f45741..71d7f464 100644 --- a/src/cmd/config.c +++ b/src/cmd/config.c @@ -49,6 +49,7 @@ usage(void) { fprintf(stderr, "usage: gcli config ssh\n"); fprintf(stderr, " gcli config ssh add --title some-title --key path/to/key.pub\n"); + fprintf(stderr, " gcli config ssh delete id\n"); fprintf(stderr, "\n"); version(); copyright(); @@ -121,6 +122,35 @@ add_sshkey(int argc, char *argv[]) return EXIT_SUCCESS; } +static int +delete_sshkey(int argc, char *argv[]) +{ + int id; + char *endptr; + + /* skip 'delete' keyword */ + --argc; ++argv; + + if (argc != 1) { + fprintf(stderr, "error: incorrect number of arguments\n"); + usage(); + return EXIT_FAILURE; + } + + /* parse the id */ + id = strtol(argv[0], &endptr, 10); + + if (endptr != argv[0] + strlen(argv[0])) { + fprintf(stderr, "error: could not parse ID of SSH key to delete\n"); + return EXIT_FAILURE; + } + + if (gcli_sshkeys_delete_key(id) < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + static int subcommand_ssh(int argc, char *argv[]) { @@ -133,6 +163,8 @@ subcommand_ssh(int argc, char *argv[]) if (strcmp(cmdname, "add") == 0) return add_sshkey(argc, argv); + else if (strcmp(cmdname, "delete") == 0) + return delete_sshkey(argc, argv); fprintf(stderr, "error: unrecognised subcommand »%s«.\n", cmdname); usage(); diff --git a/src/forges.c b/src/forges.c index bf36dc31..01370c2e 100644 --- a/src/forges.c +++ b/src/forges.c @@ -186,6 +186,7 @@ gitlab_forge_descriptor = .get_account = gitlab_get_account, .get_sshkeys = gitlab_get_sshkeys, .add_sshkey = gitlab_add_sshkey, + .delete_sshkey = gitlab_delete_sshkey, .get_api_error_string = gitlab_api_error_string, .user_object_key = "username", .html_url_key = "web_url", diff --git a/src/gitlab/sshkeys.c b/src/gitlab/sshkeys.c index 128fe1fc..1602d976 100644 --- a/src/gitlab/sshkeys.c +++ b/src/gitlab/sshkeys.c @@ -96,3 +96,16 @@ gitlab_add_sshkey(char const *const title, return 0; } + +int +gitlab_delete_sshkey(int id) +{ + char *url; + + url = sn_asprintf("%s/user/keys/%d", gcli_get_apibase(), id); + gcli_fetch_with_method("DELETE", url, NULL, NULL, NULL); + + free(url); + + return 0; +} diff --git a/src/sshkeys.c b/src/sshkeys.c index 6b1e1cca..63ca4395 100644 --- a/src/sshkeys.c +++ b/src/sshkeys.c @@ -111,3 +111,9 @@ gcli_sshkeys_add_key(char const *title, fclose(f); return rc; } + +int +gcli_sshkeys_delete_key(int id) +{ + return gcli_forge()->delete_sshkey(id); +} From 4419e5beec3b53706dd58179da581a72fab26119 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 30 Jun 2023 23:42:52 +0200 Subject: [PATCH 18/49] Add a proper read_file function I could potentially maybe if I was bothered replace all calls to sn_mmap_file with calls to this new file. I'll leave this for Future-Nico. Signed-off-by: Nico Sonack --- src/sshkeys.c | 21 ++++----------------- thirdparty/sn/sn.c | 34 ++++++++++++++++++++++++++++++++++ thirdparty/sn/sn.h | 1 + 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/sshkeys.c b/src/sshkeys.c index 63ca4395..9ae77473 100644 --- a/src/sshkeys.c +++ b/src/sshkeys.c @@ -86,29 +86,16 @@ gcli_sshkeys_add_key(char const *title, char const *public_key_path, gcli_sshkey *out) { - FILE *f; - size_t len; int rc; char *buffer; - /* open file and determine length */ - f = fopen(public_key_path, "r"); - if (!f) - return -1; - - fseek(f, 0, SEEK_END); - len = ftell(f); - rewind(f); - - /* TODO proper error handling */ - buffer = malloc(len + 1); - if (fread(buffer, 1, len, f) != len) - return -1; + rc = sn_read_file(public_key_path, &buffer); + if (rc < 0) + return rc; rc = gcli_forge()->add_sshkey(title, buffer, out); - free(buffer); - fclose(f); + return rc; } diff --git a/thirdparty/sn/sn.c b/thirdparty/sn/sn.c index 4c36b53e..3533197b 100644 --- a/thirdparty/sn/sn.c +++ b/thirdparty/sn/sn.c @@ -236,6 +236,40 @@ sn_mmap_file(const char *path, void **buffer) return stat_buf.st_size; } +int +sn_read_file(char const *path, char **buffer) +{ + FILE *f; + size_t len; + int rc = 0; + + /* open file and determine length */ + f = fopen(path, "r"); + if (!f) + return -1; + + if (fseek(f, 0, SEEK_END) < 0) + goto err_seek; + + len = ftell(f); + rewind(f); + + /* TODO proper error handling */ + *buffer = malloc(len + 1); + if (fread(*buffer, 1, len, f) != len) { + rc = -1; + goto err_read; + } + + rc = (int)(len); + +err_read: +err_seek: + fclose(f); + + return rc; +} + sn_sv sn_sv_trim_front(sn_sv it) { diff --git a/thirdparty/sn/sn.h b/thirdparty/sn/sn.h index 5552701f..d30b0ba1 100644 --- a/thirdparty/sn/sn.h +++ b/thirdparty/sn/sn.h @@ -110,6 +110,7 @@ void pretty_print(const char *input, int indent, int maxlinelen, FILE *out); /* io file mapping */ int sn_mmap_file(const char *path, void **buffer); +int sn_read_file(char const *path, char **buffer); /* stringview */ typedef struct sn_sv sn_sv; From c59362e8d8eb8ca578b1d8ec9b096551222d193f Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Sat, 1 Jul 2023 00:09:21 +0200 Subject: [PATCH 19/49] (#181) Document new config subcommand Adds both the gcli-config(1) manual page as well as links from the main manual page at gcli(1). Signed-off-by: Nico Sonack --- Makefile.am | 1 + configure.ac | 1 + docs/gcli-config.1.in | 65 +++++++++++++++++++++++++++++++++++++++++++ docs/gcli.1.in | 5 ++++ 4 files changed, 72 insertions(+) create mode 100644 docs/gcli-config.1.in diff --git a/Makefile.am b/Makefile.am index 636b0658..1e1ea084 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,6 +39,7 @@ gcli_LDADD = libgcli.la libpdjson.la libsn.la dist_man_MANS = \ docs/gcli-api.1 \ docs/gcli-comment.1 \ + docs/gcli-config.1 \ docs/gcli-forks.1 \ docs/gcli-gists.1 \ docs/gcli-issues.1 \ diff --git a/configure.ac b/configure.ac index 3c18f7be..6ab57672 100644 --- a/configure.ac +++ b/configure.ac @@ -64,6 +64,7 @@ dnl Generate and substitute various files AC_CONFIG_FILES([Makefile docs/gcli-api.1 docs/gcli-comment.1 + docs/gcli-config.1 docs/gcli-forks.1 docs/gcli-gists.1 docs/gcli-issues.1 diff --git a/docs/gcli-config.1.in b/docs/gcli-config.1.in new file mode 100644 index 00000000..7f3ef050 --- /dev/null +++ b/docs/gcli-config.1.in @@ -0,0 +1,65 @@ +.Dd @PACKAGE_DATE@ +.Dt GCLI-ISSUES 1 +.Os @PACKAGE_STRING@ +.Sh NAME +.Nm gcli config +.Nd Git Forge Configuration +.Sh SYNOPSIS +.Nm +.Cm ssh +.Nm +.Cm ssh add +.Fl t Ar title +.Fl k Ar keypath +.Nm +.Cm ssh delete +.Fl i Ar id +.Sh DESCRIPTION +.Nm +is used to change the settings of the Git Forge Account. You can use +it to e.g. add or delete SSH Public Keys used to push to forges. +.Sh OPTIONS +.Bl -tag -width xxxxxxxxxxxxxxxxx +.It Fl t , -title Ar title +Set the title of the SSH Key to be added. This is a short description +of the key. +.It Fl k , -key Pa keypath +Path to the file containing the SSH public key. +.It Fl i , -id Ar id +ID of the public key to delete. +.El +. +.Sh SUBCOMMANDS +.Bl -tag -width xxxxxxxxxxx +.It Cm ssh +List SSH public keys for the current user. +.It Cm ssh add +Add a SSH public key for the current user. +.It Cm ssh delete +Delete a SSH public key for the current user. +.El +.Sh EXAMPLES +Print a list of registered SSH public keys: +.Bd -literal -offset indent +$ gcli config ssh +.Ed +.Pp +Register ~/.ssh/id_rsa.pub on the default forge: +.Bd -literal -offset indent +$ gcli config ssh add \\ + -t "Key for $(hostname)" \\ + -k ~/.ssh/id_rsa.pub +.Ed +.Pp +.Sh SEE ALSO +.Xr git 1 , +.Xr gcli 1 +.Sh AUTHORS +.An Nico Sonack aka. herrhotzenplotz Aq Mt nsonack@herrhotzenplotz.de +and contributors. +.Sh BUGS +These features are currently only implemented for Gitlab and will +segfault on both Github and Gitea. +.Pp +Please report bugs at @PACKAGE_URL@, via E-Mail to @PACKAGE_BUGREPORT@ +or on Github. diff --git a/docs/gcli.1.in b/docs/gcli.1.in index eb69388e..54c10e80 100644 --- a/docs/gcli.1.in +++ b/docs/gcli.1.in @@ -70,6 +70,10 @@ Create and manage releases. See .It Cm milestones List and manage milestones. See .Xr gcli-milestones 1 . +.It Cm config +Change user settings for the forge. Allows you to e.g. upload or +delete ssh keys. See +.Xr gcli-config 1 . .It Cm api Perform direct queries to the API and dump the JSON response to stdout. This is primarily intended to assist debugging gcli. See @@ -280,6 +284,7 @@ working from contain the relevant forge and repository information. .Xr gcli-releases 1 , .Xr gcli-comment 1 .Xr gcli-pipelines 1 +.Xr gcli-config 1 .Sh HISTORY The idea for .Nm From 0bc572e94e35ec8ea812b52a658312e00ec3d17b Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Sat, 1 Jul 2023 10:45:49 +0200 Subject: [PATCH 20/49] fix: missing nul-termination in read-file Signed-off-by: Nico Sonack --- thirdparty/sn/sn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/thirdparty/sn/sn.c b/thirdparty/sn/sn.c index 3533197b..d504bc69 100644 --- a/thirdparty/sn/sn.c +++ b/thirdparty/sn/sn.c @@ -254,13 +254,14 @@ sn_read_file(char const *path, char **buffer) len = ftell(f); rewind(f); - /* TODO proper error handling */ *buffer = malloc(len + 1); if (fread(*buffer, 1, len, f) != len) { rc = -1; goto err_read; } + (*buffer)[len] = '\0'; + rc = (int)(len); err_read: From 9ac5e25f4af79be8ee8759b5492c254e42825906 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Wed, 12 Jul 2023 21:42:47 +0200 Subject: [PATCH 21/49] (#183) Add support for listing and adding gitea ssh keys This just calls into the Gitlab code as the APIs are the same. Signed-off-by: Nico Sonack --- Makefile.am | 1 + include/gcli/gitea/sshkeys.h | 40 ++++++++++++++++++++++++++++ src/forges.c | 4 +++ src/gitea/sshkeys.c | 51 ++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 include/gcli/gitea/sshkeys.h create mode 100644 src/gitea/sshkeys.c diff --git a/Makefile.am b/Makefile.am index 1e1ea084..bd088a0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -166,6 +166,7 @@ libgcli_la_SOURCES = \ src/gitea/pulls.c include/gcli/gitea/pulls.h \ src/gitea/releases.c include/gcli/gitea/releases.h \ src/gitea/repos.c include/gcli/gitea/repos.h \ + src/gitea/sshkeys.c include/gcli/gitea/sshkeys.h \ src/gitea/milestones.c include/gcli/gitea/milestones.h \ $(TEMPLATES) diff --git a/include/gcli/gitea/sshkeys.h b/include/gcli/gitea/sshkeys.h new file mode 100644 index 00000000..a110cd87 --- /dev/null +++ b/include/gcli/gitea/sshkeys.h @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Nico Sonack + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCLI_GITEA_SSHKEYS_H +#define GCLI_GITEA_SSHKEYS_H + +#include + +int gitea_get_sshkeys(gcli_sshkey_list *out); +int gitea_add_sshkey(char const *title, + char const *public_key_data, + gcli_sshkey *out); + +#endif /* GCLI_GITEA_SSHKEYS_H */ diff --git a/src/forges.c b/src/forges.c index 01370c2e..de62a47e 100644 --- a/src/forges.c +++ b/src/forges.c @@ -69,6 +69,7 @@ #include #include #include +#include static gcli_forge_descriptor const github_forge_descriptor = @@ -243,6 +244,9 @@ gitea_forge_descriptor = .repo_create = gitea_repo_create, .repo_delete = gitea_repo_delete, + .get_sshkeys = gitea_get_sshkeys, + .add_sshkey = gitea_add_sshkey, + .get_authheader = gitea_get_authheader, .get_account = gitea_get_account, .get_api_error_string = github_api_error_string, /* hack! */ diff --git a/src/gitea/sshkeys.c b/src/gitea/sshkeys.c new file mode 100644 index 00000000..2cbb3d77 --- /dev/null +++ b/src/gitea/sshkeys.c @@ -0,0 +1,51 @@ +/* + * Copyright 2023 Nico Sonack + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +/* NOTE(Nico): The APIs of all the three forges we currently implement + * are the same. Thus, we just call into the gitlab + * implementation. Yes, this looks absurd. */ + +#include + +int +gitea_get_sshkeys(gcli_sshkey_list *list) +{ + return gitlab_get_sshkeys(list); +} + +int +gitea_add_sshkey(char const *const title, + char const *const pubkey, + gcli_sshkey *const out) +{ + return gitlab_add_sshkey(title, pubkey, out); +} From 6dee5e40328744ec4d1ce1a0cd33a66070323f4b Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Wed, 12 Jul 2023 22:10:59 +0200 Subject: [PATCH 22/49] (#183) Add support for deleting ssh keys on gitea Again, call into the Gitlab implementation as the APIs are the same. Signed-off-by: Nico Sonack --- include/gcli/gitea/sshkeys.h | 1 + src/forges.c | 1 + src/gitea/sshkeys.c | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/include/gcli/gitea/sshkeys.h b/include/gcli/gitea/sshkeys.h index a110cd87..5f047573 100644 --- a/include/gcli/gitea/sshkeys.h +++ b/include/gcli/gitea/sshkeys.h @@ -36,5 +36,6 @@ int gitea_get_sshkeys(gcli_sshkey_list *out); int gitea_add_sshkey(char const *title, char const *public_key_data, gcli_sshkey *out); +int gitea_delete_sshkey(int id); #endif /* GCLI_GITEA_SSHKEYS_H */ diff --git a/src/forges.c b/src/forges.c index de62a47e..bcb3bdde 100644 --- a/src/forges.c +++ b/src/forges.c @@ -246,6 +246,7 @@ gitea_forge_descriptor = .get_sshkeys = gitea_get_sshkeys, .add_sshkey = gitea_add_sshkey, + .delete_sshkey = gitea_delete_sshkey, .get_authheader = gitea_get_authheader, .get_account = gitea_get_account, diff --git a/src/gitea/sshkeys.c b/src/gitea/sshkeys.c index 2cbb3d77..ae0c2532 100644 --- a/src/gitea/sshkeys.c +++ b/src/gitea/sshkeys.c @@ -49,3 +49,9 @@ gitea_add_sshkey(char const *const title, { return gitlab_add_sshkey(title, pubkey, out); } + +int +gitea_delete_sshkey(int id) +{ + return gitlab_delete_sshkey(id); +} From 01e17da435a14a134074436d9523c83c88e226ab Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Wed, 12 Jul 2023 22:41:50 +0200 Subject: [PATCH 23/49] (#182) Add support for listing ssh keys on Github Worst error cod ever if you don't have the read:public_key permission on your token. Go figure, webdevs... Signed-off-by: Nico Sonack --- Makefile.am | 1 + include/gcli/github/sshkeys.h | 37 ++++++++++++++++++++++++++++++++ src/forges.c | 4 ++++ src/github/sshkeys.c | 40 +++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+) create mode 100644 include/gcli/github/sshkeys.h create mode 100644 src/github/sshkeys.c diff --git a/Makefile.am b/Makefile.am index bd088a0f..dcea2267 100644 --- a/Makefile.am +++ b/Makefile.am @@ -158,6 +158,7 @@ libgcli_la_SOURCES = \ src/github/review.c include/gcli/github/review.h \ src/github/checks.c include/gcli/github/checks.h \ src/github/gists.c include/gcli/github/gists.h \ + src/github/sshkeys.c include/gcli/github/sshkeys.h \ src/gitea/issues.c include/gcli/gitea/issues.h \ src/gitea/labels.c include/gcli/gitea/labels.h \ src/gitea/forks.c include/gcli/gitea/forks.h \ diff --git a/include/gcli/github/sshkeys.h b/include/gcli/github/sshkeys.h new file mode 100644 index 00000000..58c952f6 --- /dev/null +++ b/include/gcli/github/sshkeys.h @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Nico Sonack + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCLI_GITHUB_SSHKEYS_H +#define GCLI_GITHUB_SSHKEYS_H + +#include + +int github_get_sshkeys(gcli_sshkey_list *out); + +#endif /* GCLI_GITHUB_SSHKEYS_H */ diff --git a/src/forges.c b/src/forges.c index bcb3bdde..91387774 100644 --- a/src/forges.c +++ b/src/forges.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -122,6 +123,9 @@ github_forge_descriptor = .get_reviews = github_review_get_reviews, .repo_create = github_repo_create, .repo_delete = github_repo_delete, + + .get_sshkeys = github_get_sshkeys, + .get_notifications = github_get_notifications, .notification_mark_as_read = github_notification_mark_as_read, .get_authheader = github_get_authheader, diff --git a/src/github/sshkeys.c b/src/github/sshkeys.c new file mode 100644 index 00000000..99bd1ff6 --- /dev/null +++ b/src/github/sshkeys.c @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Nico Sonack + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/* NOTE(Nico): This looks strange because it reuses the Gitlab code + * because the APIs are the same. */ +#include + +int +github_get_sshkeys(gcli_sshkey_list *out) +{ + return gitlab_get_sshkeys(out); +} From 1ac4baad695552e998e18e01ea9d8862021ffccf Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Wed, 12 Jul 2023 22:45:09 +0200 Subject: [PATCH 24/49] (#182) Add support for deleting ssh keys on Github Signed-off-by: Nico Sonack --- include/gcli/github/sshkeys.h | 3 +++ src/forges.c | 1 + src/github/sshkeys.c | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/include/gcli/github/sshkeys.h b/include/gcli/github/sshkeys.h index 58c952f6..a1ac251b 100644 --- a/include/gcli/github/sshkeys.h +++ b/include/gcli/github/sshkeys.h @@ -33,5 +33,8 @@ #include int github_get_sshkeys(gcli_sshkey_list *out); +int github_add_sshkey(char const *const title, + char const *const pubkey, + gcli_sshkey *out); #endif /* GCLI_GITHUB_SSHKEYS_H */ diff --git a/src/forges.c b/src/forges.c index 91387774..690fb349 100644 --- a/src/forges.c +++ b/src/forges.c @@ -125,6 +125,7 @@ github_forge_descriptor = .repo_delete = github_repo_delete, .get_sshkeys = github_get_sshkeys, + .add_sshkey = github_add_sshkey, .get_notifications = github_get_notifications, .notification_mark_as_read = github_notification_mark_as_read, diff --git a/src/github/sshkeys.c b/src/github/sshkeys.c index 99bd1ff6..bdaca267 100644 --- a/src/github/sshkeys.c +++ b/src/github/sshkeys.c @@ -38,3 +38,11 @@ github_get_sshkeys(gcli_sshkey_list *out) { return gitlab_get_sshkeys(out); } + +int +github_add_sshkey(char const *const title, + char const *const pubkey, + gcli_sshkey *out) +{ + return gitlab_add_sshkey(title, pubkey, out); +} From c0118eb19c3d2471bb865e014c717a3734157b92 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Wed, 12 Jul 2023 22:46:27 +0200 Subject: [PATCH 25/49] (#182) Add support for deleting ssh keys on Github Signed-off-by: Nico Sonack --- include/gcli/github/sshkeys.h | 1 + src/forges.c | 1 + src/github/sshkeys.c | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/include/gcli/github/sshkeys.h b/include/gcli/github/sshkeys.h index a1ac251b..a68144eb 100644 --- a/include/gcli/github/sshkeys.h +++ b/include/gcli/github/sshkeys.h @@ -36,5 +36,6 @@ int github_get_sshkeys(gcli_sshkey_list *out); int github_add_sshkey(char const *const title, char const *const pubkey, gcli_sshkey *out); +int github_delete_sshkey(int id); #endif /* GCLI_GITHUB_SSHKEYS_H */ diff --git a/src/forges.c b/src/forges.c index 690fb349..4a041c0c 100644 --- a/src/forges.c +++ b/src/forges.c @@ -126,6 +126,7 @@ github_forge_descriptor = .get_sshkeys = github_get_sshkeys, .add_sshkey = github_add_sshkey, + .delete_sshkey = github_delete_sshkey, .get_notifications = github_get_notifications, .notification_mark_as_read = github_notification_mark_as_read, diff --git a/src/github/sshkeys.c b/src/github/sshkeys.c index bdaca267..f2cd61ae 100644 --- a/src/github/sshkeys.c +++ b/src/github/sshkeys.c @@ -46,3 +46,9 @@ github_add_sshkey(char const *const title, { return gitlab_add_sshkey(title, pubkey, out); } + +int +github_delete_sshkey(int id) +{ + return gitlab_delete_sshkey(id); +} From 463c6d163a18cdfc42479aa9553db23f7811ae3f Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Wed, 12 Jul 2023 22:50:21 +0200 Subject: [PATCH 26/49] fix: prevent leak of strings when escaping json body parameters Signed-off-by: Nico Sonack --- src/gitlab/sshkeys.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gitlab/sshkeys.c b/src/gitlab/sshkeys.c index 1602d976..fdd966fa 100644 --- a/src/gitlab/sshkeys.c +++ b/src/gitlab/sshkeys.c @@ -82,6 +82,8 @@ gitlab_add_sshkey(char const *const title, payload = sn_asprintf( "{ \"title\": \"%s\", \"key\": \"%s\" }", e_title, e_key); + free(e_title); + free(e_key); gcli_fetch_with_method("POST", url, payload, NULL, &buf); if (out) { From 58506d6bd0735112dae44eed7f490317e0ac524b Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Wed, 12 Jul 2023 22:55:18 +0200 Subject: [PATCH 27/49] fix: Mention weird behaviour when read:public_key scope is missing Signed-off-by: Nico Sonack --- docs/gcli-config.1.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/gcli-config.1.in b/docs/gcli-config.1.in index 7f3ef050..2a61264f 100644 --- a/docs/gcli-config.1.in +++ b/docs/gcli-config.1.in @@ -58,8 +58,10 @@ $ gcli config ssh add \\ .An Nico Sonack aka. herrhotzenplotz Aq Mt nsonack@herrhotzenplotz.de and contributors. .Sh BUGS -These features are currently only implemented for Gitlab and will -segfault on both Github and Gitea. +When using this feature to manage SSH keys on Github be aware that you need the +.Dq read:public_key +scope enabled on your access token. You will receive HTTP 404 errors +otherwise. .Pp Please report bugs at @PACKAGE_URL@, via E-Mail to @PACKAGE_BUGREPORT@ or on Github. From 2c3e2211354539bc7fb5f4fedb042ed184b6b675 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 06:37:03 +0200 Subject: [PATCH 28/49] (#184) issues: Add number of comments to table of issues I called the column "NOTES" because "COMMENTS", "THRD", "CMNTS" are all unreadable or too long. I should add an alias for the "comments" action though that is called "notes" such that we get a consistent ux. Signed-off-by: Nico Sonack --- src/issues.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/issues.c b/src/issues.c index ddcc79cd..50683ebc 100644 --- a/src/issues.c +++ b/src/issues.c @@ -83,6 +83,7 @@ gcli_print_issues_table(enum gcli_output_flags const flags, gcli_tbl table; gcli_tblcoldef cols[] = { { .name = "NUMBER", .type = GCLI_TBLCOLTYPE_INT, .flags = GCLI_TBLCOL_JUSTIFYR }, + { .name = "NOTES", .type = GCLI_TBLCOLTYPE_INT, .flags = GCLI_TBLCOL_JUSTIFYR }, { .name = "STATE", .type = GCLI_TBLCOLTYPE_SV, .flags = GCLI_TBLCOL_STATECOLOURED }, { .name = "TITLE", .type = GCLI_TBLCOLTYPE_SV, .flags = 0 }, }; @@ -108,6 +109,7 @@ gcli_print_issues_table(enum gcli_output_flags const flags, if (!list->issues[n - 1 - 1].is_pr) { gcli_tbl_add_row(table, list->issues[n - i - 1].number, + list->issues[n - i - 1].comments, list->issues[n - i - 1].state, list->issues[n - i - 1].title); } else { @@ -119,6 +121,7 @@ gcli_print_issues_table(enum gcli_output_flags const flags, if (!list->issues[i].is_pr) { gcli_tbl_add_row(table, list->issues[i].number, + list->issues[i].comments, list->issues[i].state, list->issues[i].title); } else { From 9d1724fbb3d9486594e402a5f9a4b98c29b696fd Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 06:43:00 +0200 Subject: [PATCH 29/49] (#184) issues: Add alias "notes" that lists comments Signed-off-by: Nico Sonack --- src/cmd/issues.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cmd/issues.c b/src/cmd/issues.c index 8b4bbf10..e345f67e 100644 --- a/src/cmd/issues.c +++ b/src/cmd/issues.c @@ -68,6 +68,7 @@ usage(void) fprintf(stderr, " remove \n"); fprintf(stderr, " milestone Assign this issue to the given milestone\n"); fprintf(stderr, " milestone -d Clear the assigned milestone of the given issue\n"); + fprintf(stderr, " notes Alias for comments\n"); fprintf(stderr, "\n"); version(); copyright(); @@ -378,7 +379,8 @@ handle_issues_actions(int argc, char *argv[], puts("\nORIGINAL POST\n"); gcli_issue_print_op(&issue); - } else if (strcmp("comments", operation) == 0) { + } else if (strcmp("comments", operation) == 0 || + strcmp("notes", operation) == 0) { /* Doesn't require fetching the issue data */ gcli_issue_comments(owner, repo, issue_id); From f72492e731354a16df35446b868f322eb3653a7b Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 06:43:28 +0200 Subject: [PATCH 30/49] (#184) gcli-issues.1: Document new notes alias Signed-off-by: Nico Sonack --- docs/gcli-issues.1.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/gcli-issues.1.in b/docs/gcli-issues.1.in index de5bed49..9ac54a98 100644 --- a/docs/gcli-issues.1.in +++ b/docs/gcli-issues.1.in @@ -107,6 +107,10 @@ Remove the given label from the issue. .It Cm milestone Ar id Assign the issue to a milestone with the given .Ar id . +.It Cm notes +Alias for the +.Cm comments +action that prints the list of comments associated with the issue. .El .Sh EXAMPLES Print a list of issues in the current project: From 226a239e1cf245a15af9a1082b73ee681563056a Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 06:52:23 +0200 Subject: [PATCH 31/49] (#184) pulls: Add number of comments to list of pull requests This is missing the equivalent alias as well. Signed-off-by: Nico Sonack --- src/pulls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pulls.c b/src/pulls.c index 5bacc677..33344f2b 100644 --- a/src/pulls.c +++ b/src/pulls.c @@ -73,6 +73,7 @@ gcli_print_pulls_table(enum gcli_output_flags const flags, { .name = "STATE", .type = GCLI_TBLCOLTYPE_STRING, .flags = GCLI_TBLCOL_STATECOLOURED }, { .name = "MERGED", .type = GCLI_TBLCOLTYPE_BOOL, .flags = 0 }, { .name = "CREATOR", .type = GCLI_TBLCOLTYPE_STRING, .flags = GCLI_TBLCOL_BOLD }, + { .name = "NOTES", .type = GCLI_TBLCOLTYPE_INT, .flags = GCLI_TBLCOL_JUSTIFYR }, { .name = "TITLE", .type = GCLI_TBLCOLTYPE_STRING, .flags = 0 }, }; @@ -99,6 +100,7 @@ gcli_print_pulls_table(enum gcli_output_flags const flags, list->pulls[n-i-1].state, list->pulls[n-i-1].merged, list->pulls[n-i-1].author, + list->pulls[n-i-1].comments, list->pulls[n-i-1].title); } } else { @@ -108,6 +110,7 @@ gcli_print_pulls_table(enum gcli_output_flags const flags, list->pulls[i].state, list->pulls[i].merged, list->pulls[i].author, + list->pulls[i].comments, list->pulls[i].title); } } From d9c66260545d8a05895b06f416f638dcea281032 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 06:54:20 +0200 Subject: [PATCH 32/49] (#184) pulls: Add alias 'notes' for pull request comments Signed-off-by: Nico Sonack --- src/cmd/pulls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cmd/pulls.c b/src/cmd/pulls.c index a5f35f7c..0bad4445 100644 --- a/src/cmd/pulls.c +++ b/src/cmd/pulls.c @@ -67,6 +67,7 @@ usage(void) fprintf(stderr, " op Display original post\n"); fprintf(stderr, " status Display PR metadata\n"); fprintf(stderr, " comments Display comments\n"); + fprintf(stderr, " notes Alias for notes\n"); fprintf(stderr, " commits Display commits of the PR\n"); fprintf(stderr, " ci Display CI/Pipeline status information about the PR\n"); fprintf(stderr, " merge [-s] [-D] Merge the PR (-s = squash commits, -d = inhibit deleting source branch)\n"); @@ -415,7 +416,8 @@ handle_pull_actions(int argc, char *argv[], } else if (strcmp(action, "diff") == 0) { gcli_print_pull_diff(stdout, owner, repo, pr); - } else if (strcmp(action, "comments") == 0) { + } else if (strcmp(action, "comments") == 0 || + strcmp(action, "notes") == 0) { gcli_pull_comments(owner, repo, pr); } else if (strcmp(action, "ci") == 0) { From 561a06fbcd3fbe5188518c6128b57cc58fc1059d Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 06:57:40 +0200 Subject: [PATCH 33/49] (#184) gcli-pulls.1: Update manual page for new notes alias Signed-off-by: Nico Sonack --- docs/gcli-pulls.1.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/gcli-pulls.1.in b/docs/gcli-pulls.1.in index 4dc13de6..f3fe0f38 100644 --- a/docs/gcli-pulls.1.in +++ b/docs/gcli-pulls.1.in @@ -141,6 +141,10 @@ Squash the commits before merging. .It Fl -inhibit-delete , D Delete the source branch after merging. .El +.It Cm notes +Alias for the +.Cm comments +action that prints a list of comments associated with the PR. .It Cm reviews Print reviews including comments under them. .It Cm labels Op Ar options From b4698ccc577741056d6181440c515df9361da480 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 07:04:21 +0200 Subject: [PATCH 34/49] (#186) pulls: Add missing title to usage in pulls create subcommand Fixes #186 Signed-off-by: Nico Sonack --- src/cmd/pulls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/pulls.c b/src/cmd/pulls.c index 0bad4445..0ccd6a97 100644 --- a/src/cmd/pulls.c +++ b/src/cmd/pulls.c @@ -46,7 +46,7 @@ static void usage(void) { fprintf(stderr, "usage: gcli pulls create [-o owner -r repo] [-f from]\n"); - fprintf(stderr, " [-t to] [-d] [-l label]\n"); + fprintf(stderr, " [-t to] [-d] [-l label] pull-request-title\n"); fprintf(stderr, " gcli pulls [-o owner -r repo] [-a] [-A author ][-n number] [-s]\n"); fprintf(stderr, " gcli pulls [-o owner -r repo] -i pull-id actions...\n"); fprintf(stderr, "OPTIONS:\n"); From c190b78aa74b50225ff3888452d3b5fa7c23f0ba Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 07:07:11 +0200 Subject: [PATCH 35/49] (#185) gcli-issues.1: Add missing documentation milestones -d action Fixes #185 Signed-off-by: Nico Sonack --- docs/gcli-issues.1.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/gcli-issues.1.in b/docs/gcli-issues.1.in index 9ac54a98..6adfb230 100644 --- a/docs/gcli-issues.1.in +++ b/docs/gcli-issues.1.in @@ -107,6 +107,8 @@ Remove the given label from the issue. .It Cm milestone Ar id Assign the issue to a milestone with the given .Ar id . +.It Cm milestone Fl d +Clear associated milestone of the given issue. .It Cm notes Alias for the .Cm comments From 8e424b3ee9356e6e815354a78963736352583570 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 07:43:59 +0200 Subject: [PATCH 36/49] (#187) Add new milestone action to the pulls subcommand This is missing the implementations. Signed-off-by: Nico Sonack --- src/cmd/pulls.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/cmd/pulls.c b/src/cmd/pulls.c index 0ccd6a97..33f68f9b 100644 --- a/src/cmd/pulls.c +++ b/src/cmd/pulls.c @@ -71,6 +71,8 @@ usage(void) fprintf(stderr, " commits Display commits of the PR\n"); fprintf(stderr, " ci Display CI/Pipeline status information about the PR\n"); fprintf(stderr, " merge [-s] [-D] Merge the PR (-s = squash commits, -d = inhibit deleting source branch)\n"); + fprintf(stderr, " milestone Assign this PR to a milestone\n"); + fprintf(stderr, " milestone -d Clear associated milestones from the PR\n"); fprintf(stderr, " close Close the PR\n"); fprintf(stderr, " reopen Reopen a closed PR\n"); fprintf(stderr, " labels ... Add or remove labels:\n"); @@ -488,6 +490,27 @@ handle_pull_actions(int argc, char *argv[], free(add_labels); free(remove_labels); + } else if (strcmp("milestone", action) == 0) { + char const *arg = shift(&argc, &argv); + + if (strcmp(arg, "-d") == 0) { + fprintf(stderr, "error: -d is not implemented for milestones action\n"); + return EXIT_FAILURE; + } else { + int milestone_id = 0; + char *endptr; + + milestone_id = strtoul(arg, &endptr, 10); + if (endptr != arg + strlen(arg)) { + fprintf(stderr, "error: cannot parse milestone id »%s«\n", arg); + return EXIT_FAILURE; + } + + (void) milestone_id; + + fprintf(stderr, "error: assigning milestones is not yet implemented\n"); + return EXIT_FAILURE; + } } else { /* At this point we found an unknown action / stray * options on the command line. Error out in this case. */ From a759ba404ddadb415ea34e4a04f1b972fab387c2 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 07:49:36 +0200 Subject: [PATCH 37/49] (#187) pulls: Add dispatch routine for setting milestones Signed-off-by: Nico Sonack --- include/gcli/pulls.h | 5 +++++ src/cmd/pulls.c | 5 +---- src/pulls.c | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/include/gcli/pulls.h b/include/gcli/pulls.h index 0664c348..e01612fe 100644 --- a/include/gcli/pulls.h +++ b/include/gcli/pulls.h @@ -167,4 +167,9 @@ void gcli_pull_remove_labels(char const *owner, char const *const labels[], size_t labels_size); +void gcli_pull_set_milestone(char const *owner, + char const *repo, + int pr_number, + int milestone_id); + #endif /* PULLS_H */ diff --git a/src/cmd/pulls.c b/src/cmd/pulls.c index 33f68f9b..72ee7ba7 100644 --- a/src/cmd/pulls.c +++ b/src/cmd/pulls.c @@ -506,10 +506,7 @@ handle_pull_actions(int argc, char *argv[], return EXIT_FAILURE; } - (void) milestone_id; - - fprintf(stderr, "error: assigning milestones is not yet implemented\n"); - return EXIT_FAILURE; + gcli_pull_set_milestone(owner, repo, pr, milestone_id); } } else { /* At this point we found an unknown action / stray diff --git a/src/pulls.c b/src/pulls.c index 33344f2b..a1155406 100644 --- a/src/pulls.c +++ b/src/pulls.c @@ -392,3 +392,18 @@ gcli_pull_remove_labels(char const *owner, gcli_forge()->pr_remove_labels( owner, repo, pr_number, labels, labels_size); } + +void +gcli_pull_set_milestone(char const *owner, + char const *repo, + int pr_number, + int milestone_id) +{ + (void) owner; + (void) repo; + (void) pr_number; + (void) milestone_id; + + fprintf(stderr, "error: setting milestones on pulls is not yet implemented\n"); + abort(); +} From b2d1fcfb8daab58b05c5d925c9d71f5cd32e750e Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 07:53:04 +0200 Subject: [PATCH 38/49] (#187) pulls: Add entry for assigning milestones to forge dispatch table No implementations are provided right now, so this will just segfault. Signed-off-by: Nico Sonack --- include/gcli/forges.h | 8 ++++++++ src/pulls.c | 8 +------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/gcli/forges.h b/include/gcli/forges.h index 8f8d23e6..ce3d37ec 100644 --- a/include/gcli/forges.h +++ b/include/gcli/forges.h @@ -320,6 +320,14 @@ struct gcli_forge_descriptor { char const *const labels[], size_t labels_size); + /** + * Assign a PR to a milestone */ + void (*pr_set_milestone)( + char const *owner, + char const *repo, + int pr, + int milestone_id); + /** * Get a list of releases in the given repo */ int (*get_releases)( diff --git a/src/pulls.c b/src/pulls.c index a1155406..ceca80f7 100644 --- a/src/pulls.c +++ b/src/pulls.c @@ -399,11 +399,5 @@ gcli_pull_set_milestone(char const *owner, int pr_number, int milestone_id) { - (void) owner; - (void) repo; - (void) pr_number; - (void) milestone_id; - - fprintf(stderr, "error: setting milestones on pulls is not yet implemented\n"); - abort(); + gcli_forge()->pr_set_milestone(owner, repo, pr_number, milestone_id); } From 077679f7436fc508c953dc7443afc32064dfc045 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 07:57:10 +0200 Subject: [PATCH 39/49] (#187) pulls: Add routine for gitlab Signed-off-by: Nico Sonack --- include/gcli/gitlab/merge_requests.h | 5 +++++ src/forges.c | 1 + src/gitlab/merge_requests.c | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/include/gcli/gitlab/merge_requests.h b/include/gcli/gitlab/merge_requests.h index 663e77cd..bf0e7c4c 100644 --- a/include/gcli/gitlab/merge_requests.h +++ b/include/gcli/gitlab/merge_requests.h @@ -88,4 +88,9 @@ void gitlab_mr_remove_labels(char const *owner, char const *const labels[], size_t labels_size); +void gitlab_mr_set_milestone(char const *owner, + char const *repo, + int mr, + int milestone_id); + #endif /* GITLAB_MERGE_REQUESTS_H */ diff --git a/src/forges.c b/src/forges.c index 4a041c0c..148614c5 100644 --- a/src/forges.c +++ b/src/forges.c @@ -176,6 +176,7 @@ gitlab_forge_descriptor = .get_pull = gitlab_get_pull, .pr_add_labels = gitlab_mr_add_labels, .pr_remove_labels = gitlab_mr_remove_labels, + .pr_set_milestone = gitlab_mr_set_milestone, .get_releases = gitlab_get_releases, .create_release = gitlab_create_release, .delete_release = gitlab_delete_release, diff --git a/src/gitlab/merge_requests.c b/src/gitlab/merge_requests.c index d52ce649..a9b0ef76 100644 --- a/src/gitlab/merge_requests.c +++ b/src/gitlab/merge_requests.c @@ -430,3 +430,16 @@ gitlab_mr_remove_labels(char const *owner, free(list); free(buffer.data); } + +void +gitlab_mr_set_milestone(char const *owner, + char const *repo, + int mr, + int milestone_id) +{ + (void) owner; + (void) repo; + (void) mr; + (void) milestone_id; + errx(1, "%s is not yet implemented", __func__); +} From 296922d5aa1ac07f465700ee7d814324cc760d24 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:00:57 +0200 Subject: [PATCH 40/49] (#187) pulls: Implement setting milestones for Gitlab Signed-off-by: Nico Sonack --- src/gitlab/merge_requests.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/gitlab/merge_requests.c b/src/gitlab/merge_requests.c index a9b0ef76..63fe4cb6 100644 --- a/src/gitlab/merge_requests.c +++ b/src/gitlab/merge_requests.c @@ -437,9 +437,16 @@ gitlab_mr_set_milestone(char const *owner, int mr, int milestone_id) { - (void) owner; - (void) repo; - (void) mr; - (void) milestone_id; - errx(1, "%s is not yet implemented", __func__); + char *url = NULL; + char *data = NULL; + + url = sn_asprintf("%s/projects/%s%%2F%s/merge_requests/%d", + gitlab_get_apibase(), owner, repo, mr); + + data = sn_asprintf("{ \"milestone_id\": \"%d\"}", milestone_id); + + gcli_fetch_with_method("PUT", url, data, NULL, NULL); + + free(url); + free(data); } From c48d94944ad0e894bcc653c66c7193b1a2139434 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:03:56 +0200 Subject: [PATCH 41/49] (#187) pulls: Add routines and dispatch points for clearing milestones Signed-off-by: Nico Sonack --- include/gcli/forges.h | 7 +++++++ include/gcli/pulls.h | 4 ++++ src/cmd/pulls.c | 4 ++-- src/pulls.c | 8 ++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/gcli/forges.h b/include/gcli/forges.h index ce3d37ec..1a267f82 100644 --- a/include/gcli/forges.h +++ b/include/gcli/forges.h @@ -328,6 +328,13 @@ struct gcli_forge_descriptor { int pr, int milestone_id); + /** + * Clear a milestone on a PR */ + void (*pr_clear_milestone)( + char const *owner, + char const *repo, + int pr); + /** * Get a list of releases in the given repo */ int (*get_releases)( diff --git a/include/gcli/pulls.h b/include/gcli/pulls.h index e01612fe..3f347f4e 100644 --- a/include/gcli/pulls.h +++ b/include/gcli/pulls.h @@ -172,4 +172,8 @@ void gcli_pull_set_milestone(char const *owner, int pr_number, int milestone_id); +void gcli_pull_clear_milestone(char const *owner, + char const *repo, + int pr_number); + #endif /* PULLS_H */ diff --git a/src/cmd/pulls.c b/src/cmd/pulls.c index 72ee7ba7..28180832 100644 --- a/src/cmd/pulls.c +++ b/src/cmd/pulls.c @@ -494,8 +494,8 @@ handle_pull_actions(int argc, char *argv[], char const *arg = shift(&argc, &argv); if (strcmp(arg, "-d") == 0) { - fprintf(stderr, "error: -d is not implemented for milestones action\n"); - return EXIT_FAILURE; + gcli_pull_clear_milestone(owner, repo, pr); + } else { int milestone_id = 0; char *endptr; diff --git a/src/pulls.c b/src/pulls.c index ceca80f7..b6e44dc6 100644 --- a/src/pulls.c +++ b/src/pulls.c @@ -401,3 +401,11 @@ gcli_pull_set_milestone(char const *owner, { gcli_forge()->pr_set_milestone(owner, repo, pr_number, milestone_id); } + +void +gcli_pull_clear_milestone(char const *owner, + char const *repo, + int pr_number) +{ + gcli_forge()->pr_clear_milestone(owner, repo, pr_number); +} From cfd500c043fe33c1a219e5915e2429fffab6809c Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:06:48 +0200 Subject: [PATCH 42/49] (#187) pulls: Implement clearing PR milestones for Gitlab Signed-off-by: Nico Sonack --- include/gcli/gitlab/merge_requests.h | 4 ++++ src/forges.c | 1 + src/gitlab/merge_requests.c | 13 +++++++++++++ 3 files changed, 18 insertions(+) diff --git a/include/gcli/gitlab/merge_requests.h b/include/gcli/gitlab/merge_requests.h index bf0e7c4c..5b73ce00 100644 --- a/include/gcli/gitlab/merge_requests.h +++ b/include/gcli/gitlab/merge_requests.h @@ -93,4 +93,8 @@ void gitlab_mr_set_milestone(char const *owner, int mr, int milestone_id); +void gitlab_mr_clear_milestone(char const *owner, + char const *repo, + int mr); + #endif /* GITLAB_MERGE_REQUESTS_H */ diff --git a/src/forges.c b/src/forges.c index 148614c5..6171e1af 100644 --- a/src/forges.c +++ b/src/forges.c @@ -177,6 +177,7 @@ gitlab_forge_descriptor = .pr_add_labels = gitlab_mr_add_labels, .pr_remove_labels = gitlab_mr_remove_labels, .pr_set_milestone = gitlab_mr_set_milestone, + .pr_clear_milestone = gitlab_mr_clear_milestone, .get_releases = gitlab_get_releases, .create_release = gitlab_create_release, .delete_release = gitlab_delete_release, diff --git a/src/gitlab/merge_requests.c b/src/gitlab/merge_requests.c index 63fe4cb6..688efd0c 100644 --- a/src/gitlab/merge_requests.c +++ b/src/gitlab/merge_requests.c @@ -450,3 +450,16 @@ gitlab_mr_set_milestone(char const *owner, free(url); free(data); } + +void +gitlab_mr_clear_milestone(char const *owner, + char const *repo, + int mr) +{ + /* GitLab's REST API docs state: + * + * The global ID of a milestone to assign the merge request + * to. Set to 0 or provide an empty value to unassign a + * milestone. */ + gitlab_mr_set_milestone(owner, repo, mr, 0); +} From 94d4f3200b7b282a47d884640a388170b7074fff Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:12:25 +0200 Subject: [PATCH 43/49] (#187) pulls: Return error codes when changing milestones This is needed for compatiblity of the github implementation. Also this will make it easier in the future when we want to make a library of the backend code. Signed-off-by: Nico Sonack --- include/gcli/forges.h | 4 ++-- include/gcli/gitlab/merge_requests.h | 14 +++++++------- include/gcli/pulls.h | 16 ++++++++-------- src/gitlab/merge_requests.c | 8 ++++++-- src/pulls.c | 8 ++++---- 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/include/gcli/forges.h b/include/gcli/forges.h index 1a267f82..ad295da3 100644 --- a/include/gcli/forges.h +++ b/include/gcli/forges.h @@ -322,7 +322,7 @@ struct gcli_forge_descriptor { /** * Assign a PR to a milestone */ - void (*pr_set_milestone)( + int (*pr_set_milestone)( char const *owner, char const *repo, int pr, @@ -330,7 +330,7 @@ struct gcli_forge_descriptor { /** * Clear a milestone on a PR */ - void (*pr_clear_milestone)( + int (*pr_clear_milestone)( char const *owner, char const *repo, int pr); diff --git a/include/gcli/gitlab/merge_requests.h b/include/gcli/gitlab/merge_requests.h index 5b73ce00..c110296b 100644 --- a/include/gcli/gitlab/merge_requests.h +++ b/include/gcli/gitlab/merge_requests.h @@ -88,13 +88,13 @@ void gitlab_mr_remove_labels(char const *owner, char const *const labels[], size_t labels_size); -void gitlab_mr_set_milestone(char const *owner, - char const *repo, - int mr, - int milestone_id); +int gitlab_mr_set_milestone(char const *owner, + char const *repo, + int mr, + int milestone_id); -void gitlab_mr_clear_milestone(char const *owner, - char const *repo, - int mr); +int gitlab_mr_clear_milestone(char const *owner, + char const *repo, + int mr); #endif /* GITLAB_MERGE_REQUESTS_H */ diff --git a/include/gcli/pulls.h b/include/gcli/pulls.h index 3f347f4e..3f0ff511 100644 --- a/include/gcli/pulls.h +++ b/include/gcli/pulls.h @@ -167,13 +167,13 @@ void gcli_pull_remove_labels(char const *owner, char const *const labels[], size_t labels_size); -void gcli_pull_set_milestone(char const *owner, - char const *repo, - int pr_number, - int milestone_id); - -void gcli_pull_clear_milestone(char const *owner, - char const *repo, - int pr_number); +int gcli_pull_set_milestone(char const *owner, + char const *repo, + int pr_number, + int milestone_id); + +int gcli_pull_clear_milestone(char const *owner, + char const *repo, + int pr_number); #endif /* PULLS_H */ diff --git a/src/gitlab/merge_requests.c b/src/gitlab/merge_requests.c index 688efd0c..3fcbeeaa 100644 --- a/src/gitlab/merge_requests.c +++ b/src/gitlab/merge_requests.c @@ -431,7 +431,7 @@ gitlab_mr_remove_labels(char const *owner, free(buffer.data); } -void +int gitlab_mr_set_milestone(char const *owner, char const *repo, int mr, @@ -449,9 +449,11 @@ gitlab_mr_set_milestone(char const *owner, free(url); free(data); + + return 0; } -void +int gitlab_mr_clear_milestone(char const *owner, char const *repo, int mr) @@ -462,4 +464,6 @@ gitlab_mr_clear_milestone(char const *owner, * to. Set to 0 or provide an empty value to unassign a * milestone. */ gitlab_mr_set_milestone(owner, repo, mr, 0); + + return 0; } diff --git a/src/pulls.c b/src/pulls.c index b6e44dc6..d9f1116e 100644 --- a/src/pulls.c +++ b/src/pulls.c @@ -393,19 +393,19 @@ gcli_pull_remove_labels(char const *owner, owner, repo, pr_number, labels, labels_size); } -void +int gcli_pull_set_milestone(char const *owner, char const *repo, int pr_number, int milestone_id) { - gcli_forge()->pr_set_milestone(owner, repo, pr_number, milestone_id); + return gcli_forge()->pr_set_milestone(owner, repo, pr_number, milestone_id); } -void +int gcli_pull_clear_milestone(char const *owner, char const *repo, int pr_number) { - gcli_forge()->pr_clear_milestone(owner, repo, pr_number); + return gcli_forge()->pr_clear_milestone(owner, repo, pr_number); } From 97a3264672eb847ffd1a93d6edae6d441e236356 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:15:11 +0200 Subject: [PATCH 44/49] (#187) pulls: Implement changing milestones for Github forges Signed-off-by: Nico Sonack --- src/forges.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/forges.c b/src/forges.c index 6171e1af..0c9e652f 100644 --- a/src/forges.c +++ b/src/forges.c @@ -112,6 +112,12 @@ github_forge_descriptor = .perform_submit_pr = github_perform_submit_pull, .get_pull_commits = github_get_pull_commits, .get_pull = github_get_pull, + + /* This works because the function signatures are the same and + * GitHub treats pull requests as issues */ + .pr_set_milestone = github_issue_set_milestone, + .pr_clear_milestone = github_issue_clear_milestone, + .get_releases = github_get_releases, .create_release = github_create_release, .delete_release = github_delete_release, From c66b3d335ea383f4a79f64798a3aa1cc4ae56450 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:26:38 +0200 Subject: [PATCH 45/49] (#187) pulls: Add support for setting milestones in Gitea forges Signed-off-by: Nico Sonack --- include/gcli/gitea/pulls.h | 5 +++++ src/forges.c | 1 + src/gitea/pulls.c | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/include/gcli/gitea/pulls.h b/include/gcli/gitea/pulls.h index 11162c04..b9eea7c6 100644 --- a/include/gcli/gitea/pulls.h +++ b/include/gcli/gitea/pulls.h @@ -77,4 +77,9 @@ int gitea_pull_checks(char const *owner, char const *repo, int pr_number); +int gitea_pull_set_milestone(char const *owner, + char const *repo, + int pr_number, + int milestone_id); + #endif /* GITEA_PULLS_H */ diff --git a/src/forges.c b/src/forges.c index 0c9e652f..e17faf2b 100644 --- a/src/forges.c +++ b/src/forges.c @@ -243,6 +243,7 @@ gitea_forge_descriptor = .get_pull_comments = gitea_get_comments, .get_pull = gitea_get_pull, .get_pull_commits = gitea_get_pull_commits, + .pr_set_milestone = gitea_pull_set_milestone, .get_releases = gitea_get_releases, .create_release = gitea_create_release, .delete_release = gitea_delete_release, diff --git a/src/gitea/pulls.c b/src/gitea/pulls.c index 30394aa8..5da57143 100644 --- a/src/gitea/pulls.c +++ b/src/gitea/pulls.c @@ -30,6 +30,7 @@ #include #include #include +#include int gitea_get_pulls(char const *owner, @@ -182,3 +183,12 @@ gitea_pull_checks(char const *owner, return 0; } + +int +gitea_pull_set_milestone(char const *owner, + char const *repo, + int pr_number, + int milestone_id) +{ + return github_issue_set_milestone(owner, repo, pr_number, milestone_id); +} From af3a4ded423426e76ca82c58a103df0a7750eb07 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:30:26 +0200 Subject: [PATCH 46/49] (#187) pulls: Add support for clearing the assigned milestone on Gitea Signed-off-by: Nico Sonack --- include/gcli/gitea/pulls.h | 4 ++++ src/forges.c | 1 + src/gitea/pulls.c | 12 ++++++++++++ 3 files changed, 17 insertions(+) diff --git a/include/gcli/gitea/pulls.h b/include/gcli/gitea/pulls.h index b9eea7c6..05d2e839 100644 --- a/include/gcli/gitea/pulls.h +++ b/include/gcli/gitea/pulls.h @@ -82,4 +82,8 @@ int gitea_pull_set_milestone(char const *owner, int pr_number, int milestone_id); +int gitea_pull_clear_milestone(char const *owner, + char const *repo, + int pr_number); + #endif /* GITEA_PULLS_H */ diff --git a/src/forges.c b/src/forges.c index e17faf2b..37145eaa 100644 --- a/src/forges.c +++ b/src/forges.c @@ -244,6 +244,7 @@ gitea_forge_descriptor = .get_pull = gitea_get_pull, .get_pull_commits = gitea_get_pull_commits, .pr_set_milestone = gitea_pull_set_milestone, + .pr_clear_milestone = gitea_pull_clear_milestone, .get_releases = gitea_get_releases, .create_release = gitea_create_release, .delete_release = gitea_delete_release, diff --git a/src/gitea/pulls.c b/src/gitea/pulls.c index 5da57143..064a83db 100644 --- a/src/gitea/pulls.c +++ b/src/gitea/pulls.c @@ -192,3 +192,15 @@ gitea_pull_set_milestone(char const *owner, { return github_issue_set_milestone(owner, repo, pr_number, milestone_id); } + +int +gitea_pull_clear_milestone(char const *owner, + char const *repo, + int pr_number) +{ + /* NOTE: The github routine for clearing issues sets the milestone + * to null (not the integer zero). However this does not work in + * the case of Gitea which clear the milestone by setting it to + * the integer value zero. */ + return github_issue_set_milestone(owner, repo, pr_number, 0); +} From 4ae45c862e140cd7907e0c5853bacb14dfd7d742 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:32:50 +0200 Subject: [PATCH 47/49] (#187) gcli-pulls.1: Document new milestone actions Signed-off-by: Nico Sonack --- docs/gcli-pulls.1.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/gcli-pulls.1.in b/docs/gcli-pulls.1.in index f3fe0f38..855683de 100644 --- a/docs/gcli-pulls.1.in +++ b/docs/gcli-pulls.1.in @@ -141,6 +141,11 @@ Squash the commits before merging. .It Fl -inhibit-delete , D Delete the source branch after merging. .El +.It Cm milestone Ar milestone-id +Assign the pull request to the given +.Ar milestone-id . +.It Cm milestone Fl d +Clear a set milestone on the pull request. .It Cm notes Alias for the .Cm comments From 52a0db0398d5a6fb96c9f8622e0f0b9e960ef139 Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:44:58 +0200 Subject: [PATCH 48/49] (#187) pulls: print milestone for pull request if set This was easier than expected because all the forges respond with the actual milestone object in the response. Signed-off-by: Nico Sonack --- include/gcli/pulls.h | 1 + src/pulls.c | 4 +++- templates/github/pulls.t | 7 ++++++- templates/gitlab/merge_requests.t | 7 ++++++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/gcli/pulls.h b/include/gcli/pulls.h index 3f0ff511..e40714fa 100644 --- a/include/gcli/pulls.h +++ b/include/gcli/pulls.h @@ -61,6 +61,7 @@ struct gcli_pull { char *head_label; char *base_label; char *head_sha; + char *milestone; int id; int number; int comments; diff --git a/src/pulls.c b/src/pulls.c index d9f1116e..4a68efa5 100644 --- a/src/pulls.c +++ b/src/pulls.c @@ -144,6 +144,9 @@ gcli_pull_print_status(gcli_pull const *const it) gcli_dict_add_string(dict, "STATE", GCLI_TBLCOL_STATECOLOURED, 0, it->state); gcli_dict_add(dict, "COMMENTS", 0, 0, "%d", it->comments); + if (it->milestone) + gcli_dict_add_string(dict, "MILESTONE", 0, 0, it->milestone); + if (!(forge->pull_summary_quirks & GCLI_PRS_QUIRK_ADDDEL)) /* FIXME: move printing colours into the dictionary printer? */ gcli_dict_add(dict, "ADD:DEL", 0, 0, "%s%d%s:%s%d%s", @@ -282,7 +285,6 @@ gcli_pull_free(gcli_pull *const it) free(it->labels); } - void gcli_get_pull(char const *owner, char const *repo, diff --git a/templates/github/pulls.t b/templates/github/pulls.t index 805460da..fa4b9ec1 100644 --- a/templates/github/pulls.t +++ b/templates/github/pulls.t @@ -29,6 +29,10 @@ parser github_branch_label is object of gcli_pull with ("label" => base_label as string); +parser github_pull_milestone is +object of gcli_pull with + ("title" => milestone as string); + parser github_pull is object of gcli_pull with ("title" => title as string, @@ -49,7 +53,8 @@ object of gcli_pull with "draft" => draft as bool, "user" => author as user, "head" => use parse_github_pull_head, - "base" => use parse_github_branch_label); + "base" => use parse_github_branch_label, + "milestone" => use parse_github_pull_milestone); parser github_pr_merge_message is object of char* select "message" as string; diff --git a/templates/gitlab/merge_requests.t b/templates/gitlab/merge_requests.t index eb00ceea..3ef123e6 100644 --- a/templates/gitlab/merge_requests.t +++ b/templates/gitlab/merge_requests.t @@ -1,5 +1,9 @@ include "gcli/gitlab/merge_requests.h"; +parser gitlab_mr_milestone is +object of gcli_pull with + ("title" => milestone as string); + parser gitlab_mr is object of gcli_pull with ("title" => title as string, @@ -15,7 +19,8 @@ object of gcli_pull with "author" => author as user, "source_branch" => head_label as string, "sha" => head_sha as string, - "target_branch" => base_label as string); + "target_branch" => base_label as string, + "milestone" => use parse_gitlab_mr_milestone); parser gitlab_mrs is array of gcli_pull use parse_gitlab_mr; From 132d81e959be91d39f2f7f1b498bd072c754f8fc Mon Sep 17 00:00:00 2001 From: Nico Sonack Date: Fri, 11 Aug 2023 08:56:58 +0200 Subject: [PATCH 49/49] (#188) issues: Provide implementation for clearing milestones in gitea forges Signed-off-by: Nico Sonack --- include/gcli/gitea/issues.h | 4 ++++ src/forges.c | 1 + src/gitea/issues.c | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/include/gcli/gitea/issues.h b/include/gcli/gitea/issues.h index 0cb9f097..3f4b5b6c 100644 --- a/include/gcli/gitea/issues.h +++ b/include/gcli/gitea/issues.h @@ -80,4 +80,8 @@ int gitea_issue_set_milestone(char const *owner, int issue, int milestone); +int gitea_issue_clear_milestone(char const *owner, + char const *repo, + int issue); + #endif /* GITEA_ISSUES_H */ diff --git a/src/forges.c b/src/forges.c index 37145eaa..b1d1d767 100644 --- a/src/forges.c +++ b/src/forges.c @@ -222,6 +222,7 @@ gitea_forge_descriptor = .issue_reopen = gitea_issue_reopen, .issue_assign = gitea_issue_assign, .issue_set_milestone = gitea_issue_set_milestone, + .issue_clear_milestone = gitea_issue_clear_milestone, .get_issue_comments = gitea_get_comments, .get_milestones = gitea_get_milestones, .get_milestone = gitea_get_milestone, diff --git a/src/gitea/issues.c b/src/gitea/issues.c index 8a650a2a..f988902e 100644 --- a/src/gitea/issues.c +++ b/src/gitea/issues.c @@ -259,3 +259,11 @@ gitea_issue_set_milestone(char const *const owner, { return github_issue_set_milestone(owner, repo, issue, milestone); } + +int +gitea_issue_clear_milestone(char const *owner, + char const *repo, + int issue) +{ + return github_issue_set_milestone(owner, repo, issue, 0); +}