Skip to content

Commit

Permalink
Merge pull request #7 from orta/add_labels
Browse files Browse the repository at this point in the history
Adds a way to set labels
  • Loading branch information
orta authored Aug 28, 2020
2 parents e151799 + 999dcc1 commit 4871daf
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 16 deletions.
10 changes: 5 additions & 5 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ packages/typescriptlang-org/src/copy/pt/**/*.ts @khaosdoctor @danilofuchs @orta
packages/documentation/copy/pt/**/*.ts @khaosdoctor @danilofuchs @orta

# Collaborators for Spanish Translation of the Website
packages/playground-examples/copy/es/**/*.md @KingDarBoja
packages/playground-examples/copy/es/**/*.ts @KingDarBoja
packages/tsconfig-reference/copy/es/**/*.md @KingDarBoja
packages/typescriptlang-org/src/copy/es/**/*.ts @KingDarBoja
packages/documentation/copy/es/**/*.ts @KingDarBoja
packages/playground-examples/copy/es/**/*.md @KingDarBoja [translate] [es]
packages/playground-examples/copy/es/**/*.ts @KingDarBoja [translate] [es]
packages/tsconfig-reference/copy/es/**/*.md @KingDarBoja [translate] [es]
packages/typescriptlang-org/src/copy/es/**/*.ts @KingDarBoja [translate] [es]
packages/documentation/copy/es/**/*.ts @KingDarBoja [translate] [es]

