UNPKG

autoforce

Version:

Developer Automation tool for Github / Gitlab and Salesforce projects.

312 lines (311 loc) 10.6 kB
import { logWarning } from "./color.js"; import { GitHubApi } from "./github-graphql.js"; export class GitHubProjectApi extends GitHubApi { projectNumber; constructor(token, owner, repo, projectNumber) { super(token, owner, repo); this.projectNumber = projectNumber; } async getColumnValueMap() { const query = ` query getFieldOptions($owner:String!, $repo: String!, $projectNumber: Int!) { repository(owner: $owner, name: $repo) { projectV2(number: $projectNumber) { field(name: "Status") { ... on ProjectV2SingleSelectField { id name options { name id } } } } } } `; const { repository } = await this.graphqlAuth(query, { projectNumber: this.projectNumber, ...this.repoVar }); const mapValues = {}; for (const option of repository.projectV2.field.options) { mapValues[option.name] = option.id; } return mapValues; } async findMilestoneByName(title) { if (title) { const milestones = await this.getMilestones(); if (milestones.length > 0) { for (const milestone of milestones) { if (milestone.title === title) { return milestone; } } } } return; } async findLabelByName(name) { if (name) { const labels = await this.getLabels(); if (labels.length > 0) { for (const label of labels) { if (label.name === name) { return label; } } } } return; } async createIssue(title, state, label, body, milestone) { const user = await this.getUser(); const repository = await this.getRepository(); const repositoryId = repository.id; const labelId = label?.startsWith('LA_') ? label : (await this.findLabelByName(label))?.id; const milestoneId = milestone?.startsWith('MI_') ? milestone : (await this.findMilestoneByName(milestone))?.id; const projectId = repository.projectV2.id; const variables = { labelId, body, assignId: user.id, projectId, repositoryId, title, milestoneId: milestoneId ? milestoneId : null }; const mutationIssue = ` mutation createIssue($repositoryId: ID!, $assignId: ID!, $title: String!, $body: String, $milestoneId: ID ${labelId ? ', $labelId: ID!' : ''} ) { createIssue( input: { repositoryId: $repositoryId, assigneeIds: [$assignId], title: $title, milestoneId: $milestoneId, body: $body ${labelId ? ',labelIds: [$labelId]' : ''} } ) { issue { id number url milestone { title dueOn url } } } }`; const { createIssue } = await this.graphqlAuth(mutationIssue, variables); const issue = createIssue.issue; if (!state || !issue.number) { return issue; } const mutationItem = ` mutation addProjectV2ItemById($projectId: ID!, $contentId: ID! ) { addProjectV2ItemById( input: { projectId: $projectId contentId: $contentId } ) { clientMutationId, item { id } } }`; const { addProjectV2ItemById } = await this.graphqlAuth(mutationItem, { projectId, contentId: issue.id }); const itemId = addProjectV2ItemById.item.id; const fieldId = repository.projectV2.field.id; const mapValues = await this.getColumnValueMap(); const columnValue = mapValues[state]; if (!columnValue) { logWarning(`No se encontro la columna ${state} en las lista de columnas del proyecto ${Object.keys(mapValues).join(",")}`); } else { const mutationColumn = ` mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $columnValue: String!) { updateProjectV2ItemFieldValue( input: { projectId: $projectId, itemId: $itemId, fieldId: $fieldId, value: {singleSelectOptionId: $columnValue} } ) { clientMutationId } }`; await this.graphqlAuth(mutationColumn, { projectId, itemId, fieldId, columnValue }); } return issue; } async getIssueState(issueNumber) { const issue = await this._getIssue(issueNumber); return issue.projectItems?.nodes[0]?.fieldValueByName?.name; } getIssueName(title) { return title.toLowerCase().replaceAll(' ', '-'); } async _getIssue(issueNumber) { const query = ` query getIssue($owner:String!, $repo: String!, $issueNumber: Int!) { repository(owner: $owner, name: $repo) { issue(number: $issueNumber) { title number, id url body labels(first:3, orderBy: { field: CREATED_AT, direction: DESC}) { nodes { color name } } projectItems(last: 1) { nodes{ id, project { id } fieldValueByName(name: "Status"){ ... on ProjectV2ItemFieldSingleSelectValue { name id field { ... on ProjectV2SingleSelectField { id } } } } } } linkedBranches(last:1){ nodes { ref { id name } } } } } } `; const { repository } = await this.graphqlAuth(query, { issueNumber: Number.parseInt(issueNumber), ...this.repoVar }); return repository.issue; } async getIssue(issueNumber) { const issue = await this._getIssue(issueNumber); const issueObject = { number: issue.number, title: issue.title, id: issue.id, url: issue.url, body: issue.body }; issueObject.name = this.getIssueName(issue.title); if (issue.linkedBranches.nodes.length > 0) { issueObject.branch = issue.linkedBranches.nodes[0].ref.name; } if (issue.projectItems.nodes.length > 0) { issueObject.state = issue.projectItems.nodes[0].fieldValueByName.name; } if (issue.labels.nodes.length > 0) { issueObject.labels = []; for (const node of issue.labels.nodes) { issueObject.labels.push(node.name); } } return issueObject; } async getIssues() { return await this.getIssuesWithFilter(`{ states: OPEN }`); } async searchIssues(title) { const query = `query getIssues() { search(query: "repo:${this.repoVar.owner}/${this.repoVar.repo} in:title ${title}", type: ISSUE, first: 10) { nodes { ... on Issue { id number title } } } }`; const { search } = await this.graphqlAuth(query, this.repoVar); return search.nodes; } async getIssuesWithFilter(filterBy) { const query = ` query getIssues($owner:String!, $repo: String!) { repository(owner: $owner, name: $repo) { issues(last: 10, filterBy: ${filterBy} ) { nodes { number title body state url milestone { dueOn title } labels ( last: 3, orderBy: { field: CREATED_AT, direction: DESC} ) { nodes { color name } } assignees ( last: 3 ) { nodes { login } } id } } } } `; const { repository } = await this.graphqlAuth(query, this.repoVar); return repository.issues.nodes; } async moveIssue(issueNumber, state) { const issue = await this._getIssue(issueNumber); const itemId = issue.projectItems.nodes[0].id; const projectId = issue.projectItems.nodes[0].project.id; const fieldId = issue.projectItems.nodes[0].fieldValueByName.field.id; const mapValues = await this.getColumnValueMap(); const columnValue = mapValues[state]; const mutation = ` mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $columnValue: String!) { updateProjectV2ItemFieldValue( input: { projectId: $projectId, itemId: $itemId, fieldId: $fieldId, value: {singleSelectOptionId: $columnValue} } ) { projectV2Item { id } } }`; const { updateProjectV2ItemFieldValue } = await this.graphqlAuth(mutation, { projectId, itemId, fieldId, columnValue }); return updateProjectV2ItemFieldValue?.projectV2Item ? true : false; } async assignIssueToMe(issueNumber) { const user = await this.getUser(); const issue = await this._getIssue(issueNumber); const mutation = ` mutation assignUser( $issueId: ID!, $userId: ID!) { addAssigneesToAssignable(input: { assignableId: $issueId assigneeIds: [ $userId ] }) { assignable { assignees { totalCount } } } } `; const { addAssigneesToAssignable } = await this.graphqlAuth(mutation, { issueId: issue.id, userId: user.id }); return addAssigneesToAssignable.assignable.assignees.totalCount > 0; } }