Skip to content

Commit

Permalink
Merge pull request #4248 from cloud-gov/feat-skeleton-build-task
Browse files Browse the repository at this point in the history
Feat skeleton build task
  • Loading branch information
drewbo authored Oct 5, 2023
2 parents 9282d2f + 1b2e73b commit 676e150
Show file tree
Hide file tree
Showing 29 changed files with 465 additions and 5 deletions.
1 change: 1 addition & 0 deletions admin-client/src/Router.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
page('/organizations/:id/edit', queryString, render(Pages.Organization.Edit));
page('/organizations-report', queryString, render(Pages.Organization.Report));
page('/reports', queryString, render(Pages.Reports));
page('/tasks', queryString, render(Pages.Tasks));
page('*', render(Pages.NotFound));
page();
</script>
Expand Down
49 changes: 49 additions & 0 deletions admin-client/src/components/TaskTable.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script>
import { formatDateTime } from '../helpers/formatter';
import DataTable from './DataTable.svelte';
export let tasks = [];
export let borderless = false;
const stateColor = (buildState) => ({
success: 'bg-mint',
error: 'bg-red',
processing: 'bg-gold',
}[buildState] || 'bg-gray-30');
</script>

<DataTable data={tasks} {borderless}>
<tr slot="header">
<th class="center">Status</th>
<th>Id</th>
<th>Build</th>
<th>Task Type</th>
<th>Name</th>
<th>Artifact</th>
<th>Created</th>
<th>Updated</th>
</tr>
<tr slot="item" let:item={task}>
<td class="center">
<span class="usa-tag radius-pill {stateColor(task.status)}">{task.status}</span>
</td>
<td>{task.id}</td>
<td><a href="/builds/{task.buildId}">{task.buildId}</a></td>
<td>{task.buildTaskTypeId}</td>
<td>{task.name}</td>
<td>{task.artifact}</td>
<td title={formatDateTime(task.createdAt)}>{formatDateTime(task.createdAt, true)}</td>
<td title={formatDateTime(task.updatedAt)}>{formatDateTime(task.udpatedAt, true)}</td>
</tr>
<p slot="empty">No build tasks found</p>
</DataTable>

<style>
.center {
text-align: center;
}
.wrap {
white-space: normal;
}
</style>
1 change: 1 addition & 0 deletions admin-client/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export { default as SiteForm } from './SiteForm.svelte';
export { default as SiteFormOrganization } from './SiteFormOrganization.svelte';
export { default as SiteFormWebhook } from './SiteFormWebhook.svelte';
export { default as SiteMetadata } from './SiteMetadata.svelte';
export { default as TaskTable } from './TaskTable.svelte';
export { default as TextInput } from './TextInput.svelte';
export { default as UserTable } from './UserTable.svelte';
export { default as UserTableRoles } from './UserTableRoles.svelte';
5 changes: 5 additions & 0 deletions admin-client/src/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,10 @@ async function logout() {
return get('/logout').catch(() => null);
}

async function fetchTasks(query = {}) {
return get('/tasks', query).catch(() => []);
}

