// Releases: a git tag with notes and downloadable files (binaries, installers, checksums). The
// files themselves are kept on disk under data/releases/; these records describe them.
const text = (name, opts = {}) => ({ type: "text", name, max: 1000, ...opts });
const number = (name, opts = {}) => ({ type: "number", name, onlyInt: true, ...opts });
const time = (name, opts = {}) => number(name, { min: 0, ...opts });
const relation = (name, collection, opts = {}) => ({
type: "relation",
name,
collectionId: collection.id,
maxSelect: 1,
cascadeDelete: false,
...opts,
});
const parent = (name, collection) => relation(name, collection, { required: true, cascadeDelete: true });
function create(app, name, fields, indexes = []) {
const collection = new Collection({
type: "base",
name,
listRule: null,
viewRule: null,
createRule: null,
updateRule: null,
deleteRule: null,
fields,
indexes,
});
app.save(collection);
return collection;
}
migrate(
(app) => {
const users = app.findCollectionByNameOrId("users");
const repos = app.findCollectionByNameOrId("repos");
const releases = create(
app,
"releases",
[
parent("repo", repos),
// The tag name without refs/tags/. A draft's tag may not exist yet.
text("tag", { required: true, max: 255 }),
// The branch or commit the tag is created from, if it doesn't exist when the release is published
text("target", { max: 255 }),
text("title", { max: 256 }),
text("body", { max: 65536 }),
{ type: "bool", name: "draft" },
{ type: "bool", name: "prerelease" },
relation("author", users),
time("created_at", { required: true }),
time("updated_at", { required: true }),
// 0 while it's a draft
time("published_at"),
],
["CREATE UNIQUE INDEX idx_releases_repo_tag ON releases (repo, tag)", "CREATE INDEX idx_releases_published ON releases (repo, published_at)"],
);
create(
app,
"release_assets",
[
parent("release", releases),
text("name", { required: true, max: 255 }),
number("size", { min: 0 }),
// hex
text("sha256", { required: true, max: 64 }),
number("download_count", { min: 0 }),
relation("uploader", users),
time("created_at", { required: true }),
// When the file was last replaced
time("updated_at", { required: true }),
],
["CREATE UNIQUE INDEX idx_release_assets_name ON release_assets (release, name)"],
);
},
(app) => {
app.delete(app.findCollectionByNameOrId("release_assets"));
app.delete(app.findCollectionByNameOrId("releases"));
},
);