Skip to content

Commit e72dedb

Browse files
authored
feat: ✨ support two depots: stable and beta
1 parent f5a4ec8 commit e72dedb

File tree

7 files changed

+182
-60
lines changed

7 files changed

+182
-60
lines changed

action.yml

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,46 @@ inputs:
1313
description: 'The string represetation of the repo name (eg: lemlib/lemlib)'
1414
required: false
1515

16-
github_token:
16+
token:
1717
description: 'Your GitHub Access Token. Necessary to not get rate limited.'
1818
required: true
1919
default: ${{ github.token }}
2020

2121
branch:
22-
description: 'The branch you want to put the depot json on.'
22+
description: 'The branch where the stable depot json will be placed.'
2323
required: true
2424
default: 'depot'
2525

26+
pre-release-branch:
27+
description: |
28+
The branch of the depot where pre release versions should be placed.
29+
If omitted, then the pre-release versions will not placed in a depot.
30+
required: false
31+
default: 'depot'
32+
2633
path:
27-
description: 'The path to the depot json.'
34+
description: 'The path to the stable depot json.'
2835
required: true
29-
default: 'depot.json'
36+
default: 'stable.json'
37+
38+
pre-release-path:
39+
description: |
40+
The path to the depot where pre release versions should be placed.
41+
If omitted, then the pre-release versions will not placed in a depot.
42+
If pre-release-branch == branch AND pre-release-path == path,
43+
then the pre-release versions will be placed in the same depot as the stable versions.
44+
45+
If pre-release-branch is not defined, then this input will be ignored.
46+
required: false
47+
default: 'beta.json'
3048

3149
readable-json:
3250
description: 'Whether the depot json should be formatted to be human readable (true/false).'
3351
required: true
3452
default: false
3553

36-
messsage:
37-
description: 'The commit message for the new commit depot json.'
54+
message:
55+
description: 'The commit message that will be used when updating the depot'
3856
required: false
3957

4058
# Define your outputs here.

