diff --git a/.github/ranger.yml b/.github/ranger.yml index ec029b19..6cba1cce 100644 --- a/.github/ranger.yml +++ b/.github/ranger.yml @@ -15,10 +15,6 @@ labels: "squash when passing": merge "rebase when passing": merge "merge when passing": merge - stale: - action: close - delay: 7 days - comment: "⚠️ This issue has been marked stale and will automatically be closed in $DELAY." "new contributor": action: comment delay: 5s diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..945de5a3 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,12 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 180 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 5 +# Label to apply when stale. +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no activity occurs in the next 5 days. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5e0f2fec..e08c5eab 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -420,7 +420,7 @@ jobs: uses: actions/checkout@v2 - name: Run Trivy vulnerability scanner in repo mode #Commit SHA for v0.0.17 - uses: aquasecurity/trivy-action@9438b49cc3156b2e8c77c1ba8ffbaa3bae24e3c2 + uses: aquasecurity/trivy-action@8eccb5539730451af599c84f444c6d6cf0fc2bb0 with: scan-type: "fs" scan-ref: "." diff --git a/.github/workflows/docs-preview.yaml b/.github/workflows/docs-preview.yaml new file mode 100644 index 00000000..3f4ed05c --- /dev/null +++ b/.github/workflows/docs-preview.yaml @@ -0,0 +1,94 @@ +name: Docs preview + +on: + pull_request: + branches: + - main + +permissions: + actions: none + checks: none + contents: read + deployments: none + issues: none + packages: none + pull-requests: write + repository-projects: none + security-events: none + statuses: none + +jobs: + preview: + name: Docs preview + runs-on: ubuntu-20.04 + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.9.1 + + - name: Checkout m + uses: actions/checkout@v2 + with: + repository: cdr/m + ref: refs/heads/master + token: ${{ secrets.GH_ACCESS_TOKEN }} + submodules: true + fetch-depth: 0 + + - name: Install Node.js + uses: actions/setup-node@v2 + with: + node-version: 12.x + + - name: Cache Node Modules + uses: actions/cache@v2 + with: + path: "/node_modules" + key: node-${{ hashFiles('yarn.lock') }} + + - name: Create Deployment + id: deployment + run: ./ci/scripts/github_deployment.sh create + env: + GITHUB_TOKEN: ${{ github.token }} + DEPLOY_ENVIRONMENT: codercom-preview-docs + + - name: Deploy Preview to Vercel + id: preview + run: ./ci/scripts/deploy_vercel.sh + env: + VERCEL_ORG_ID: team_tGkWfhEGGelkkqUUm9nXq17r + VERCEL_PROJECT_ID: QmZRucMRh3GFk1817ZgXjRVuw5fhTspHPHKct3JNQDEPGd + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + CODE_SERVER_DOCS_MAIN_BRANCH: ${{ github.event.pull_request.head.sha }} + + - name: Install node_modules + run: yarn install + + - name: Check docs + run: yarn ts-node ./product/coder.com/site/scripts/checkDocs.ts + env: + BASE_URL: ${{ steps.preview.outputs.url }} + + - name: Update Deployment + # If we don't specify always, it won't run this check if failed. + # This means the deployment would be stuck pending. + if: always() + run: ./ci/scripts/github_deployment.sh update + env: + GITHUB_DEPLOYMENT: ${{ steps.deployment.outputs.id }} + GITHUB_TOKEN: ${{ github.token }} + DEPLOY_STATUS: ${{ steps.preview.outcome }} + DEPLOY_URL: ${{ steps.preview.outputs.url }} + + - name: Comment Credentials + uses: marocchino/sticky-pull-request-comment@v2 + if: always() + with: + header: codercom-preview-docs + message: | + ✨ Coder.com for PR #${{ github.event.number }} deployed! It will be updated on every commit. + + * _Host_: ${{ steps.preview.outputs.url }}/docs/code-server + * _Last deploy status_: ${{ steps.preview.outcome }} + * _Commit_: ${{ github.event.pull_request.head.sha }} + * _Workflow status_: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/ci/build/build-release.sh b/ci/build/build-release.sh index fe788d7c..838c6551 100755 --- a/ci/build/build-release.sh +++ b/ci/build/build-release.sh @@ -48,7 +48,7 @@ bundle_code_server() { { "commit": "$(git rev-parse HEAD)", "scripts": { - "postinstall": "./postinstall.sh" + "postinstall": "bash ./postinstall.sh" } } EOF diff --git a/ci/build/build-vscode.sh b/ci/build/build-vscode.sh index faddf46e..d2f10d2a 100755 --- a/ci/build/build-vscode.sh +++ b/ci/build/build-vscode.sh @@ -10,7 +10,7 @@ main() { cd "$(dirname "${0}")/../.." cd lib/vscode - yarn gulp compile-build compile-extensions-build + yarn gulp compile-build compile-extensions-build compile-extension-media yarn gulp optimize --gulpfile ./coder.js if [[ $MINIFY ]]; then yarn gulp minify --gulpfile ./coder.js diff --git a/ci/helm-chart/values.yaml b/ci/helm-chart/values.yaml index c95c3d97..90d3427c 100644 --- a/ci/helm-chart/values.yaml +++ b/ci/helm-chart/values.yaml @@ -57,8 +57,18 @@ ingress: # Optional additional arguments extraArgs: [] -# - --allow-http -# - --no-auth + # These are the arguments normally passed to code-server; run + # code-server --help for a list of available options. + # + # Each argument and parameter must have its own entry; if you use + # --param value on the command line, then enter it here as: + # + # - --param + # - value + # + # If you receive an error like "Unknown option --param value", it may be + # because both the parameter and value are specified as a single argument, + # rather than two separate arguments (e.g. "- --param value" on a line). # Optional additional environment variables extraVars: [] diff --git a/ci/release-image/Dockerfile b/ci/release-image/Dockerfile index 4b637014..cbd7f5d6 100644 --- a/ci/release-image/Dockerfile +++ b/ci/release-image/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:10 +FROM debian:11 RUN apt-get update \ && apt-get install -y \ diff --git a/ci/release-image/docker-bake.hcl b/ci/release-image/docker-bake.hcl index 3ef2f0b4..cb55da69 100644 --- a/ci/release-image/docker-bake.hcl +++ b/ci/release-image/docker-bake.hcl @@ -12,6 +12,9 @@ group "default" { target "code-server" { dockerfile = "ci/release-image/Dockerfile" - tags = ["docker.io/codercom/code-server:${VERSION}"] + tags = [ + "docker.io/codercom/code-server:latest", + notequal("latest",VERSION) ? "docker.io/codercom/code-server:${VERSION}" : "", + ] platforms = ["linux/amd64", "linux/arm64"] } diff --git a/ci/steps/publish-npm.sh b/ci/steps/publish-npm.sh index ea65780d..0b3d8bd0 100755 --- a/ci/steps/publish-npm.sh +++ b/ci/steps/publish-npm.sh @@ -20,6 +20,10 @@ main() { download_artifact npm-package ./release-npm-package # https://github.com/actions/upload-artifact/issues/38 tar -xzf release-npm-package/package.tar.gz + + # Ignore symlink when publishing npm package + # See: https://github.com/cdr/code-server/pull/3935 + echo "node_modules.asar" > release/.npmignore yarn publish --non-interactive release } diff --git a/docs/FAQ.md b/docs/FAQ.md index e5947acf..8ade51ce 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -29,6 +29,7 @@ - [What's the difference between code-server and VS Code Codespaces?](#whats-the-difference-between-code-server-and-vs-code-codespaces) - [Does code-server have any security login validation?](#does-code-server-have-any-security-login-validation) - [Are there community projects involving code-server?](#are-there-community-projects-involving-code-server) +- [How do I change the port?](#how-do-i-change-the-port) @@ -399,3 +400,10 @@ minute plus an additional twelve per hour. Visit the [awesome-code-server](https://github.com/cdr/awesome-code-server) repository to view community projects and guides with code-server! Feel free to add your own! + +## How do I change the port? + +There are two ways to change the port on which code-server runs: + +1. with an environment variable e.g. `PORT=3000 code-server` +2. using the flag `--bind-addr` e.g. `code-server --bind-addr localhost:3000` diff --git a/docs/MAINTAINING.md b/docs/MAINTAINING.md index 0bdfc91a..35f172c4 100644 --- a/docs/MAINTAINING.md +++ b/docs/MAINTAINING.md @@ -12,6 +12,8 @@ - [Changelog](#changelog) - [Releases](#releases) - [Publishing a release](#publishing-a-release) +- [Documentation](#documentation) + - [Troubleshooting](#troubleshooting) @@ -156,3 +158,16 @@ If you're the current release manager, follow these steps: 1. Update the AUR package. Instructions for updating the AUR package are at [cdr/code-server-aur](https://github.com/cdr/code-server-aur). 1. Wait for the npm package to be published. + +## Documentation + +### Troubleshooting + +Our docs are hosted on [Vercel](https://vercel.com/). Vercel only shows logs in realtime, which means you need to have the logs open in one tab and reproduce your error in another tab. Since our logs are private to Coder the organization, you can only follow these steps if you're a Coder employee. Ask a maintainer for help if you need it. + +Taking a real scenario, let's say you wanted to troubleshoot [this docs change](https://github.com/cdr/code-server/pull/4042). Here is how you would do it: + +1. Go to https://vercel.com/codercom/codercom +2. Click "View Function Logs" +3. In a separate tab, open the preview link from github-actions-bot +4. Now look at the function logs and see if there are errors in the logs diff --git a/docs/README.md b/docs/README.md index 04b87aaa..ee3ab1d7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -30,7 +30,7 @@ There are three ways to get started: automates most of the process. The script uses the system package manager if possible. 2. Manually [installing - code-server](https://coder.com/docs/code-server/v3.11.1/install) + code-server](https://coder.com/docs/code-server/latest/install) 3. Using our one-click buttons and guides to [deploy code-server to a cloud provider](https://github.com/cdr/deploy-code-server) ⚡ @@ -51,20 +51,20 @@ When done, the install script prints out instructions for running and starting code-server. We also have an in-depth [setup and -configuration](https://coder.com/docs/code-server/v3.11.1/guide) guide. +configuration](https://coder.com/docs/code-server/latest/guide) guide. ## TLS and authentication (beta) -To add TLS and authentication out of the box, use [code-server --link](https://coder.com/docs/code-server/v3.11.0/link). +To add TLS and authentication out of the box, use [code-server --link](https://coder.com/docs/code-server/latest/link). ## Questions? See answers to [frequently asked -questions](https://coder.com/docs/code-server/v3.11.1/FAQ). +questions](https://coder.com/docs/code-server/latest/FAQ). ## Want to help? -See [Contributing](https://coder.com/docs/code-server/v3.11.1/CONTRIBUTING) for +See [Contributing](https://coder.com/docs/code-server/latest/CONTRIBUTING) for details. ## Hiring diff --git a/docs/assets/screenshot.png b/docs/assets/screenshot.png index 77ab4611..a35720ac 100644 Binary files a/docs/assets/screenshot.png and b/docs/assets/screenshot.png differ diff --git a/docs/guide.md b/docs/guide.md index 06a77361..c60d985a 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -14,6 +14,10 @@ - [Using a subpath](#using-a-subpath) - [Stripping `/proxy/` from the request path](#stripping-proxyport-from-the-request-path) - [Proxying to create a React app](#proxying-to-create-a-react-app) + - [Proxying to a Vue app](#proxying-to-a-vue-app) +- [SSH into code-server on VS Code](#ssh-into-code-server-on-vs-code) + - [Option 1: cloudflared tunnel](#option-1-cloudflared-tunnel) + - [Option 2: ngrok tunnel](#option-2-ngrok-tunnel) @@ -33,7 +37,7 @@ testing, but it doesn't work if you want to access code-server from a different machine. > **Rate limits:** code-server rate limits password authentication attempts to -> two per minute and twelve per hour. +> two per minute plus an additional twelve per hour. There are several approaches to operating and exposing code-server securely: @@ -348,3 +352,114 @@ You should then be able to visit `https://my-code-server-address.io/absproxy/300 code-server! > We highly recommend using the subdomain approach instead to avoid this class of issue. + +### Proxying to a Vue app + +Similar to the situation with React apps, you have to make a few modifications to proxy a Vue app. + +1. add `vue.config.js` +2. update the values to match this (you can use any free port): + +```js +module.exports = { + devServer: { + port: 3454, + sockPath: "sockjs-node", + }, + publicPath: "/absproxy/3454", +} +``` + +3. access app at `/absproxy/3454` e.g. `http://localhost:8080/absproxy/3454` + +Read more about `publicPath` in the [Vue.js docs](https://cli.vuejs.org/config/#publicpath) + +## SSH into code-server on VS Code + +[![SSH](https://img.shields.io/badge/SSH-363636?style=for-the-badge&logo=GNU+Bash&logoColor=ffffff)](https://ohmyz.sh/) [![Terminal](https://img.shields.io/badge/Terminal-2E2E2E?style=for-the-badge&logo=Windows+Terminal&logoColor=ffffff)](https://img.shields.io/badge/Terminal-2E2E2E?style=for-the-badge&logo=Windows+Terminal&logoColor=ffffff) [![Visual Studio Code](https://img.shields.io/badge/Visual_Studio_Code-007ACC?style=for-the-badge&logo=Visual+Studio+Code&logoColor=ffffff)](vscode:extension/ms-vscode-remote.remote-ssh) + +Follow these steps where code-server is running: + +1. Install `openssh-server`, `wget`, and `unzip`. + +```bash +# example for Debian and Ubuntu operating systems +sudo apt update +sudo apt install wget unzip openssh-server +``` + +2. Start the SSH server and set the password for your user, if you haven't already. If you use [deploy-code-server](https://github.com/cdr/deploy-code-server), + +```bash +sudo service ssh start +sudo passwd {user} # replace user with your code-server user +``` + +### Option 1: cloudflared tunnel + +[![Cloudflared](https://img.shields.io/badge/Cloudflared-E4863B?style=for-the-badge&logo=cloudflare&logoColor=ffffff)](https://github.com/cloudflare/cloudflared) + +1. Install [cloudflared](https://github.com/cloudflare/cloudflared#installing-cloudflared) on your local computer +2. Then go to `~/.ssh/config` and add the following: + +```shell +Host *.trycloudflare.com +HostName %h +User root +Port 22 +ProxyCommand "cloudflared location" access ssh --hostname %h +``` + +3. Run `cloudflared tunnel --url ssh://localhost:22` on the remote server + +4. Finally on VS Code or any IDE that supports SSH, run `ssh coder@https://your-link.trycloudflare.com` or `ssh coder@your-link.trycloudflare.com` + +### Option 2: ngrok tunnel + +[![Ngrok](https://img.shields.io/badge/Ngrok-1F1E37?style=for-the-badge&logo=ngrok&logoColor=ffffff)](https://ngrok.com/) + +1. Make a new account for ngrok [here](https://dashboard.ngrok.com/login) + +2. Now, get the ngrok binary with `wget` and unzip it with `unzip`: + +```bash +wget "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip" +unzip "ngrok-stable-linux-amd64.zip" +``` + +5. Then, go to [dashboard.ngrok.com](https://dashboard.ngrok.com) and go to the `Your Authtoken` section. +6. Copy the Authtoken shown there. +7. Now, go to the folder where you unzipped ngrok and store the Authtoken from the ngrok Dashboard. + +```bash +./ngrok authtoken YOUR_AUTHTOKEN # replace YOUR_AUTHTOKEN with the ngrok authtoken. +``` + +8. Now, forward port 22, which is the SSH port with this command: + +```bash +./ngrok tcp 22 +``` + +Now, you get a screen in the terminal like this: + +```console +ngrok by @inconshreveable(Ctrl+C to quit) + +Session Status online +Account {Your name} (Plan: Free) +Version 2.3.40 +Region United States (us) +Web Interface http://127.0.0.1:4040 +Forwarding tcp://0.tcp.ngrok.io:19028 -> localhost:22 +``` + +In this case, copy the forwarded link `0.tcp.ngrok.io` and remember the port number `19028`. Type this on your local Visual Studio Code: + +```bash +ssh user@0.tcp.ngrok.io -p 19028 +``` + +The port redirects you to the default SSH port 22, and you can then successfully connect to code-server by entering the password you set for the user. + +Note: the port and the url provided by ngrok will change each time you run it so modify as needed. diff --git a/docs/install.md b/docs/install.md index d22b83e6..29725227 100644 --- a/docs/install.md +++ b/docs/install.md @@ -12,6 +12,7 @@ - [macOS](#macos) - [Docker](#docker) - [Helm](#helm) +- [Windows](#windows) - [Raspberry Pi](#raspberry-pi) - [Termux](#termux) - [Cloud providers](#cloud-providers) @@ -99,27 +100,16 @@ _exact_ same commands presented in the rest of this document. We recommend installing with `yarn` or `npm` when: 1. You aren't using a machine with `amd64` or `arm64`. -2. You're on Linux with `glibc` < v2.17, `glibcxx` < v3.4.18 on `amd64`, `glibc` +1. You are installing code-server on Windows +1. You're on Linux with `glibc` < v2.17, `glibcxx` < v3.4.18 on `amd64`, `glibc` < v2.23, or `glibcxx` < v3.4.21 on `arm64`. -3. You're running Alpine Linux or are using a non-glibc libc. See +1. You're running Alpine Linux or are using a non-glibc libc. See [#1430](https://github.com/cdr/code-server/issues/1430#issuecomment-629883198) for more information. Installing code-server with `yarn` or `npm` builds native modules on install. -This process requires C dependencies; see our guide on [installing these -dependencies][./npm.md](./npm.md) for more information. -You must have Node.js v12 (or later) installed. See -[#1633](https://github.com/cdr/code-server/issues/1633). - -To install: - -```bash -yarn global add code-server -# Or: npm install -g code-server -code-server -# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml -``` +This process requires C dependencies; see our guide on [installing with yarn and npm][./npm.md](./npm.md) for more information. ## Standalone releases @@ -236,6 +226,12 @@ alternative](https://hub.docker.com/r/linuxserver/code-server). You can install code-server via [Helm](https://github.com/cdr/code-server/blob/main/ci/helm-chart/README.md). +## Windows + +We currently [do not publish Windows releases](https://github.com/cdr/code-server/issues/1397). We recommend installing code-server onto Windows with [`yarn` or `npm`](#yarn-npm). + +> Note: You will also need to [build cdr/cloud-agent manually](https://github.com/cdr/cloud-agent/issues/17) if you would like to use `code-server --link` on Windows. + ## Raspberry Pi We recommend installing code-server onto Raspberry Pi with [`yarn` or diff --git a/docs/npm.md b/docs/npm.md index d16d4943..f02cec56 100644 --- a/docs/npm.md +++ b/docs/npm.md @@ -8,7 +8,11 @@ - [Alpine](#alpine) - [macOS](#macos) - [FreeBSD](#freebsd) -- [Issues with Node.js after version upgrades](#issues-with-nodejs-after-version-upgrades) +- [Windows](#windows) +- [Installing](#installing) +- [Troubleshooting](#troubleshooting) + - [Issues with Node.js after version upgrades](#issues-with-nodejs-after-version-upgrades) + - [Debugging install issues with npm](#debugging-install-issues-with-npm) @@ -35,6 +39,8 @@ sudo apt-get install -y \ npm config set python python3 ``` +Proceed to [installing](#installing) + ## Fedora, CentOS, RHEL ```bash @@ -44,6 +50,8 @@ sudo yum install -y python2 npm config set python python2 ``` +Proceed to [installing](#installing) + ## Alpine ```bash @@ -51,12 +59,16 @@ apk add alpine-sdk bash libstdc++ libc6-compat npm config set python python3 ``` +Proceed to [installing](#installing) + ## macOS ```bash xcode-select --install ``` +Proceed to [installing](#installing) + ## FreeBSD ```sh @@ -64,7 +76,49 @@ pkg install -y git python npm-node14 yarn-node14 pkgconf pkg install -y libinotify ``` -## Issues with Node.js after version upgrades +Proceed to [installing](#installing) + +## Windows + +Installing code-server requires all of the [prerequisites for VS Code development](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites). When installing the C++ compiler tool chain, we recommend using "Option 2: Visual Studio 2019" for best results. + +Next, install code-server with: + +```bash +yarn global add code-server +# Or: npm install -g code-server +code-server +# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml +``` + +A `postinstall.sh` script will attempt to run. Select your terminal (e.g., Git bash) as the default application for `.sh` files. If an additional dialog does not appear, run the install command again. + +If the `code-server` command is not found, you'll need to [add a directory to your PATH](https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/). To find the directory, use the following command: + +```shell +yarn global bin +# Or: npm config get prefix +``` + +For help and additional troubleshooting, see [#1397](https://github.com/cdr/code-server/issues/1397). + +## Installing + +After adding the dependencies for your OS, install the code-server package globally: + +```bash +yarn global add code-server +# Or: npm install -g code-server +code-server +# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml +``` + +## Troubleshooting + +If you need further assistance, post on our [GitHub Discussions +page](https://github.com/cdr/code-server/discussions). + +### Issues with Node.js after version upgrades Occasionally, you may run into issues with Node.js. @@ -80,5 +134,14 @@ A step-by-step example of how you might do this is: 3. Recompile the native modules: `npm rebuild` 4. Restart code-server -If you need further assistance, post on our [GitHub Discussions -page](https://github.com/cdr/code-server/discussions). +### Debugging install issues with npm + +`yarn` suppresses logs when running `yarn global add`, so to debug installation issues, install with `npm` instead: + +```shell +# Uninstall +npm uninstall -g --unsafe-perm code-server > /dev/null 2>&1 + +# Install with logging +npm install --loglevel verbose -g --unsafe-perm code-server +``` diff --git a/docs/requirements.md b/docs/requirements.md index 8e785b6d..128e18fd 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -9,7 +9,7 @@ At the minimum, we recommend: - 2 CPU cores You can use any Linux distribution, but [our -docs](https://coder.com/docs/code-server/v3.11.1/guide) assume that you're using +docs](https://coder.com/docs/code-server/latest/guide) assume that you're using Debian hosted by Google Cloud (see the following section for instructions on setting this up). @@ -53,3 +53,4 @@ Notes: - To lower costs, you can shut down your server when you're not using it. - We recommend using the `gcloud cli` to avoid using the GCP Dashboard if possible. +- For serving code-server over HTTPS, we recommend using an external domain name along with a service such as Let's Encrypt diff --git a/install.sh b/install.sh index 6f47c5e4..61dff00d 100755 --- a/install.sh +++ b/install.sh @@ -2,7 +2,7 @@ set -eu # code-server's automatic install script. -# See https://coder.com/docs/code-server/v3.11.1/install +# See https://coder.com/docs/code-server/latest/install usage() { arg0="$0" @@ -66,7 +66,7 @@ fall back to npm so on architectures without pre-built releases this will error. The installer will cache all downloaded assets into ~/.cache/code-server -More installation docs are at https://coder.com/docs/code-server/v3.11.1/install +More installation docs are at https://coder.com/docs/code-server/latest/install EOF } @@ -433,7 +433,7 @@ install_npm() { fi echoerr "Please install npm or yarn to install code-server!" echoerr "You will need at least node v12 and a few C dependencies." - echoerr "See the docs https://coder.com/docs/code-server/v3.11.1/install#yarn-npm" + echoerr "See the docs https://coder.com/docs/code-server/latest/install#yarn-npm" exit 1 } diff --git a/lib/vscode/extensions/github-authentication/package.json b/lib/vscode/extensions/github-authentication/package.json index 2064e28d..22a3d21c 100644 --- a/lib/vscode/extensions/github-authentication/package.json +++ b/lib/vscode/extensions/github-authentication/package.json @@ -96,6 +96,9 @@ "@types/node-fetch": "^2.5.7", "@types/uuid": "8.0.0" }, + "resolutions": { + "axios": "^0.21.2" + }, "repository": { "type": "git", "url": "https://github.com/microsoft/vscode.git" diff --git a/lib/vscode/extensions/github-authentication/yarn.lock b/lib/vscode/extensions/github-authentication/yarn.lock index 090dc94d..8eff3566 100644 --- a/lib/vscode/extensions/github-authentication/yarn.lock +++ b/lib/vscode/extensions/github-authentication/yarn.lock @@ -55,12 +55,12 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -axios@^0.21.1: - version "0.21.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" - integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== +axios@^0.21.1, axios@^0.21.2: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== dependencies: - follow-redirects "^1.10.0" + follow-redirects "^1.14.0" cls-hooked@^4.2.2: version "4.2.2" @@ -110,10 +110,10 @@ emitter-listener@^1.0.1, emitter-listener@^1.1.1: dependencies: shimmer "^1.2.0" -follow-redirects@^1.10.0: - version "1.13.3" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267" - integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA== +follow-redirects@^1.14.0: + version "1.14.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.3.tgz#6ada78118d8d24caee595595accdc0ac6abd022e" + integrity sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw== form-data@^3.0.0: version "3.0.0" diff --git a/lib/vscode/package.json b/lib/vscode/package.json index 1403dad8..67857724 100644 --- a/lib/vscode/package.json +++ b/lib/vscode/package.json @@ -218,6 +218,10 @@ "elliptic": "^6.5.3", "nwmatcher": "^1.4.4", "chrome-remote-interface": "^0.30.0", - "glob-parent": "^5.1.2" + "glob-parent": "^5.1.2", + "tar": "^6.1.9", + "pac-resolver": "^5.0.0", + "path-parse": "^1.0.7", + "yargs-parser": "^13.1.2" } } diff --git a/lib/vscode/src/vs/workbench/api/common/shared/webview.ts b/lib/vscode/src/vs/workbench/api/common/shared/webview.ts index c0449b6f..0a6a1e72 100644 --- a/lib/vscode/src/vs/workbench/api/common/shared/webview.ts +++ b/lib/vscode/src/vs/workbench/api/common/shared/webview.ts @@ -24,7 +24,10 @@ export const webviewResourceBaseHost = 'vscode-webview.net'; export const webviewRootResourceAuthority = `vscode-resource.${webviewResourceBaseHost}`; -export const webviewGenericCspSource = `https://*.${webviewResourceBaseHost}`; +// NOTE@coder: This is a temporary change to include ":*" +// due to the patch we had to make for webview resources. +// See PR#3895 and https://github.com/cdr/code-server/issues/3936 for more details. +export const webviewGenericCspSource = `https://*.${webviewResourceBaseHost}:*`; /** * Construct a uri that can load resources inside a webview diff --git a/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js b/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js index 73555697..2cbe115c 100644 --- a/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -242,7 +242,28 @@ const workerReady = new Promise(async (resolve, reject) => { } }; navigator.serviceWorker.addEventListener('message', versionHandler); - assertIsDefined(registration.active).postMessage({ channel: 'version' }); + + const postVersionMessage = () => { + assertIsDefined(navigator.serviceWorker.controller).postMessage({ channel: 'version' }); + }; + + // At this point, either the service worker is ready and + // became our controller, or we need to wait for it. + // Note that navigator.serviceWorker.controller could be a + // controller from a previously loaded service worker. + const currentController = navigator.serviceWorker.controller; + if (currentController && currentController.scriptURL.endsWith(swPath)) { + // service worker already loaded & ready to receive messages + postVersionMessage(); + } else { + // either there's no controlling service worker, or it's an old one: + // wait for it to change before posting the message + const onControllerChange = () => { + navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange); + postVersionMessage(); + }; + navigator.serviceWorker.addEventListener('controllerchange', onControllerChange); + } }, error => { reject(new Error(`Could not register service workers: ${error}.`)); diff --git a/lib/vscode/src/vs/workbench/services/extensions/browser/extensionService.ts b/lib/vscode/src/vs/workbench/services/extensions/browser/extensionService.ts index 1ab76641..dead7008 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/lib/vscode/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -9,7 +9,7 @@ import { IWorkbenchExtensionEnablementService, IWebExtensionsScannerService } fr import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IExtensionService, IExtensionHost } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtensionService, IExtensionHost, ExtensionHostKind, } from 'vs/workbench/services/extensions/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -28,6 +28,7 @@ import { IExtensionManagementService } from 'vs/platform/extensionManagement/com import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit'; +import { IRemoteExplorerService } from '../../remote/common/remoteExplorerService'; export class ExtensionService extends AbstractExtensionService implements IExtensionService { @@ -51,6 +52,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, @IUserDataInitializationService private readonly _userDataInitializationService: IUserDataInitializationService, + @IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService ) { super( new ExtensionRunningLocationClassifier( @@ -75,7 +77,24 @@ export class ExtensionService extends AbstractExtensionService implements IExten // Initialize installed extensions first and do it only after workbench is ready this._lifecycleService.when(LifecyclePhase.Ready).then(async () => { await this._userDataInitializationService.initializeInstalledExtensions(this._instantiationService); - this._initialize(); + this._initialize().then(async () => { + try { + // This enables the `vscode.workspace.registerRemoteAuthorityResolver` API to be executed. + // + // It's specifically scoped to the "coder-link" scheme at the moment to reduce external + // dependency on forking VS Code functionality. + // + // The remote host doesn't resolve to an extension host like the API expects, but instead + // we only utilize the tunnel functionality. + const extHost = this._getExtensionHostManager(ExtensionHostKind.Remote); + const resolved = await extHost?.resolveAuthority('coder-link+web'); + if (resolved) { + this._remoteExplorerService.setTunnelInformation(resolved.tunnelInformation); + } + } catch (ex) { + this._logOrShowMessage(Severity.Error, nls.localize('link', "Failed to initialize remote Link authority: {0}", ex)); + } + }); }); this._initFetchFileSystem(); diff --git a/lib/vscode/yarn.lock b/lib/vscode/yarn.lock index e5170b96..15d3d0e7 100644 --- a/lib/vscode/yarn.lock +++ b/lib/vscode/yarn.lock @@ -2466,14 +2466,15 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -degenerator@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-2.2.0.tgz#49e98c11fa0293c5b26edfbb52f15729afcdb254" - integrity sha512-aiQcQowF01RxFI4ZLFMpzyotbQonhNpBao6dkI8JPk5a+hmSjR5ErHp2CQySmQe8os3VBqLCIh87nDBgZXvsmg== +degenerator@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-3.0.1.tgz#7ef78ec0c8577a544477308ddf1d2d6e88d51f5b" + integrity sha512-LFsIFEeLPlKvAKXu7j3ssIG6RT0TbI7/GhsqrI0DnHASEQjXQ0LUSYcjJteGgRGmZbl1TnMSxpNQIAiJ7Du5TQ== dependencies: ast-types "^0.13.2" escodegen "^1.8.1" esprima "^4.0.0" + vm2 "^3.9.3" delayed-stream@~1.0.0: version "1.0.0" @@ -5901,7 +5902,7 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.0.4, object.assign@^4.1.0, object.assign@^4.1.1: +object.assign@^4.0.4, object.assign@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== @@ -6131,12 +6132,12 @@ pac-proxy-agent@^4.1.0: raw-body "^2.2.0" socks-proxy-agent "5" -pac-resolver@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-4.2.0.tgz#b82bcb9992d48166920bc83c7542abb454bd9bdd" - integrity sha512-rPACZdUyuxT5Io/gFKUeeZFfE5T7ve7cAkE5TUZRRfuKP0u5Hocwe48X7ZEm6mYB+bTB0Qf+xlVlA/RM/i6RCQ== +pac-resolver@^4.1.0, pac-resolver@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-5.0.0.tgz#1d717a127b3d7a9407a16d6e1b012b13b9ba8dc0" + integrity sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA== dependencies: - degenerator "^2.2.0" + degenerator "^3.0.1" ip "^1.1.5" netmask "^2.0.1" @@ -6263,10 +6264,10 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-parse@^1.0.6, path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-root-regex@^0.1.0: version "0.1.2" @@ -8020,10 +8021,10 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar@^6.0.2: - version "6.0.5" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" - integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== +tar@^6.0.2, tar@^6.1.9: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -8640,6 +8641,11 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== +vm2@^3.9.3: + version "3.9.3" + resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.3.tgz#29917f6cc081cc43a3f580c26c5b553fd3c91f40" + integrity sha512-smLS+18RjXYMl9joyJxMNI9l4w7biW8ilSDaVRvFBDwOH8P0BK1ognFQTpg0wyQ6wIKLTblHJvROW692L/E53Q== + vscode-debugprotocol@1.47.0: version "1.47.0" resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.47.0.tgz#700055bea38633a9530a5a552fb3ea314d76b73f" @@ -9049,7 +9055,7 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@13.1.2, yargs-parser@^13.1.2: +yargs-parser@13.1.2, yargs-parser@5.0.0-security.0, yargs-parser@^13.1.0, yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== @@ -9057,22 +9063,6 @@ yargs-parser@13.1.2, yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@5.0.0-security.0: - version "5.0.0-security.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz#4ff7271d25f90ac15643b86076a2ab499ec9ee24" - integrity sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ== - dependencies: - camelcase "^3.0.0" - object.assign "^4.1.0" - -yargs-parser@^13.1.0: - version "13.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" - integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-unparser@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" diff --git a/package.json b/package.json index 2075b2cc..6c70ada9 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "eslint-config-prettier": "^8.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.18.2", - "eslint-plugin-prettier": "^3.1.0", + "eslint-plugin-prettier": "^4.0.0", "prettier": "^2.2.1", "prettier-plugin-sh": "^0.7.1", "shellcheck": "^1.0.0", @@ -80,7 +80,7 @@ "browserslist": "^4.16.5", "safe-buffer": "^5.1.1", "vfile-message": "^2.0.2", - "argon2/@mapbox/node-pre-gyp/tar": "^6.1.3", + "argon2/@mapbox/node-pre-gyp/tar": "^6.1.9", "path-parse": "^1.0.7" }, "dependencies": { diff --git a/src/browser/pages/vscode.ts b/src/browser/pages/vscode.ts index 128df2c4..61648dd3 100644 --- a/src/browser/pages/vscode.ts +++ b/src/browser/pages/vscode.ts @@ -24,13 +24,13 @@ type NlsConfiguration = { * Helper function to create the path to the bundle * for getNlsConfiguration. */ -export function createBundlePath(_resolvedLanguagePackCoreLocation: string, bundle: string) { +export function createBundlePath(_resolvedLanguagePackCoreLocation: string | undefined, bundle: string) { // NOTE@jsjoeio - this comment was here before me // Refers to operating systems that use a different path separator. // Probably just Windows but we're not sure if "/" breaks on Windows // so we'll leave it alone for now. // FIXME: Only works if path separators are /. - return _resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json" + return (_resolvedLanguagePackCoreLocation || "") + "/" + bundle.replace(/\//g, "!") + ".nls.json" } /** @@ -72,20 +72,22 @@ export function getNlsConfiguration(_document: Document, base: string) { type LoadBundleCallback = (_: undefined, result?: string) => void - nlsConfig.loadBundle = (bundle: string, _language: string, cb: LoadBundleCallback): void => { + nlsConfig.loadBundle = async (bundle: string, _language: string, cb: LoadBundleCallback): Promise => { const result = bundles[bundle] + if (result) { return cb(undefined, result) } - // FIXME: Only works if path separators are /. - const path = createBundlePath(nlsConfig._resolvedLanguagePackCoreLocation || "", bundle) - fetch(`${base}/vscode/resource/?path=${encodeURIComponent(path)}`) - .then((response) => response.json()) - .then((json) => { - bundles[bundle] = json - cb(undefined, json) - }) - .catch(cb) + + try { + const path = createBundlePath(nlsConfig._resolvedLanguagePackCoreLocation, bundle) + const response = await fetch(`${base}/vscode/resource/?path=${encodeURIComponent(path)}`) + const json = await response.json() + bundles[bundle] = json + return cb(undefined, json) + } catch (error) { + return cb(error) + } } } diff --git a/src/node/app.ts b/src/node/app.ts index 97ad62c3..ab185e40 100644 --- a/src/node/app.ts +++ b/src/node/app.ts @@ -69,10 +69,10 @@ export const createApp = async (args: DefaultedArgs): Promise<[Express, Express, export const ensureAddress = (server: http.Server): string => { const addr = server.address() if (!addr) { - throw new Error("server has no address") + throw new Error("server has no address") // NOTE@jsjoeio test this line } if (typeof addr !== "string") { return `http://${addr.address}:${addr.port}` } - return addr + return addr // NOTE@jsjoeio test this line } diff --git a/test/package.json b/test/package.json index a23c4d11..1996a5b0 100644 --- a/test/package.json +++ b/test/package.json @@ -7,17 +7,18 @@ "@types/jsdom": "^16.2.6", "@types/node-fetch": "^2.5.8", "@types/supertest": "^2.0.10", + "@types/wtfnode": "^0.7.0", "argon2": "^0.28.0", "jest": "^26.6.3", + "jest-fetch-mock": "^3.0.3", "jsdom": "^16.4.0", "node-fetch": "^2.6.1", "playwright": "^1.12.1", "supertest": "^6.1.1", "ts-jest": "^26.4.4", - "@types/wtfnode": "^0.7.0", "wtfnode": "^0.9.0" }, "resolutions": { - "argon2/@mapbox/node-pre-gyp/tar": "^6.1.3" + "argon2/@mapbox/node-pre-gyp/tar": "^6.1.9" } } diff --git a/test/unit/browser/pages/vscode.test.ts b/test/unit/browser/pages/vscode.test.ts index 99c109bb..2c0d1a38 100644 --- a/test/unit/browser/pages/vscode.test.ts +++ b/test/unit/browser/pages/vscode.test.ts @@ -1,6 +1,7 @@ /** * @jest-environment jsdom */ +import fetchMock from "jest-fetch-mock" import { JSDOM } from "jsdom" import { getNlsConfiguration, @@ -20,6 +21,11 @@ describe("vscode", () => { // We use underscores to not confuse with global values const { window: _window } = new JSDOM() _document = _window.document + fetchMock.enableMocks() + }) + + afterEach(() => { + fetchMock.resetMocks() }) it("should throw an error if no nlsConfigElement", () => { @@ -60,7 +66,7 @@ describe("vscode", () => { _document.body.removeChild(mockElement) }) - it("should return have loadBundle property if _resolvedLangaugePackCoreLocation", () => { + it("should return and have a loadBundle property if _resolvedLangaugePackCoreLocation", async () => { const mockElement = _document.createElement("div") const dataSettings = { locale: "en", @@ -76,6 +82,32 @@ describe("vscode", () => { expect(nlsConfig._resolvedLanguagePackCoreLocation).not.toBe(undefined) expect(nlsConfig.loadBundle).not.toBe(undefined) + const mockCallbackFn = jest.fn((_, bundle) => { + return bundle + }) + + fetchMock.mockOnce(JSON.stringify({ key: "hello world" })) + // Ensure that load bundle works as expected + // by mocking the fetch response and checking that the callback + // had the expected value + await nlsConfig.loadBundle("hello", "en", mockCallbackFn) + expect(mockCallbackFn).toHaveBeenCalledTimes(1) + expect(mockCallbackFn).toHaveBeenCalledWith(undefined, { key: "hello world" }) + + // Call it again to ensure it loads from the cache + // it should return the same value + await nlsConfig.loadBundle("hello", "en", mockCallbackFn) + expect(mockCallbackFn).toHaveBeenCalledTimes(2) + expect(mockCallbackFn).toHaveBeenCalledWith(undefined, { key: "hello world" }) + + fetchMock.mockReject(new Error("fake error message")) + const mockCallbackFn2 = jest.fn((error) => error) + // Call it for a different bundle and mock a failed fetch call + // to ensure we get the expected error + const error = await nlsConfig.loadBundle("goodbye", "es", mockCallbackFn2) + expect(error.message).toEqual("fake error message") + + // Clean up _document.body.removeChild(mockElement) }) }) @@ -87,6 +119,13 @@ describe("vscode", () => { const actual = createBundlePath(_resolvedLangaugePackCoreLocation, bundle) expect(actual).toBe(expected) }) + it("should return the correct path (even if _resolvedLangaugePackCoreLocation is undefined)", () => { + const _resolvedLangaugePackCoreLocation = undefined + const bundle = "/bundle.js" + const expected = "/!bundle.js.nls.json" + const actual = createBundlePath(_resolvedLangaugePackCoreLocation, bundle) + expect(actual).toBe(expected) + }) }) describe("setBodyBackgroundToThemeBackgroundColor", () => { let _document: Document @@ -228,11 +267,6 @@ describe("vscode", () => { }, recordStats: true, - // TODO@jsjoeio address trustedTypesPolicy part - // might need to look up types - // and find a way to test the function - // maybe extract function into function - // and test manually trustedTypesPolicy: undefined, "vs/nls": { availableLanguages: {}, @@ -280,6 +314,11 @@ describe("vscode", () => { expect(loader.trustedTypesPolicy).not.toBe(undefined) expect(loader.trustedTypesPolicy.name).toBe("amdLoader") + + // Check that we can actually create a script URL + // using the createScriptURL on the loader object + const scriptUrl = loader.trustedTypesPolicy.createScriptURL("http://localhost/foo.js") + expect(scriptUrl).toBe("http://localhost/foo.js") }) }) describe("_createScriptURL", () => { diff --git a/test/unit/node/app.test.ts b/test/unit/node/app.test.ts new file mode 100644 index 00000000..41b5515a --- /dev/null +++ b/test/unit/node/app.test.ts @@ -0,0 +1,30 @@ +import * as http from "http" +import { ensureAddress } from "../../../src/node/app" +import { getAvailablePort } from "../../utils/helpers" + +describe("ensureAddress", () => { + let mockServer: http.Server + + beforeEach(() => { + mockServer = http.createServer() + }) + + afterEach(() => { + mockServer.close() + }) + + it("should throw and error if no address", () => { + expect(() => ensureAddress(mockServer)).toThrow("server has no address") + }) + it("should return the address if it exists and not a string", async () => { + const port = await getAvailablePort() + mockServer.listen(port) + const address = ensureAddress(mockServer) + expect(address).toBe(`http://:::${port}`) + }) + it("should return the address if it exists", async () => { + mockServer.address = () => "http://localhost:8080" + const address = ensureAddress(mockServer) + expect(address).toBe(`http://localhost:8080`) + }) +}) diff --git a/test/yarn.lock b/test/yarn.lock index 418eeeec..9b729d37 100644 --- a/test/yarn.lock +++ b/test/yarn.lock @@ -1757,6 +1757,13 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +cross-fetch@^3.0.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + dependencies: + node-fetch "2.6.1" + cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -2800,6 +2807,14 @@ jest-environment-node@^26.6.2: jest-mock "^26.6.2" jest-util "^26.6.2" +jest-fetch-mock@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz#31749c456ae27b8919d69824f1c2bd85fe0a1f3b" + integrity sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw== + dependencies: + cross-fetch "^3.0.4" + promise-polyfill "^8.1.3" + jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" @@ -3418,7 +3433,7 @@ node-addon-api@^3.0.2: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== -node-fetch@^2.6.1: +node-fetch@2.6.1, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -3762,6 +3777,11 @@ progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +promise-polyfill@^8.1.3: + version "8.2.0" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.2.0.tgz#367394726da7561457aba2133c9ceefbd6267da0" + integrity sha512-k/TC0mIcPVF6yHhUvwAp7cvL6I2fFV7TzF1DuGPI8mBh4QQazf36xCKEHKTZKRysEoTQoQdKyP25J8MPJp7j5g== + prompts@^2.0.1: version "2.4.0" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" @@ -4392,10 +4412,10 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -tar@^6.1.0, tar@^6.1.3: - version "6.1.6" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.6.tgz#c23d797b0a1efe5d479b1490805c5443f3560c5d" - integrity sha512-oaWyu5dQbHaYcyZCTfyPpC+VmI62/OM2RTUYavTk1MDr1cwW5Boi3baeYQKiZbY2uSQJGr+iMOzb/JFxLrft+g== +tar@^6.1.0, tar@^6.1.9: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" diff --git a/yarn.lock b/yarn.lock index 42eda6b7..ec7be87a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1934,10 +1934,10 @@ eslint-plugin-import@^2.18.2: resolve "^1.20.0" tsconfig-paths "^3.9.0" -eslint-plugin-prettier@^3.1.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7" - integrity sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw== +eslint-plugin-prettier@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" + integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== dependencies: prettier-linter-helpers "^1.0.0" @@ -4882,10 +4882,10 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^6.1.0, tar@^6.1.3: - version "6.1.6" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.6.tgz#c23d797b0a1efe5d479b1490805c5443f3560c5d" - integrity sha512-oaWyu5dQbHaYcyZCTfyPpC+VmI62/OM2RTUYavTk1MDr1cwW5Boi3baeYQKiZbY2uSQJGr+iMOzb/JFxLrft+g== +tar@^6.1.0, tar@^6.1.9: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0"