Skip to content

Commit 0ac677d

Browse files
authored
feat(cli): Refactoring the pull request creation to use git commands and support vector map update. (#2780)
* test commit * Update the pull request creation to use github cli instead of api. * Fix comments * Update the commit messages * Make the repo as cli arguments. * Add bot to the branch name
1 parent e79e440 commit 0ac677d

File tree

3 files changed

+126
-169
lines changed

3 files changed

+126
-169
lines changed

packages/cli/src/cli/cogify/action.make.cog.pr.ts

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ConfigLayer } from '@basemaps/config';
2-
import { fsa, LogConfig } from '@basemaps/shared';
2+
import { LogConfig } from '@basemaps/shared';
33
import { CommandLineAction, CommandLineFlagParameter, CommandLineStringParameter } from '@rushstack/ts-command-line';
4-
import { owner, repo } from '../github/github.js';
54
import { MakeCogGithub } from '../github/make.cog.pr.js';
65

76
export enum Category {
@@ -35,10 +34,10 @@ export function parseCategory(category: string): Category {
3534

3635
export class CommandCogPullRequest extends CommandLineAction {
3736
private layer: CommandLineStringParameter;
38-
private output: CommandLineStringParameter;
39-
private jira: CommandLineStringParameter;
4037
private category: CommandLineStringParameter;
38+
private repository: CommandLineStringParameter;
4139
private disabled: CommandLineFlagParameter;
40+
private vector: CommandLineFlagParameter;
4241

4342
public constructor() {
4443
super({
@@ -53,18 +52,6 @@ export class CommandCogPullRequest extends CommandLineAction {
5352
argumentName: 'LAYER',
5453
parameterLongName: '--layer',
5554
description: 'Input config layer',
56-
required: true,
57-
});
58-
this.output = this.defineStringParameter({
59-
argumentName: 'OUTPUT',
60-
parameterLongName: '--output',
61-
description: 'Output the pull request url',
62-
required: false,
63-
});
64-
this.jira = this.defineStringParameter({
65-
argumentName: 'JIRA',
66-
parameterLongName: '--jira',
67-
description: 'Jira number to add to pull request title',
6855
required: false,
6956
});
7057
this.category = this.defineStringParameter({
@@ -73,33 +60,42 @@ export class CommandCogPullRequest extends CommandLineAction {
7360
description: 'New Imagery Category, like Rural Aerial Photos, Urban Aerial Photos, Satellite Imagery',
7461
required: false,
7562
});
63+
this.repository = this.defineStringParameter({
64+
argumentName: 'REPOSITORY',
65+
parameterLongName: '--repository',
66+
description: 'Github repository reference',
67+
defaultValue: 'linz/basemaps-config',
68+
required: false,
69+
});
7670
this.disabled = this.defineFlagParameter({
7771
parameterLongName: '--disabled',
7872
description: 'Disable the layer in the config',
7973
required: false,
8074
});
75+
this.vector = this.defineFlagParameter({
76+
parameterLongName: '--vector',
77+
description: 'Commit changes for vector map',
78+
required: false,
79+
});
8180
}
8281

8382
async onExecute(): Promise<void> {
8483
const logger = LogConfig.get();
8584
const layerStr = this.layer.value;
8685
const category = this.category.value ? parseCategory(this.category.value) : Category.Other;
86+
const repo = this.repository.value ?? this.repository.defaultValue;
8787
if (layerStr == null) throw new Error('Please provide a valid input layer and urls');
88+
if (repo == null) throw new Error('Please provide a repository');
8889
let layer: ConfigLayer;
8990
try {
9091
layer = JSON.parse(layerStr);
9192
} catch {
9293
throw new Error('Please provide a valid input layer');
9394
}
9495

95-
const git = new MakeCogGithub(layer.name, logger);
96+
const git = new MakeCogGithub(repo, layer.name, logger);
9697
if (this.disabled.value) layer.disabled = true;
97-
const prNumber = await git.createTileSetPullRequest(layer, this.jira.value, category);
98-
99-
const output = this.output.value;
100-
if (output) {
101-
const prUrl = `https://github.com/${owner}/${repo}/pull/${prNumber}`;
102-
fsa.write(output, prUrl);
103-
}
98+
if (this.vector.value) await git.updateVectorTileSet('topographic', layer);
99+
else await git.updateRasterTileSet('aerial', layer, category);
104100
}
105101
}
Lines changed: 43 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,73 @@
11
import { Env, LogType } from '@basemaps/shared';
2-
import { Octokit } from '@octokit/core';
3-
import { Api } from '@octokit/plugin-rest-endpoint-methods/dist-types/types.js';
4-
import { restEndpointMethods } from '@octokit/plugin-rest-endpoint-methods';
5-
6-
export const owner = 'linz'; // The Owner of the Github repository
7-
export const repo = 'basemaps-config'; // Github repository name
8-
export const base = 'master'; // Base head name of repository
9-
10-
export interface Job {
11-
imagery: string;
12-
tileMatrix: string;
13-
content: string;
14-
}
15-
16-
export interface Blob {
17-
path: string;
18-
mode: '100644';
19-
type: 'blob';
20-
sha: string;
21-
}
2+
import { execFileSync } from 'child_process';
223

234
export class Github {
24-
octokit: Api;
5+
repo: string;
256
logger: LogType;
267

27-
constructor(logger: LogType) {
8+
constructor(repo: string, logger: LogType) {
9+
this.repo = repo;
2810
this.logger = logger;
29-
const token = Env.get(Env.GitHubToken);
30-
if (token == null) throw new Error('Please set up github token environment variable.');
31-
this.octokit = restEndpointMethods(new Octokit({ auth: token }));
3211
}
3312

34-
isOk = (s: number): boolean => s >= 200 && s <= 299;
35-
3613
/**
37-
* Get branch by name if exists
14+
* Clone the repository
3815
*
39-
* @returns {ref} github references or the new created branch
4016
*/
41-
async getBranch(ref: string): Promise<string | undefined> {
42-
this.logger.info({ ref }, 'GitHub: Get branch');
43-
try {
44-
const response = await this.octokit.rest.git.getRef({ owner, repo, ref });
45-
if (this.isOk(response.status)) return response.data.object.sha;
46-
} catch {
47-
this.logger.info({ ref }, 'GitHub: Brach Not Found');
48-
return;
49-
}
50-
return;
17+
clone(): void {
18+
const https = `https://github.com/${this.repo}.git`;
19+
this.logger.info({ repository: this.repo }, 'GitHub: Clone');
20+
execFileSync('git', ['clone', https]).toString().trim();
5121
}
5222

5323
/**
54-
* Create a new branch from the latest master branch
24+
* Get branch by name if exists, or create a new branch by name.
5525
*
56-
* @returns {ref} github references or the new created branch
26+
* @returns {branch} github references or the new created branch
5727
*/
58-
async createBranch(branch: string, ref: string): Promise<string> {
59-
// Get the latest sha from master branch
60-
const master = await this.octokit.rest.git.getRef({ owner, repo, ref: `heads/${base}` });
61-
if (!this.isOk(master.status)) throw new Error('Failed to get master head.');
62-
const sha = master.data.object.sha;
63-
64-
// Create new branch from the latest master
65-
this.logger.info({ branch }, 'GitHub: Create branch');
66-
const response = await this.octokit.rest.git.createRef({ owner, repo, ref: `refs/${ref}`, sha });
67-
if (!this.isOk(response.status)) throw new Error(`Failed to create branch ${branch}.`);
68-
return sha;
69-
}
70-
71-
async createBlobs(content: string, path: string): Promise<Blob> {
72-
// Create the blobs with the files content
73-
this.logger.info({ path }, 'GitHub: Create blob');
74-
const blobRes = await this.octokit.rest.git.createBlob({ owner, repo, content, encoding: 'utf-8' });
75-
if (!this.isOk(blobRes.status)) throw new Error(`Failed to create data blob.`);
76-
77-
const blobSha = blobRes.data.sha;
78-
return { path, mode: '100644', type: 'blob', sha: blobSha };
28+
getBranch(branch: string): string {
29+
this.logger.info({ branch }, 'GitHub: Get branch');
30+
try {
31+
execFileSync('git', ['checkout', branch], { cwd: this.repo }).toString().trim();
32+
this.logger.info({ branch }, 'GitHub: Branch Checkout');
33+
return branch;
34+
} catch {
35+
this.logger.info({ branch }, 'GitHub: Create New Branch');
36+
execFileSync('git', ['checkout', '-b', branch], { cwd: this.repo }).toString().trim();
37+
return branch;
38+
}
7939
}
8040

8141
/**
82-
* Create a file imagery config file into basemaps-config/config/imagery and commit
42+
* Config github user email and user name
43+
*
8344
*/
84-
async commit(branch: string, ref: string, blobs: Blob[], message: string, sha: string): Promise<void> {
85-
// Create a tree which defines the folder structure
86-
const treeRes = await this.octokit.rest.git.createTree({ owner, repo, base_tree: sha, tree: blobs });
87-
if (!this.isOk(treeRes.status)) throw new Error(`Failed to create tree.`);
88-
89-
const treeSha = treeRes.data.sha;
90-
91-
// Create the commit
92-
const commitRes = await this.octokit.rest.git.createCommit({
93-
owner,
94-
repo,
95-
message,
96-
parents: [sha],
97-
tree: treeSha,
98-
});
99-
if (!this.isOk(commitRes.status)) throw new Error(`Failed to create commit.`);
100-
101-
const commitSha = commitRes.data.sha;
102-
103-
// Update the reference of your branch to point to the new commit SHA
104-
const response = await this.octokit.rest.git.updateRef({ owner, repo, ref, sha: commitSha });
105-
if (!this.isOk(response.status)) throw new Error(`Failed to update branch ${branch} sha.`);
45+
configUser(): void {
46+
const email = Env.get('GIT_USER_EMAIL') ?? 'basemaps@linz.govt.nz';
47+
const name = Env.get('GIT_USER_NAME') ?? 'basemaps[bot]';
48+
this.logger.info({ repository: this.repo }, 'GitHub: Config User Email');
49+
execFileSync('git', ['config', 'user.email', email], { cwd: this.repo }).toString().trim();
50+
this.logger.info({ repository: this.repo }, 'GitHub: Config User Name');
51+
execFileSync('git', ['config', 'user.name', name], { cwd: this.repo }).toString().trim();
10652
}
10753

10854
/**
109-
* Create a new pull request from the given branch and return pull request number
55+
* Commit the changes to current branch
56+
*
11057
*/
111-
async createPullRequest(branch: string, title: string, draft: boolean): Promise<number> {
112-
// Create pull request from the give head
113-
const response = await this.octokit.rest.pulls.create({ owner, repo, title, head: branch, base, draft });
114-
if (!this.isOk(response.status)) throw new Error('Failed to create pull request.');
115-
this.logger.info({ branch, url: response.data.html_url }, 'GitHub: Create Pull Request');
116-
return response.data.number;
58+
commit(message: string): void {
59+
this.logger.info({ repository: this.repo }, 'GitHub: Commit all');
60+
execFileSync('git', ['commit', '-am', `"${JSON.stringify(message)}"`], { cwd: this.repo })
61+
.toString()
62+
.trim();
11763
}
11864

11965
/**
120-
* Update a new pull request from pull request number
66+
* Push the local brach
67+
*
12168
*/
122-
async updatePullRequest(branch: string, title: string, pull_number: number): Promise<void> {
123-
// Update pull request by given pull_number
124-
const response = await this.octokit.rest.pulls.update({ owner, repo, pull_number, title, base });
125-
if (!this.isOk(response.status)) throw new Error('Failed to update pull request.');
126-
this.logger.info({ branch, pull_number }, 'GitHub: Update Pull Request');
69+
push(): void {
70+
this.logger.info({ repository: this.repo }, 'GitHub: Push');
71+
execFileSync('git', ['push', 'origin', 'HEAD'], { cwd: this.repo }).toString().trim();
12772
}
12873
}

0 commit comments

Comments
 (0)