Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: project and mr detection #3

Merged
merged 1 commit into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/popular-camels-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"glab-status": patch
---

Fix detecting project and merge request
30 changes: 13 additions & 17 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async function main() {
try {
const git = new Git();
const repoName = await git.repoName().catch(() => {
console.warn("Failed getting repository name");
console.warn("Failed getting remote url");
console.warn("It seems that you are not in a Git repository.");
process.exit(1);
});
Expand All @@ -33,32 +33,28 @@ async function main() {
});

const gitlab = new GitLab(process.env.GITLAB_TOKEN);
const myProjects = await gitlab.myProjectsByName(repoName);
const project = await gitlab.projectByUrl(repoName);

if (myProjects.length === 0) {
if (!project) {
const name = colors.bold(repoName);
const branchName = colors.bold(branch);

console.warn(
`Trying to find projects for ${name} on branch ${branchName}`
`Trying to find project for ${name} on branch ${branchName}`
);
console.warn("No Gitlab projects found for this repository.");
console.warn("No Gitlab project found for this repository.");
process.exit(0);
}

for (const project of myProjects) {
const pipeline = await project.pipelineBy(branch);
const pipeline = await project.pipelineBy(branch);

if (pipeline) {
new Display(
new DisplayCommit(await project.commitBy(pipeline.sha), pipeline),
new DisplayMergeRequest(await project.mergeRequestBy(branch)),
new DisplayEnvironment(await project.environmentsBy(branch)),
new DisplayPipelineJobs(await project.pipelineJobsBy(pipeline.id))
);
} else {
console.error("No pipelines found for this project.");
}
if (pipeline) {
new Display(
new DisplayCommit(await project.commitBy(pipeline.sha), pipeline),
new DisplayMergeRequest(await project.mergeRequestBy(branch)),
new DisplayEnvironment(await project.environmentsBy(branch)),
new DisplayPipelineJobs(await project.pipelineJobsBy(pipeline.id))
);
}
} catch (error: unknown) {
if (error instanceof Error) {
Expand Down
54 changes: 31 additions & 23 deletions src/display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,47 @@ export class Display {
}

export class DisplayEnvironment extends Display {
constructor(environment: { external_url: string }) {
super([
colors.bold("Environment"),
`> ${colors.blue(environment.external_url)}`,
"",
]);
constructor(environment?: { external_url: string }) {
if (environment) {
super([
colors.bold("Environment"),
`> ${colors.blue(environment.external_url)}`,
"",
]);
}

super();
}
}

export class DisplayMergeRequest extends Display {
constructor(mr: {
constructor(mr?: {
merged_at: string;
state: string;
title: string;
iid: string;
web_url: string;
}) {
const mrid = colors.red(`#${mr.iid}`);
const date = colors.green(`(${dayjs(mr.merged_at).fromNow()})`);
const statusEmojis = {
opened: colors.greenBright("✅ Opened"),
closed: colors.redBright("❌ Closed"),
merged: colors.greenBright("✅ Merged"),
} as Record<string, string>;

const status = statusEmojis[mr.state] || "";

super([
colors.bold("Merge Request"),
`${mrid} - ${mr.title} - ${status} ${date}`,
`> ${colors.blue(mr.web_url)}`,
"",
]);
if (mr) {
const mrid = colors.red(`#${mr.iid}`);
const date = colors.green(`(${dayjs(mr.merged_at).fromNow()})`);
const statusEmojis = {
opened: colors.greenBright("✅ Opened"),
closed: colors.redBright("❌ Closed"),
merged: colors.greenBright("✅ Merged"),
} as Record<string, string>;

const status = statusEmojis[mr.state] || "";

super([
colors.bold("Merge Request"),
`${mrid} - ${mr.title} - ${status} ${date}`,
`> ${colors.blue(mr.web_url)}`,
"",
]);
} else {
super([]);
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/git.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { exec } from "node:child_process";
import { promisify } from "node:util";
import process from "node:process";
import url from "node:url";

const $ = async (...args: Parameters<typeof exec>) => {
const e = promisify(exec);
Expand Down Expand Up @@ -36,7 +37,11 @@ export class Git {
}

async repoName() {
const projectName = (remoteUrl: string) => remoteUrl.split("/").pop();
const projectName = (remoteUrl: string) => {
const project = url.parse(remoteUrl).pathname?.slice(1);

return project;
};

return projectName(await this.remoteUrl())!;
}
Expand Down
57 changes: 24 additions & 33 deletions src/gitlab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type GitLabProjectDTO = {
ssh_url_to_repo: string;
http_url_to_repo: string;
web_url: string;
default_branch: string;
};

export class GitlabProject {
Expand All @@ -13,7 +14,11 @@ export class GitlabProject {
GITLAB_API_PROJECT_MRS_URL = `/projects/:id/merge_requests`;
GITLAB_API_ENVS_URL = `/projects/:id/environments`;

constructor(public gitlab: GitLab, public projectId: string) {}
constructor(
public gitlab: GitLab,
public projectId: string,
public defaultBranch: string
) {}

async commitBy(sha: string) {
return this.gitlab._get(
Expand All @@ -34,9 +39,14 @@ export class GitlabProject {
}

async mergeRequestBy(branch: string) {
if (branch === this.defaultBranch) {
return null;
}

return this.gitlab
._get(this.GITLAB_API_PROJECT_MRS_URL.replace(":id", this.projectId), {
source_branch: branch,
target_branch: this.defaultBranch,
})
.then((mrs) => mrs[0]);
}
Expand All @@ -61,44 +71,25 @@ export class GitlabProject {

export class GitLab {
BASE_URL = "https://gitlab.com/api/v4";
GITLAB_API_PROJECTS_URL = `/projects`;
GITLAB_API_PROJECT_URL = `/projects/:url`;

constructor(public token: string) {}

async _get(url: string, params = {}) {
return fetch(
`${this.BASE_URL}${url}?${new URLSearchParams(params).toString()}`,
{
headers: { "Private-Token": this.token },
}
).then((res) => res.json());
}
const query = new URLSearchParams(params || {}).toString();

async projectsByName(name: string) {
return this._get(this.GITLAB_API_PROJECTS_URL, {
search: name,
per_page: 100,
}).then((projects) =>
projects.map((item: GitLabProjectDTO) => ({
id: item.id,
name: item.name,
ssh_url_to_repo: item.ssh_url_to_repo,
http_url_to_repo: item.http_url_to_repo,
web_url: item.web_url,
}))
);
return fetch(`${this.BASE_URL}${url}?${query}`, {
headers: { "Private-Token": this.token },
}).then((res) => res.json());
}

async myProjectsByName(name: string) {
const filterProjects = (projects: GitLabProjectDTO[], name: string) =>
projects.filter(
(project) =>
project.ssh_url_to_repo.includes(name) ||
project.http_url_to_repo.includes(name)
);

return filterProjects(await this.projectsByName(name), name).map(
(project) => new GitlabProject(this, project.id)
);
async projectByUrl(url: string) {
return this._get(
this.GITLAB_API_PROJECT_URL.replace(":url", encodeURIComponent(url))
).then((item: GitLabProjectDTO) => {
return item?.id
? new GitlabProject(this, item.id, item.default_branch)
: null;
});
}
}
Loading