export {
destroySite,
fetchMe,
Expand Down Expand Up @@ -323,4 +327,5 @@ export {
resendInvite,
logout,
updateSite,
fetchTasks,
};
24 changes: 24 additions & 0 deletions admin-client/src/pages/Site.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
fetchOrganizations,
fetchSite,
fetchSiteWebhooks,
fetchTasks,
fetchUserEnvironmentVariables,
fetchUsers,
updateSite,
Expand All @@ -23,6 +24,7 @@
SiteFormOrganization,
SiteFormWebhook,
SiteMetadata,
TaskTable,
UserTable,
} from '../components';
import { destroySite } from '../flows';
Expand All @@ -32,6 +34,7 @@
$: sitePromise = fetchSite(id);
$: siteWebhookPromise = fetchSiteWebhooks(id);
$: buildsPromise = fetchBuilds({ site: id, limit: 10 });
$: buildTasksPromise = fetchTasks({ site: id, limit: 10 });
$: orgsPromise = fetchOrganizations({ limit: 100 });
$: usersPromise = fetchUsers({ site: id });
$: uevsPromise = fetchUserEnvironmentVariables({ site: id });
Expand Down Expand Up @@ -193,6 +196,27 @@
<BuildTable builds={builds.data} borderless={true} />
</Await>
</AccordionContent>
<AccordionContent title="Build Tasks">
<h3>Registered Build Tasks</h3>
<DataTable data={site.SiteBuildTasks} borderless={true}>
<tr slot="header">
<th>BuildTaskTypeId</th>
<th>Branch</th>
<th>Metadata</th>
<th>Created At</th>
</tr>
<tr slot="item" let:item={sbt}>
<td>{sbt.buildTaskTypeId}</td>
<td>{sbt.branch}</td>
<td>{JSON.stringify(sbt.metadata)}</td>
<td>{sbt.createdAt}</td>
</tr>
<p slot="empty">No build tasks registered</p>
</DataTable>
<Await on={buildTasksPromise} let:response={buildTasks}>
<TaskTable tasks={buildTasks.data} borderless={true} />
</Await>
</AccordionContent>
<AccordionContent title="Collaborators">
<Await on={usersPromise} let:response={users}>
<UserTable users={users.data} borderless={true} />
Expand Down
10 changes: 10 additions & 0 deletions admin-client/src/pages/Tasks.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script>
import { fetchTasks } from '../lib/api';
import { PaginatedQueryPage, TaskTable } from '../components';
const fields = {};
</script>

<PaginatedQueryPage path="tasks" query={fetchTasks} {fields} let:data>
<TaskTable tasks={data} />
</PaginatedQueryPage>
1 change: 1 addition & 0 deletions admin-client/src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { default as NotFound } from './NotFound.svelte';
export { default as Reports } from './Reports.svelte';
export { default as Site } from './Site.svelte';
export { default as Sites } from './Sites.svelte';
export { default as Tasks } from './Tasks.svelte';
export * as Domain from './domain';
export * as Organization from './organization';
export * as User from './user';
2 changes: 2 additions & 0 deletions api/admin/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const Organization = require('./organization');
const OrganizationRole = require('./organization-role');
const Role = require('./role');
const Site = require('./site');
const Task = require('./task');
const UserEnvironmentVariable = require('./user-environment-variable');
const User = require('./user');