# Collaborators for Chinese Translation of the Website
packages/playground-examples/copy/zh/**/*.md @Kingwl
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ Then you should be good to go.
We force the use of [`pull_request_target`](https://github.blog/2020-08-03-github-actions-improvements-for-fork-and-pull-request-workflows/) as a workflow event to ensure that someone cannot change the CODEOWNER files at the same time as having that change be used to validate if they can merge.

### Extras

You can use this label to set labels for specific sections of the codebase, by having square brackets to indicate labels to make: `[label]`

```sh
# Collaborators for Spanish Translation of the Website
packages/playground-examples/copy/es/**/*.md @KingDarBoja [translate] [es]
packages/playground-examples/copy/es/**/*.ts @KingDarBoja [translate] [es]
packages/tsconfig-reference/copy/es/**/*.md @KingDarBoja [translate] [es]
packages/typescriptlang-org/src/copy/es/**/*.ts @KingDarBoja [translate] [es]
packages/documentation/copy/es/**/*.ts @KingDarBoja [translate] [es]
```

### Dev

Use `npx jest --watch` to run tests.
Expand Down
58 changes: 51 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const {readFileSync} = require("fs")

// Effectively the main function
async function run() {
core.info("Running version 1.3.1")
core.info("Running version 1.3.2")

// Tell folks they can merge
if (context.eventName === "pull_request_target") {
Expand Down Expand Up @@ -40,7 +40,8 @@ async function commentOnMergablePRs() {
core.info(`Changed files: \n - ${changedFiles.join("\n - ")}`)

const codeowners = findCodeOwnersForChangedFiles(changedFiles, cwd)
core.info(`Code-owners: \n - ${codeowners.join("\n - ")}`)
core.info(`Code-owners: \n - ${codeowners.users.join("\n - ")}`)
core.info(`Labels: \n - ${codeowners.labels.join("\n - ")}`)

if (!codeowners.length) {
console.log("This PR does not have any code-owners")
Expand All @@ -49,7 +50,7 @@ async function commentOnMergablePRs() {

// Determine who has access to merge every file in this PR
const ownersWhoHaveAccessToAllFilesInPR = []
codeowners.forEach(owner => {
codeowners.users.forEach(owner => {
const filesWhichArentOwned = getFilesNotOwnedByCodeOwner(owner, changedFiles, cwd)
if (filesWhichArentOwned.length === 0) ownersWhoHaveAccessToAllFilesInPR.push(owner)
})
Expand All @@ -75,6 +76,12 @@ This section of the codebase is owned by ${owners} - if they write a comment say
${ourSignature}`

await octokit.issues.createComment({ ...thisRepo, issue_number: pr.number, body: message });

// Add labels
for (const label of codeowners.labels) {
const labelConfig = { name: label, color: Math.random().toString(16).slice(2, 8) }
await createOrAddLabel(octokit, { ...thisRepo, id: pr.number }, labelConfig)
}
}

async function mergeIfLGTMAndHasAccess() {
Expand Down Expand Up @@ -108,8 +115,12 @@ async function mergeIfLGTMAndHasAccess() {
}

core.info(`Creating comments and merging`)
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Merging because @${sender} is a code-owner of all the changes - thanks!` });
await octokit.pulls.merge({ ...thisRepo, pull_number: issue.number });
try {
await octokit.pulls.merge({ ...thisRepo, pull_number: issue.number });
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Merging because @${sender} is a code-owner of all the changes - thanks!` });
} catch (error) {
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Looks good to merge, thanks ${sender}.` });
}
}

function getFilesNotOwnedByCodeOwner(owner, files, cwd) {
Expand Down Expand Up @@ -141,15 +152,22 @@ function listFilesWithOwners(files, cwd) {

function findCodeOwnersForChangedFiles(changedFiles, cwd) {
const owners = new Set()
const labels = new Set()
const codeowners = new Codeowners(cwd);

for (const file of changedFiles) {
const relative = file.startsWith("/") ? file.slice(1) : file
const filesOwners = codeowners.getOwner(relative);
filesOwners.forEach(o => owners.add(o))
filesOwners.forEach(o => {
if (o.startsWith("@")) owners.add(o)
if (o.startsWith("[")) labels.add(o.slice(1, o.length-1))
})
}

return Array.from(owners)
return {
users: Array.from(owners),
labels: Array.from(labels)
}
}

async function getPRChangedFiles(octokit, repoDeets, prNumber) {
Expand All @@ -162,6 +180,32 @@ async function getPRChangedFiles(octokit, repoDeets, prNumber) {
return fileStrings
}



async function createOrAddLabel(octokit, repoDeets, labelConfig) {
let label = null
const existingLabels = await octokit.paginate('GET /repos/:owner/:repo/labels', { owner: repoDeets.owner, repo: repoDeets.repo })
label = existingLabels.find(l => l.name == labelConfig.name)

// Create the label if it doesn't exist yet
if (!label) {
await octokit.issues.createLabel({
owner: repoDeets.owner,
repo: repoDeets.repo,
name: labelConfig.name,
color: labelConfig.color,
description: labelConfig.description,
})
}

await octokit.issues.addLabels({
owner: repoDeets.owner,
repo: repoDeets.repo,
issue_number: repoDeets.id,
labels: [labelConfig.name],
})
}

process.on('uncaughtException', function (error) {
core.setFailed(error.message)
})
Expand Down
16 changes: 12 additions & 4 deletions index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,29 @@ const { getFilesNotOwnedByCodeOwner, findCodeOwnersForChangedFiles } = require("

test("determine who owns a set of files", () => {
const noFiles = findCodeOwnersForChangedFiles(["root-codeowners/one.two.js"], "./test-code-owners-repo");
expect(noFiles).toEqual(["@two"]);
expect(noFiles.users).toEqual(["@two"]);

const filesNotInCodeowners = findCodeOwnersForChangedFiles(["root-codeowners/one.two.ts"], "./test-code-owners-repo");
expect(filesNotInCodeowners).toEqual([]);
expect(filesNotInCodeowners.users).toEqual([]);
});

test("real world", () => {
const changed = ["/packages/tsconfig-reference/copy/pt/options/files.md"];
const filesNotInCodeowners = findCodeOwnersForChangedFiles(changed, ".");
expect(filesNotInCodeowners).toEqual(["@khaosdoctor", "@danilofuchs", "@orta"]);
expect(filesNotInCodeowners.users).toEqual(["@khaosdoctor", "@danilofuchs", "@orta"]);
});

test("real world 2", () => {
const changed = ["/packages/typescriptlang-org/src/copy/pt/index.ts", "/packages/typescriptlang-org/src/copy/pt/nav.ts"];
const filesNotInCodeowners = findCodeOwnersForChangedFiles(changed, ".");
expect(filesNotInCodeowners).toEqual(["@khaosdoctor", "@danilofuchs", "@orta"]);
expect(filesNotInCodeowners.users).toEqual(["@khaosdoctor", "@danilofuchs", "@orta"]);
});

test("real world with labels", () => {
// spanish has [] labels in the CODEOWNERS
const changed = ["/packages/typescriptlang-org/src/copy/es/index.ts", "/packages/typescriptlang-org/src/copy/es/nav.ts"];
const filesNotInCodeowners = findCodeOwnersForChangedFiles(changed, ".");
expect(filesNotInCodeowners.labels).toEqual(["translate", "es"]);
});

test("deciding if someone has access to merge", () => {
Expand All @@ -28,3 +35,4 @@ test("deciding if someone has access to merge", () => {
expect(filesNotInCodeowners).toEqual(["random-path/file.ts"]);
});


0 comments on commit 4871daf

Please sign in to comment.