Skip to content
This repository was archived by the owner on Oct 13, 2020. It is now read-only.

Commit 0fc4fb8

Browse files
committed
feat(repo): add action logic
- create logic for writing annotations from a given json file - add action.yml - add example into workflow [ch8753]
1 parent 12281b2 commit 0fc4fb8

File tree

12 files changed

+311
-22
lines changed

12 files changed

+311
-22
lines changed

.github/workflows/master-check-publish.yml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,8 @@ on:
66
- master
77

88
jobs:
9-
healthCheck:
10-
strategy:
11-
matrix:
12-
command:
13-
- typecheck
14-
- lint
15-
- format
16-
name: ${{ matrix.command }}
9+
healthcheck:
10+
name: 'healthcheck'
1711
runs-on: ubuntu-18.04
1812
steps:
1913
- uses: actions/checkout@v1
@@ -39,9 +33,14 @@ jobs:
3933
GITHUB_TOKEN: ${{ secrets.ADMIN_GH_TOKEN }}
4034
- name: 'Install dependencies'
4135
run: yarn install --frozen-lockfile
42-
- run: yarn ${{ matrix.command }}
36+
- name: 'Typecheck'
37+
run: yarn typecheck
38+
- name: 'Lint'
39+
run: yarn lint
40+
- name: 'Format'
41+
run: yarn format
4342
publish:
44-
needs: [healthCheck]
43+
needs: [healthcheck]
4544
runs-on: ubuntu-18.04
4645
steps:
4746
- uses: actions/checkout@v1

.github/workflows/pull-request-check.yml

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,8 @@ name: Pull Request Check
22
on: [pull_request]
33

44
jobs:
5-
prCheck:
6-
strategy:
7-
matrix:
8-
command:
9-
- typecheck
10-
- lint
11-
- format
12-
- build
13-
name: ${{ matrix.command }}
5+
healthcheck:
6+
name: 'healthcheck'
147
runs-on: ubuntu-18.04
158
steps:
169
- uses: actions/checkout@v1
@@ -36,4 +29,19 @@ jobs:
3629
GITHUB_TOKEN: ${{ secrets.ADMIN_GH_TOKEN }}
3730
- name: 'Install dependencies'
3831
run: yarn install --frozen-lockfile
39-
- run: yarn ${{ matrix.command }}
32+
- name: 'Typecheck'
33+
run: yarn typecheck
34+
- name: 'Lint'
35+
run: yarn lint
36+
- name: 'Format'
37+
run: yarn format
38+
- name: 'Build'
39+
run: yarn build
40+
- name: 'Install dependencies (production)'
41+
run: yarn install --frozen-lockfile --production
42+
- name: 'Test'
43+
uses: ./
44+
with:
45+
path: ./annotations.json
46+
title: Annotation Test
47+
token: ${{ secrets.GITHUB_TOKEN }}

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,23 @@ Then install with
2020
```
2121
yarn
2222
```
23+
24+
## Example workflow
25+
26+
`workflow.yml`
27+
28+
```
29+
name: workflow
30+
on: [push]
31+
jobs:
32+
job:
33+
runs-on: ubuntu-18.04
34+
steps:
35+
- uses: actions/checkout@v1
36+
- name: Annotate
37+
uses: Attest/[email protected]
38+
with:
39+
token: ${{ secrets.GITHUB_TOKEN }}
40+
input: './annotations.json'
41+
title: 'Annotate Files'
42+
```

action.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: 'Annotations Action'
2+
description: 'Dynamically label pull requests affecting packages in a monorepo / workspace'
3+
author: 'Attest Engineering <[email protected]> (https://askattest.com)'
4+
icon: 'edit-3'
5+
color: 'blue'
6+
inputs:
7+
secret:
8+
description: 'The GITHUB_TOKEN secret'
9+
path:
10+
description: 'The JSON file to consume'
11+
title:
12+
description: 'The actions title'
13+
runs:
14+
using: 'node12'
15+
main: 'dist/index.js'