package-lock.json

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

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@
6969
"@actions/core": "^1.10.1",
7070
"@actions/github": "^6.0.0",
7171
"@octokit/rest": "^20.0.2",
72-
"adm-zip": "^0.5.10"
72+
"adm-zip": "^0.5.10",
73+
"semver": "^7.5.4"
7374
},
7475
"devDependencies": {
7576
"@types/adm-zip": "^0.5.5",

src/main.ts

Lines changed: 93 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,116 @@
11
import * as core from '@actions/core'
22
import * as github from '@actions/github'
3-
import { populateDepotJsonFromGithub } from './populate'
3+
import { populateDepotJsonsFromGithub } from './populate'
44
import { Octokit } from '@octokit/rest'
55
import { pushDepotJsonToGithub } from './pushDepot'
66
import { createCommitMessage } from './message'
7+
import { DepotLocation, DepotType, RepositoryIdentifier } from './types'
78

89
const repoInputRegex = /[^\/\n\s\t]+\/[^\/\n\s\t]+/
910

11+
function getRepositoryIdentifier(): RepositoryIdentifier {
12+
const repo: { owner: string; repo: string } = { owner: '', repo: '' }
13+
const repoInput = core.getInput('repo')
14+
15+
if (repoInput.match(repoInputRegex)) {
16+
const parsedRepoInput = repoInput.split('/')
17+
repo.owner = parsedRepoInput[0]
18+
repo.repo = parsedRepoInput[1]
19+
} else throw new Error('Invalid repository input: ' + repoInput)
20+
return repo
21+
}
22+
23+
function getDepotLocations(
24+
repo: RepositoryIdentifier
25+
): Record<DepotType, RepositoryIdentifier & Partial<DepotLocation>> {
26+
const stableBranch = core.getInput('branch')
27+
const stablePath = core.getInput('path')
28+
const betaBranch = core.getInput('pre-release-branch')
29+
const betaPath = core.getInput('pre-release-path')
30+
31+
return {
32+
stable: {
33+
...repo,
34+
branch: stableBranch,
35+
path: stablePath
36+
},
37+
beta: {
38+
...repo,
39+
branch: betaBranch,
40+
path: betaPath
41+
}
42+
}
43+
}
44+
45+
function filterDepots(
46+
locations: ReturnType<typeof getDepotLocations>,
47+
jsons: Awaited<ReturnType<typeof populateDepotJsonsFromGithub>>
48+
): Array<DepotLocation & { json: string }> {
49+
const depots: Array<DepotLocation & { json: string }> = []
50+
for (const rawType in locations) {
51+
const type = rawType as DepotType
52+
const location = locations[type]
53+
const json = jsons[type]
54+
55+
if (location?.path != null && location?.branch != null && json != null) {
56+
depots.push({
57+
...location,
58+
path: location.path,
59+
branch: location.branch,
60+
json
61+
})
62+
}
63+
}
64+
65+
return depots
66+
}
67+
68+
async function updateDepotJsons(
69+
locations: ReturnType<typeof getDepotLocations>,
70+
jsons: Awaited<ReturnType<typeof populateDepotJsonsFromGithub>>,
71+
client: Octokit
72+
) {
73+
const depots = filterDepots(locations, jsons)
74+
const messageInput = core.getInput('message')
75+
for (const depot of depots) {
76+
const message = createCommitMessage(depot.json, depot, client)
77+
if (message === undefined) continue
78+
await pushDepotJsonToGithub(
79+
depot.json,
80+
depot,
81+
messageInput ?? message,
82+
client
83+
)
84+
}
85+
return depots
86+
}
87+
1088
/**
1189
* The main function for the action.
1290
* @returns {Promise<void>} Resolves when the action is complete.
1391
*/
1492
export async function run(): Promise<void> {
1593
try {
16-
const repo: { owner: string; repo: string } = { owner: '', repo: '' }
17-
const repoInput = core.getInput('repo')
18-
19-
if (repoInput.match(repoInputRegex)) {
20-
const parsedRepoInput = repoInput.split('/')
21-
repo.owner = parsedRepoInput[0]
22-
repo.repo = parsedRepoInput[1]
23-
} else throw new Error('Invalid repository input: ' + repoInput)
94+
const repo = getRepositoryIdentifier()
95+
const locations = getDepotLocations(repo)
2496

25-
const ghToken = core.getInput('token')
2697
const readableFlag = core.getInput('readable') === 'true'
98+
const ghToken = core.getInput('token')
2799

28100
const client = new Octokit({ auth: ghToken })
101+
102+
const unified =
103+
locations.beta.branch === locations.stable.branch &&
104+
locations.beta.path === locations.stable.path
29105

30-
const json = await populateDepotJsonFromGithub(repo, client, readableFlag)
31-
32-
const dest = {
33-
...repo,
34-
branch: core.getInput('branch'),
35-
path: core.getInput('path')
36-
}
37-
38-
const message =
39-
core.getInput('message') ?? createCommitMessage(json, dest, client)
40-
41-
await pushDepotJsonToGithub(
42-
json,
43-
{
44-
owner: dest.owner,
45-
repo: dest.repo,
46-
path: dest.path,
47-
branch: dest.branch
48-
},
49-
message,
50-
client
106+
const jsons = await populateDepotJsonsFromGithub(
107+
repo,
108+
client,
109+
readableFlag,
110+
unified
51111
)
112+
113+
updateDepotJsons(locations, jsons, client)
52114
} catch (error) {
53115
// Fail the workflow run if an error occurs
54116
if (error instanceof Error) core.setFailed(error.message)

src/message.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ function jsonToDepot(json: string): Depot {
66
return JSON.parse(json)
77
}
88

9-
async function getOldDepot(
9+
async function getOldJson(
1010
location: DepotLocation,
1111
client: Octokit
12-
): Promise<Depot> {
12+
): Promise<string> {
1313
const res = await client.repos.getContent({
1414
...location,
1515
ref: location.branch
1616
})
17-
const json = res.data.toString()
18-
return jsonToDepot(json)
17+
return res.data.toString()
1918
}
2019

2120
function depotEntryIsEqual(temp1: DepotEntry, temp2: DepotEntry): boolean {
@@ -34,23 +33,41 @@ function depotEntryIsEqual(temp1: DepotEntry, temp2: DepotEntry): boolean {
3433
function formatCommitMessage(message: string): string {
3534
const gitmoji = ':bookmark:'
3635
const automationMessage = `This commit was generated by an automated workflow: ${actionURL}`
37-
return `${gitmoji} message \n\n${automationMessage}`
36+
let msg = message
37+
if (!msg.trim().startsWith(':')) msg = gitmoji + ' ' + msg
38+
msg += '\n\n'
39+
msg += automationMessage
40+
return msg
3841
}
3942

43+
/**
44+
*
45+
* @param newJson
46+
* @param location
47+
* @param client
48+
* @returns formatted commit message unless the json's are the same, in which case it returns undefined, indicating that no commit is necessary
49+
*/
4050
export async function createCommitMessage(
4151
newJson: string,
4252
location: DepotLocation,
4353
client: Octokit
44-
): Promise<string> {
45-
return formatCommitMessage(await createRawMessage(newJson, location, client))
54+
): Promise<string | undefined> {
55+
const raw = await createRawMessage(newJson, location, client)
56+
if (raw === undefined) return raw
57+
else return formatCommitMessage(raw)
4658
}
4759

4860
async function createRawMessage(
4961
newJson: string,
5062
location: DepotLocation,
5163
client: Octokit
52-
): Promise<string> {
53-
const oldDepot = await getOldDepot(location, client)
64+
): Promise<string | undefined> {
65+
const oldJson = await getOldJson(location, client)
66+
67+
if (oldJson === newJson) return undefined
68+
if (oldJson === '') return `:tada: Create Depot: ${location.path}`
69+
70+
const oldDepot = jsonToDepot(oldJson)
5471
const newDepot = jsonToDepot(newJson)
5572

5673
const changedTemplates: DepotEntry[] = []

src/populate.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Octokit, RestEndpointMethodTypes } from '@octokit/rest'
22
import AdmZip from 'adm-zip'
3-
import { DepotEntry } from './types'
3+
import { Depot, DepotEntry, DepotType } from './types'
4+
import semver from 'semver'
45

56
interface TemplateDetails {
67
name: string
@@ -77,21 +78,27 @@ function createDepotEntry({
7778
version
7879
}
7980
}
81+
function stringifyDepot(depot: Depot, readable: boolean): string {
82+
return JSON.stringify(depot, null, readable ? 2 : undefined)
83+
}
84+
8085
/**
8186
* Creates a JSON string by populating the depot with templates from a GitHub repository.
8287
* @param repoId The repository to populate the depot from.
8388
* @param client The client to use for GitHub API requests.
8489
* @param readable Whether to format the JSON string for human readability.
90+
* @param unified Whether the beta and stable versions should be contained in a single depot.
8591
* @returns
8692
*/
87-
export async function populateDepotJsonFromGithub(
93+
export async function populateDepotJsonsFromGithub(
8894
repoId: {
8995
owner: string
9096
repo: string
9197
},
9298
client: Octokit = new Octokit(),
93-
readable: boolean = true
94-
): Promise<string> {
99+
readable: boolean = true,
100+
unified: boolean = false
101+
): Promise<Record<'stable', string> & Partial<Record<DepotType, string>>> {
95102
const rawReleases = await client.repos.listReleases(repoId)
96103

97104
const templatePromises: Promise<TemplateDetails | null>[] =
@@ -111,6 +118,23 @@ export async function populateDepotJsonFromGithub(
111118
)
112119

113120
const depotEntries = templates.map(createDepotEntry)
114-
const depotJson = JSON.stringify(depotEntries, null, readable ? 2 : undefined)
115-
return depotJson
121+
if (unified) return { stable: stringifyDepot(depotEntries, readable) }
122+
123+
const stableEntries = []
124+
const betaEntries = []
125+
126+
for (const entry of depotEntries) {
127+
if (semver.parse(entry.version)?.prerelease.length ?? 0 > 0) {
128+
betaEntries.push(entry)
129+
} else {
130+
stableEntries.push(entry)
131+
}
132+
}
133+
134+
const stableJson = stringifyDepot(stableEntries, readable)
135+
const betaJson = stringifyDepot(betaEntries, readable)
136+
return {
137+
stable: stableJson,
138+
beta: betaJson
139+
}
116140
}

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ export interface DepotEntry {
2020
}
2121

2222
export type Depot = DepotEntry[]
23+
24+
export type DepotType = "stable" | "beta";

0 commit comments

Comments
 (0)