1:- module(sourcehut_git,
    2          [sourcehut_git_repositories/2,
    3           sourcehut_git_set_repository_visibility/3,
    4           sourcehut_git_set_repository_description/3,
    5           sourcehut_git_repository/4,
    6           sourcehut_git_refs/4,
    7           sourcehut_git_delete_artifact/2,
    8           sourcehut_git_upload_artifact/5
    9          ]).   10
   11:- use_module(common).

SourceHut Git GraphQL API client

This module provides an interface for interacting with the Git service of a SourceHut (https://sourcehut.org/) instance, such as https://git.sr.ht/ */

   22:- predicate_options(sourcehut_git_repositories/2,
   23                     2,
   24                     [user(+text),
   25                      page(+integer),
   26                      cursor(+text),
   27                      next(-text),
   28                      pass_to(sourcehut_graphql/3, 3)]).   29
   30%% sourcehut_git_repositories(-Repos, +Options) is semidet.
   31%
   32%  Unifies Repos with a list of dicts describing Git repositories
   33%  hosted on a remote SourceHut instance.  Notably, _Repo.id_ can be
   34%  used with sourcehut_git_upload_artifact/5 to attach arbitrary files
   35%  to tagged revisions of the remote repository.
   36%
   37%  The identity of the calling user is determined by the remote
   38%  SourceHut instance according to the provided OAuth2 token.
   39%
   40%  Options processed:
   41%
   42%    - user(+User)
   43%      Return repositories owned by User.
   44%    - page(+Page:integer)
   45%      Maximum number of repositories to fetch in this query.
   46%    - cursor(+Cursor)
   47%      Query the server for repositories starting from Cursor, which
   48%      is a string obtained from the remote SourceHut instance through
   49%      the `next(-Next)` option of the previous call to this predicate.
   50%    - next(-Next)
   51%      Next is unified with the atom `null` if there are no more
   52%      repositories to described, otherwise Next is a string that can
   53%      be passed as the `cursor(+Cursor)` argument to a following call
   54%      to this predicate to fetch more results.
   55%
   56%  The rest of the provided options are passed to sourcehut_graphql/3.
   57sourcehut_git_repositories(Repos, Options) :-
   58    option(page(Page), Options, null),
   59    option(cursor(Cursor), Options, null),
   60    (   option(user(User), Options)
   61    ->  sourcehut_graphql(
   62            query {
   63                user(username:User) {
   64                    repositories(filter: {count : Page}, cursor: Cursor) {
   65                        cursor,
   66                        results {
   67                            id,
   68                            name,
   69                            description,
   70                            visibility,
   71                            created,
   72                            updated,
   73                            'HEAD' {
   74                                name,
   75                                target
   76                            },
   77                            owner {
   78                                id,
   79                                canonicalName
   80                            }
   81                        }
   82                    }
   83                }
   84            },
   85            Dict,
   86            Options),
   87        get_dict(data, Dict, Data0),
   88        get_dict(user, Data0, Data)
   89    ;   sourcehut_graphql(
   90            query {
   91                repositories(filter: {count : Page}, cursor: Cursor) {
   92                    cursor,
   93                    results {
   94                        id,
   95                        name,
   96                        description,
   97                        visibility,
   98                        created,
   99                        updated,
  100                        'HEAD' {
  101                            name,
  102                            target
  103                        },
  104                        owner {
  105                            id,
  106                            canonicalName
  107                        }
  108                    }
  109                }
  110            },
  111            Dict,
  112            Options),
  113        get_dict(data, Dict, Data)
  114    ),
  115    get_dict(repositories, Data, Repos0),
  116    get_dict(cursor, Repos0, Next),
  117    option(next(Next), Options, Next),
  118    get_dict(results, Repos0, Repos).
  119
  120
  121:- predicate_options(sourcehut_git_repository/4,
  122                     4,
  123                     [pass_to(sourcehut_graphql/3, 3)]).  124
  125%% sourcehut_git_repository(+UserName, +RepoName, -Repo, +Options) is semidet.
  126%
  127%  Unifies Repo with a dict describing the Git repository RepoName
  128%  owned by the user UserName on a remote SourceHut instance.
  129%
  130%  Options are passed to sourcehut_graphql/3.
  131sourcehut_git_repository(UserName, RepoName, Repo, Options) :-
  132    sourcehut_graphql(
  133        query {
  134            user(username:UserName) {
  135                repository(name:RepoName) {
  136                    id,
  137                    name,
  138                    description,
  139                    visibility,
  140                    created,
  141                    updated,
  142                    'HEAD' {
  143                        name,
  144                        target
  145                    }
  146                }
  147            }
  148        },
  149        Dict,
  150        Options),
  151    get_dict(data, Dict, Data),
  152    get_dict(user, Data, User),
  153    get_dict(repository, User, Repo),
  154    Repo \= null.
  155
  156
  157:- predicate_options(sourcehut_git_refs/4,
  158                     4,
  159                     [cursor(+text),
  160                      next(-text),
  161                      pass_to(sourcehut_graphql/3, 3)]).  162
  163
  164%% sourcehut_git_refs(+UserName, +RepoName, -Refs, +Options) is semidet.
  165%
  166%  Unifies Refs with a list of dicts describing Git refs in the
  167%  repository RepoName owned by the user UserName on a remote
  168%  SourceHut instance.
  169%
  170%  Options processed:
  171%
  172%    - cursor(+Cursor)
  173%      Query the server for refs starting from Cursor, which
  174%      is a string obtained from the remote SourceHut instance through
  175%      the `next(-Next)` option of the previous call to this predicate.
  176%    - next(-Next)
  177%      Next is unified with the atom `null` if there are no more
  178%      refs to described, otherwise Next is a string that can
  179%      be passed as the `cursor(+Cursor)` argument to a following call
  180%      to this predicate to fetch more results.
  181%
  182%  The rest of the provided Options are passed to sourcehut_graphql/3.
  183sourcehut_git_refs(UserName, RepoName, Refs, Options) :-
  184    option(cursor(Cursor), Options, null),
  185    sourcehut_graphql(
  186            query {
  187                user(username:UserName) {
  188                    repository(name:RepoName) {
  189                        references(cursor:Cursor) {
  190                            cursor,
  191                            results {
  192                                name,
  193                                target,
  194                                artifacts {
  195                                    results {
  196                                        id,
  197                                        created,
  198                                        filename,
  199                                        checksum,
  200                                        size,
  201                                        url
  202                                    }
  203                                }
  204                            }
  205                        }
  206                    }
  207                }
  208            },
  209            Dict,
  210            Options),
  211    get_dict(data, Dict, Data),
  212    get_dict(user, Data, User),
  213    get_dict(repository, User, Repo),
  214    get_dict(references, Repo, Refs0),
  215    get_dict(cursor, Refs0, Next),
  216    option(next(Next), Options, Next),
  217    get_dict(results, Refs0, Refs).
  218
  219:- predicate_options(sourcehut_git_upload_artifact/5,
  220                     5,
  221                     [pass_to(sourcehut_graphql/5, 5)]).  222
  223%% sourcehut_git_upload_artifact(+RepoId, +Tag, +File, -Artifact, +Options) is det.
  224%
  225%  Uploads the file located at File as an artifact of the remote Git
  226%  repository RepoId at tag Tag.  RepoId is an integer identifying the
  227%  specific repository on the remote SourceHut instance, Tag is a
  228%  string denoting the Git tag to attach File to.
  229%
  230%  Artifact is unified with a dict describing the newly created
  231%  artifact. _Artifact.id_ can be used with
  232%  sourcehut_git_delete_artifact/2 to later delete it.
  233%
  234%  Options are passed on to sourcehut_graphql/5.
  235sourcehut_git_upload_artifact(RepoId, Tag, File, Artifact, Options) :-
  236    sourcehut_graphql(
  237        mutation('$file':'Upload!') {
  238            uploadArtifact(repoId:RepoId, revspec:Tag, file:'$file') {
  239                id,
  240                created,
  241                filename,
  242                checksum,
  243                size, url
  244            }
  245        },
  246        _{file:null},
  247        [map='{"0": ["variables.file"]}', '0'=file(File)],
  248        Dict,
  249        Options),
  250    get_dict(data, Dict, Data),
  251    get_dict(uploadArtifact, Data, Artifact).
  252
  253
  254:- predicate_options(sourcehut_git_delete_artifact/2,
  255                     2,
  256                     [pass_to(sourcehut_graphql/3, 3)]).  257
  258%% sourcehut_git_delete_artifact(+ArtifactId, +Options) is det.
  259%
  260%  Deletes artifact ArtifactId from the remote SourceHut instance.
  261%
  262%  Options are passed on to sourcehut_graphql/3.
  263sourcehut_git_delete_artifact(ArtifactId, Options) :-
  264    sourcehut_graphql(
  265        mutation {
  266            deleteArtifact(id:ArtifactId) {
  267                id
  268            }
  269        },
  270        _Artifact,
  271        Options).
  272
  273
  274:- predicate_options(sourcehut_git_set_repository_visibility/3,
  275                     3,
  276                     [pass_to(sourcehut_graphql/3, 3)]).  277
  278%% sourcehut_git_set_repository_visibility(+RepoId, +Visibility, +Options) is det.
  279%
  280%  Sets the visibility of the Git repository RepoId to Visibility,
  281%  which can be one of `'PUBLIC'`, `'PRIVATE'` or `'UNLISTED'`.
  282%
  283%  Options are passed on to sourcehut_graphql/3.
  284sourcehut_git_set_repository_visibility(RepoId, Visibility, Options) :-
  285    sourcehut_graphql(
  286        mutation {
  287            updateRepository(id:RepoId, input: {visibility:Visibility}) {
  288                id
  289            }
  290        },
  291        _Result,
  292        Options).
  293
  294
  295:- predicate_options(sourcehut_git_set_repository_description/3,
  296                     3,
  297                     [pass_to(sourcehut_graphql/3, 3)]).  298
  299%% sourcehut_git_set_repository_description(+RepoId, +Description, +Options) is det.
  300%
  301%  Sets the description of the Git repository RepoId to the string
  302%  Description.
  303%
  304%  Options are passed on to sourcehut_graphql/3.
  305sourcehut_git_set_repository_description(RepoId, Description, Options) :-
  306    sourcehut_graphql(
  307        mutation