Skip to content

Commit 47c7af1

Browse files
committed
fix all lint errors
1 parent 28e9ff5 commit 47c7af1

File tree

6 files changed

+217
-85
lines changed

6 files changed

+217
-85
lines changed

__tests__/main.test.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ import * as path from 'path'
55
import {expect, test} from '@jest/globals'
66

77
test('throws invalid number', async () => {
8-
let token = process.env.GH_TOKEN!;
9-
let changelog = await generateChangelog(token, "sdfsdf");
10-
console.log(changelog);
8+
let token = process.env.GH_TOKEN!
9+
let changelog = await generateChangelog(
10+
token,
11+
'v0.2022.04.11.09.09.stable_01',
12+
'Stable'
13+
)
14+
console.log(changelog)
1115
// await expect(generateChangelog(token, "sdfsdf")).resolves;
1216
// // await expect(wait(input)).rejects.toThrow('milliseconds not a number')
1317
})

action.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,19 @@ name: 'Generate Warp Changelog'
22
description: 'Generates a Warp changelog for a given version and relase channel'
33
author: 'warpdotdev'
44
inputs:
5-
github_auth_token: # change this
5+
github_auth_token:
66
required: true
7-
description: 'input description here'
7+
description: 'The auth token to authenticate requests to the GitHub API'
8+
version:
9+
required: true
10+
description: 'The current version of the app the changelog should be generated for'
11+
channel:
12+
required: true
13+
description: 'The channel the changelog should be generated for. One of stable/beta/dev.'
14+
outputs:
15+
changelog:
16+
description: 'The generated changelog, as JSON'
17+
818
runs:
919
using: 'node16'
1020
main: 'dist/index.js'

