From d5cdd86d2bd90604d1f47fe1fb1da089dc7b0107 Mon Sep 17 00:00:00 2001 From: Erich Behrens Date: Sat, 31 Mar 2018 12:55:17 +0200 Subject: [PATCH 1/5] Handle network errors --- package.json | 2 +- src/extension.js | 40 +++++++++++++++++++++++++++++++--------- src/requests.js | 39 +++++++++++++++++++++++++-------------- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 423f8e6..660278b 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "GitHub Pull Request Monitor", "description": "Monitors the status of GitHub pull requests. Checks for conflicts, status reports, reviews and whether the branch is up to date.", "icon": "icon.png", - "version": "1.4.0", + "version": "1.5.0", "publisher": "erichbehrens", "author": "Erich Behrens ", "license": "MIT", diff --git a/src/extension.js b/src/extension.js index 5bd61f9..a7832ce 100644 --- a/src/extension.js +++ b/src/extension.js @@ -22,14 +22,29 @@ function createStatusBarItem(context, prId, url) { statusBarItems[prId] = statusBarItem; } -async function getPullRequests(context) { +let pullRequests = []; +let refreshButton; + +async function getPullRequests(context, showError) { clearTimeout(timer); + let overrideRefreshInterval; try { const mode = context.globalState.get('mode', MODES.VIEWER); const repository = context.globalState.get('currentRepository'); const showMerged = vscode.workspace.getConfiguration('pullRequestMonitor').get('showMerged'); const showClosed = vscode.workspace.getConfiguration('pullRequestMonitor').get('showClosed'); - const pullRequests = await loadPullRequests(context.globalState.get('token'), { mode, showMerged, showClosed, repository }); + const updatedPullRequests = await loadPullRequests(context.globalState.get('token'), { mode, showMerged, showClosed, repository, showError }); + if (!updatedPullRequests) { + refreshButton.command = 'PullRequestMonitor.refresh.showError'; + refreshButton.text = '$(zap)'; + refreshButton.tooltip = 'Connect Pull Request Monitor'; + overrideRefreshInterval = 15; + } else { + refreshButton.command = 'PullRequestMonitor.refresh'; + refreshButton.text = '$(sync)'; + refreshButton.tooltip = 'Refresh Pull Request Monitor'; + pullRequests = updatedPullRequests; + } if (!statusBarItems) { statusBarItems = {}; } else { @@ -73,7 +88,7 @@ async function getPullRequests(context) { vscode.window.showErrorMessage('Pull Request Monitor error rendering'); } // we store the interval in seconds and prevent the users to set a value lower than 15s - const userRefreshInterval = Number.parseInt(vscode.workspace.getConfiguration('pullRequestMonitor').get('refreshInterval'), 10); + const userRefreshInterval = overrideRefreshInterval || Number.parseInt(vscode.workspace.getConfiguration('pullRequestMonitor').get('refreshInterval'), 10); const refreshInterval = userRefreshInterval >= 15 ? userRefreshInterval : 60; if (!refreshInterval) return; timer = setTimeout(() => getPullRequests(context), refreshInterval * 1000); @@ -93,12 +108,12 @@ function setRepository(context, nameWithOwner) { } function activate(context) { - const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right); - statusBarItem.command = 'PullRequestMonitor.refresh'; - statusBarItem.text = '$(sync)'; - statusBarItem.tooltip = 'Refresh Pull Request Monitor'; - statusBarItem.show(); - context.subscriptions.push(statusBarItem); + refreshButton = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right); + refreshButton.command = 'PullRequestMonitor.refresh'; + refreshButton.text = '$(sync)'; + refreshButton.tooltip = 'Refresh Pull Request Monitor'; + refreshButton.show(); + context.subscriptions.push(refreshButton); let disposable = vscode.commands.registerCommand('PullRequestMonitor.start', (options = {}) => { const { silent } = options; @@ -122,6 +137,13 @@ function activate(context) { context.subscriptions.push(disposable); + disposable = vscode.commands.registerCommand('PullRequestMonitor.refresh.showError', () => { + getPullRequests(context, true); + vscode.window.showInformationMessage('Pull Request Monitor refreshing'); + }); + + context.subscriptions.push(disposable); + disposable = vscode.commands.registerCommand('PullRequestMonitor.setMode', async () => { const selectedMode = await vscode.window.showQuickPick([MODES.REPOSITORY, MODES.VIEWER], { placeHolder: 'Please select the mode' }); if (selectedMode && context.globalState.get('mode') !== selectedMode) { diff --git a/src/requests.js b/src/requests.js index 763b249..bd09d2e 100644 --- a/src/requests.js +++ b/src/requests.js @@ -3,7 +3,12 @@ const fetch = require('isomorphic-fetch'); const queries = require('./queries'); const { getStatesFilter } = require('./utils'); -async function execQuery(token, query) { +let errorCount = 0; + +async function execQuery(token, query, showError) { + if (showError) { + errorCount = 0; + } if (!token) { window.showWarningMessage('Pull Request Monitor needs a token'); return; @@ -18,23 +23,29 @@ async function execQuery(token, query) { return data; } catch (e) { console.error(e); // eslint-disable-line no-console - window.showErrorMessage('Pull Request Monitor error fetching data'); + if (!showError) { + errorCount += 1; + } + if (showError || errorCount === 2) { + window.showErrorMessage('Pull Request Monitor error fetching data'); + } } } -exports.loadPullRequests = async (token, { mode, showMerged, showClosed, repository }) => { - let query = queries[mode].replace('@states', getStatesFilter(showMerged, showClosed)); - if (mode === 'repository') { - if (!repository) { - window.showWarningMessage('Pull Request Monitor needs a repository to watch'); - return; +exports.loadPullRequests = + async (token, { mode, showMerged, showClosed, repository, showError }) => { + let query = queries[mode].replace('@states', getStatesFilter(showMerged, showClosed)); + if (mode === 'repository') { + if (!repository) { + window.showWarningMessage('Pull Request Monitor needs a repository to watch'); + return; + } + query = query.replace('@owner', repository.owner).replace('@name', repository.name); } - query = query.replace('@owner', repository.owner).replace('@name', repository.name); - } - const data = await execQuery(token, query); - const pullRequests = data[mode].pullRequests.nodes; - return pullRequests; -}; + const data = await execQuery(token, query, showError); + const pullRequests = data && data[mode].pullRequests.nodes; + return pullRequests; + }; exports.loadRepositories = async (token) => { const data = await execQuery(token, queries.repositories); From 83ba9b228dd7b5a664a65c4bd008ad16e2ae7c55 Mon Sep 17 00:00:00 2001 From: Erich Behrens Date: Sat, 31 Mar 2018 12:56:07 +0200 Subject: [PATCH 2/5] Update tests --- test/extension.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/extension.test.js b/test/extension.test.js index 21b1ec3..773daf3 100644 --- a/test/extension.test.js +++ b/test/extension.test.js @@ -17,6 +17,7 @@ suite('Extension Tests', () => { 'PullRequestMonitor.start', 'PullRequestMonitor.stop', 'PullRequestMonitor.refresh', + 'PullRequestMonitor.refresh.showError', 'PullRequestMonitor.setMode', 'PullRequestMonitor.selectRepository', 'PullRequestMonitor.enterRepositoryName', From d459ec45dfbcdd8ba5e28b6260b71b60838f00da Mon Sep 17 00:00:00 2001 From: Erich Behrens Date: Sat, 31 Mar 2018 14:55:02 +0200 Subject: [PATCH 3/5] Handle invalid/expired token --- src/extension.js | 9 +++++++-- src/requests.js | 17 ++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/extension.js b/src/extension.js index a7832ce..c09f0fc 100644 --- a/src/extension.js +++ b/src/extension.js @@ -34,7 +34,12 @@ async function getPullRequests(context, showError) { const showMerged = vscode.workspace.getConfiguration('pullRequestMonitor').get('showMerged'); const showClosed = vscode.workspace.getConfiguration('pullRequestMonitor').get('showClosed'); const updatedPullRequests = await loadPullRequests(context.globalState.get('token'), { mode, showMerged, showClosed, repository, showError }); - if (!updatedPullRequests) { + if (updatedPullRequests.code === 401) { + refreshButton.command = 'PullRequestMonitor.setToken'; + refreshButton.text = '$(key)'; + refreshButton.tooltip = 'Set GitHub token for Pull Request Monitor'; + return; + } else if (updatedPullRequests.status === 'error') { refreshButton.command = 'PullRequestMonitor.refresh.showError'; refreshButton.text = '$(zap)'; refreshButton.tooltip = 'Connect Pull Request Monitor'; @@ -43,7 +48,7 @@ async function getPullRequests(context, showError) { refreshButton.command = 'PullRequestMonitor.refresh'; refreshButton.text = '$(sync)'; refreshButton.tooltip = 'Refresh Pull Request Monitor'; - pullRequests = updatedPullRequests; + pullRequests = updatedPullRequests.data; } if (!statusBarItems) { statusBarItems = {}; diff --git a/src/requests.js b/src/requests.js index bd09d2e..2a28b54 100644 --- a/src/requests.js +++ b/src/requests.js @@ -19,8 +19,14 @@ async function execQuery(token, query, showError) { headers: { Authorization: `bearer ${token}` }, body: JSON.stringify({ query }), }); - const { data } = await res.json(); - return data; + if (res.status === 200) { + const { data } = await res.json(); + return { status: 'ok', data }; + } + if (res.status === 401 || res.status === 403) { + window.showErrorMessage('Pull Request Monitor token not authorized'); + return { status: 'error', code: 401 }; + } } catch (e) { console.error(e); // eslint-disable-line no-console if (!showError) { @@ -29,6 +35,7 @@ async function execQuery(token, query, showError) { if (showError || errorCount === 2) { window.showErrorMessage('Pull Request Monitor error fetching data'); } + return { status: 'error' }; } } @@ -38,13 +45,13 @@ exports.loadPullRequests = if (mode === 'repository') { if (!repository) { window.showWarningMessage('Pull Request Monitor needs a repository to watch'); - return; + return { status: 'error' }; } query = query.replace('@owner', repository.owner).replace('@name', repository.name); } - const data = await execQuery(token, query, showError); + const { status, code, data } = await execQuery(token, query, showError); const pullRequests = data && data[mode].pullRequests.nodes; - return pullRequests; + return { status, code, data: pullRequests }; }; exports.loadRepositories = async (token) => { From 6274fd1002a0ea3f7223ba159b00f7aaeff7b2d5 Mon Sep 17 00:00:00 2001 From: Erich Behrens Date: Sat, 31 Mar 2018 14:57:22 +0200 Subject: [PATCH 4/5] Lint readme --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7de2f34..f4d48d8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # GitHub Pull Request Monitor + [![Travis](https://img.shields.io/travis/erichbehrens/pull-request-monitor.svg)](https://travis-ci.org/erichbehrens/pull-request-monitor) [![Marketplace Version](https://vsmarketplacebadge.apphb.com/version/erichbehrens.pull-request-monitor.svg)](https://marketplace.visualstudio.com/items?itemName=erichbehrens.pull-request-monitor) [![Installs](https://vsmarketplacebadge.apphb.com/installs/erichbehrens.pull-request-monitor.svg)](https://marketplace.visualstudio.com/items?itemName=erichbehrens.pull-request-monitor) - This extension uses the GitHub api to monitor the state of your pull requests and let you know when it's time to merge or if someone requested changes. ![Statusbar items](images/statusBarItems.png) @@ -18,6 +18,7 @@ Source code on GitHub: https://github.com/erichbehrens/pull-request-monitor - Colors and icons to identify pull requests that require attention ### Colors + ![color green](images/color-green.png) **Green**: there are no conflicts, build is passing (if any), reviews are approved (if any) ![color red](images/color-red.png) **Red**: opposite of green or pull request closed @@ -27,7 +28,9 @@ Source code on GitHub: https://github.com/erichbehrens/pull-request-monitor ![color violet](images/color-violet.png) **Violet**: merged ### Icons + Note: white icons can become green or red depending on the pull request state. + #### State ![icon](images/icon-state-open.png) Open @@ -43,6 +46,7 @@ Note: white icons can become green or red depending on the pull request state. ![icon](images/icon-build-ko.png) Build fails #### Branch + ![icon](images/icon-mergeable-ok.png) Mergeable ![icon](images/icon-mergeable-ko.png) Conflicts @@ -50,6 +54,7 @@ Note: white icons can become green or red depending on the pull request state. ![icon](images/icon-mergeable-unknown.png) Unknown mergeable state #### Reviews + ![icon](images/icon-reviews-ok.png) Approved reviews ![icon](images/icon-reviews-ko.png) Changes requested @@ -84,7 +89,7 @@ Note: white icons can become green or red depending on the pull request state. - `PullRequestMonitor.selectRepository`: select the repository to monitor through the list of your repositories (some private repositories will not appear here, in this case use `PullRequestMonitor.enterRepositoryName` ) -- `PullRequestMonitor.enterRepositoryName`: set the private repository name you want to monitor. Something like `your-team-nam/awesome-project` +- `PullRequestMonitor.enterRepositoryName`: set the private repository name you want to monitor. Something like `your-team-name/awesome-project` ## Extension configuration @@ -97,6 +102,7 @@ Note: white icons can become green or red depending on the pull request state. - `pullRequestMonitor.autostart` `boolean`, automatically start the extension ### Default configuration + ```json { "pullRequestMonitor.refreshInterval": 60, @@ -105,10 +111,3 @@ Note: white icons can become green or red depending on the pull request state. "pullRequestMonitor.autostart": true, } ``` -## Known Issues - -Please report any bugs here: https://github.com/erichbehrens/pull-request-monitor/issues - - - - From 132b03b14467703cc40e26756a04e2ffcfe046f6 Mon Sep 17 00:00:00 2001 From: Erich Behrens Date: Sat, 31 Mar 2018 15:02:29 +0200 Subject: [PATCH 5/5] Update changelog --- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fefc3f4..a9bf3f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,38 @@ # Change Log +## v1.5.1 + +- Improved network and auth error handling + ## v1.4.0 + - Autostart extension with VS Code ## v1.3.1 + - Update readme with icons ## v1.3.0 + - Add configuration for refresh interval and to show/hide closed/merged pull requests - Major code cleanup ## v1.2.0 + - Changed name to *GitHub Pull Request Monitor* - Use more distinguishable icons for failing tests and conflicts - Show icon for comments - Improve showing icons for `approved` and `change requested` ## v1.1.0 + - Save user settings - Rename `setRepository` command to `enterRepositoryName` ## v1.0.4 + - Use `isomorphic-fetch` to support systems other than Windows ## v1.0.0 + - Initial release diff --git a/package.json b/package.json index 660278b..0016576 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "GitHub Pull Request Monitor", "description": "Monitors the status of GitHub pull requests. Checks for conflicts, status reports, reviews and whether the branch is up to date.", "icon": "icon.png", - "version": "1.5.0", + "version": "1.5.1", "publisher": "erichbehrens", "author": "Erich Behrens ", "license": "MIT",