Skip to content

Commit

Permalink
Merge pull request #121 from SocketDev/cg/addReposCommand
Browse files Browse the repository at this point in the history
Add repos command
  • Loading branch information
charliegerard authored Jun 21, 2024
2 parents d6f7dd9 + 3a61d87 commit 8a69483
Show file tree
Hide file tree
Showing 9 changed files with 759 additions and 5 deletions.
1 change: 1 addition & 0 deletions lib/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './report/index.js'
export * from './wrapper/index.js'
export * from './scan/index.js'
export * from './audit-log/index.js'
export * from './repos/index.js'
166 changes: 166 additions & 0 deletions lib/commands/repos/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/* eslint-disable no-console */

import chalk from 'chalk'
import meow from 'meow'
import ora from 'ora'

import { outputFlags } from '../../flags/index.js'
import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
import { prepareFlags } from '../../utils/flags.js'
import { printFlagList } from '../../utils/formatting.js'
import { getDefaultKey, setupSdk } from '../../utils/sdk.js'

/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
export const create = {
description: 'Create a repository in an organization',
async run (argv, importMeta, { parentName }) {
const name = parentName + ' create'

const input = setupCommand(name, create.description, argv, importMeta)
if (input) {
const spinnerText = 'Creating repository... \n'
const spinner = ora(spinnerText).start()
await createRepo(input.orgSlug, input, spinner)
}
}
}

const repositoryCreationFlags = prepareFlags({
repoName: {
type: 'string',
shortFlag: 'n',
default: '',
description: 'Repository name',
},
repoDescription: {
type: 'string',
shortFlag: 'd',
default: '',
description: 'Repository description',
},
homepage: {
type: 'string',
shortFlag: 'h',
default: '',
description: 'Repository url',
},
defaultBranch: {
type: 'string',
shortFlag: 'b',
default: 'main',
description: 'Repository default branch',
},
visibility: {
type: 'string',
shortFlag: 'v',
default: 'private',
description: 'Repository visibility (Default Private)',
}
})

// Internal functions

/**
* @typedef CommandContext
* @property {boolean} outputJson
* @property {boolean} outputMarkdown
* @property {string} orgSlug
* @property {string} name
* @property {string} description
* @property {string} homepage
* @property {string} default_branch
* @property {string} visibility
*/

/**
* @param {string} name
* @param {string} description
* @param {readonly string[]} argv
* @param {ImportMeta} importMeta
* @returns {void|CommandContext}
*/
function setupCommand (name, description, argv, importMeta) {
const flags = {
...outputFlags,
...repositoryCreationFlags
}

const cli = meow(`
Usage
$ ${name} <org slug>
Options
${printFlagList(flags, 6)}
Examples
$ ${name} FakeOrg --repoName=test-repo
`, {
argv,
description,
importMeta,
flags
})

const {
json: outputJson,
markdown: outputMarkdown,
repoName,
repoDescription,
homepage,
defaultBranch,
visibility
} = cli.flags

const [orgSlug = ''] = cli.input

if (!orgSlug) {
console.error(`${chalk.bgRed('Input error')}: Please provide an organization slug \n`)
cli.showHelp()
return
}

if (!repoName) {
console.error(`${chalk.bgRed('Input error')}: Repository name is required. \n`)
cli.showHelp()
return
}

return {
outputJson,
outputMarkdown,
orgSlug,
name: repoName,
description: repoDescription,
homepage,
default_branch: defaultBranch,
visibility
}
}

/**
* @typedef RepositoryData
* @property {import('@socketsecurity/sdk').SocketSdkReturnType<'createOrgRepo'>["data"]} data
*/

/**
* @param {string} orgSlug
* @param {CommandContext} input
* @param {import('ora').Ora} spinner
* @returns {Promise<void|RepositoryData>}
*/
async function createRepo (orgSlug, input, spinner) {
const socketSdk = await setupSdk(getDefaultKey())
const result = await handleApiCall(socketSdk.createOrgRepo(orgSlug, input), 'creating repository')

if (!result.success) {
return handleUnsuccessfulApiResponse('createOrgRepo', result, spinner)
}

spinner.stop()

console.log('\n✅ Repository created successfully \n')

return {
data: result.data
}
}
93 changes: 93 additions & 0 deletions lib/commands/repos/delete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/* eslint-disable no-console */

import chalk from 'chalk'
import meow from 'meow'
import ora from 'ora'

import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
import { getDefaultKey, setupSdk } from '../../utils/sdk.js'

/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
export const del = {
description: 'Delete a repository in an organization',
async run (argv, importMeta, { parentName }) {
const name = parentName + ' del'

const input = setupCommand(name, del.description, argv, importMeta)
if (input) {
const spinnerText = 'Deleting repository... \n'
const spinner = ora(spinnerText).start()
await deleteRepository(input.orgSlug, input.repoName, spinner)
}
}
}

// Internal functions

/**
* @typedef CommandContext
* @property {string} orgSlug
* @property {string} repoName
*/

/**
* @param {string} name
* @param {string} description
* @param {readonly string[]} argv
* @param {ImportMeta} importMeta
* @returns {void|CommandContext}
*/
function setupCommand (name, description, argv, importMeta) {
const cli = meow(`
Usage
$ ${name} <org slug> <repo slug>
Examples
$ ${name} FakeOrg test-repo
`, {
argv,
description,
importMeta
})

const [orgSlug = '', repoName = ''] = cli.input

if (!orgSlug || !repoName) {
console.error(`${chalk.bgRed('Input error')}: Please provide an organization slug and repository slug \n`)
cli.showHelp()
return
}

return {
orgSlug,
repoName
}
}

/**
* @typedef RepositoryData
* @property {import('@socketsecurity/sdk').SocketSdkReturnType<'deleteOrgRepo'>["data"]} data
*/

/**
* @param {string} orgSlug
* @param {string} repoName
* @param {import('ora').Ora} spinner
* @returns {Promise<void|RepositoryData>}
*/
async function deleteRepository (orgSlug, repoName, spinner) {
const socketSdk = await setupSdk(getDefaultKey())
const result = await handleApiCall(socketSdk.deleteOrgRepo(orgSlug, repoName), 'deleting repository')

if (!result.success) {
return handleUnsuccessfulApiResponse('deleteOrgRepo', result, spinner)
}

spinner.stop()

console.log('\n✅ Repository deleted successfully \n')

return {
data: result.data
}
}
30 changes: 30 additions & 0 deletions lib/commands/repos/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { create } from './create.js'
import { del } from './delete.js'
import { list } from './list.js'
import { update } from './update.js'
import { view } from './view.js'
import { meowWithSubcommands } from '../../utils/meow-with-subcommands.js'

const description = 'Repositories related commands'

/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
export const repo = {
description,
run: async (argv, importMeta, { parentName }) => {
await meowWithSubcommands(
{
create,
view,
list,
del,
update
},
{
argv,
description,
importMeta,
name: parentName + ' repo',
}
)
}
}
Loading

0 comments on commit 8a69483

Please sign in to comment.