Skip to content

Commit 49ecaf5

Browse files
Saas 1059 repo commands (#249)
repo commands
1 parent 3f78963 commit 49ecaf5

File tree

13 files changed

+418
-2
lines changed

13 files changed

+418
-2
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
const Command = require('../../Command');
2+
const { repository } = require('../../../../logic').api;
3+
const addRoot = require('../root/add.cmd');
4+
5+
const command = new Command({
6+
command: 'repository [fullname]',
7+
aliases: ['repo'],
8+
parent: addRoot,
9+
description: 'Add a repository from git context to codefresh',
10+
webDocs: {
11+
category: 'Repository',
12+
title: 'Add Repository',
13+
weight: 10,
14+
},
15+
builder: (yargs) => {
16+
yargs
17+
.positional('fullname', {
18+
describe: 'Full name of repo (template: "owner/repo")',
19+
required: true,
20+
})
21+
.option('context', {
22+
describe: 'Name of the git context to use, if not passed the default will be used',
23+
alias: 'c',
24+
})
25+
.example('codefresh add repo codefresh-io/some-repo', 'Add repo "some-repo" of "codefresh-io" owner from default git context')
26+
.example('codefresh add repo codefresh-io/some-repo -c bitbucket', 'Add repo "some-repo" of "codefresh-io" owner from git context "bitbucket"');
27+
return yargs;
28+
},
29+
handler: async (argv) => {
30+
let { context, fullname } = argv;
31+
32+
if (!fullname) {
33+
console.log('Full repo name is not provided');
34+
return;
35+
}
36+
37+
const [owner, repoName] = fullname.split('/');
38+
if (!owner) {
39+
console.log('Owner name not provided!');
40+
console.log('Please follow the repo name template: "<owner>/<repo>"');
41+
return;
42+
}
43+
if (!repoName) {
44+
console.log('Repo name not provided!');
45+
console.log('Please follow the repo name template: "<owner>/<repo>"');
46+
return;
47+
}
48+
49+
try {
50+
// throws on not found
51+
const gitRepo = await repository.getAvailableGitRepo(owner, repoName, context);
52+
console.log(`Found repository "${gitRepo.name}" at context "${context || gitRepo.provider}"`);
53+
if (!context) {
54+
context = gitRepo.provider;
55+
}
56+
57+
// following the ui logic on duplication
58+
try {
59+
await repository.get(fullname, context);
60+
const contextPrefix = `${context}-${context}`;
61+
console.log(`Repo with such name already exists -- adding context prefix: ${contextPrefix}`);
62+
fullname = `${contextPrefix}/${fullname}`; // aka github-github/codefresh-io/cf-api
63+
} catch (e) {
64+
// if response is "not found" - all is ok, else re-throw
65+
if (!e.statusCode || e.statusCode !== 404) {
66+
throw e;
67+
}
68+
}
69+
70+
// throws on duplicate, not found, other errors...
71+
await repository.create(fullname, owner, repoName, context);
72+
console.log(`Repository added: ${fullname}`);
73+
} catch (e) {
74+
console.log('Cannot add repository:');
75+
console.log(` - ${e.message.replace('service', 'repo')}`);
76+
}
77+
},
78+
});
79+
80+
module.exports = command;
81+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
const Command = require('../../Command');
2+
const { repository } = require('../../../../logic').api;
3+
const deleteRoot = require('../root/delete.cmd');
4+
5+
const command = new Command({
6+
command: 'repository [name_id]',
7+
aliases: ['repo'],
8+
parent: deleteRoot,
9+
description: 'Remove repository by name_id',
10+
webDocs: {
11+
category: 'Repository',
12+
title: 'Delete Repository',
13+
description: 'Remove repository by name_id ("name_id" can be retrieved with "get" command, typically "repo_owner/repo_name")',
14+
weight: 30,
15+
},
16+
builder: (yargs) => {
17+
yargs
18+
.positional('name_id', {
19+
describe: 'Repository "name_id" (can be retrieved with "get" command, typically "repo_owner/repo_name")',
20+
required: true,
21+
})
22+
.option('context', {
23+
describe: 'Name of the git context to use, if not passed the default will be used',
24+
alias: 'c',
25+
})
26+
.example('codefresh delete repo codefresh-io/some-repo', 'Delete codefresh repo with name_id "codefresh-io/some-repo"');
27+
return yargs;
28+
},
29+
handler: async (argv) => {
30+
const { name_id: name, context } = argv;
31+
32+
if (!name) {
33+
console.log('Repository name_id not provided');
34+
return;
35+
}
36+
37+
try {
38+
await repository.deleteRepo(name, context);
39+
console.log(`Successfully deleted repo: ${name}`);
40+
} catch (e) {
41+
console.log('Failed to delete repo:');
42+
console.log(` - ${e.message}`);
43+
}
44+
},
45+
});
46+
47+
module.exports = command;
48+
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
const Command = require('../../Command');
2+
const _ = require('lodash');
3+
const { repository } = require('../../../../logic').api;
4+
const { specifyOutputForArray } = require('../../helpers/get');
5+
const getRoot = require('../root/get.cmd');
6+
const Spinner = require('ora');
7+
8+
const command = new Command({
9+
command: 'repository [names..]',
10+
aliases: ['repo'],
11+
parent: getRoot,
12+
description: 'You can either get codefresh repos (previously added) or any repo from your git context (using option "--available" and "--context")',
13+
webDocs: {
14+
category: 'Repository',
15+
title: 'Get Repositories',
16+
weight: 20,
17+
},
18+
builder: (yargs) => {
19+
yargs
20+
.positional('names', {
21+
describe: 'Names for filtering repos',
22+
})
23+
.option('available', {
24+
describe: 'Get all available git repos from provided or default git context',
25+
alias: 'a',
26+
})
27+
.option('limit', {
28+
describe: 'Maximum displayed repos number',
29+
alias: 'l',
30+
default: 25,
31+
})
32+
.option('context', {
33+
describe: 'Name of the git context to use, if not passed the default will be used',
34+
alias: 'c',
35+
})
36+
.example('codefresh get repo', 'Get all codefresh repos')
37+
.example('codefresh get repo codefresh-io', 'Get codefresh repos containing "codefresh-io" in its name')
38+
.example('codefresh get repo some-repo', 'Get codefresh repos containing "some-repo" in its name')
39+
.example('codefresh get repo -a', 'Get all available repos from default git context')
40+
.example('codefresh get repo -a -c bitbucket', 'Get all available repos from "bitbucket" git context');
41+
return yargs;
42+
},
43+
handler: async (argv) => {
44+
const { context, names, available, limit } = argv;
45+
46+
const loadRepos = available ? repository.getAllAvailableGitRepos : repository.getAll;
47+
const contextText = context ? `git context "${context}"` : 'default user git context';
48+
const filterProperty = available ? 'info.repo_shortcut' : 'info.serviceName';
49+
50+
const spinner = Spinner(`Loading ${available ? `git repos for ${contextText}` : 'codefresh'}`).start();
51+
try {
52+
let repos = await loadRepos(context);
53+
spinner.succeed('Successfully loaded repos!');
54+
55+
56+
if (!_.isEmpty(names)) {
57+
repos = repos.filter((r) => {
58+
return names.reduce((bool, name) => bool || _.get(r, filterProperty).includes(name), false);
59+
});
60+
}
61+
specifyOutputForArray(argv.output, repos.slice(0, limit), argv.pretty);
62+
63+
const lengthDiff = repos.length - limit;
64+
if (lengthDiff > 0) {
65+
console.log(`... ${lengthDiff} more repos available - pass greater --limit option to show more`);
66+
}
67+
} catch (e) {
68+
spinner.fail('Failed to load repositories:');
69+
console.log(` - ${e.message}`);
70+
}
71+
},
72+
});
73+
74+
module.exports = command;
75+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const Command = require('../../Command');
2+
3+
const add = new Command({
4+
root: true,
5+
command: 'add',
6+
description: 'Add a resource',
7+
usage: 'codefresh add --help',
8+
webDocs: {
9+
title: 'Add',
10+
weight: 70,
11+
},
12+
builder: (yargs) => {
13+
return yargs
14+
.demandCommand(1, 'You need at least one command before moving on');
15+
},
16+
});
17+
18+
module.exports = add;

lib/logic/api/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const team = require('./team');
1414
const board = require('./board');
1515
const section = require('./section');
1616
const cluster = require('./cluster');
17+
const repository = require('./repository');
1718

1819
module.exports = {
1920
user,
@@ -32,4 +33,5 @@ module.exports = {
3233
board,
3334
section,
3435
cluster,
36+
repository,
3537
};

lib/logic/api/repository.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
const { sendHttpRequest } = require('./helper');
2+
const GitRepo = require('../entities/GitRepo');
3+
const CodefreshRepo = require('../entities/CodefreshRepo');
4+
5+
/**
6+
* codefresh repo (aka "service")
7+
* */
8+
const get = async (name, context) => {
9+
const userOptions = {
10+
url: `/api/services/${encodeURIComponent(name)}`,
11+
method: 'get',
12+
qs: { context },
13+
};
14+
15+
return sendHttpRequest(userOptions);
16+
};
17+
18+
/**
19+
* codefresh repo (aka "service")
20+
* */
21+
const deleteRepo = async (name, context) => {
22+
const userOptions = {
23+
url: `/api/services/${encodeURIComponent(name)}`,
24+
method: 'delete',
25+
qs: { context },
26+
};
27+
return sendHttpRequest(userOptions);
28+
};
29+
30+
/**
31+
* codefresh repo (aka "service")
32+
* */
33+
const getAll = async (context) => {
34+
const userOptions = {
35+
url: '/api/repos/existing',
36+
method: 'get',
37+
qs: { context, thin: '' },
38+
};
39+
40+
const response = await sendHttpRequest(userOptions);
41+
return response.map(CodefreshRepo.fromResponse);
42+
};
43+
44+
/**
45+
* codefresh repo (aka "service")
46+
* */
47+
const create = async (name, owner, repo, context) => {
48+
const body = {
49+
serviceDetails: {
50+
name,
51+
scm: {
52+
name: repo,
53+
owner: {
54+
name: owner,
55+
},
56+
},
57+
},
58+
};
59+
const userOptions = {
60+
url: '/api/services/',
61+
method: 'post',
62+
qs: { context },
63+
body,
64+
};
65+
66+
return sendHttpRequest(userOptions);
67+
};
68+
69+
/**
70+
* get available repo from git provider (github, bitbucket...)
71+
*
72+
* @throws if repo does not exist or user does not have the right permissions or if the context is not configured
73+
* */
74+
const getAvailableGitRepo = async (owner, repo, context) => {
75+
const userOptions = {
76+
url: `/api/repos/${owner}/${repo}`,
77+
method: 'get',
78+
qs: { context },
79+
};
80+
81+
return sendHttpRequest(userOptions);
82+
};
83+
84+
/**
85+
* get all available repos from git provider (github, bitbucket...)
86+
* */
87+
const getAllAvailableGitRepos = async (context) => {
88+
const userOptions = {
89+
url: '/api/repos',
90+
method: 'get',
91+
qs: { context },
92+
};
93+
94+
const response = await sendHttpRequest(userOptions);
95+
return response.map(GitRepo.fromResponse);
96+
};
97+
98+
99+
module.exports = {
100+
create,
101+
getAvailableGitRepo,
102+
get,
103+
getAll,
104+
getAllAvailableGitRepos,
105+
deleteRepo,
106+
};

lib/logic/entities/CodefreshRepo.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const Entity = require('./Entity');
2+
3+
class CodefreshRepo extends Entity {
4+
constructor(data) {
5+
super();
6+
this.entityType = 'codefresh-repo';
7+
this.info = data;
8+
this.defaultColumns = ['git_context', 'owner', 'name', 'name_id'];
9+
this.wideColumns = this.defaultColumns.concat([]);
10+
}
11+
12+
static fromResponse(response) {
13+
const data = Object.assign({}, response);
14+
data.name_id = response.serviceName;
15+
data.git_context = response.provider;
16+
data.owner = response.owner.login;
17+
data.repo_shortcut = `${data.owner}/${data.name}`;
18+
return new CodefreshRepo(data);
19+
}
20+
}
21+
22+
module.exports = CodefreshRepo;

lib/logic/entities/GitRepo.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const Entity = require('./Entity');
2+
3+
class GitRepo extends Entity {
4+
constructor(data) {
5+
super();
6+
this.entityType = 'git-repo';
7+
this.info = data;
8+
this.defaultColumns = ['git_context', 'owner', 'name', 'repo_shortcut'];
9+
this.wideColumns = this.defaultColumns.concat(['private', 'ssh_url']);
10+
}
11+
12+
static fromResponse(response) {
13+
const data = Object.assign({}, response);
14+
data.git_context = response.provider;
15+
data.owner = response.owner.login;
16+
data.repo_shortcut = `${data.owner}/${data.name}`;
17+
return new GitRepo(data);
18+
}
19+
}
20+
21+
module.exports = GitRepo;

0 commit comments

Comments
 (0)