diff options
author | Joseph Hunkeler <jhunkeler@users.noreply.github.com> | 2024-07-22 19:56:58 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-22 19:56:58 -0400 |
commit | b506bb73be5e4c8dde16c5c8bd613c00b3d75565 (patch) | |
tree | 983eb884ba6f4e9413506020e62520e87272f4ee | |
parent | 9489d31f6314322d26ec43196284b94069d6cd3a (diff) | |
download | stasis-b506bb73be5e4c8dde16c5c8bd613c00b3d75565.tar.gz |
Check release (#14)
* Add jfrog_cli_rt_search() and JFRT_Search structure
* Ensure authentication arguments are written before a subsystem task's arguments
* When artifactory is enabled check if the release is already present.
* When artifactory is disabled the check will be made against the local filesystem.
-rw-r--r-- | include/artifactory.h | 42 | ||||
-rw-r--r-- | src/artifactory.c | 93 | ||||
-rw-r--r-- | src/delivery.c | 38 | ||||
-rw-r--r-- | src/stasis_main.c | 5 |
4 files changed, 140 insertions, 38 deletions
diff --git a/include/artifactory.h b/include/artifactory.h index 6880d17..c6e5c2b 100644 --- a/include/artifactory.h +++ b/include/artifactory.h @@ -88,6 +88,31 @@ struct JFRT_Download { bool validate_symlinks; }; +struct JFRT_Search { + char *bundle; + bool count; + char *sort_by; + char *sort_order; + int limit; + int offset; + char *spec; + char *spec_vars; + char *props; + bool recursive; + char *build; + bool fail_no_op; + char *exclusions; + char *exclude_artifacts; + char *exclude_patterns; + char *exclude_props; + char *archive_entries; + char *include; + char *include_deps; + char *include_dirs; + char *project; + char *transitive; +}; + /** * Download the JFrog CLI tool from jfrog.com * ```c @@ -135,17 +160,19 @@ int artifactory_download_cli(char *dest, * auth_ctx.url = strdup("https://myserver.tld/artifactory"); * jfrt_auth_init(&auth_ctx); * - * if (jfrog_cli(&auth_ctx, "ping") { + * if (jfrog_cli(&auth_ctx, "rt", "ping", NULL) { * fprintf(stderr, "Failed to ping artifactory server: %s\n", auth_ctx.url); * exit(1); * } * ``` * * @param auth JFRT_Auth structure + * @param subsystem "jf" tool subsystem (i.e. "rt") + * @param task "jf" tool task "upload", "download", etc * @param args Command line arguments to pass to "jf" tool * @return exit code from "jf" */ -int jfrog_cli(struct JFRT_Auth *auth, char *args); +int jfrog_cli(struct JFRT_Auth *auth, const char *subsystem, const char *task, char *args); /** * Issue an Artifactory server ping @@ -225,6 +252,17 @@ int jfrog_cli_rt_upload(struct JFRT_Auth *auth, struct JFRT_Upload *ctx, char *s int jfrog_cli_rt_download(struct JFRT_Auth *auth, struct JFRT_Download *ctx, char *repo_path, char *dest); /** + * Search for files in an Artifactory repository + * + * @param auth JFRT_Auth structure + * @param ctx JFRT_Search structure + * @param repo_path Remote repository w/ file pattern + * @param dest Local destination path + * @return exit code from "jf" + */ +int jfrog_cli_rt_search(struct JFRT_Auth *auth, struct JFRT_Search *ctx, char *repo_path, char *pattern); + +/** * Collect runtime data for Artifactory build object. * * ```c diff --git a/src/artifactory.c b/src/artifactory.c index bd9aa99..6c4079a 100644 --- a/src/artifactory.c +++ b/src/artifactory.c @@ -127,9 +127,9 @@ void jfrt_upload_init(struct JFRT_Upload *ctx) { ctx->retries = 3; } -static int auth_required(char *cmd) { +static int auth_required(const char *cmd) { const char *modes[] = { - "rt build-collect-env", + "build-collect-env", NULL, }; for (size_t i = 0; modes[i] != NULL; i++) { @@ -193,7 +193,7 @@ int jfrt_auth_init(struct JFRT_Auth *auth_ctx) { return 0; } -int jfrog_cli(struct JFRT_Auth *auth, char *args) { +int jfrog_cli(struct JFRT_Auth *auth, const char *subsystem, const char *task, char *args) { struct Process proc; char cmd[STASIS_BUFSIZ]; char cmd_redacted[STASIS_BUFSIZ]; @@ -209,7 +209,7 @@ int jfrog_cli(struct JFRT_Auth *auth, char *args) { } char *auth_args = NULL; - if (auth_required(args)) { + if (auth_required(task)) { // String options jfrt_register_opt_str(auth->url, "url", &arg_map); jfrt_register_opt_str(auth->user, "user", &arg_map); @@ -236,14 +236,14 @@ int jfrog_cli(struct JFRT_Auth *auth, char *args) { auth->client_cert_path, auth->password, }; - snprintf(cmd, sizeof(cmd) - 1, "jf %s %s", args, auth_args); + snprintf(cmd, sizeof(cmd) - 1, "jf %s %s %s %s", subsystem, task, auth_args, args ? args : ""); redact_sensitive(redactable, sizeof(redactable) / sizeof (*redactable), cmd, cmd_redacted, sizeof(cmd_redacted) - 1); guard_free(auth_args); guard_strlist_free(&arg_map); // Pings are noisy. Squelch them. - if (!strstr(args, "rt ping")) { + if (task && !strstr(task, "ping")) { msg(STASIS_MSG_L2, "Executing: %s\n", cmd_redacted); } @@ -255,33 +255,26 @@ int jfrog_cli(struct JFRT_Auth *auth, char *args) { return status; } -int jfrog_cli_rt(struct JFRT_Auth *auth, char *args) { - char cmd[STASIS_BUFSIZ]; - memset(cmd, 0, sizeof(cmd)); - snprintf(cmd, sizeof(cmd) - 1, "rt %s", args); - return jfrog_cli(auth, args); +static int jfrog_cli_rt(struct JFRT_Auth *auth, char *task, char *args) { + return jfrog_cli(auth, "rt", task, args); } int jfrog_cli_rt_build_collect_env(struct JFRT_Auth *auth, char *build_name, char *build_number) { char cmd[STASIS_BUFSIZ]; memset(cmd, 0, sizeof(cmd)); - snprintf(cmd, sizeof(cmd) - 1, "rt build-collect-env \"%s\" \"%s\"", build_name, build_number); - return jfrog_cli(auth, cmd); + snprintf(cmd, sizeof(cmd) - 1, "\"%s\" \"%s\"", build_name, build_number); + return jfrog_cli(auth, "rt", "build-collect-env", cmd); } int jfrog_cli_rt_build_publish(struct JFRT_Auth *auth, char *build_name, char *build_number) { char cmd[STASIS_BUFSIZ]; memset(cmd, 0, sizeof(cmd)); - snprintf(cmd, sizeof(cmd) - 1, "rt build-publish \"%s\" \"%s\"", build_name, build_number); - return jfrog_cli(auth, cmd); + snprintf(cmd, sizeof(cmd) - 1, "\"%s\" \"%s\"", build_name, build_number); + return jfrog_cli(auth, "rt", "build-publish", cmd); } int jfrog_cli_rt_ping(struct JFRT_Auth *auth) { - char cmd[STASIS_BUFSIZ]; - memset(cmd, 0, sizeof(cmd)); - - snprintf(cmd, sizeof(cmd) - 1, "rt ping"); - return jfrog_cli_rt(auth, cmd); + return jfrog_cli_rt(auth, "ping", NULL); } int jfrog_cli_rt_download(struct JFRT_Auth *auth, struct JFRT_Download *ctx, char *repo_path, char *dest) { @@ -343,11 +336,11 @@ int jfrog_cli_rt_download(struct JFRT_Auth *auth, struct JFRT_Download *ctx, cha return -1; } - snprintf(cmd, sizeof(cmd) - 1, "rt download %s '%s' %s", args, repo_path, dest ? dest : ""); + snprintf(cmd, sizeof(cmd) - 1, "%s '%s' %s", args, repo_path, dest ? dest : ""); guard_free(args); guard_strlist_free(&arg_map); - int status = jfrog_cli_rt(auth, cmd); + int status = jfrog_cli_rt(auth, "download", cmd); return status; } @@ -434,11 +427,11 @@ int jfrog_cli_rt_upload(struct JFRT_Auth *auth, struct JFRT_Upload *ctx, char *s pushd(new_src); } - snprintf(cmd, sizeof(cmd) - 1, "rt upload %s '%s' \"%s\"", args, src, repo_path); + snprintf(cmd, sizeof(cmd) - 1, "%s '%s' \"%s\"", args, src, repo_path); guard_free(args); guard_strlist_free(&arg_map); - int status = jfrog_cli_rt(auth, cmd); + int status = jfrog_cli_rt(auth, "upload", cmd); if (new_src) { popd(); guard_free(new_src); @@ -449,3 +442,55 @@ int jfrog_cli_rt_upload(struct JFRT_Auth *auth, struct JFRT_Upload *ctx, char *s return status; } + +int jfrog_cli_rt_search(struct JFRT_Auth *auth, struct JFRT_Search *ctx, char *repo_path, char *pattern) { + char cmd[STASIS_BUFSIZ]; + memset(cmd, 0, sizeof(cmd)); + + if (isempty(repo_path)) { + fprintf(stderr, "repo_path argument must be a valid artifactory repository path\n"); + return -1; + } + + struct StrList *arg_map = strlist_init(); + if (!arg_map) { + return -1; + } + + jfrt_register_opt_str(ctx->archive_entries, "archive-entries", &arg_map); + jfrt_register_opt_str(ctx->build, "build", &arg_map); + jfrt_register_opt_str(ctx->bundle, "bundle", &arg_map); + jfrt_register_opt_str(ctx->exclusions, "exclusions", &arg_map); + jfrt_register_opt_str(ctx->exclude_patterns, "exclude-patterns", &arg_map); + jfrt_register_opt_str(ctx->exclude_artifacts, "exclude-artifacts", &arg_map); + jfrt_register_opt_str(ctx->exclude_props, "exclude-props", &arg_map); + jfrt_register_opt_str(ctx->include, "include", &arg_map); + jfrt_register_opt_str(ctx->include_deps, "include_deps", &arg_map); + jfrt_register_opt_str(ctx->include_dirs, "include_dirs", &arg_map); + jfrt_register_opt_str(ctx->project, "project", &arg_map); + jfrt_register_opt_str(ctx->props, "props", &arg_map); + jfrt_register_opt_str(ctx->sort_by, "sort-by", &arg_map); + jfrt_register_opt_str(ctx->sort_order, "sort-order", &arg_map); + jfrt_register_opt_str(ctx->spec, "spec", &arg_map); + jfrt_register_opt_str(ctx->spec_vars, "spec-vars", &arg_map); + + jfrt_register_opt_bool(ctx->count, "count", &arg_map); + jfrt_register_opt_bool(ctx->fail_no_op, "fail-no-op", &arg_map); + jfrt_register_opt_bool(ctx->recursive, "recursive", &arg_map); + jfrt_register_opt_bool(ctx->transitive, "transitive", &arg_map); + + jfrt_register_opt_int(ctx->limit, "limit", &arg_map); + jfrt_register_opt_int(ctx->offset, "offset", &arg_map); + + char *args = join(arg_map->data, " "); + if (!args) { + return -1; + } + + snprintf(cmd, sizeof(cmd) - 1, "%s '%s/%s'", args, repo_path, pattern ? pattern: ""); + guard_free(args); + guard_strlist_free(&arg_map); + + int status = jfrog_cli_rt(auth, "search", cmd); + return status; +} diff --git a/src/delivery.c b/src/delivery.c index d7b9b99..8e37bc0 100644 --- a/src/delivery.c +++ b/src/delivery.c @@ -2191,18 +2191,36 @@ int delivery_fixup_test_results(struct Delivery *ctx) { } int delivery_exists(struct Delivery *ctx) { - // TODO: scan artifactory repo for the same information + int release_exists = 0; char release_pattern[PATH_MAX] = {0}; sprintf(release_pattern, "*%s*", ctx->info.release_name); - struct StrList *files = listdir(ctx->storage.delivery_dir); - for (size_t i = 0; i < strlist_count(files); i++) { - char *filename = strlist_item(files, i); - int release_exists = fnmatch(release_pattern, filename, FNM_PATHNAME); - if (!globals.enable_overwrite && !release_exists) { - guard_strlist_free(&files); - return 1; + + if (globals.enable_artifactory) { + if (jfrt_auth_init(&ctx->deploy.jfrog_auth)) { + fprintf(stderr, "Failed to initialize Artifactory authentication context\n"); + return -1; // error + } + + struct JFRT_Search search = {.fail_no_op = true}; + release_exists = jfrog_cli_rt_search(&ctx->deploy.jfrog_auth, &search, globals.jfrog.repo, release_pattern); + if (release_exists != 2) { + if (!globals.enable_overwrite && !release_exists) { + // --fail_no_op returns 2 on failure + // without: it returns an empty list "[]" and exit code 0 + return 1; // found + } } + } else { + struct StrList *files = listdir(ctx->storage.delivery_dir); + for (size_t i = 0; i < strlist_count(files); i++) { + char *filename = strlist_item(files, i); + release_exists = fnmatch(release_pattern, filename, FNM_PATHNAME); + if (!globals.enable_overwrite && !release_exists) { + guard_strlist_free(&files); + return 1; // found + } + } + guard_strlist_free(&files); } - guard_strlist_free(&files); - return 0; + return 0; // not found }
\ No newline at end of file diff --git a/src/stasis_main.c b/src/stasis_main.c index 7e2262a..686c044 100644 --- a/src/stasis_main.c +++ b/src/stasis_main.c @@ -415,9 +415,10 @@ int main(int argc, char *argv[]) { //delivery_runtime_show(&ctx); } - // Safety gate: Avoid clobbering a delivery unless the user wants that behavior + // Safety gate: Avoid clobbering a delivered release unless the user wants that behavior + msg(STASIS_MSG_L1, "Checking release history\n"); if (delivery_exists(&ctx)) { - msg(STASIS_MSG_ERROR | STASIS_MSG_L1, "Refusing to overwrite delivery: %s\nUse --overwrite to enable release clobbering.\n", ctx.info.release_name); + msg(STASIS_MSG_ERROR | STASIS_MSG_L1, "Refusing to overwrite release: %s\nUse --overwrite to enable release clobbering.\n", ctx.info.release_name); exit(1); } |