Skip to content

Commit 83680cd

Browse files
H-ANSENLeonidas-from-XIV
authored andcommitted
Add support for Gitlab organization repositories
Fixes #6723 Signed-off-by: teague hansen <[email protected]> Signed-off-by: Marek Kubica <[email protected]>
1 parent dddf3bc commit 83680cd

File tree

6 files changed

+245
-77
lines changed

6 files changed

+245
-77
lines changed

doc/changes/10766.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Add support for specifying Gitlab organization repositories in `source`
2+
stanzas (#10766, fixes #6723, @H-ANSEN)

doc/reference/dune-project/generate_opam_files.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ defined in the project:
7171
* - `Bitbucket <https://bitbucket.org>`_
7272
- ``(bitbucket user/repo)``
7373
* - `Gitlab <https://gitlab.com>`_
74-
- ``(gitlab user/repo)``
74+
- | ``(gitlab user/repo)``
75+
| ``(gitlab organization/project/repo)`` *(New in 3.17)*
7576
* - `Sourcehut <https://sr.ht>`_
7677
- ``(sourcehut user/repo)``
7778

src/dune_lang/package_info.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ let empty =
4343

4444
let example =
4545
{ source =
46-
Some (Host { kind = Source_kind.Host.Github; user = "username"; repo = "reponame" })
46+
Some (Host (Source_kind.Host.Github { user = "username"; repo = "reponame" }))
4747
; license = Some [ "LICENSE" ]
4848
; authors = Some [ "Author Name" ]
4949
; maintainers = Some [ "Maintainer Name" ]

src/dune_lang/source_kind.ml

Lines changed: 111 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,103 +2,147 @@ open Stdune
22
open Dune_sexp
33

44
module Host = struct
5-
type kind =
6-
| Github
7-
| Bitbucket
8-
| Gitlab
9-
| Sourcehut
10-
11-
let to_string = function
12-
| Github -> "github"
13-
| Bitbucket -> "bitbucket"
14-
| Gitlab -> "gitlab"
15-
| Sourcehut -> "sourcehut"
16-
;;
17-
18-
type t =
5+
type user_repo =
196
{ user : string
207
; repo : string
21-
; kind : kind
228
}
239

24-
let dyn_of_kind kind = kind |> to_string |> Dyn.string
10+
type gitlab_repo =
11+
| User_repo of user_repo
12+
| Org_repo of
13+
{ org : string
14+
; proj : string
15+
; repo : string
16+
}
17+
18+
type t =
19+
| Github of user_repo
20+
| Bitbucket of user_repo
21+
| Gitlab of gitlab_repo
22+
| Sourcehut of user_repo
23+
24+
let kind_string = function
25+
| Github _ -> "github"
26+
| Bitbucket _ -> "bitbucket"
27+
| Gitlab _ -> "gitlab"
28+
| Sourcehut _ -> "sourcehut"
29+
;;
2530

26-
let to_dyn { user; repo; kind } =
31+
let dyn_of_user_repo kind { user; repo } =
2732
let open Dyn in
28-
record [ "kind", dyn_of_kind kind; "user", string user; "repo", string repo ]
33+
record [ "kind", kind; "user", string user; "repo", string repo ]
2934
;;
3035

31-
let host_of_kind = function
32-
| Github -> "github.com"
33-
| Bitbucket -> "bitbucket.org"
34-
| Gitlab -> "gitlab.com"
35-
| Sourcehut -> "sr.ht"
36+
let dyn_of_gitlab_repo kind repo =
37+
match repo with
38+
| User_repo user_repo -> dyn_of_user_repo kind user_repo
39+
| Org_repo { org; proj; repo } ->
40+
let open Dyn in
41+
record [ "kind", kind; "org", string org; "proj", string proj; "repo", string repo ]
3642
;;
3743

38-
let base_uri { kind; user; repo } =
39-
let host = host_of_kind kind in
40-
sprintf
41-
"%s/%s/%s"
42-
host
43-
(match kind with
44-
| Sourcehut -> "~" ^ user
45-
| _ -> user)
46-
repo
44+
let to_dyn repo =
45+
let kind = Dyn.string (kind_string repo) in
46+
match repo with
47+
| Gitlab gitlab_repo -> dyn_of_gitlab_repo kind gitlab_repo
48+
| Github user_repo | Bitbucket user_repo | Sourcehut user_repo ->
49+
dyn_of_user_repo kind user_repo
50+
;;
51+
52+
let host_of_repo = function
53+
| Github _ -> "github.com"
54+
| Bitbucket _ -> "bitbucket.org"
55+
| Gitlab _ -> "gitlab.com"
56+
| Sourcehut _ -> "sr.ht"
57+
;;
58+
59+
let base_uri repo =
60+
let host = host_of_repo repo in
61+
match repo with
62+
| Gitlab (Org_repo { org; proj; repo }) -> sprintf "%s/%s/%s/%s" host org proj repo
63+
| Sourcehut { user; repo } -> sprintf "%s/~%s/%s" host user repo
64+
| Gitlab (User_repo { user; repo }) | Github { user; repo } | Bitbucket { user; repo }
65+
-> sprintf "%s/%s/%s" host user repo
4766
;;
4867

4968
let add_https s = "https://" ^ s
5069
let homepage t = add_https (base_uri t)
5170

52-
let bug_reports t =
53-
match t.kind with
54-
| Sourcehut -> add_https ("todo." ^ base_uri t)
55-
| _ ->
56-
homepage t
57-
^
58-
(match t.kind with
59-
| Sourcehut -> assert false
60-
| Bitbucket | Github -> "/issues"
61-
| Gitlab -> "/-/issues")
71+
let bug_reports = function
72+
| Gitlab _ as repo -> homepage repo ^ "/-/issues"
73+
| Github _ as repo -> homepage repo ^ "/issues"
74+
| Bitbucket _ as repo -> homepage repo ^ "/issues"
75+
| Sourcehut _ as repo -> add_https ("todo." ^ base_uri repo)
6276
;;
6377

6478
let enum k =
65-
[ "GitHub", Github, None
66-
; "Bitbucket", Bitbucket, Some (2, 8)
67-
; "Gitlab", Gitlab, Some (2, 8)
68-
; "Sourcehut", Sourcehut, Some (3, 1)
79+
let stub_user_repo = { user = ""; repo = "" } in
80+
let stub_org_repo = Org_repo { org = ""; proj = ""; repo = "" } in
81+
let repo_name k = k |> kind_string |> String.capitalize in
82+
[ Github stub_user_repo
83+
; Bitbucket stub_user_repo
84+
; Sourcehut stub_user_repo
85+
; Gitlab (User_repo stub_user_repo)
86+
; Gitlab stub_org_repo
6987
]
70-
|> List.map ~f:(fun (name, kind, since) ->
71-
let decode =
72-
let of_string ~loc s =
73-
match String.split ~on:'/' s with
74-
| [ user; repo ] -> k { kind; user; repo }
75-
| _ ->
76-
User_error.raise
77-
~loc
78-
[ Pp.textf "%s repository must be of form user/repo" name ]
79-
in
88+
|> List.map ~f:(fun kind ->
89+
let of_string ~loc str =
90+
let name = repo_name kind in
91+
match kind, String.split ~on:'/' str with
92+
| Github _, [ user; repo ] -> Github { user; repo }, None
93+
| Bitbucket _, [ user; repo ] -> Bitbucket { user; repo }, Some ((2, 8), name)
94+
| Sourcehut _, [ user; repo ] -> Sourcehut { user; repo }, Some ((3, 1), name)
95+
| Gitlab _, [ user; repo ] ->
96+
Gitlab (User_repo { user; repo }), Some ((2, 8), name)
97+
| Gitlab _, [ org; proj; repo ] ->
98+
Gitlab (Org_repo { org; proj; repo }), Some ((3, 17), "Gitlab organization repo")
99+
| Gitlab _, _ ->
100+
User_error.raise
101+
~loc
102+
[ Pp.textf "%s repository must be of form user/repo or org/proj/repo" name ]
103+
| _, [ _; _; _ ] ->
104+
User_error.raise
105+
~loc
106+
~hints:
107+
[ Pp.textf "The provided form '%s' is specific to Gitlab projects" str ]
108+
[ Pp.textf "%s repository must be of form user/repo" name ]
109+
| _, _ ->
110+
User_error.raise
111+
~loc
112+
[ Pp.textf "%s repository must be of form user/repo" name ]
113+
in
114+
let decoder =
80115
let open Decoder in
116+
plain_string of_string
117+
>>= fun (t, since) ->
81118
(match since with
82119
| None -> return ()
83-
| Some v -> Syntax.since Stanza.syntax v)
84-
>>> plain_string of_string
120+
| Some (v, what) -> Syntax.since ~what Stanza.syntax v)
121+
>>> return t
122+
>>| k
85123
in
86-
let constr = to_string kind in
87-
constr, decode)
124+
kind_string kind, decoder)
88125
;;
89126

90-
let encode { user; repo; kind } =
91-
let forge = to_string kind in
92-
let path = user ^ "/" ^ repo in
127+
let encode repo =
128+
let path =
129+
match repo with
130+
| Gitlab (Org_repo { org; proj; repo }) -> sprintf "%s/%s/%s" org proj repo
131+
| Gitlab (User_repo { user; repo }) -> sprintf "%s/%s" user repo
132+
| Sourcehut { user; repo } -> sprintf "%s/%s" user repo
133+
| Github { user; repo } -> sprintf "%s/%s" user repo
134+
| Bitbucket { user; repo } -> sprintf "%s/%s" user repo
135+
in
93136
let open Encoder in
137+
let forge = kind_string repo in
94138
pair string string (forge, path)
95139
;;
96140

97-
let to_string t =
141+
let to_string repo =
98142
let base_uri =
99-
let base = base_uri t in
100-
match t.kind with
101-
| Sourcehut -> "git." ^ base
143+
let base = base_uri repo in
144+
match repo with
145+
| Sourcehut _ -> "git." ^ base
102146
| _ -> base ^ ".git"
103147
in
104148
"git+https://" ^ base_uri

src/dune_lang/source_kind.mli

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
module Host : sig
2-
type kind =
3-
| Github
4-
| Bitbucket
5-
| Gitlab
6-
| Sourcehut
7-
8-
type t =
2+
type user_repo =
93
{ user : string
104
; repo : string
11-
; kind : kind
125
}
136

7+
type gitlab_repo =
8+
| User_repo of user_repo
9+
| Org_repo of
10+
{ org : string
11+
; proj : string
12+
; repo : string
13+
}
14+
15+
type t =
16+
| Github of user_repo
17+
| Bitbucket of user_repo
18+
| Gitlab of gitlab_repo
19+
| Sourcehut of user_repo
20+
1421
val homepage : t -> string
1522
val bug_reports : t -> string
1623
end
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
Test 'source' stanza compatibility with both user and organization paths from
2+
the supported 'github', 'gitlab', 'sourcehut', and 'bitbucket'.
3+
4+
Test a generated 'github' user repo
5+
6+
$ cat > dune-project <<EOF
7+
> (lang dune 3.17)
8+
> (name foo)
9+
> (generate_opam_files true)
10+
> (source (github user/repo))
11+
> (package
12+
> (allow_empty)
13+
> (name foo))
14+
> EOF
15+
16+
$ dune build
17+
$ cat foo.opam | grep -i github
18+
homepage: "https://github.com/user/repo"
19+
bug-reports: "https://github.com/user/repo/issues"
20+
dev-repo: "git+https://github.com/user/repo.git"
21+
22+
Test a generated 'gitlab' user repo
23+
24+
$ sed -i -e '4s|.*|(source (gitlab user/repo))|' dune-project
25+
$ dune build
26+
$ cat foo.opam | grep -i gitlab
27+
homepage: "https://gitlab.com/user/repo"
28+
bug-reports: "https://gitlab.com/user/repo/-/issues"
29+
dev-repo: "git+https://gitlab.com/user/repo.git"
30+
31+
Test a generated 'sourcehut' user repo
32+
33+
$ sed -i -e '4s|.*|(source (sourcehut user/repo))|' dune-project
34+
$ dune build
35+
$ cat foo.opam | grep -i sr.ht
36+
homepage: "https://sr.ht/~user/repo"
37+
bug-reports: "https://todo.sr.ht/~user/repo"
38+
dev-repo: "git+https://git.sr.ht/~user/repo"
39+
40+
Test a generated 'bitbucket' user repo
41+
42+
$ sed -i -e '4s|.*|(source (bitbucket user/repo))|' dune-project
43+
$ dune build
44+
$ cat foo.opam | grep -i bitbucket
45+
homepage: "https://bitbucket.org/user/repo"
46+
bug-reports: "https://bitbucket.org/user/repo/issues"
47+
dev-repo: "git+https://bitbucket.org/user/repo.git"
48+
49+
Test a generated 'gitlab' organization repo
50+
51+
$ sed -i -e '4s|.*|(source (gitlab organization/project/repo))|' dune-project
52+
$ dune build
53+
$ cat foo.opam | grep -i gitlab
54+
homepage: "https://gitlab.com/organization/project/repo"
55+
bug-reports: "https://gitlab.com/organization/project/repo/-/issues"
56+
dev-repo: "git+https://gitlab.com/organization/project/repo.git"
57+
58+
Test that the creation of a source stanza of the form 'org/project/repo' is
59+
disallowed by any forge type other than gitlab and that associated error
60+
messages are provided
61+
62+
Test github forge.
63+
64+
$ sed -i -e '4s|.*|(source (github org/proj/repo))|' dune-project
65+
$ dune build
66+
File "dune-project", line 4, characters 16-29:
67+
4 | (source (github org/proj/repo))
68+
^^^^^^^^^^^^^
69+
Error: Github repository must be of form user/repo
70+
Hint: The provided form 'org/proj/repo' is specific to Gitlab projects
71+
[1]
72+
73+
Test bitbucket forge.
74+
75+
$ sed -i -e '4s|.*|(source (bitbucket org/proj/repo))|' dune-project
76+
$ dune build
77+
File "dune-project", line 4, characters 19-32:
78+
4 | (source (bitbucket org/proj/repo))
79+
^^^^^^^^^^^^^
80+
Error: Bitbucket repository must be of form user/repo
81+
Hint: The provided form 'org/proj/repo' is specific to Gitlab projects
82+
[1]
83+
84+
Test sourcehut forge.
85+
86+
$ sed -i -e '4s|.*|(source (sourcehut org/proj/repo))|' dune-project
87+
$ dune build
88+
File "dune-project", line 4, characters 19-32:
89+
4 | (source (sourcehut org/proj/repo))
90+
^^^^^^^^^^^^^
91+
Error: Sourcehut repository must be of form user/repo
92+
Hint: The provided form 'org/proj/repo' is specific to Gitlab projects
93+
[1]
94+
95+
So far we have been using '(lang dune 3.17)' which supports gitlab organization
96+
style syntax, we will bump the version down and check to make sure an error is
97+
thrown telling us we need a more recent version of dune to use orginaziton
98+
syntax.
99+
100+
$ sed -i -e '1s|.*|(lang dune 3.16)|' dune-project
101+
$ sed -i -e '4s|.*|(source (gitlab org/proj/repo))|' dune-project
102+
$ dune build
103+
File "dune-project", line 4, characters 8-30:
104+
4 | (source (gitlab org/proj/repo))
105+
^^^^^^^^^^^^^^^^^^^^^^
106+
Error: Gitlab organization repo is only available since version 3.17 of the
107+
dune language. Please update your dune-project file to have (lang dune 3.17).
108+
[1]
109+
110+
With the version bumped down we will also check to make sure that the user/repo
111+
style gitlab stanza still works without any error.
112+
113+
$ sed -i -e '4s|.*|(source (gitlab user/repo))|' dune-project
114+
$ dune build

0 commit comments

Comments
 (0)