Skip to content

feat: add repository settings to mirror creation page to disable actions #201

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"prepare": "test -d node_modules/husky && husky || echo \"husky is not installed\""
},
"dependencies": {
"@hookform/resolvers": "3.7.0",
"@octokit/auth-app": "6.1.1",
"@octokit/graphql-schema": "15.18.1",
"@primer/octicons-react": "19.9.0",
Expand All @@ -37,6 +38,7 @@
"proxy-agent": "6.4.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-hook-form": "7.52.1",
"simple-git": "3.25.0",
"styled-components": "5.3.11",
"superjson": "2.2.1",
Expand Down
4 changes: 4 additions & 0 deletions src/app/[organizationId]/forks/[forkId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import Fuse from 'fuse.js'
import { useForkData } from 'hooks/useFork'
import { useOrgData } from 'hooks/useOrganization'
import { useCallback, useState } from 'react'
import { RepositorySettingsSchema } from 'server/repos/schema'

const Fork = () => {
const { organizationId } = useParams()
Expand Down Expand Up @@ -204,9 +205,11 @@ const Fork = () => {
async ({
repoName,
branchName,
settings,
}: {
repoName: string
branchName: string
settings: RepositorySettingsSchema
}) => {
// close other flashes and dialogs when this is opened
closeAllFlashes()
Expand All @@ -219,6 +222,7 @@ const Fork = () => {
forkRepoName: forkData?.data?.name ?? '',
forkRepoOwner: forkData?.data?.owner.login ?? '',
forkId: String(forkData?.data?.id),
settings,
})
.then((res) => {
if (res.success) {
Expand Down
78 changes: 73 additions & 5 deletions src/app/components/dialog/CreateMirrorDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import { Box, FormControl, Label, Link, Text, TextInput } from '@primer/react'
import { zodResolver } from '@hookform/resolvers/zod'
import {
Box,
Checkbox,
FormControl,
Label,
Link,
Select,
Text,
TextInput,
} from '@primer/react'
import { Stack } from '@primer/react/lib-esm/Stack'
import { Dialog } from '@primer/react/lib-esm/drafts'

import { useState } from 'react'
import { useForm } from 'react-hook-form'
import { RepositorySettingsSchema } from 'server/repos/schema'

interface CreateMirrorDialogProps {
orgLogin: string
forkParentOwnerLogin: string
forkParentName: string
isOpen: boolean
closeDialog: () => void
createMirror: (data: { repoName: string; branchName: string }) => void
createMirror: (data: {
repoName: string
branchName: string
settings: RepositorySettingsSchema
}) => void
}

export const CreateMirrorDialog = ({
Expand All @@ -23,6 +38,9 @@ export const CreateMirrorDialog = ({
}: CreateMirrorDialogProps) => {
// set to default value of 'repository-name' for display purposes
const [repoName, setRepoName] = useState('repository-name')
const { register, watch, getValues } = useForm<RepositorySettingsSchema>({
resolver: zodResolver(RepositorySettingsSchema),
})

if (!isOpen) {
return null
Expand All @@ -44,7 +62,11 @@ export const CreateMirrorDialog = ({
content: 'Confirm',
variant: 'primary',
onClick: () => {
createMirror({ repoName, branchName: repoName })
createMirror({
repoName,
branchName: repoName,
settings: getValues(),
})
setRepoName('repository-name')
},
disabled: repoName === 'repository-name' || repoName === '',
Expand Down Expand Up @@ -76,7 +98,7 @@ export const CreateMirrorDialog = ({
</Link>
</FormControl.Caption>
</FormControl>
<FormControl>
<FormControl sx={{ marginBottom: '10px' }}>
<FormControl.Label>Mirror location</FormControl.Label>
<Box
sx={{
Expand Down Expand Up @@ -124,6 +146,52 @@ export const CreateMirrorDialog = ({
</Stack>
</Box>
</FormControl>
<FormControl>
<FormControl.Label>Mirror Settings</FormControl.Label>
<Box
sx={{
padding: '15px',
border: '1px solid',
borderColor: 'border.default',
borderRadius: '6px',
width: '100%',
}}
>
<FormControl
sx={{
marginBottom: '10px',
}}
>
<Checkbox {...register('actions.enabled')} />
<FormControl.Label>Enable Actions</FormControl.Label>
</FormControl>
<FormControl
sx={{
width: '100%',
}}
disabled={!watch().actions?.enabled}
>
<FormControl.Label>Allowed Actions Settings</FormControl.Label>
<Select
sx={{
width: '100%',
}}
{...register('actions.allowedActions')}
>
<Select.Option value="all">
Allow all actions and reusable workflows
</Select.Option>
<Select.Option value="local_only">
Allow enterprise actions and reusable workflows
</Select.Option>
<Select.Option value="selected">
Allow enterprise, and select non-enterprise, actions and
reusable workflows
</Select.Option>
</Select>
</FormControl>
</Box>
</FormControl>
</Box>
</Dialog>
)
Expand Down
27 changes: 26 additions & 1 deletion src/server/repos/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */

import { TRPCError } from '@trpc/server'
import simpleGit, { SimpleGitOptions } from 'simple-git'
import { generateAuthUrl } from 'utils/auth'
import { temporaryDirectory } from 'utils/dir'
Expand All @@ -18,7 +19,6 @@ import {
EditMirrorSchema,
ListMirrorsSchema,
} from './schema'
import { TRPCError } from '@trpc/server'

const reposApiLogger = logger.getSubLogger({ name: 'repos-api' })

Expand Down Expand Up @@ -136,6 +136,31 @@ export const createMirrorHandler = async ({
},
})

reposApiLogger.info('Created new repo', { newRepo })

// apply settings for actions
await privateOctokit.request(
'PUT /repos/{owner}/{repo}/actions/permissions',
{
owner: privateOrg,
repo: input.newRepoName,
enabled: input.settings.actions.enabled,
allowed_actions: input.settings.actions.enabled
? input.settings.actions.allowedActions
: undefined,
headers: {
'X-GitHub-Api-Version': '2022-11-28',
},
},
)

reposApiLogger.debug('Applied settings for actions for repo', {
owner: privateOrg,
repo: input.newRepoName,
enabled: input.settings.actions.enabled,
allowed_actions: input.settings.actions.allowedActions,
})

const defaultBranch = forkData.data.default_branch

// Add the mirror remote
Expand Down
9 changes: 9 additions & 0 deletions src/server/repos/schema.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { z } from 'zod'

export const RepositorySettingsSchema = z.object({
actions: z.object({
enabled: z.boolean(),
allowedActions: z.enum(['all', 'local_only', 'selected']).optional(),
}),
})

export const CreateMirrorSchema = z.object({
orgId: z.string(),
forkRepoOwner: z.string(),
forkRepoName: z.string(),
forkId: z.string(),
newRepoName: z.string().max(100),
newBranchName: z.string(),
settings: RepositorySettingsSchema,
})

export const ListMirrorsSchema = z.object({
Expand All @@ -29,3 +37,4 @@ export type CreateMirrorSchema = z.TypeOf<typeof CreateMirrorSchema>
export type ListMirrorsSchema = z.TypeOf<typeof ListMirrorsSchema>
export type EditMirrorSchema = z.TypeOf<typeof EditMirrorSchema>
export type DeleteMirrorSchema = z.TypeOf<typeof DeleteMirrorSchema>
export type RepositorySettingsSchema = z.TypeOf<typeof RepositorySettingsSchema>
2 changes: 2 additions & 0 deletions test/octomock/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// This is taken from https://github.com/Chocrates/octomock

let mockFunctions = {
request: jest.fn(),
config: {
get: jest.fn(),
},
Expand Down Expand Up @@ -306,6 +307,7 @@ export class Octomock {
mockFunctions: {
rest: Record<string, Record<string, jest.Mock>>
config: Record<string, jest.Mock>
request: jest.Mock
}
defaultContext: { payload: { issue: { body: string; user: {} } } }

Expand Down
Loading