Skip to content

Commit

Permalink
✨ feat: Adds comments upon successful completion
Browse files Browse the repository at this point in the history
  • Loading branch information
TzviPM committed Oct 30, 2023
1 parent fcd7f33 commit fb2607f
Show file tree
Hide file tree
Showing 19 changed files with 342 additions and 91 deletions.
154 changes: 77 additions & 77 deletions dist/index.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { PrOpenedRunner } from './commands/pr_opened.command';
import { PrClosedRunner } from './commands/pr_closed.command';
import { CoreModule } from './core/core.module';
import { LoggingModule } from './logging/logging.module';
import { PrMergedRunner } from './commands/pr_merged.command';

@Module({
imports: [ConfigModule.forRoot(), GithubModule, CoreModule, LoggingModule],
providers: [PrActionRunner, PrOpenedRunner, PrClosedRunner],
providers: [PrActionRunner, PrOpenedRunner, PrClosedRunner, PrMergedRunner],
})
export class AppModule {}
13 changes: 12 additions & 1 deletion src/commands/pr_closed.command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Logger } from '@nestjs/common';
import { CommandRunner, Command } from 'nest-commander';
import { DeploymentService } from 'src/core/deployment/deployment.service';
import { CommentsService } from 'src/github/comments/comments.service';
import { Message } from 'src/github/comments/messages';
import { ContextService } from 'src/github/context/context.service';

