Currently, a request to delete a repository is blocked until the
repository is completely removed from the filesystem. When CephFS is
under load and a user deletes a large-ish repo, this can cause signicant
request latency, making the user abort the request or even timing out
completely. The context gets canceled, causing the transaction to roll
back, even though the data is eventually wiped completely from storage,
leaving users with broken repositories on their profile.
Instead, simply do the deletion from storage asynchronously, so that the
user gets instant feedback. Even though the deletion itself blocks for
potentially a long time, experience has shown that it finishes even in
case of cancellation. As such, I expect that the deletion will go
through even if the go-routine were to be aborted (e.g. by a restart of
the API).
During the upgrade to `gqlgen` version 1.17.42 a breaking change was
introduced, as `map[string]interface{}` values were changed to be type
checked in 1.17.40 (commit 74e918f9, PR
https://github.com/99designs/gqlgen/pull/2830). As Emersion noted,
changing `OptionalString` to `Optional` fixes this.
Additionally, I replaced the "placeholder" error message with something
a bit more descriptive as a stopgap measure.
As lists of repositories are sorted and paginated by their "updated"
timestamp, a cursor carries such a timestamp, so that the next query can
pick up where the last one left off. However, the passing of this
timestamp is broken on systems that do not run on UTC.
Go translates time values to the system's timezone, but this timezone
information gets lost when handing the value to postgres, presumably
because the column type is "timestamp without time zone".
Avoid the issue by converting the parsed timestamp back to UTC right
away.
Lists of repositories are sorted and paginated based on their "updated"
timestamp. However, fractional seconds are discarded. This can cause
issues with repositories that have been updated in the same second (e.g.
by running a script).
This commit leverages the micro-second resolution of the timestamp in
postgres to make this case not impossible, yet highly unlikely.
The left join used for listing repositories has a curious issue: if you
grant access to a private repo to x people, where x > 1, this repo will
show up x times if you list your own repos via GraphQL.
To fix, add an additional join restriction: we are only interested in
ACLs for the calling user. This makes sure that at most one ACL will be
returned, hence avoiding duplicate repositories.
Only join with access entries if the second condition of the OR
condition in the WHERE clause (i.e. `repo.visibility = 'PUBLIC') is
false, which prevents WHERE from short-circuiting for every row.
Add a 'visibility' enum type to the database and use it for the
repository.visibility column.
This required changes to scm.sr.ht code. Instead of updating scm.sr.ht,
most of the scm.sr.ht code that git.sr.ht uses was moved to git.sr.ht.
This adds two new columns to the database: clone_status and clone_error,
which are used to store the clone status as well as any error that
occurs. The error is then displayed to the user in the frontend.
Upon deleting a repository, gather a list of all the artifacts
associated with it and schedule their deletion in a background task.
Fixes: https://todo.sr.ht/~sircmpwn/git.sr.ht/356
Execute GraphQL webhook queries after the repository has been deleted
from the database, but before the files have been removed from the
filesystem. This prevents filesystem errors during query execution.
We don't need to execute the query before the repository is deleted from
the database since all the information we need from the database has
been retrieved.
References: https://todo.sr.ht/~sircmpwn/sr.ht/301
Add a HEAD field to the RepoInput type to allow setting the default
branch name with the updateRepository GraphQL mutation. Also modify the
frontend to use the HEAD field for the repository settings page.
Implements: https://todo.sr.ht/~sircmpwn/git.sr.ht/358