package-lock.json

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"license": "MIT",
2727
"dependencies": {
2828
"@actions/core": "^1.6.0",
29+
"@types/shelljs": "^0.8.11",
2930
"https": "^1.0.0",
3031
"octokit": "^1.7.1",
3132
"shelljs": "^0.8.5",

src/github.ts

Lines changed: 139 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,94 @@
1-
import * as util from 'util'
2-
import { Octokit } from '@octokit/core';
3-
import { graphql } from '@octokit/graphql';
1+
import {graphql} from '@octokit/graphql'
2+
import shell from 'shelljs'
43

5-
const GH_GRAPHQL_URL = 'https://api.github.com';
6-
const GH_API_URL = 'https://api.github.com';
4+
// Regexes to find the changelog contents within a PR.
5+
const FIXES_REGEX = /^CHANGELOG-FIXES:(.*)/gm
6+
const ADDS_REGEX = /^CHANGELOG-ADDS:(.*)/gm
77

88
export interface Changelog {
9-
added: string[];
9+
added: string[]
1010
fixed: string[]
1111
}
1212

13-
export async function generateChangelog(githubAuthToken: string, current_version: string): Promise<Changelog | null> {
14-
const octokit = new Octokit({
15-
baseUrl: GH_API_URL,
16-
auth: githubAuthToken,
17-
});
13+
interface ReleaseInfo {
14+
name: string
15+
version: string
16+
}
17+
18+
interface GraphQLRelease {
19+
name: string
20+
tag: {
21+
name: string
22+
}
23+
}
1824

25+
// Generates a changelog by parsing PRs that were newly merged into the currentVersion.
26+
export async function generateChangelog(
27+
githubAuthToken: string,
28+
currentVersion: string,
29+
channel: string
30+
): Promise<Changelog> {
1931
const graphqlWithAuth = graphql.defaults({
2032
headers: {
21-
authorization: `token ${githubAuthToken}`,
22-
},
23-
});
24-
25-
26-
return fetchPullRequestMetadataFromCommits([
27-
"b8e834998860d062943d27ec0134e406016771d0",
28-
"239753dbce79925f83e8b378dd41c6b899f159d8",
29-
"9297e57f422596ffed102d6ec291d186d78fdb90"
30-
], graphqlWithAuth).then((pullRequestMetadata) => {
31-
console.log(pullRequestMetadata);
32-
return {
33-
added: ["sdfsdf"],
34-
fixed: ["sdfsdf"]
33+
authorization: `token ${githubAuthToken}`
3534
}
3635
})
36+
37+
const releases = await getReleases(graphqlWithAuth)
38+
39+
// Find the most recent release prior to this one, ignoring any releases that were the same version from a
40+
// prior cherrypick (e.g. v0.2022.01.01.stable_00 is still part of the same release as v0.2022.01.01.stable_01).
41+
let lastReleaseVersion
42+
for (const release of releases) {
43+
// Only consider releases of the same type as the current channel.
44+
if (release.name.startsWith(channel)) {
45+
if (
46+
!release.version.startsWith(
47+
currentVersion.substring(0, currentVersion.length - 1 - 2)
48+
)
49+
) {
50+
// Check for a release where `release.version` is less then `currentVersion`, which means `localCompare` would return `1`.
51+
if (
52+
currentVersion.localeCompare(release.version, undefined, {
53+
numeric: true,
54+
sensitivity: 'base'
55+
}) === 1
56+
) {
57+
lastReleaseVersion = release.version
58+
break
59+
}
60+
}
61+
}
62+
}
63+
64+
if (lastReleaseVersion) {
65+
// Find all the commits between the current release and the last release.
66+
const commits = shell
67+
.exec(
68+
// eslint-disable-next-line no-useless-escape
69+
`git --no-pager -C ~/Desktop/warp/warp log ${lastReleaseVersion}..${currentVersion} --pretty=format:"\"%H\""`,
70+
{silent: true}
71+
)
72+
.stdout.trim()
73+
.split('\n')
74+
const pullRequestMetadata = await fetchPullRequestBodyFromCommits(
75+
commits,
76+
graphqlWithAuth
77+
)
78+
return parseChangelogFromPrDescriptions(pullRequestMetadata)
79+
} else {
80+
return Promise.reject(
81+
Error('Unable to find last release prior to the given release')
82+
)
83+
}
3784
}
3885

39-
async function fetchPullRequestMetadataFromCommits(commits: string[], graphql: Function): Promise<string[]> {
40-
let commitsSubQuery = '';
86+
// Fetches PR body text from a series of commits.
87+
async function fetchPullRequestBodyFromCommits(
88+
commits: string[],
89+
graphqlWithAuth: Function
90+
): Promise<string[]> {
91+
let commitsSubQuery = ''
4192
for (const oid of commits) {
4293
commitsSubQuery += `
4394
commit_${oid}: object(oid: "${oid}") {
@@ -53,72 +104,83 @@ async function fetchPullRequestMetadataFromCommits(commits: string[], graphql: F
53104
}
54105
}
55106
}
56-
`;
107+
`
57108
}
58109

59-
const response = await graphql(`
110+
const response = await graphqlWithAuth(`
60111
{
61112
repository(owner: "warpdotdev", name: "warp-internal") {
62113
${commitsSubQuery}
63114
}
64115
}
65-
`);
116+
`)
66117

67-
const commitsInfo: string[] = [];
68-
118+
const commitsInfo: string[] = []
69119
for (const oid of commits) {
70-
let commitResponse = response.repository['commit_' + oid];
71-
console.log(commitResponse);
120+
const commitResponse = response.repository[`commit_${oid}`]
72121
if (commitResponse.associatedPullRequests.nodes.length > 0) {
73-
commitsInfo.push(commitResponse.associatedPullRequests.nodes[0].body);
122+
commitsInfo.push(commitResponse.associatedPullRequests.nodes[0].body)
74123
}
75124
}
76-
return commitsInfo;
125+
return commitsInfo
77126
}
78127

128+
// Returns the most recent 100 releases, sorted by creation.
129+
async function getReleases(graphqlWithAuth: Function): Promise<ReleaseInfo[]> {
130+
const releaseQuery = `releases(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {
131+
nodes {
132+
name
133+
tag {
134+
name
135+
}
136+
}
137+
}`
138+
139+
const response = await graphqlWithAuth(`
140+
{
141+
repository(owner: "warpdotdev", name: "warp-internal") {
142+
${releaseQuery}
143+
}
144+
}
145+
`)
146+
147+
const releaseInfo: ReleaseInfo[] = []
148+
const releases = response.repository.releases.nodes as GraphQLRelease[]
79149

150+
for (const release of releases) {
151+
releaseInfo.push({name: release.name, version: release.tag.name})
152+
}
80153

81-
// export async function wait(milliseconds: number): Promise<string> {
82-
// return new Promise(resolve => {
83-
// if (isNaN(milliseconds)) {
84-
// throw new Error('milliseconds not a number')
85-
// }
86-
87-
// setTimeout(() => resolve('done!'), milliseconds)
88-
// })
89-
// }
90-
91-
// export async function fetchPullRequestFromCommit(commits: string[]): Promise<string[]> {
92-
// let commitsSubQuery = '';
93-
// for (const oid of commits) {
94-
// commitsSubQuery += `
95-
// commit_${oid}: object(oid: "${oid}") {
96-
// ... on Commit {
97-
// oid
98-
// associatedPullRequests(first: 1) {
99-
// nodes {
100-
// body
101-
// }
102-
// }
103-
// }
104-
// }
105-
// `;
106-
// }
107-
108-
// const response = await graphqlRequest(`
109-
// {
110-
// repository(owner: "warpdotdev", name: "warp-internal") {
111-
// ${commitsSubQuery}
112-
// }
113-
// }
114-
// `);
115-
116-
// const commitsInfo: string[] = [];
117-
// for (const oid of commits) {
118-
// commitsInfo.push(response.repository['commit_' + oid].associatedPullRequests.nodes[0].body);
119-
// }
120-
// return commitsInfo;
121-
// }
154+
return releaseInfo
155+
}
122156

157+
// Produces the changelog from an array of PR descriptions. At a high level, we
158+
// traverse each PR description searching for `CHANGELOG-FIXES:` or `CHANGELOG-ADDS:`
159+
// to determine what the changelog conntents should be.
160+
function parseChangelogFromPrDescriptions(prDescriptions: string[]): Changelog {
161+
const changelog_fixed: string[] = []
162+
const changelog_new: string[] = []
163+
164+
for (const prDescription of prDescriptions) {
165+
const fixMatches = prDescription.matchAll(FIXES_REGEX)
166+
if (fixMatches) {
167+
const fixMatchesArray = [...fixMatches]
168+
for (const fixMatch of fixMatchesArray) {
169+
changelog_fixed.push(fixMatch[1].trim())
170+
}
171+
}
123172

173+
const addMatches = prDescription.matchAll(ADDS_REGEX)
174+
if (addMatches) {
175+
const addMatchesArray = [...addMatches]
176+
for (const addMatch of addMatchesArray) {
177+
changelog_new.push(addMatch[1].trim())
178+
}
179+
}
180+
}
124181

182+
return {
183+
added: changelog_new,
184+
fixed: changelog_fixed
185+
}
186+
}

0 commit comments

Comments
 (0)