mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-10-02 21:10:08 +00:00
ci/github-script: convert more to TypeScript
This commit is contained in:
2
.github/workflows/pull-request-target.yml
vendored
2
.github/workflows/pull-request-target.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
# https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/index.ts#L14
|
||||
retry-exempt-status-codes: 400,401,403,404
|
||||
script: |
|
||||
const { default: prepare } = await import('${{ github.workspace }}/ci/github-script/prepare.js')
|
||||
const { default: prepare } = await import('${{ github.workspace }}/ci/github-script/prepare.ts')
|
||||
await prepare({
|
||||
github,
|
||||
context,
|
||||
|
||||
2
.github/workflows/teams.yml
vendored
2
.github/workflows/teams.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
with:
|
||||
github-token: ${{ steps.app-token.outputs.token }}
|
||||
script: |
|
||||
const { default: getTeams } = await import('${{ github.workspace }}/ci/github-script/get-teams.js')
|
||||
const { default: getTeams } = await import('${{ github.workspace }}/ci/github-script/get-teams.ts')
|
||||
await getTeams({
|
||||
github,
|
||||
context,
|
||||
|
||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
# https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/index.ts#L14
|
||||
retry-exempt-status-codes: 400,401,403,404
|
||||
script: |
|
||||
const { default: prepare } = await import('${{ github.workspace }}/ci/github-script/prepare.js')
|
||||
const { default: prepare } = await import('${{ github.workspace }}/ci/github-script/prepare.ts')
|
||||
await prepare({
|
||||
github,
|
||||
context,
|
||||
@@ -88,13 +88,13 @@ jobs:
|
||||
'ci/github-script/merge.js',
|
||||
'ci/github-script/package.json',
|
||||
'ci/github-script/package-lock.json',
|
||||
'ci/github-script/prepare.js',
|
||||
'ci/github-script/prepare.ts',
|
||||
'ci/github-script/reminders.ts',
|
||||
'ci/github-script/reviewers.js',
|
||||
'ci/github-script/reviews.ts',
|
||||
'ci/github-script/supportedBranches.ts',
|
||||
'ci/github-script/supportedSystems.ts',
|
||||
'ci/github-script/withRateLimit.js',
|
||||
'ci/github-script/withRateLimit.ts',
|
||||
'ci/pinned.json',
|
||||
'pkgs/top-level/release-supported-systems.json',
|
||||
].includes(file) || file.startsWith('ci/github-script/reminders/'))) core.setOutput('pr', true)
|
||||
|
||||
@@ -5,7 +5,7 @@ import { DefaultArtifactClient } from '@actions/artifact'
|
||||
import { handleMerge } from './merge.js'
|
||||
import { handleReviewers } from './reviewers.js'
|
||||
import { classify } from './supportedBranches.ts'
|
||||
import withRateLimit from './withRateLimit.js'
|
||||
import withRateLimit from './withRateLimit.ts'
|
||||
|
||||
export default async ({ github, context, core, dry }) => {
|
||||
const artifactClient = new DefaultArtifactClient()
|
||||
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
import { dismissReviews, postReview } from './reviews.ts'
|
||||
import { split } from './supportedBranches.ts'
|
||||
|
||||
// TODO: should this be combined with the branch checks in prepare.js?
|
||||
// TODO: should this be combined with the branch checks in prepare.ts?
|
||||
// They do seem quite similar, but this needs to run after eval,
|
||||
// and prepare.js obviously doesn't.
|
||||
// and prepare.ts obviously doesn't.
|
||||
|
||||
const reviewKey = 'check-target-branch'
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { context as actionsContext } from '@actions/github'
|
||||
import type { GitHub } from '@actions/github/lib/utils'
|
||||
import { dismissReviews, postReview } from './reviews.ts'
|
||||
import { classify } from './supportedBranches.ts'
|
||||
import withRateLimit from './withRateLimit.js'
|
||||
import withRateLimit from './withRateLimit.ts'
|
||||
|
||||
const dirname = import.meta.dirname
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import { writeFileSync } from 'node:fs'
|
||||
import withRateLimit from './withRateLimit.js'
|
||||
import withRateLimit from './withRateLimit.ts'
|
||||
|
||||
const excludeTeams = [
|
||||
/^voters.*$/,
|
||||
@@ -8,25 +7,58 @@ const excludeTeams = [
|
||||
/^nixpkgs-committers$/,
|
||||
]
|
||||
|
||||
export default async ({ github, context, core, outFile }) => {
|
||||
type GitHub = InstanceType<typeof import('@actions/github/lib/utils').GitHub>
|
||||
type Context = typeof import('@actions/github').context
|
||||
type Core = typeof import('@actions/core')
|
||||
type Team = Awaited<
|
||||
ReturnType<GitHub['rest']['repos']['listTeams']>
|
||||
>['data'][number]
|
||||
type User = Awaited<
|
||||
ReturnType<GitHub['rest']['teams']['listMembersInOrg']>
|
||||
>['data'][number]
|
||||
|
||||
interface Result {
|
||||
[slug: string]: {
|
||||
description: string | null
|
||||
id: number
|
||||
maintainers: unknown
|
||||
members: unknown
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
||||
export default async ({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
outFile,
|
||||
}: {
|
||||
github: GitHub
|
||||
context: Context
|
||||
core: Core
|
||||
outFile: string
|
||||
}) => {
|
||||
const org = context.repo.owner
|
||||
|
||||
const result = {}
|
||||
const result: Result = {}
|
||||
|
||||
await withRateLimit({ github, core }, async () => {
|
||||
// Turn an Array of users into an Object, mapping user.login -> user.id
|
||||
function makeUserSet(users) {
|
||||
function makeUserSet(users: User[]) {
|
||||
// Sort in-place and build result by mutation
|
||||
users.sort((a, b) => (a.login > b.login ? 1 : -1))
|
||||
|
||||
return users.reduce((acc, user) => {
|
||||
acc[user.login] = user.id
|
||||
return acc
|
||||
}, {})
|
||||
return users.reduce(
|
||||
(acc, user) => {
|
||||
acc[user.login] = user.id
|
||||
return acc
|
||||
},
|
||||
{} as { [login: string]: number },
|
||||
)
|
||||
}
|
||||
|
||||
// Process a list of teams and append to the result variable
|
||||
async function processTeams(teams) {
|
||||
async function processTeams(teams: Team[]) {
|
||||
for (const team of teams) {
|
||||
core.notice(`Processing team ${team.slug}`)
|
||||
if (!excludeTeams.some((regex) => team.slug.match(regex))) {
|
||||
@@ -74,7 +106,7 @@ export default async ({ github, context, core, outFile }) => {
|
||||
.reduce((acc, key) => {
|
||||
acc[key] = result[key]
|
||||
return acc
|
||||
}, {})
|
||||
}, {} as Result)
|
||||
|
||||
const json = `${JSON.stringify(sorted, null, 2)}\n`
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
// @ts-nocheck
|
||||
import { dismissReviews, postReview } from './reviews.ts'
|
||||
import { classify } from './supportedBranches.ts'
|
||||
import { type BranchClassification, classify } from './supportedBranches.ts'
|
||||
import supportedSystems from './supportedSystems.ts'
|
||||
|
||||
const reviewKey = 'prepare'
|
||||
|
||||
export default async ({ github, context, core, dry }) => {
|
||||
const pull_number = context.payload.pull_request.number
|
||||
type GitHub = InstanceType<typeof import('@actions/github/lib/utils').GitHub>
|
||||
type Context = typeof import('@actions/github').context
|
||||
type Core = typeof import('@actions/core')
|
||||
|
||||
export default async ({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
dry,
|
||||
}: {
|
||||
github: GitHub
|
||||
context: Context
|
||||
core: Core
|
||||
dry: boolean
|
||||
}) => {
|
||||
const pull_number = context.payload.pull_request?.number
|
||||
if (!pull_number) throw new Error('Not a pull request')
|
||||
|
||||
for (const retryInterval of [5, 10, 20, 40, 80]) {
|
||||
core.info('Checking whether the pull request can be merged...')
|
||||
@@ -89,7 +103,11 @@ export default async ({ github, context, core, dry }) => {
|
||||
.filter(({ stable, type }) => type.includes('primary') && stable)
|
||||
.sort((a, b) => b.version.localeCompare(a.version))
|
||||
|
||||
async function mergeBase({ branch, order, version }) {
|
||||
async function mergeBase({
|
||||
branch,
|
||||
order,
|
||||
version,
|
||||
}: Pick<BranchClassification, 'branch' | 'order' | 'version'>) {
|
||||
const { data } = await github.rest.repos.compareCommitsWithBasehead({
|
||||
...context.repo,
|
||||
basehead: `${branch}...${head.sha}`,
|
||||
@@ -152,7 +170,7 @@ export default async ({ github, context, core, dry }) => {
|
||||
)
|
||||
.sort((a, b) => a.order - b.order)
|
||||
|
||||
const best = candidates.at(0)
|
||||
const best = candidates[0]
|
||||
|
||||
core.info('The base branches for this PR are:')
|
||||
core.info(`github: ${base.ref}`)
|
||||
@@ -188,9 +206,9 @@ export default async ({ github, context, core, dry }) => {
|
||||
}
|
||||
}
|
||||
|
||||
let mergedSha, targetSha
|
||||
let mergedSha: string, targetSha: string
|
||||
|
||||
if (prInfo.mergeable) {
|
||||
if (prInfo.mergeable && prInfo.merge_commit_sha != null) {
|
||||
core.info('The PR can be merged.')
|
||||
|
||||
mergedSha = prInfo.merge_commit_sha
|
||||
@@ -224,7 +242,7 @@ export default async ({ github, context, core, dry }) => {
|
||||
const files = (
|
||||
await github.paginate(github.rest.pulls.listFiles, {
|
||||
...context.repo,
|
||||
pull_number: context.payload.pull_request.number,
|
||||
pull_number,
|
||||
per_page: 100,
|
||||
})
|
||||
).map((file) => file.filename)
|
||||
@@ -175,7 +175,7 @@ interface PostReviewProps {
|
||||
core: typeof import('@actions/core')
|
||||
dry: boolean
|
||||
body: string
|
||||
event: keyof typeof eventToState
|
||||
event?: keyof typeof eventToState
|
||||
reviewKey: string
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ program
|
||||
.argument('<pr>', 'Number of the Pull Request to check')
|
||||
.option('--no-dry', 'Make actual modifications')
|
||||
.action(async (owner, repo, pr, options) => {
|
||||
const prepare = (await import('./prepare.js')).default
|
||||
const prepare = (await import('./prepare.ts')).default
|
||||
await run(prepare, owner, repo, pr, options)
|
||||
})
|
||||
|
||||
@@ -90,7 +90,7 @@ program
|
||||
.argument('<repo>', 'Name of the GitHub repository to label (Example: nixpkgs)')
|
||||
.argument('[outFile]', 'Path to the output file (Example: github-teams.json). If not set, prints to stdout')
|
||||
.action(async (owner, repo, outFile, options) => {
|
||||
const getTeams = (await import('./get-teams.js')).default
|
||||
const getTeams = (await import('./get-teams.ts')).default
|
||||
await run(getTeams, owner, repo, undefined, { ...options, outFile })
|
||||
})
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
type BranchType = 'channel' | 'development' | 'primary' | 'secondary'
|
||||
type BranchType = 'channel' | 'development' | 'primary' | 'secondary' | 'wip'
|
||||
|
||||
const typeConfig: Record<string, BranchType[]> = {
|
||||
master: ['development', 'primary'],
|
||||
@@ -19,7 +19,7 @@ const typeConfig: Record<string, BranchType[]> = {
|
||||
}
|
||||
|
||||
// "order" ranks the development branches by how likely they are the intended base branch
|
||||
// when they are an otherwise equally good fit according to ci/github-script/prepare.js.
|
||||
// when they are an otherwise equally good fit according to ci/github-script/prepare.ts.
|
||||
const orderConfig: Record<string, number> = {
|
||||
master: 0,
|
||||
release: 1,
|
||||
@@ -44,7 +44,7 @@ function split(branch: string) {
|
||||
return groups as unknown as SplitResult
|
||||
}
|
||||
|
||||
interface BranchClassification {
|
||||
export interface BranchClassification {
|
||||
branch: string
|
||||
order: number
|
||||
stable: boolean
|
||||
|
||||
@@ -1,8 +1,28 @@
|
||||
// @ts-nocheck
|
||||
import Bottleneck from 'bottleneck'
|
||||
|
||||
export default async ({ github, core, maxConcurrent = 1 }, callback) => {
|
||||
const stats = {
|
||||
type GitHub = InstanceType<typeof import('@actions/github/lib/utils').GitHub>
|
||||
type Core = typeof import('@actions/core')
|
||||
|
||||
export interface Stats {
|
||||
issues: number
|
||||
prs: number
|
||||
requests: number
|
||||
artifacts: number
|
||||
}
|
||||
|
||||
export default async (
|
||||
{
|
||||
github,
|
||||
core,
|
||||
maxConcurrent = 1,
|
||||
}: {
|
||||
github: GitHub
|
||||
core: Core
|
||||
maxConcurrent?: number
|
||||
},
|
||||
callback: (stats: Stats) => Promise<void>,
|
||||
) => {
|
||||
const stats: Stats = {
|
||||
issues: 0,
|
||||
prs: 0,
|
||||
requests: 0,
|
||||
@@ -30,12 +50,12 @@ export default async ({ github, core, maxConcurrent = 1 }, callback) => {
|
||||
if (options.url.startsWith('/search/')) return request(options)
|
||||
stats.requests++
|
||||
if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(options.method))
|
||||
return writeLimits.schedule(request.bind(null, options))
|
||||
else return allLimits.schedule(request.bind(null, options))
|
||||
return writeLimits.schedule(async () => request(options))
|
||||
else return allLimits.schedule(async () => request(options))
|
||||
})
|
||||
|
||||
async function updateReservoir() {
|
||||
let response
|
||||
let response: Awaited<ReturnType<typeof github.rest.rateLimit.get>>
|
||||
try {
|
||||
response = await github.rest.rateLimit.get()
|
||||
} catch (err) {
|
||||
Reference in New Issue
Block a user