Skip to content

Commit

Permalink
feat: refactor cli to be a package
Browse files Browse the repository at this point in the history
  • Loading branch information
msagi committed Mar 23, 2024
1 parent 2ae9571 commit 9c39dcc
Show file tree
Hide file tree
Showing 10 changed files with 1,240 additions and 692 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ jobs:
run: npm i

- name: Code Linting
run: npm run lint
run: |
npm run lint
npm run lint --workspaces
1,704 changes: 1,036 additions & 668 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"lint": "eslint --fix . --ext .js,.jsx",
"gen-schema-doc": "node ./scripts/doc-schema.js"
},
"workspaces": [
"./packages/git-proxy-cli"
],
"bin": "./index.js",
"author": "Paul Groves",
"license": "Apache-2.0",
Expand Down
52 changes: 35 additions & 17 deletions src/cli/git-proxy-cli.js → packages/git-proxy-cli/index.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
#!/usr/bin/env node
const axios = require('axios');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const fs = require('fs');

// Git-Proxy UI URL (configurable via environment variable)
const { GIT_PROXY_UI_URL = 'http://localhost:8080' } = process.env;
// Git-Proxy UI HOST and PORT (configurable via environment variable)
const { GIT_PROXY_UI_HOST: uiHost = 'http://localhost' } = process.env;
const { GIT_PROXY_UI_PORT: uiPort } =
require('@finos/git-proxy/src/config/env').Vars;
const GIT_PROXY_UI_URL = `${uiHost}:${uiPort}`;
const GIT_PROXY_COOKIE_FILE = 'git-proxy-cookie';

// Set default timeout to 5 seconds
axios.defaults.timeout = 5000;

