Skip to content

Commit

Permalink
Add getCommitSha, getFile, get Permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
d2lam committed Oct 18, 2016
1 parent 4d3549e commit a0a5023
Show file tree
Hide file tree
Showing 3 changed files with 486 additions and 23 deletions.
61 changes: 59 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Decorated commit in the form of:
```

#### Expected Promise response
1. Resolve with a decorate commit object for the repository
1. Resolve with a decorated commit object for the repository
2. Reject if not able to decorate commit

### decorateAuthor
Expand All @@ -118,9 +118,66 @@ Decorated author in the form of:
```

#### Expected Promise response
1. Resolve with a decorate author object for the repository
1. Resolve with a decorated author object for the repository
2. Reject if not able to decorate author

### getPermissions
Required parameters:

| Parameter | Type | Description |
| :------------- | :---- | :-------------|
| config | Object | Configuration Object |
| config.scmUri | String | The scm uri to get permissions on (ex: `bitbucket.org:batman/{1234}:branchName`) |
| config.token | String | Access token for scm |

#### Expected Outcome
Permissions for a given token on a repository in the form of:
```js
{
admin: true,
push: true,
pull: true
}
```

#### Expected Promise response
1. Resolve with a permissions object for the repository
2. Reject if not able to get permissions

### getCommitSha
Required parameters:

| Parameter | Type | Description |
| :------------- | :---- | :-------------|
| config | Object | Configuration Object |
| config.scmUri | String | The scm uri (ex: `bitbucket.orgin:batman/{1234}:branchName`) |
| config.token | String | Access token for scm |

#### Expected Outcome
The commit sha for a given branch on a repository.

#### Expected Promise response
1. Resolve with a commit sha string for the given `scmUri`
2. Reject if not able to get a sha

### getFile
The parameters required are:

| Parameter | Type | Required | Description |
| :------------- | :---- | :------- | :-------------|
| config | Object | true | Configuration Object |
| config.scmUri | String | true | The scm uri (ex: `bitbucket.org:batman/{1234}:branchName`) |
| config.token | String | true | Access token for scm |
| config.path | String | true | The path to the file on scm to read. For example: `screwdriver.yaml` |
| config.ref | String | false | The reference to the scm repo, could be a branch or sha |

#### Expected Outcome
The contents of the file at `path` in the repository

#### Expected Promise Response
1. Resolve with the contents of `path`
2. Reject if the `path` cannot be downloaded, decoded, or is not a file

## Testing

