attempt to reject GOT_AUTHOR values without an email address
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
diff --git a/got/got.1 b/got/got.1
index a6c2e61..967828d 100644
--- a/got/got.1
+++ b/got/got.1
@@ -1081,12 +1081,13 @@ and
.Cm got import ,
for example:
.An Flan Hacker Aq Mt flan_hacker@openbsd.org .
+Because
.Xr git 1
-may fail to parse commits created with
+may fail to parse commits without an email address in author data,
.Nm
-if the
+attempts to reject
.Ev GOT_AUTHOR
-environment variable does not contain an email address.
+environment variables with a missing email address.
.It Ev VISUAL, Ev EDITOR
The editor spawned by
.Cm got commit .
diff --git a/got/got.c b/got/got.c
index 7042801..c05635e 100644
--- a/got/got.c
+++ b/got/got.c
@@ -483,12 +483,47 @@ import_progress(void *arg, const char *path)
}
static const struct got_error *
+get_author(const char **author)
+{
+ const char *got_author;
+
+ *author = NULL;
+
+ got_author = getenv("GOT_AUTHOR");
+ if (got_author == NULL) {
+ /* TODO: Look up user in password database? */
+ return got_error(GOT_ERR_COMMIT_NO_AUTHOR);
+ }
+
+ *author = got_author;
+
+ /*
+ * Really dumb email address check; we're only doing this to
+ * avoid git's object parser breaking on commits we create.
+ */
+ while (*got_author && *got_author != '<')
+ got_author++;
+ if (*got_author != '<')
+ return got_error(GOT_ERR_COMMIT_NO_EMAIL);
+ while (*got_author && *got_author != '@')
+ got_author++;
+ if (*got_author != '@')
+ return got_error(GOT_ERR_COMMIT_NO_EMAIL);
+ while (*got_author && *got_author != '>')
+ got_author++;
+ if (*got_author != '>')
+ return got_error(GOT_ERR_COMMIT_NO_EMAIL);
+
+ return NULL;
+}
+
+static const struct got_error *
cmd_import(int argc, char *argv[])
{
const struct got_error *error = NULL;
char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL;
char *editor = NULL;
- const char *got_author = getenv("GOT_AUTHOR");
+ const char *author;
const char *branch_name = "master";
char *refname = NULL, *id_str = NULL;
struct got_repository *repo = NULL;
@@ -544,11 +579,9 @@ cmd_import(int argc, char *argv[])
if (argc != 1)
usage_import();
- if (got_author == NULL) {
- /* TODO: Look current user up in password database */
- error = got_error(GOT_ERR_COMMIT_NO_AUTHOR);
- goto done;
- }
+ error = get_author(&author);
+ if (error)
+ return error;
if (repo_path == NULL) {
repo_path = getcwd(NULL, 0);
@@ -603,7 +636,7 @@ cmd_import(int argc, char *argv[])
goto done;
error = got_repo_import(&new_commit_id, path_dir, logmsg,
- got_author, &ignores, repo, import_progress, NULL);
+ author, &ignores, repo, import_progress, NULL);
if (error)
goto done;
@@ -3447,7 +3480,7 @@ cmd_commit(int argc, char *argv[])
char *cwd = NULL, *id_str = NULL;
struct got_object_id *id = NULL;
const char *logmsg = NULL;
- const char *got_author = getenv("GOT_AUTHOR");
+ const char *author;
struct collect_commit_logmsg_arg cl_arg;
char *editor = NULL;
int ch, rebase_in_progress, histedit_in_progress;
@@ -3475,11 +3508,9 @@ cmd_commit(int argc, char *argv[])
"unveil", NULL) == -1)
err(1, "pledge");
#endif
- if (got_author == NULL) {
- /* TODO: Look current user up in password database */
- error = got_error(GOT_ERR_COMMIT_NO_AUTHOR);
- goto done;
- }
+ error = get_author(&author);
+ if (error)
+ return error;
cwd = getcwd(NULL, 0);
if (cwd == NULL) {
@@ -3535,7 +3566,7 @@ cmd_commit(int argc, char *argv[])
cl_arg.branch_name += 11;
}
cl_arg.repo_path = got_repo_get_path(repo);
- error = got_worktree_commit(&id, worktree, &paths, got_author, NULL,
+ error = got_worktree_commit(&id, worktree, &paths, author, NULL,
collect_commit_logmsg, &cl_arg, print_status, NULL, repo);
if (error) {
if (cl_arg.logmsg_path)
diff --git a/include/got_error.h b/include/got_error.h
index cd6c014..884a46a 100644
--- a/include/got_error.h
+++ b/include/got_error.h
@@ -121,6 +121,7 @@
#define GOT_ERR_FILE_NOT_STAGED 105
#define GOT_ERR_STAGED_PATHS 106
#define GOT_ERR_PATCH_CHOICE 107
+#define GOT_ERR_COMMIT_NO_EMAIL 108
static const struct got_error {
int code;
@@ -246,6 +247,9 @@ static const struct got_error {
{ GOT_ERR_STAGED_PATHS, "work tree contains files with staged "
"changes; these changes must be committed or unstaged first" },
{ GOT_ERR_PATCH_CHOICE, "invalid patch choice" },
+ { GOT_ERR_COMMIT_NO_EMAIL,"GOT_AUTHOR environment variable contains "
+ "no email address; an email address is required for compatibility "
+ "with Git" },
};
/*
diff --git a/regress/cmdline/commit.sh b/regress/cmdline/commit.sh
index 385f2ae..337efdc 100755
--- a/regress/cmdline/commit.sh
+++ b/regress/cmdline/commit.sh
@@ -541,6 +541,44 @@ function test_commit_outside_refs_heads {
test_done "$testroot" "$ret"
}
+function test_commit_no_email {
+ local testroot=`test_init commit_no_email`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "modified alpha" > $testroot/wt/alpha
+ (cd $testroot/wt && env GOT_AUTHOR=":flan_hacker:" \
+ got commit -m 'test no email' > $testroot/stdout \
+ 2> $testroot/stderr)
+
+ echo -n "got: GOT_AUTHOR environment variable contains no email " \
+ > $testroot/stderr.expected
+ echo -n "address; an email address is required for compatibility "\
+ >> $testroot/stderr.expected
+ echo "with Git" >> $testroot/stderr.expected
+ cmp -s $testroot/stderr.expected $testroot/stderr
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo -n > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
+
run_test test_commit_basic
run_test test_commit_new_subdir
@@ -555,3 +593,4 @@ run_test test_commit_path_prefix
run_test test_commit_dir_path
run_test test_commit_selected_paths
run_test test_commit_outside_refs_heads
+run_test test_commit_no_email