feat: add foreign keys to table collaboration (#9724)

This appears to be as easy as a foreign-key addition possibly could be; no automated tests required adjustments.

Manual testing conducted:
- Added collaborator to a repo
- Removed collaborator from a repo
- Deleted a repo with a collaborator on it
- Deleted a user that is a collaborator
- Verified database definitions to ensure foreign keys are present.

## Checklist

The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org).

### Tests

- I added test coverage for Go changes...
  - [ ] in their respective `*_test.go` for unit tests.
  - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- I added test coverage for JavaScript changes...
  - [ ] in `web_src/js/*.test.js` if it can be unit tested.
  - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)).

### Documentation

- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [x] I did not document these changes and I do not expect someone else to do it.

### Release notes

- [ ] I do not want this change to show in the release notes.
- [x] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.

<!--start release-notes-assistant-->

## Release notes
<!--URL:https://codeberg.org/forgejo/forgejo-->
- Features
  - [PR](https://codeberg.org/forgejo/forgejo/pulls/9724): <!--number 9724 --><!--line 0 --><!--description YWRkIGZvcmVpZ24ga2V5cyB0byB0YWJsZSBjb2xsYWJvcmF0aW9u-->add foreign keys to table collaboration<!--description-->
<!--end release-notes-assistant-->

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/9724
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
This commit is contained in:
Mathieu Fenniak 2025-10-18 02:50:50 +02:00 committed by Mathieu Fenniak
parent 3f1731a765
commit 3f5a01e42b
3 changed files with 58 additions and 2 deletions

View file

@ -0,0 +1,31 @@
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
package forgejo_migrations
import (
"errors"
"forgejo.org/modules/log"
"xorm.io/xorm"
)
func syncDoctorForeignKey(x *xorm.Engine, beans []any) error {
for _, bean := range beans {
// Sync() drops indexes by default, which will cause unnecessary rebuilding of indexes when syncDoctorForeignKey
// is used with partial bean definitions; so we disable that option
_, err := x.SyncWithOptions(xorm.SyncOptions{IgnoreDropIndices: true}, bean)
if err != nil {
if errors.Is(err, xorm.ErrForeignKeyViolation) {
tableName := x.TableName(bean)
log.Error(
"Foreign key creation on table %s failed. Run `forgejo doctor check --all` to identify the orphaned records preventing this foreign key from being created. Error was: %v",
tableName, err)
return err
}
return err
}
}
return nil
}

View file

@ -0,0 +1,25 @@
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
package forgejo_migrations
import (
"xorm.io/xorm"
)
func init() {
registerMigration(&Migration{
Description: "add forgejo_migration table",
Upgrade: addForeignKeysCollaboration,
})
}
func addForeignKeysCollaboration(x *xorm.Engine) error {
type Collaboration struct {
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL REFERENCES(repository, id)"`
UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL REFERENCES(user, id)"`
}
return syncDoctorForeignKey(x, []any{
new(Collaboration),
})
}

View file

@ -19,8 +19,8 @@ import (
// Collaboration represent the relation between an individual and a repository.
type Collaboration struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL REFERENCES(repository, id)"`
UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL REFERENCES(user, id)"`
Mode perm.AccessMode `xorm:"DEFAULT 2 NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`