diff --git a/api/models/build-task-type.js b/api/models/build-task-type.js new file mode 100644 index 000000000..4aa55dc61 --- /dev/null +++ b/api/models/build-task-type.js @@ -0,0 +1,37 @@ +const associate = ({ + BuildTaskType, + BuildTask, + SiteBuildTask, +}) => { + // Associations + BuildTaskType.hasMany(BuildTask, { + foreignKey: 'buildTaskTypeId', + }); + BuildTaskType.hasMany(SiteBuildTask, { + foreignKey: 'buildTaskTypeId', + }); +}; + +module.exports = (sequelize, DataTypes) => { + const BuildTaskType = sequelize.define( + 'BuildTaskType', + { + name: { + type: DataTypes.STRING, + allowNull: false, + }, + description: { + type: DataTypes.STRING, + allowNull: false, + }, + metadata: { + type: DataTypes.JSON, + }, + }, { + tableName: 'build_task_type', + } + ); + + BuildTaskType.associate = associate; + return BuildTaskType; +}; diff --git a/api/models/build-task.js b/api/models/build-task.js new file mode 100644 index 000000000..ab4c096a9 --- /dev/null +++ b/api/models/build-task.js @@ -0,0 +1,56 @@ +const { buildEnum } = require('../utils'); + +const Statuses = buildEnum([ + 'created', + 'queued', + 'tasked', + 'error', + 'processing', + 'skipped', // remove? + 'success', +]); + +const associate = ({ BuildTask, Build }) => { + BuildTask.belongsTo(Build, { + foreignKey: 'buildId', + allowNull: false, + }); +}; + +module.exports = (sequelize, DataTypes) => { + const BuildTask = sequelize.define( + 'BuildTask', + { + name: { + type: DataTypes.STRING, + allowNull: false, + }, + artifact: { + type: DataTypes.STRING, + }, + status: { + type: DataTypes.ENUM, + values: Statuses.values, + defaultValue: Statuses.Created, + allowNull: false, + validate: { + isIn: [Statuses.values], + }, + }, + }, { + tableName: 'build_task', + paranoid: true, + indexes: [ + { + name: 'build_task_build_id_type_index', + unique: true, + fields: ['buildId', 'buildTaskTypeId'], + }, + ], + } + ); + + BuildTask.associate = associate; + + return BuildTask; +}; diff --git a/api/models/build.js b/api/models/build.js index 91a55e24a..652ff582f 100644 --- a/api/models/build.js +++ b/api/models/build.js @@ -20,6 +20,7 @@ const States = buildEnum([ const associate = ({ Build, BuildLog, + BuildTask, Organization, Site, User, @@ -37,6 +38,9 @@ const associate = ({ foreignKey: 'user', allowNull: false, }); + Build.hasMany(BuildTask, { + foreignKey: 'buildId', + }); // Scopes Build.addScope('byOrg', id => ({ diff --git a/api/models/index.js b/api/models/index.js index c980fba76..2a30c9a13 100644 --- a/api/models/index.js +++ b/api/models/index.js @@ -17,8 +17,11 @@ const sequelize = new Sequelize(database, username, password, { require('./build')(sequelize, DataTypes); require('./build-log')(sequelize, DataTypes); +require('./build-task-type')(sequelize, DataTypes); +require('./build-task')(sequelize, DataTypes); require('./site')(sequelize, DataTypes); require('./site-branch-config')(sequelize, DataTypes); +require('./site-build-task')(sequelize, DataTypes); require('./site-user')(sequelize, DataTypes); require('./user')(sequelize, DataTypes); require('./user-action')(sequelize, DataTypes); diff --git a/api/models/site-build-task.js b/api/models/site-build-task.js new file mode 100644 index 000000000..477c8785d --- /dev/null +++ b/api/models/site-build-task.js @@ -0,0 +1,33 @@ +const associate = ({ BuildTaskType, Site, SiteBuildTask }) => { + SiteBuildTask.belongsTo(BuildTaskType, { + foreignKey: 'buildTaskTypeId', + allowNull: false, + }); + SiteBuildTask.belongsTo(Site, { + foreignKey: 'siteId', + }); +}; + +module.exports = (sequelize, DataTypes) => { + const SiteBuildTask = sequelize.define( + 'SiteBuildTask', + { + + branch: { + type: DataTypes.STRING, + allowNull: true, + }, + metadata: { + type: DataTypes.JSON, + allowNull: true, + }, + }, { + tableName: 'site_build_task', + paranoid: true, + } + ); + + SiteBuildTask.associate = associate; + + return SiteBuildTask; +}; diff --git a/api/models/site.js b/api/models/site.js index a50b6d10a..44b2b9328 100644 --- a/api/models/site.js +++ b/api/models/site.js @@ -32,6 +32,7 @@ const associate = ({ OrganizationRole, Site, SiteBranchConfig, + SiteBuildTask, SiteUser, User, UserAction, @@ -62,6 +63,9 @@ const associate = ({ Site.belongsTo(Organization, { foreignKey: 'organizationId', }); + Site.hasMany(SiteBuildTask, { + foreignKey: 'siteId', + }); // Scopes Site.addScope('byIdOrText', (search) => { diff --git a/migrations/20230829172947-build-tasks.js b/migrations/20230829172947-build-tasks.js new file mode 100644 index 000000000..0f04ef48b --- /dev/null +++ b/migrations/20230829172947-build-tasks.js @@ -0,0 +1,99 @@ + +const TYPE_TABLE_NAME = "build_task_type"; +const TYPE_TABLE_SCHEMA = { + id: { type: "int", primaryKey: true, autoIncrement: true }, + name: { type: "string", notNull: true }, + description: { type: "string", notNull: true }, + metadata: { type: "jsonb", allowNull: true }, + createdAt: { type: "timestamp", notNull: true }, + updatedAt: { type: "timestamp", notNull: true }, +}; + +const TABLE_NAME = "build_task"; +const TABLE_INDEX_NAME = "build_task_build_id_type_index"; +const TABLE_SCHEMA = { + id: { type: "int", primaryKey: true, autoIncrement: true }, + buildId: { + type: "int", + notNull: true, + foreignKey: { + name: "build_task_build_id_fk", + table: "build", + rules: { + onDelete: "CASCADE", + onUpdate: "RESTRICT" + }, + mapping: "id" + } + }, + buildTaskTypeId: { + type: "int", + notNull: true, + foreignKey: { + name: "build_task_build_task_type_id_fk", + table: "build_task_type", + rules: { + onDelete: "CASCADE", + onUpdate: "RESTRICT" + }, + mapping: "id" + } + }, + name: { type: "string", notNull: true }, + status: { type: "string", notNull: true, default: "created" }, + artifact: { type: "string", allowNull: true }, + createdAt: { type: "timestamp", notNull: true }, + updatedAt: { type: "timestamp", notNull: true }, + deletedAt: { type: "timestamp", allowNull: true }, +}; + +const SITE_TABLE_NAME = "site_build_task"; +const SITE_TABLE_SCHEMA = { + id: { type: "int", primaryKey: true, autoIncrement: true }, + siteId: { + type: "int", + notNull: true, + foreignKey: { + name: "site_build_task_site_id_fk", + table: "site", + rules: { + onDelete: "CASCADE", + onUpdate: "RESTRICT" + }, + mapping: "id" + } + }, + buildTaskTypeId: { + type: "int", + notNull: true, + foreignKey: { + name: "site_build_task_build_task_type_id_fk", + table: "build_task_type", + rules: { + onDelete: "CASCADE", + onUpdate: "RESTRICT" + }, + mapping: "id" + } + }, + branch: { type: "string", allowNull: true }, + metadata: { type: "jsonb", allowNull: true }, + createdAt: { type: "timestamp", notNull: true }, + updatedAt: { type: "timestamp", notNull: true }, + deletedAt: { type: "timestamp", allowNull: true }, +}; + + +exports.up = async (db) => { + await db.createTable(TYPE_TABLE_NAME, TYPE_TABLE_SCHEMA); + await db.createTable(SITE_TABLE_NAME, SITE_TABLE_SCHEMA); + await db.createTable(TABLE_NAME, TABLE_SCHEMA) + await db.addIndex(TABLE_NAME, TABLE_INDEX_NAME, ["buildId", "buildTaskTypeId"], true); +}; + +exports.down = async (db) => { + await db.dropTable(TABLE_NAME); + await db.dropTable(SITE_TABLE_NAME); + return db.dropTable(TYPE_TABLE_NAME); +}; + diff --git a/scripts/create-dev-data.js b/scripts/create-dev-data.js index 43e3dd90a..3b02eb264 100644 --- a/scripts/create-dev-data.js +++ b/scripts/create-dev-data.js @@ -8,11 +8,14 @@ const cleanDatabase = require('../api/utils/cleanDatabase'); const { ActionType, Build, + BuildTaskType, + BuildTask, BuildLog, Domain, Event, Organization, Role, + SiteBuildTask, User, UserAction, } = require('../api/models'); @@ -434,6 +437,29 @@ async function createData() { })), ]); + const taskType = await BuildTaskType.create({ + name: 'test', + description: 'test description', + metadata: { + foo: 'bar', + }, + }); + await BuildTask.create({ + buildId: nodeSiteBuilds[0].id, + buildTaskTypeId: taskType.id, + name: 'type', + status: 'processing', + }); + + await SiteBuildTask.create({ + siteId: nodeSite.id, + buildTaskTypeId: taskType.id, + branch: 'test', + metadata: { + nightly: true, + }, + }); + const goSiteBuilds = await Promise.all([ Build.create({ branch: goSite.defaultBranch, diff --git a/test/api/unit/services/NightlyBuildsHelper.test.js b/test/api/unit/services/NightlyBuildsHelper.test.js index 50c585b9e..8b75146a9 100644 --- a/test/api/unit/services/NightlyBuildsHelper.test.js +++ b/test/api/unit/services/NightlyBuildsHelper.test.js @@ -20,7 +20,7 @@ describe('NightlyBuildsHelper', () => { beforeEach(async () => { await Promise.all([ - Build.truncate(), + Build.truncate({ force: true, cascade: true }), Site.truncate(), SiteBranchConfig.truncate(), ]); @@ -29,7 +29,7 @@ describe('NightlyBuildsHelper', () => { afterEach(async () => { sinon.restore(); await Promise.all([ - Build.truncate(), + Build.truncate({ force: true, cascade: true }), Site.truncate(), SiteBranchConfig.truncate(), ]);