/**
* Function to login to Git Proxy
* Log in to Git Proxy
* @param {*} username The user name to login with
* @param {*} password The password to use for the login
*/
async function login(username, password) {
try {
const response = await axios.post(
let response = await axios.post(
`${GIT_PROXY_UI_URL}/auth/login`,
{
username,
Expand All @@ -25,31 +32,38 @@ async function login(username, password) {
withCredentials: true,
},
);
const cookies = response.headers['set-cookie'];

fs.writeFileSync(
GIT_PROXY_COOKIE_FILE,
JSON.stringify(response.headers['set-cookie']),
'utf8',
);
console.log(`Auth '${username}': OK`);
response = await axios.get(`${GIT_PROXY_UI_URL}/auth/profile`, {
headers: { Cookie: cookies },
withCredentials: true,
});

fs.writeFileSync(GIT_PROXY_COOKIE_FILE, JSON.stringify(cookies), 'utf8');

const user = `"${response.data.username}" <${response.data.email}>`;
const isAdmin = response.data.admin ? ' (admin)' : '';
console.log(`Login ${user}${isAdmin}: OK`);
} catch (error) {
if (error.response) {
console.error(`Error: Auth '${username}': '${error.response.status}'`);
console.error(`Error: Login '${username}': '${error.response.status}'`);
process.exitCode = 2;
} else {
console.error(`Error: Auth '${username}': '${error.message}'`);
console.error(`Error: Login '${username}': '${error.message}'`);
process.exitCode = 1;
}
process.exit(1);
}
}

/**
* Function to approve commit
* Approve commit by ID
* @param {*} commitId The ID of the commit to approve
*/
async function approveCommit(commitId) {
if (!fs.existsSync(GIT_PROXY_COOKIE_FILE)) {
console.error('Error: Authentication required');
process.exit(1);
process.exitCode = 1;
return;
}

try {
Expand All @@ -72,20 +86,23 @@ async function approveCommit(commitId) {
if (error.response) {
if (error.response.status == 401) {
console.log(`Approve: Authentication required`);
process.exitCode = 2;
} else if (error.response.status == 404) {
console.log(`Approve: ID: '${commitId}': Not Found`);
process.exitCode = 3;
} else {
console.error(`Error: Approve: '${error.response.status}'`);
process.exitCode = 4;
}
} else {
console.error(`Error: Approve: '${error.message}'`);
process.exitCode = 1;
}
process.exit(1);
}
}

/**
* Function to log out
* Log out (and clean up)
*/
async function logout() {
try {
Expand All @@ -96,6 +113,7 @@ async function logout() {
console.log('Logout: OK');
} catch (error) {
console.error(`Error: Logout: ${error.message}`);
process.exitCode = 1;
}
}

Expand Down
21 changes: 21 additions & 0 deletions packages/git-proxy-cli/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@finos/git-proxy-cli",
"version": "1.0.0",
"description": "Command line interface tool for FINOS Git Proxy.",
"bin": "./index.js",
"main": "index.js",
"dependencies": {
"axios": "^1.6.0",
"yargs": "^17.7.2",
"@finos/git-proxy": "file:../.."
},
"devDependencies": {
"@jsdevtools/chai-exec": "^2.1.1"
},
"scripts": {
"lint": "eslint --fix . --ext .js,.jsx",
"test": "mocha --exit"
},
"author": "Miklos Sagi",
"license": "Apache-2.0"
}
57 changes: 57 additions & 0 deletions packages/git-proxy-cli/test/testCli.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Import the dependencies for testing
const chaiExec = require("@jsdevtools/chai-exec");
const chai = require('chai');
const service = require('../../../src/service');
const util = require("util")

chai.use(chaiExec);
const expect = chai.expect;

chaiExec.defaults = {
options: {
timeout: 10000 // fail test case if server hangs
}
};

describe('test git-proxy-cli', async () => {
let app;

before(async function () {
// app = await service.start();
// console.log("");
});

describe('test git-proxy-cli :: login', async function () {
it('login shoud fail with invalid credentials', async function () {
let username = "unkn0wn"
let password = "p4ssw0rd"
let cli = chaiExec(`npx -- @finos/git-proxy-cli login --username ${username} --password ${password}`);
expect(cli).to.exit.with.code(2);
});
it('login shoud be successful with valid (default) admin credentials', async function () {
let username = "admin"
let password = "admin"
let cli = chaiExec(`npx -- @finos/git-proxy-cli login --username ${username} --password ${password}`);
expect(cli).to.exit.with.code(0);
});
});

describe('test git-proxy-cli :: approve commit', async function () {
it('attempt to approve non-existing commit should return exit code 3', async function () {
let commitId =
'0000000000000000000000000000000000000000__79b4d8953cbc324bcc1eb53d6412ff89666c241f'; // eslint-disable-line max-len
cli = chaiExec(`npx -- @finos/git-proxy-cli approve --commitId ${commitId}`);
expect(cli).to.exit.with.code(3);
});
});

describe('test git-proxy-cli :: logout', async function () {
it('attempt to log out should be successful', async function () {
cli = chaiExec(`npx -- @finos/git-proxy-cli logout`);
expect(cli).to.exit.with.code(0);
});
});
after(async function () {
// await service.httpServer.close();
});
});
56 changes: 56 additions & 0 deletions test/testPush.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Import the dependencies for testing
const chai = require('chai');
const chaiHttp = require('chai-http');
const db = require('../src/db');
const service = require('../src/service');

chai.use(chaiHttp);
chai.should();
const expect = chai.expect;

describe('auth', async () => {
let app;
let cookie;

before(async function () {
app = await service.start();
await db.deleteUser('login-test-user');

const res = await chai.request(app).post('/auth/login').send({
username: 'admin',
password: 'admin',
});

expect(res).to.have.cookie('connect.sid');
res.should.have.status(200);

// Get the connect cooie
res.headers['set-cookie'].forEach((x) => {
if (x.startsWith('connect')) {
cookie = x.split(';')[0];
}
});
});

describe('test push API', async function () {
it('should get 404 for unknown push', async function () {
const commitId =
'0000000000000000000000000000000000000000__79b4d8953cbc324bcc1eb53d6412ff89666c241f'; // eslint-disable-line max-len
const res = await chai
.request(app)
.get(`/api/v1/push/${commitId}`)
.set('Cookie', `${cookie}`);
res.should.have.status(404);
});
});

after(async function () {
const res = await chai
.request(app)
.post('/auth/logout')
.set('Cookie', `${cookie}`);
res.should.have.status(200);

await service.httpServer.close();
});
});
14 changes: 13 additions & 1 deletion website/docs/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,26 @@ description: How to install Git Proxy in your environment

To install Git Proxy, you must first install [Node.js](https://nodejs.org/en/download). Then, use the [npm package manager](https://www.npmjs.com/):

To install Git Proxy
```bash
npm install -g @finos/git-proxy
```

To install Git Proxy Command Line Tool (CLI)
```bash
npm install -g @finos/git-proxy-cli
```

### Install a specific version

To install a specific version of Git Proxy, append the version to the end of the install command:

```bash
npm install -g @finos/git-proxy@1.1.0
```
```

To install a specific version of Git Proxy CLI, append the version to the end of the install command:

```bash
npm install -g @finos/git-proxy-cli@1.0.0
```
8 changes: 4 additions & 4 deletions website/docs/quickstart/approve.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
### Prerequisites

- Proxy and REST API are running ([default behaviour](https://github.com/finos/git-proxy/blob/main/index.js))
- The Git Proxy URL is configured via the GIT_PROXY_UI_URL environment variable (defaults to `http://localhost:8080`). Note: this documentation assumes that Git Proxy UI is running on `http://git-proxy.com:8080`.
- The Git Proxy URL is configured via the GIT_PROXY_UI_HOST (defaults to `http://localhost`) and GIT_PROXY_UI_PORT (defaults to `8080`) environment variables. Note: this documentation assumes that Git Proxy UI is running on `http://git-proxy.com:8080`.
- [Intercepting a push](/docs/quickstart/intercept) instructions have been followed and you've reached [Push via Git Proxy](/docs/quickstart/intercept#push-via-git-proxy)

### Instructions
Expand All @@ -103,7 +103,7 @@ The `ID` for your push corresponds to the last part of the URL:
Use the default & auto-generated Git Proxy username & password credentials to authenticate and obtain a cookie. The cookie value is saved to a file (`git-proxy-cookie`):

```bash
$ npm run-script cli -- login --username admin --password admin
$ npx -- @finos/git-proxy-cli login --username admin --password admin
Git-Proxy URL: http://git-proxy.com:8080
Auth 'admin': OK
```
Expand All @@ -113,7 +113,7 @@ Auth 'admin': OK
Use the commit `ID` to approve your push with the CLI:

```bash
$ npm run-script cli -- approve --commitId 0000000000000000000000000000000000000000__79b4d8953cbc324bcc1eb53d6412ff89666c241f
$ npx -- @finos/git-proxy-cli approve --commitId 0000000000000000000000000000000000000000__79b4d8953cbc324bcc1eb53d6412ff89666c241f
Git-Proxy URL: http://git-proxy.com:8080
Approve: ID: '0000000000000000000000000000000000000000__79b4d8953cbc324bcc1eb53d6412ff89666c241f': OK
```
Expand All @@ -138,7 +138,7 @@ remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
Clean up your connect cookie via logging out:

```bash
$ npm run-script cli -- logout
$ npx -- @finos/git-proxy-cli logout
Git-Proxy URL: http://git-proxy.com:8080
Logout: OK
```
Expand Down
13 changes: 12 additions & 1 deletion website/docs/usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,26 @@ description: How to run Git Proxy in your environment

Once you have followed the [installation](installation) steps, run:

To run Git Proxy
```bash
git-proxy
```

To run Git Proxy CLI
```bash
git-proxy-cli
```

### Using [npx instead of npm](https://www.freecodecamp.org/news/npm-vs-npx-whats-the-difference/)

You can also install & run `git-proxy` in one step:
You can also install & run `git-proxy` and `git-proxy-cli` in one step:

Git Proxy
```bash
npx -- @finos/git-proxy
```

Git Proxy CLI
```bash
npx -- @finos/git-proxy-cli
```

0 comments on commit 9c39dcc

Please sign in to comment.