annotations.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[
2+
{
3+
"message": "This is a annotation message",
4+
"path": "annotations.json",
5+
"column": { "start": 17, "end": 45 },
6+
"line": { "start": 3, "end": 3 },
7+
"level": "notice"
8+
},
9+
{
10+
"message": "This is a annotation group",
11+
"path": "annotations.json",
12+
"column": { "start": 3, "end": 4 },
13+
"line": { "start": 9, "end": 15 },
14+
"level": "notice"
15+
},
16+
{
17+
"message": "This is a annotation on file outside of changed",
18+
"path": "LICENSE.md",
19+
"line": { "start": 1, "end": 1 },
20+
"level": "warning"
21+
}
22+
]

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@
4646
}
4747
},
4848
"dependencies": {
49-
"@octokit/core": "^2.2.0"
49+
"@actions/core": "^1.2.2",
50+
"@actions/github": "^2.1.0",
51+
"@octokit/core": "^2.2.0",
52+
"@octokit/rest": "^16.39.0"
5053
},
5154
"devDependencies": {
5255
"@attest/config-babel-preset-env-node": "^0.1.17",

src/annotation.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export interface Annotation {
2+
message: string
3+
path: string
4+
line?: AnnotationSourcePositionReference
5+
column?: AnnotationSourcePositionReference
6+
level: AnnotationLevel
7+
}
8+
9+
export type AnnotationLevel = 'notice' | 'warning' | 'failure'
10+
export interface AnnotationSourcePositionReference {
11+
start?: number
12+
end?: number
13+
}

src/annotations.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Annotation } from '@/annotation'
2+
3+
export type AnnotationsConclusion = 'success' | 'failure' | 'neutral'
4+
5+
export class Annotations extends Array<Annotation> {
6+
public static fromJSON(json: string): Annotations {
7+
return new Annotations(...JSON.parse(json))
8+
}
9+
10+
public hasFailure(): boolean {
11+
return this.some(annotation => annotation.level === 'failure')
12+
}
13+
14+
public hasWarning(): boolean {
15+
return this.some(annotation => annotation.level === 'warning')
16+
}
17+
18+
public get failures(): Annotation[] {
19+
return this.filter(annotation => annotation.level === 'failure')
20+
}
21+
22+
public get warnings(): Annotation[] {
23+
return this.filter(annotation => annotation.level === 'warning')
24+
}
25+
26+
public get notices(): Annotation[] {
27+
return this.filter(annotation => annotation.level === 'notice')
28+
}
29+
30+
public get conclusion(): AnnotationsConclusion {
31+
if (this.length === 0) return 'success'
32+
if (this.hasFailure()) return 'failure'
33+
if (this.hasWarning()) return 'neutral'
34+
return 'success'
35+
}
36+
}

src/github.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Annotations } from '@/annotations'
2+
import { ChecksCreateResponse, ChecksUpdateParamsOutputAnnotations } from '@octokit/rest'
3+
import { Context } from '@actions/github/lib/context'
4+
import github from '@actions/github'
5+
6+
export class Github {
7+
private readonly client: github.GitHub
8+
private readonly context: Context
9+
private readonly owner: string
10+
private readonly repo: string
11+
private readonly sha: string
12+
private check: ChecksCreateResponse | null = null
13+
14+
public constructor(token: string) {
15+
this.client = new github.GitHub({
16+
auth: token,
17+
})
18+
this.context = github.context
19+
this.owner = this.context.repo.owner
20+
this.repo = this.context.repo.repo
21+
this.sha = this.context.payload.pull_request?.head.sha ?? this.context.sha
22+
}
23+
24+
private static githubAnnotationFromAnnotation(
25+
annotations: Annotations,
26+
): ChecksUpdateParamsOutputAnnotations[] {
27+
return annotations.map(annotation => {
28+
const { level, message, path, column = {}, line = {} } = annotation
29+
30+
const startLine = line?.start ?? 0
31+
const endLine = line?.end ?? 0
32+
33+
const isSameLinePosition = startLine === endLine
34+
const startColumn = isSameLinePosition ? column?.start ?? line.end : undefined
35+
const endColumn = isSameLinePosition ? column?.end ?? line.start : undefined
36+
37+
return {
38+
annotation_level: level,
39+
message,
40+
path,
41+
start_column: startColumn,
42+
end_column: endColumn,
43+
start_line: startLine,
44+
end_line: endLine,
45+
}
46+
})
47+
}
48+
49+
public async createCheck(name: string): Promise<this> {
50+
const { owner, repo, sha } = this
51+
52+
const response = await this.client.checks.create({
53+
owner,
54+
repo,
55+
name,
56+
head_sha: sha,
57+
status: 'in_progress',
58+
})
59+
60+
this.check = response.data
61+
62+
return this
63+
}
64+
65+
public async updateCheckWithAnnotations(annotations: Annotations): Promise<void> {
66+
if (this.check === null) return
67+
68+
const { owner, repo } = this
69+
const { name, id } = this.check
70+
71+
await this.client.checks.update({
72+
owner,
73+
repo,
74+
check_run_id: id,
75+
name,
76+
status: 'completed',
77+
conclusion: annotations.conclusion,
78+
output: {
79+
title: `${name}: output`,
80+
summary: `${annotations.length} annotations written`,
81+
text: `
82+
- Failures: ${annotations.failures.length}
83+
- Warnings: ${annotations.warnings.length}
84+
- Notices: ${annotations.notices.length}
85+
`,
86+
annotations: Github.githubAnnotationFromAnnotation(annotations),
87+
},
88+
})
89+
}
90+
}

src/index.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Annotations } from '@/annotations'
2+
import { Github } from '@/github'
3+
import { getInputs } from '@/inputs'
4+
import core from '@actions/core'
5+
import fs from 'fs'
6+
7+
async function main(): Promise<void> {
8+
const { token, title, path } = getInputs()
9+
10+
const github = new Github(token)
11+
12+
await github.createCheck(title)
13+
14+
const file = fs.readFileSync(path)
15+
const annotations = Annotations.fromJSON(file.toString())
16+
17+
await github.updateCheckWithAnnotations(annotations)
18+
}
19+
20+
main().catch(error => {
21+
/* eslint-disable-next-line no-console */
22+
console.error(error.stack)
23+
core.setFailed(`annotations-action: ${error.message}`)
24+
})

0 commit comments

Comments
 (0)