```bash
Expand Down
147 changes: 126 additions & 21 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ const hoek = require('hoek');
const url = require('url');
const request = require('request');
const schema = require('screwdriver-data-schema');
const API_URL = 'https://api.bitbucket.org/2.0';
const API_URL_V1 = 'https://api.bitbucket.org/1.0';
const API_URL_V2 = 'https://api.bitbucket.org/2.0';
const REPO_URL = `${API_URL_V2}/repositories`;
const USER_URL = `${API_URL_V2}/users`;
const MATCH_COMPONENT_HOSTNAME = 1;
const MATCH_COMPONENT_USER = 2;
const MATCH_COMPONENT_REPO = 3;
Expand All @@ -16,21 +19,22 @@ const MATCH_COMPONENT_BRANCH = 4;
* Get repo information
* @method getRepoInfo
* @param {String} checkoutUrl The url to check out repo
* @return {Object} An object with host, repo, branch, and username
* @return {Object} An object with hostname, repo, branch, and username
*/
function getRepoInfo(checkoutUrl) {
const regex = schema.config.regex.CHECKOUT_URL;
const matched = regex.exec(checkoutUrl);

return {
hostname: matched[MATCH_COMPONENT_HOSTNAME],
username: matched[MATCH_COMPONENT_USER],
repo: matched[MATCH_COMPONENT_REPO],
branch: matched[MATCH_COMPONENT_BRANCH].slice(1)
branch: matched[MATCH_COMPONENT_BRANCH].slice(1),
username: matched[MATCH_COMPONENT_USER]
};
}

/**
* Get hostname, repoId, and branch from scmUri
* @method getScmUriParts
* @param {String} scmUri
* @return {Object}
Expand Down Expand Up @@ -61,16 +65,16 @@ class BitbucketScm extends Scm {
* Parse the url for a repo for the specific source control
* @method parseUrl
* @param {Object} config
* @param {String} config.checkoutUrl Url to parse
* @param {String} config.token The token used to authenticate to the SCM
* @return {Promise}
* @param {String} config.checkoutUrl Url to parse
* @param {String} config.token The token used to authenticate to the SCM
* @return {Promise} Resolves to scmUri
*/
_parseUrl(config) {
const repoInfo = getRepoInfo(config.checkoutUrl);
const getBranchUrl = `${API_URL}/repositories/${repoInfo.username}/${repoInfo.repo}` +
const branchUrl = `${REPO_URL}/${repoInfo.username}/${repoInfo.repo}` +
`/refs/branches/${repoInfo.branch}?access_key=${config.token}`;
const options = {
url: getBranchUrl,
url: branchUrl,
method: 'GET'
};

Expand Down Expand Up @@ -148,11 +152,11 @@ class BitbucketScm extends Scm {
* @param {Object} config Configuration object
* @param {Object} config.token Access token to authenticate with Bitbucket
* @param {Object} config.username Username to query more information for
* @return {Promise}
* @return {Promise} Resolves to a decorated author with url, name, username, avatar
*/
_decorateAuthor(config) {
const options = {
url: `${API_URL}/users/${config.username}?access_key=${config.token}`,
url: `${USER_URL}/${config.username}?access_key=${config.token}`,
method: 'GET'
};

Expand Down Expand Up @@ -181,12 +185,12 @@ class BitbucketScm extends Scm {
* @param {Config} config Configuration object
* @param {String} config.scmUri The SCM URI the commit belongs to
* @param {String} config.token Service token to authenticate with Github
* @return {Object}
* @return {Object} Resolves to a decoratedUrl with url, name, and branch
*/
_decorateUrl(config) {
const scm = getScmUriParts(config.scmUri);
const options = {
url: `${API_URL}/repositories/${scm.repoId}?access_key=${config.token}`,
url: `${REPO_URL}/${scm.repoId}?access_key=${config.token}`,
method: 'GET'
};

Expand All @@ -209,17 +213,16 @@ class BitbucketScm extends Scm {
/**
* Decorate the commit based on the repository
* @method _decorateCommit
* @param {Object} config Configuration object
* @param {Object} config.sha Commit sha to decorate
* @param {Object} config.scmUri SCM URI the commit belongs to
* @param {Object} config.token Service token to authenticate with Github
* @return {Promise}
* @param {Object} config Configuration object
* @param {Object} config.sha Commit sha to decorate
* @param {Object} config.scmUri SCM URI the commit belongs to
* @param {Object} config.token Service token to authenticate with Github
* @return {Promise} Resolves to a decorated object with url, message, and author
*/
_decorateCommit(config) {
const scm = getScmUriParts(config.scmUri);
const options = {
url: `${API_URL}/repositories/${scm.repoId}` +
`/commit/${config.sha}?access_key=${config.token}`,
url: `${REPO_URL}/${scm.repoId}/commit/${config.sha}?access_key=${config.token}`,
method: 'GET'
};

Expand All @@ -244,7 +247,109 @@ class BitbucketScm extends Scm {
}

/**
* Retreive stats for the scm
* Get a commit sha for a specific repo#branch
* @method getCommitSha
* @param {Object} config Configuration
* @param {String} config.scmUri The scmUri to get commit sha of
* @param {String} config.token The token used to authenticate to the SCM
* @return {Promise} Resolves to the sha for the scmUri
*/
_getCommitSha(config) {
const scm = getScmUriParts(config.scmUri);
const branchUrl =
`${REPO_URL}/${scm.repoId}/refs/branches/${scm.branch}?access_key=${config.token}`;
const options = {
url: branchUrl,
method: 'GET'
};

return this.breaker.runCommand(options)
.then((response) => {
if (response.statusCode !== 200) {
throw new Error(`STATUS CODE ${response.statusCode}: ${response.body}`);
}

return response.body.target.hash;
});
}

/**
* Fetch content of a file from Bitbucket
* @method getFile
* @param {Object} config Configuration
* @param {String} config.scmUri The scmUri to get permissions on
* @param {String} config.path The file in the repo to fetch
* @param {String} config.token The token used to authenticate to the SCM
* @param {String} config.ref The reference to the SCM, either branch or sha
* @return {Promise} Resolves to the content of the file
*/
_getFile(config) {
const scm = getScmUriParts(config.scmUri);
const fileUrl = `${API_URL_V1}/repositories/${scm.repoId}` +
`/src/${config.ref}/${config.path}?access_key=${config.token}`;
const options = {
url: fileUrl,
method: 'GET'
};

return this.breaker.runCommand(options)
.then((response) => {
if (response.statusCode !== 200) {
throw new Error(`STATUS CODE ${response.statusCode}: ${response.body}`);
}

return response.body.data;
});
}

/**
* Get a user's permissions on a repository
* @method _getPermissions
* @param {Object} config Configuration
* @param {String} config.scmUri The scmUri to get permissions on
* @param {String} config.token The token used to authenticate to the SCM
* @return {Promise} Resolves to permissions object with admin, push, pull
*/
_getPermissions(config) {
const scm = getScmUriParts(config.scmUri);
const getPerm = (repoId, desiredAccess, token) => {
const [owner, uuid] = repoId.split('/');
const options = {
url: `${API_URL_V2}/repositories/${owner}`,
method: 'GET'
};

if (desiredAccess === 'admin') {
options.url = `${options.url}?role=admin&access_key=${token}`;
} else if (desiredAccess === 'push') {
options.url = `${options.url}?role=contributor&access_key=${token}`;
} else {
options.url = `${options.url}?access_key=${token}`;
}

return this.breaker.runCommand(options)
.then((response) => {
if (response.statusCode !== 200) {
throw new Error(`STATUS CODE ${response.statusCode}: ${response.body}`);
}

return response.body.values.some(r => r.uuid === uuid);
});
};

return Promise.all([
getPerm(scm.repoId, 'admin', config.token),
getPerm(scm.repoId, 'push', config.token),
getPerm(scm.repoId, 'pull', config.token)
]).then(([admin, push, pull]) => ({
admin,
push,
pull
}));
}

/**
* Retrieve stats for the scm
* @method stats
* @param {Response} Object Object containing stats for the scm
*/
Expand Down
Loading

0 comments on commit a0a5023

Please sign in to comment.