+28
-4
appview/state/pull.go
+28
-4
appview/state/pull.go
···
558
558
sourceBranch := r.FormValue("sourceBranch")
559
559
patch := r.FormValue("patch")
560
560
561
-
// Validate required fields for all PR types
562
-
if title == "" || body == "" || targetBranch == "" {
563
-
s.pages.Notice(w, "pull", "Title, body and target branch are required.")
561
+
if targetBranch == "" {
562
+
s.pages.Notice(w, "pull", "Target branch is required.")
564
563
return
565
564
}
566
565
567
566
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
568
567
if err != nil {
569
-
log.Println("failed to create unsigned client to %s: %v", f.Knot, err)
568
+
log.Printf("failed to create unsigned client to %s: %v", f.Knot, err)
570
569
s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
571
570
return
572
571
}
···
816
815
}
817
816
818
817
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pullId))
818
+
}
819
+
820
+
func (s *State) ValidatePatch(w http.ResponseWriter, r *http.Request) {
821
+
_, err := fullyResolvedRepo(r)
822
+
if err != nil {
823
+
log.Println("failed to get repo and knot", err)
824
+
return
825
+
}
826
+
827
+
patch := r.FormValue("patch")
828
+
if patch == "" {
829
+
s.pages.Notice(w, "patch-error", "Patch is required.")
830
+
return
831
+
}
832
+
833
+
if patch == "" || !patchutil.IsPatchValid(patch) {
834
+
s.pages.Notice(w, "patch-error", "Invalid patch format. Please provide a valid git diff or format-patch.")
835
+
return
836
+
}
837
+
838
+
if patchutil.IsFormatPatch(patch) {
839
+
s.pages.Notice(w, "patch-preview", "Format patch detected. Title and description are optional; if left out, they will be extracted from the first commit.")
840
+
} else {
841
+
s.pages.Notice(w, "patch-preview", "Regular diff detected. Please provide a title and description.")
842
+
}
819
843
}
820
844
821
845
func (s *State) PatchUploadFragment(w http.ResponseWriter, r *http.Request) {
+1
appview/state/router.go
+1
appview/state/router.go
···
96
96
r.With(AuthMiddleware(s)).Route("/new", func(r chi.Router) {
97
97
r.Get("/", s.NewPull)
98
98
r.Get("/patch-upload", s.PatchUploadFragment)
99
+
r.Post("/validate-patch", s.ValidatePatch)
99
100
r.Get("/compare-branches", s.CompareBranchesFragment)
100
101
r.Get("/compare-forks", s.CompareForksFragment)
101
102
r.Get("/fork-branches", s.CompareForksBranchesFragment)
+10
-5
input.css
+10
-5
input.css
···
35
35
font-size: 15px;
36
36
}
37
37
@supports (font-variation-settings: normal) {
38
-
html {
39
-
font-feature-settings: 'ss01' 1, 'kern' 1, 'liga' 1, 'cv05' 1, 'tnum' 1;
40
-
}
38
+
html {
39
+
font-feature-settings:
40
+
"ss01" 1,
41
+
"kern" 1,
42
+
"liga" 1,
43
+
"cv05" 1,
44
+
"tnum" 1;
45
+
}
41
46
}
42
47
43
48
a {
···
48
53
@apply block mb-2 text-gray-900 text-sm font-bold py-2 uppercase dark:text-gray-100;
49
54
}
50
55
input {
51
-
@apply bg-white border border-gray-400 rounded-sm focus:ring-black p-3 dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:ring-gray-400;
56
+
@apply border border-gray-400 block rounded bg-gray-50 focus:ring-black p-3 dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:ring-gray-400;
52
57
}
53
58
textarea {
54
-
@apply bg-white border border-gray-400 rounded-sm focus:ring-black p-3 dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:ring-gray-400;
59
+
@apply border border-gray-400 block rounded bg-gray-50 focus:ring-black p-3 dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:ring-gray-400;
55
60
}
56
61
details summary::-webkit-details-marker {
57
62
display: none;