Expand All @@ -16,6 +17,7 @@ module.exports = {
OrganizationRole,
Role,
Site,
Task,
UserEnvironmentVariable,
User,
};
3 changes: 2 additions & 1 deletion api/admin/controllers/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const {
Organization,
Site,
SiteBranchConfig,
SiteBuildTask,
} = require('../../models');
const SiteDestroyer = require('../../services/SiteDestroyer');
const GithubBuildHelper = require('../../services/GithubBuildHelper');
Expand Down Expand Up @@ -87,7 +88,7 @@ module.exports = wrapHandlers({
} = req;

const site = await fetchModelById(id, Site, {
include: [SiteBranchConfig, Domain],
include: [SiteBranchConfig, Domain, SiteBuildTask],
});
if (!site) return res.notFound();

Expand Down
30 changes: 30 additions & 0 deletions api/admin/controllers/task.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* eslint-disable no-await-in-loop */

const { BuildTask } = require('../../models');
const { paginate, wrapHandlers } = require('../../utils');

module.exports = wrapHandlers({
async list(req, res) {
const {
limit, page, site,
} = req.query;

const scopes = [];

if (site) {
scopes.push(BuildTask.siteScope(site));
}

const pagination = await paginate(
BuildTask.scope(scopes),
a => a,
{ limit, page }
);

const json = {
...pagination,
};

return res.json(json);
},
});
1 change: 1 addition & 0 deletions api/admin/routers/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ apiRouter.put('/sites/:id', AdminControllers.Site.update);
apiRouter.get('/sites/:id/webhooks', AdminControllers.Site.listWebhooks);
apiRouter.post('/sites/:id/webhooks', AdminControllers.Site.createWebhook);
apiRouter.delete('/sites/:id', authorize(['pages.admin']), AdminControllers.Site.destroy);
apiRouter.get('/tasks', AdminControllers.Task.list);
apiRouter.get('/me', AdminControllers.User.me);
apiRouter.get('/user-environment-variables', AdminControllers.UserEnvironmentVariable.list);
apiRouter.get('/users', AdminControllers.User.list);
Expand Down
2 changes: 2 additions & 0 deletions api/bull-board/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const slowDown = require('express-slow-down');

const {
ArchiveBuildLogsQueue,
BuildTasksQueue,
DomainQueue,
FailStuckBuildsQueue,
MailQueue,
Expand Down Expand Up @@ -44,6 +45,7 @@ createBullBoard({
queues: [
new BullAdapter(createQueue('site-build-queue')),
new BullMQAdapter(new ArchiveBuildLogsQueue(connection)),
new BullMQAdapter(new BuildTasksQueue(connection)),
new BullMQAdapter(new DomainQueue(connection)),
new BullMQAdapter(new FailStuckBuildsQueue(connection)),
new BullMQAdapter(new MailQueue(connection)),
Expand Down
30 changes: 30 additions & 0 deletions api/models/build-task-type.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const { buildEnum } = require('../utils');

const associate = ({
BuildTaskType,
BuildTask,
Expand All @@ -12,6 +14,16 @@ const associate = ({
});
};

const Runners = buildEnum([
'cf_task',
'worker',
]);

const StartsWhens = buildEnum([
'build',
'complete',
]);

module.exports = (sequelize, DataTypes) => {
const BuildTaskType = sequelize.define(
'BuildTaskType',
Expand All @@ -27,11 +39,29 @@ module.exports = (sequelize, DataTypes) => {
metadata: {
type: DataTypes.JSON,
},
runner: {
type: DataTypes.ENUM,
values: Runners.values,
allowNull: false,
validate: {
isIn: [Runners.values],
},
},
startsWhen: {
type: DataTypes.ENUM,
values: StartsWhens.values,
allowNull: false,
validate: {
isIn: [StartsWhens.values],
},
},
}, {
tableName: 'build_task_type',
}
);

BuildTaskType.associate = associate;
BuildTaskType.Runners = Runners;
BuildTaskType.StartsWhens = StartsWhens;
return BuildTaskType;
};
16 changes: 14 additions & 2 deletions api/models/build-task.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,23 @@ const Statuses = buildEnum([
'success',
]);

const associate = ({ BuildTask, Build }) => {
const associate = ({ BuildTask, Build, BuildTaskType }) => {
BuildTask.belongsTo(Build, {
foreignKey: 'buildId',
allowNull: false,
});
BuildTask.belongsTo(BuildTaskType, {
foreignKey: 'buildTaskTypeId',
allowNull: false,
});
BuildTask.addScope('bySite', id => ({
where: {
'$Build.site$': id,
},
include: [{
model: Build,
}],
}));
};

const generateToken = () => URLSafeBase64.encode(crypto.randomBytes(32));
Expand Down Expand Up @@ -69,6 +81,6 @@ module.exports = (sequelize, DataTypes) => {

BuildTask.generateToken = generateToken;
BuildTask.associate = associate;

BuildTask.siteScope = id => ({ method: ['bySite', id] });
return BuildTask;
};
30 changes: 30 additions & 0 deletions api/models/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,34 @@ const jobStateUpdate = (buildStatus, build, site, timestamp) => {
return build.update(atts);
};

const afterCreate = async (build) => {
// create relevant build tasks on build create
const { SiteBuildTask, BuildTaskType } = build.sequelize.models;
try {
await SiteBuildTask.startBuildTasks({
build,
startsWhen: BuildTaskType.StartsWhens.Build,
});
} catch (err) {
console.error(err);
}
};

const afterUpdate = async (build) => {
// we start certain build tasks on build completion
const { SiteBuildTask, BuildTaskType } = build.sequelize.models;
if (build.state === States.Success) {
try {
await SiteBuildTask.startBuildTasks({
build,
startsWhen: BuildTaskType.StartsWhens.Complete,
});
} catch (err) {
console.error(err);
}
}
};

async function enqueue() {
const build = this;

Expand Down Expand Up @@ -298,6 +326,8 @@ module.exports = (sequelize, DataTypes) => {
tableName: 'build',
hooks: {
beforeValidate,
afterCreate,
afterUpdate,
},
}
);
Expand Down
Loading

0 comments on commit 676e150

Please sign in to comment.