@Command({
Expand All @@ -10,12 +12,21 @@ import { ContextService } from 'src/github/context/context.service';
export class PrClosedRunner extends CommandRunner {
private readonly logger = new Logger(PrClosedRunner.name);

constructor(private readonly deploymentService: DeploymentService) {
constructor(
private readonly deploymentService: DeploymentService,
private readonly commentsService: CommentsService,
) {
super();
}

async run() {
this.logger.log('PR closed');
await this.deploymentService.destroyPreview(false);

const message = Message.Text(
'Deployment preview and associated resources have been teared down.',
);

this.commentsService.postComment(message);
}
}
16 changes: 14 additions & 2 deletions src/commands/pr_merged.command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Logger } from '@nestjs/common';
import { CommandRunner, Command } from 'nest-commander';
import { DeploymentService } from 'src/core/deployment/deployment.service';
import { CommentsService } from 'src/github/comments/comments.service';
import { Message } from 'src/github/comments/messages';
import { ContextService } from 'src/github/context/context.service';

@Command({
Expand All @@ -10,12 +12,22 @@ import { ContextService } from 'src/github/context/context.service';
export class PrMergedRunner extends CommandRunner {
private readonly logger = new Logger(PrMergedRunner.name);

constructor(private readonly deploymentService: DeploymentService) {
constructor(
private readonly deploymentService: DeploymentService,
private readonly commentsService: CommentsService,
) {
super();
}

async run() {
this.logger.log('PR merged');
await this.deploymentService.destroyPreview(true);
const result = await this.deploymentService.destroyPreview(true);

const message = Message.Seq(
Message.Text('A PlanetScale deploy request has been created at'),
Message.Link(result.planetScaleRequestUrl),
);

this.commentsService.postComment(message);
}
}
17 changes: 14 additions & 3 deletions src/commands/pr_opened.command.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Logger } from '@nestjs/common';
import { CommandRunner, Command } from 'nest-commander';
import { DeploymentService } from 'src/core/deployment/deployment.service';
import { ContextService } from 'src/github/context/context.service';
import { CommentsService } from 'src/github/comments/comments.service';
import { Message } from 'src/github/comments/messages';

@Command({
name: 'opened',
Expand All @@ -10,12 +11,22 @@ import { ContextService } from 'src/github/context/context.service';
export class PrOpenedRunner extends CommandRunner {
private readonly logger = new Logger(PrOpenedRunner.name);

constructor(private readonly deploymentService: DeploymentService) {
constructor(
private readonly deploymentService: DeploymentService,
private readonly commentsService: CommentsService,
) {
super();
}

async run() {
this.logger.log('PR opened');
await this.deploymentService.createPreview();
const preview = await this.deploymentService.createPreview();

const message = Message.Seq(
Message.Text('Deployment preview created at'),
Message.Link(preview.url),
);

this.commentsService.postComment(message);
}
}
23 changes: 20 additions & 3 deletions src/core/deployment/deployment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ import { PlanetScaleService } from '../pscale/pscale.service';
import { Credentials } from '../pscale/models/credentials';
import * as crypto from 'node:crypto';

interface Preview {
url: string;
}

interface MergeResult {
planetScaleRequestUrl: string;
}

@Injectable()
export class DeploymentService {
private readonly logger = new Logger(DeploymentService.name);
Expand Down Expand Up @@ -100,7 +108,7 @@ export class DeploymentService {
return database;
}

async createPreview() {
async createPreview(): Promise<Preview> {
const siteName = this.getSiteName();
const projectName = this.getEnvoyerProjectName();
const phpVersion = this.configService.getPhpVersion();
Expand Down Expand Up @@ -205,9 +213,15 @@ export class DeploymentService {

this.logger.log(`Deploying project ${project.name}`);
await project.deploy();

return {
url: siteName,
};
}

async destroyPreview(isMerge: boolean) {
async destroyPreview(isMerge: true): Promise<MergeResult>;
async destroyPreview(isMerge: false): Promise<undefined>;
async destroyPreview(isMerge: boolean): Promise<MergeResult | undefined> {
const projectName = this.getEnvoyerProjectName();
this.logger.log(`Deleting Envoyer project "${projectName}"`);
const projects = await this.envoyerService.listProjects();
Expand Down Expand Up @@ -243,7 +257,10 @@ export class DeploymentService {
this.logger.log(
`Creating deployment request in PlanetScale to merge ${branches.branch} into ${branches.base}.`,
);
await db.requestDeploy(branch, baseBranch);
const deployRequest = await db.requestDeploy(branch, baseBranch);
return {
planetScaleRequestUrl: deployRequest.htmlUrl,
};
} else {
this.logger.log(`Deleting database branch ${branches.branch}.`);
await branch.delete();
Expand Down
3 changes: 2 additions & 1 deletion src/core/pscale/models/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Organization } from './organization';
import { Branch } from './branch';
import { Backup } from './backup';
import { Observable } from 'rxjs';
import { DeployRequest } from './deploy_request';

export const databaseSchema = z.object({
id: z.string(),
Expand Down Expand Up @@ -39,7 +40,7 @@ export class Database {
return this.pscaleService.createBranch(this, parent, name, backup);
}

requestDeploy(from: Branch, into: Branch): Promise<void> {
requestDeploy(from: Branch, into: Branch): Promise<DeployRequest> {
return this.pscaleService.requestDeploy(this, from, into);
}
}
27 changes: 27 additions & 0 deletions src/core/pscale/models/deploy_request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { z } from 'zod';
import { Database } from './database';

export const deployRequestSchema = z.object({
id: z.string(),
number: z.number(),
html_url: z.string(),
});

export class DeployRequest {
public id: string;
public number: number;
public htmlUrl: string;

public get path() {
return `${this.database.path}/deploy-requests/${this.number}`;
}

constructor(
private readonly database: Database,
data: z.infer<typeof deployRequestSchema>,
) {
this.id = data.id;
this.number = data.number;
this.htmlUrl = data.html_url;
}
}
9 changes: 7 additions & 2 deletions src/core/pscale/pscale.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Branch, branchSchema } from './models/branch';
import { Backup, backupSchema } from './models/backup';
import { Credentials, credentialsSchema } from './models/credentials';
import { AGENT_NAME } from '../agent';
import { DeployRequest, deployRequestSchema } from './models/deploy_request';

export const organizationsResponseSchema = z.object({
data: z.array(organizationSchema),
Expand Down Expand Up @@ -41,6 +42,8 @@ export const credentialsResponseSchema = z.object({

export const credentialResponseSchema = credentialsSchema;

export const deployRequestResponseSchema = deployRequestSchema;

@Injectable()
export class PlanetScaleService {
private static baseUrl = 'https://api.planetscale.com/v1';
Expand Down Expand Up @@ -204,11 +207,13 @@ export class PlanetScaleService {
database: Database,
from: Branch,
into: Branch,
): Promise<void> {
await this.post(`${database.path}/deploy-requests`, {
): Promise<DeployRequest> {
const raw = await this.post(`${database.path}/deploy-requests`, {
branch: from,
into_branch: into,
notes: `Initiated via ${AGENT_NAME}`,
});
const res = deployRequestResponseSchema.parse(raw);
return new DeployRequest(database, res);
}
}
18 changes: 18 additions & 0 deletions src/github/comments/comments.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { CommentsService } from './comments.service';

describe('CommentsService', () => {
let service: CommentsService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [CommentsService],
}).compile();

service = module.get<CommentsService>(CommentsService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
7 changes: 7 additions & 0 deletions src/github/comments/comments.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Injectable } from '@nestjs/common';
import { Message } from './messages';

@Injectable()
export abstract class CommentsService {
abstract postComment(message: Message): void;
}
33 changes: 33 additions & 0 deletions src/github/comments/github_comments.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { CommentsService } from './comments.service';
import * as github from '@actions/github';
import { Injectable } from '@nestjs/common';
import { Message } from './messages';
import { ActionsService } from '../actions/actions.service';
import { ContextService } from '../context/context.service';

type OctoKit = ReturnType<typeof github.getOctokit>;

@Injectable()
export class GithubCommentsService implements CommentsService {
private token: string;
private client: OctoKit;

constructor(
private actionsService: ActionsService,
private contextService: ContextService,
) {
this.token = this.actionsService.getInput('github-token');
this.client = github.getOctokit(this.token);
}

postComment(message: Message): void {
const pr = this.contextService.getPullRequest();

this.client.rest.issues.createComment({
owner: pr.repo.owner,
repo: pr.repo.name,
issue_number: pr.number,
body: message.toGFM(),
});
}
}
12 changes: 12 additions & 0 deletions src/github/comments/logger_comments.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { CommentsService } from './comments.service';
import { Injectable, Logger } from '@nestjs/common';
import { Message } from './messages';

@Injectable()
export class LoggerCommentsService implements CommentsService {
private logger = new Logger(LoggerCommentsService.name);

postComment(message: Message): void {
this.logger.log(message.toPlainText());
}
}
31 changes: 31 additions & 0 deletions src/github/comments/messages/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { LinkNode } from './link';
import { Node } from './node';
import { SequenceNode } from './sequence';
import { TextNode } from './text';

export class Message {
static Text(text: string) {
return new Message(new TextNode(text));
}

static Link(text: string, href?: string) {
if (href == null) {
href = text;
}
return new Message(new LinkNode(text, href));
}

static Seq(...nodes: Node[]) {
return new Message(new SequenceNode(nodes));
}

private constructor(private root: Node) {}

toPlainText(): string {
return this.root.toPlainText();
}

toGFM(): string {
return this.root.toGFM();
}
}
22 changes: 22 additions & 0 deletions src/github/comments/messages/link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Node } from './node';

export class LinkNode extends Node {
constructor(
private text: string,
private href: string,
) {
super();
}

toGFM(): string {
return `[${this.text}](${this.href})`;
}

toPlainText(): string {
if (this.text === this.href) {
return this.href;
}

return `${this.text} (${this.href})`;
}
}
4 changes: 4 additions & 0 deletions src/github/comments/messages/node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export abstract class Node {
abstract toGFM(): string;
abstract toPlainText(): string;
}
15 changes: 15 additions & 0 deletions src/github/comments/messages/sequence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Node } from './node';

export class SequenceNode extends Node {
constructor(private nodes: Node[]) {
super();
}

toGFM(): string {
return this.nodes.map((node) => node.toGFM()).join(' ');
}

toPlainText(): string {
return this.nodes.map((node) => node.toPlainText()).join(' ');
}
}
Loading

0 comments on commit fb2607f

Please sign in to comment.