aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@users.noreply.github.com>2024-07-22 19:56:58 -0400
committerGitHub <noreply@github.com>2024-07-22 19:56:58 -0400
commitb506bb73be5e4c8dde16c5c8bd613c00b3d75565 (patch)
tree983eb884ba6f4e9413506020e62520e87272f4ee
parent9489d31f6314322d26ec43196284b94069d6cd3a (diff)
downloadstasis-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.h42
-rw-r--r--src/artifactory.c93
-rw-r--r--src/delivery.c38
-rw-r--r--src/stasis_main.c5
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);
}