diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f20b60f3..257d4ccf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -3,6 +3,24 @@ name: ci on: [push, pull_request] jobs: + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Run ./ci/steps/fmt.sh + uses: ./ci/container + with: + args: ./ci/steps/fmt.sh + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Run ./ci/steps/lint.sh + uses: ./ci/container + with: + args: ./ci/steps/lint.sh + test: runs-on: ubuntu-latest steps: @@ -88,3 +106,43 @@ jobs: with: name: release-packages path: ./release-packages + + docker-amd64: + runs-on: ubuntu-latest + needs: linux-amd64 + steps: + - uses: actions/checkout@v1 + - name: Download release package + uses: actions/download-artifact@v2 + with: + name: release-packages + path: ./release-packages + - name: Run ./ci/steps/build-docker-image.sh + uses: ./ci/container + with: + args: ./ci/steps/build-docker-image.sh + - name: Upload release image + uses: actions/upload-artifact@v2 + with: + name: release-images + path: ./release-images + + docker-arm64: + runs-on: ubuntu-arm64-latest + needs: linux-arm64 + steps: + - uses: actions/checkout@v1 + - name: Download release package + uses: actions/download-artifact@v2 + with: + name: release-packages + path: ./release-packages + - name: Run ./ci/steps/build-docker-image.sh + uses: ./ci/container + with: + args: ./ci/steps/build-docker-image.sh + - name: Upload release image + uses: actions/upload-artifact@v2 + with: + name: release-images + path: ./release-images diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 4230a995..2bb7df09 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -13,29 +13,19 @@ jobs: uses: ./ci/container with: args: ./ci/steps/publish-npm.sh - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - docker-amd64: + docker: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - name: Run ./ci/steps/publish-docker.sh + - name: Run ./ci/steps/push-docker-manifest.sh uses: ./ci/container with: - args: ./ci/steps/publish-docker.sh - env: - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - - docker-arm64: - runs-on: ubuntu-arm64-latest - steps: - - uses: actions/checkout@v1 - - name: Run ./ci/steps/publish-docker.sh - uses: ./ci/container - with: - args: ./ci/steps/publish-docker.sh - env: - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + args: ./ci/steps/push-docker-manifest.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.gitignore b/.gitignore index 35daca8b..f171c575 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ release/ release-static/ release-packages/ release-gcp/ +release-images/ node_modules diff --git a/README.md b/README.md index 667426ec..1d71b9dd 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,95 @@ # code-server -`code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a -remote server, accessible through the browser. +Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and access it in the browser. -Try it out: - -```bash -docker run -it -p 127.0.0.1:8080:8080 -v "$PWD:/home/coder/project" -u "$(id -u):$(id -g)" codercom/code-server:latest -``` - -- **Code anywhere:** Code on your Chromebook, tablet, and laptop with a +- **Code everywhere:** Code on your Chromebook, tablet, and laptop with a consistent dev environment. Develop on a Linux machine and pick up from any device with a web browser. -- **Server-powered:** Take advantage of large cloud servers to speed up tests, - compilations, downloads, and more. Preserve battery life when you're on the go - since all intensive computation runs on your server. +- **Server-powered:** Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. + Preserve battery life when you're on the go since all intensive tasks runs on your server. + Make use of a spare computer you have lying around and turn it into a full development environment. -![Example gif](/doc/assets/code-server.gif) +![Example gif](./doc/assets/code-server.gif) -## Getting Started +## Getting started -### Requirements +For a full setup and walkthrough, please see [./doc/guide.md](./doc/guide.md). -- 64-bit host. -- At least 1GB of RAM. -- 2 cores or more are recommended (1 core works but not optimally). -- Secure connection over HTTPS or localhost (required for service workers and - clipboard support). -- For Linux: GLIBC 2.17 or later and GLIBCXX 3.4.15 or later. +### Debian, Ubuntu -### Run over SSH +```bash +curl -sSOL https://github.com/cdr/code-server/releases/download/3.3.0/code-server_3.3.0_amd64.deb +sudo dpkg -i code-server_3.3.0_amd64.deb +systemctl --user enable --now code-server +# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml +``` -Use [sshcode](https://github.com/codercom/sshcode) for a simple setup. +### Fedora, Red Hat, SUSE -### Digital Ocean +```bash +curl -sSOL https://github.com/cdr/code-server/releases/download/3.3.0/code-server-3.3.0-amd64.rpm +sudo yum install -y code-server-3.3.0-amd64.rpm +systemctl --user enable --now code-server +# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml +``` -[![Create a Droplet](./doc/assets/droplet.svg)](https://marketplace.digitalocean.com/apps/code-server) +### npm -### Releases +We recommend installing from `npm` if we don't have a precompiled release for your machine's +platform or architecture. -1. [Download a release](https://github.com/cdr/code-server/releases). (Linux and macOS supported. Windows support planned.) -2. Unpack the downloaded release then run the included `code-server` script. -3. In your browser navigate to `localhost:8080`. +**note:** Installing via `npm` builds native modules on install and so requires C dependencies. +See [./doc/npm.md](./doc/npm.md) for installing these dependencies. + +You will need at least node v12 installed. See [#1633](https://github.com/cdr/code-server/issues/1633). + +```bash +npm install -g code-server +code-server +# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml +``` + +### macOS + +```bash +brew install code-server +brew services start code-server +# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml +``` + +### Docker + +```bash +# This will start a code-server container and expose it at http://127.0.0.1:8080. +# It will also mount your current directory into the container as `/home/coder/project` +# and forward your UID/GID so that all file system operations occur as your user outside +# the container. +docker run -it -p 127.0.0.1:8080:8080 \ + -v "$PWD:/home/coder/project" \ + -u "$(id -u):$(id -g)" \ + codercom/code-server:latest +``` + +### Static releases + +We publish self contained `.tar.gz` archives for every release on [github](https://github.com/cdr/code-server/releases). +They bundle the node binary and compiled native modules. + +1. Download the latest release archive for your system from [github](https://github.com/cdr/code-server/releases). +2. Unpack the release. +3. You can run code-server by executing `./bin/code-server`. + +Add the code-server `bin` directory to your `$PATH` to easily execute `code-server` without the full path every time. + +Here is an example script for installing and using a static `code-server` release on Linux: + +```bash +curl -sSL https://github.com/cdr/code-server/releases/download/3.3.0/code-server-3.3.0-linux-amd64.tar.gz | sudo tar -C /usr/local -xz +sudo mv /usr/local/code-server-3.3.0-linux-amd64 /usr/local/code-server +PATH="$PATH:/usr/local/code-server/bin" +code-server +# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml +``` ## FAQ @@ -53,5 +101,5 @@ See [./doc/CONTRIBUTING.md](./doc/CONTRIBUTING.md). ## Enterprise -Visit [our enterprise page](https://coder.com) for more information about our +Visit [our website](https://coder.com) for more information about our enterprise offerings. diff --git a/ci/README.md b/ci/README.md index b0954524..3fc3e7ff 100644 --- a/ci/README.md +++ b/ci/README.md @@ -2,100 +2,108 @@ This directory contains scripts used for code-server's continuous integration infrastructure. -Many of these scripts contain more detailed documentation and options in comments at the top. +Some of these scripts contain more detailed documentation and options +in header comments. -Any file and directory added into this tree should be documented here. +Any file or directory in this subdirectory should be documented here. + +- [./ci/lib.sh](./lib.sh) + - Contains code duplicated across these scripts. ## Publishing a release Make sure you have `$GITHUB_TOKEN` set and [hub](https://github.com/github/hub) installed. -1. Update the version of code-server in `package.json` and push a commit -1. GitHub actions will generate the `npm-package` and `release-packages` artifacts -1. Run `yarn release:github-draft` to create a GitHub draft release from the template with +1. Update the version of code-server in `package.json` and README.md/guide.md install examples and push a commit. +2. GitHub actions will generate the `npm-package`, `release-packages` and `release-images` artifacts. +3. Run `yarn release:github-draft` to create a GitHub draft release from the template with the updated version. 1. Summarize the major changes in the release notes and link to the relevant issues. -1. Wait for the artifacts in step 2 to build -1. Run `yarn release:github-assets` to download the artifacts and then upload them to the draft release -1. Run some basic sanity tests on one of the released packages -1. Publish the release - 1. CI will automatically grab the artifacts and then - 1. Publish the NPM package - 1. Publish the AMD64 docker image - 1. Publish the ARM64 docker image +4. Wait for the artifacts in step 2 to build. +5. Run `yarn release:github-assets` to download the `release-packages` artifact and then + upload them to the draft release. +6. Run some basic sanity tests on one of the released packages. +7. Publish the release. + 1. CI will automatically grab the artifacts and then: + 1. Publish the NPM package from `npm-package`. + 2. Publish the Docker Hub image from `release-images`. +8. Update the homebrew and AUR packages. ## dev This directory contains scripts used for the development of code-server. -- [./dev/container](./dev/container) - - See [CONTRIBUTING.md](../doc/CONTRIBUTING.md) for docs on the development container -- [./dev/ci.sh](./dev/ci.sh) (`yarn ci`) - - Runs formatters, linters and tests -- [./dev/fmt.sh](./dev/fmt.sh) (`yarn fmt`) - - Runs formatters -- [./dev/lint.sh](./dev/lint.sh) (`yarn lint`) - - Runs linters -- [./dev/test.sh](./dev/test.sh) (`yarn test`) - - Runs tests -- [./dev/vscode.sh](./dev/vscode.sh) (`yarn vscode`) - - Ensures `lib/vscode` is cloned, patched and dependencies are installed -- [./dev/vscode.patch](./dev/vscode.patch) - - Our patch of VS Code to enable remote browser access - - Generate it with `yarn vscode:diff` and apply with `yarn vscode:patch` -- [./dev/watch.ts](./dev/watch.ts) (`yarn watch`) - - Starts a process to build and launch code-server and restart on any code changes - - Example usage in [CONTRIBUTING.md](../doc/CONTRIBUTING.md) +- [./ci/dev/container](./dev/container) + - See [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md) for docs on the development container. +- [./ci/dev/fmt.sh](./dev/fmt.sh) (`yarn fmt`) + - Runs formatters. +- [./ci/dev/lint.sh](./dev/lint.sh) (`yarn lint`) + - Runs linters. +- [./ci/dev/test.sh](./dev/test.sh) (`yarn test`) + - Runs tests. +- [./ci/dev/ci.sh](./dev/ci.sh) (`yarn ci`) + - Runs `yarn fmt`, `yarn lint` and `yarn test`. +- [./ci/dev/vscode.sh](./dev/vscode.sh) (`yarn vscode`) + - Ensures [./lib/vscode](../lib/vscode) is cloned, patched and dependencies are installed. +- [./ci/dev/patch-vscode.sh](./dev/patch-vscode.sh) (`yarn vscode:patch`) + - Applies [./ci/dev/vscode.patch](./dev/vscode.patch) to [./lib/vscode](../lib/vscode). +- [./ci/dev/diff-vscode.sh](./dev/diff-vscode.sh) (`yarn vscode:diff`) + - Diffs [./lib/vscode](../lib/vscode) into [./ci/dev/vscode.patch](./dev/vscode.patch). +- [./ci/dev/vscode.patch](./dev/vscode.patch) + - Our patch of VS Code, see [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md#vs-code-patch). + - Generate it with `yarn vscode:diff` and apply with `yarn vscode:patch`. +- [./ci/dev/watch.ts](./dev/watch.ts) (`yarn watch`) + - Starts a process to build and launch code-server and restart on any code changes. + - Example usage in [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md). ## build This directory contains the scripts used to build and release code-server. You can disable minification by setting `MINIFY=`. -- [./lib.sh](./lib.sh) - - Contains code duplicated across these scripts. -- [./build/build-code-server.sh](./build/build-code-server.sh) (`yarn build`) - - Builds code-server into ./out and bundles the frontend into ./dist. -- [./build/build-vscode.sh](./build/build-vscode.sh) (`yarn build:vscode`) - - Builds vscode into ./lib/vscode/out-vscode. -- [./build/build-release.sh](./build/build-release.sh) (`yarn release`) +- [./ci/build/build-code-server.sh](./build/build-code-server.sh) (`yarn build`) + - Builds code-server into `./out` and bundles the frontend into `./dist`. +- [./ci/build/build-vscode.sh](./build/build-vscode.sh) (`yarn build:vscode`) + - Builds vscode into `./lib/vscode/out-vscode`. +- [./ci/build/build-release.sh](./build/build-release.sh) (`yarn release`) - Bundles the output of the above two scripts into a single node module at `./release`. -- [./build/build-static-release.sh](./build/build-static-release.sh) (`yarn release:static`) - - Requires a release already built in `./release`. - - Will build a static release with node and node_modules into `./release-static` -- [./build/clean.sh](./build/clean.sh) (`yarn clean`) - - Removes all git ignored files like build artifacts. - - Will also `git reset --hard lib/vscode` +- [./ci/build/build-static-release.sh](./build/build-static-release.sh) (`yarn release:static`) + - Requires a node module already built into `./release` with the above script. + - Will build a static release with node and native modules bundled into `./release-static`. +- [./ci/build/clean.sh](./build/clean.sh) (`yarn clean`) + - Removes all build artifacts. + - Will also `git reset --hard lib/vscode`. - Useful to do a clean build. -- [./build/code-server.sh](./build/code-server.sh) +- [./ci/build/code-server.sh](./build/code-server.sh) - Copied into static releases to run code-server with the bundled node binary. -- [./build/test-static-release.sh](./build/test-static-release.sh) (`yarn test:static-release`) - - Ensures code-server in the `./release-static` directory runs -- [./build/build-packages.sh](./build/build-packages.sh) (`yarn package`) - - Packages `./release-static` into an archive in `./release-packages` - - If on linux, [nfpm](https://github.com/goreleaser/nfpm) is used to generate .deb and .rpm -- [./build/nfpm.yaml](./build/nfpm.yaml) - - Used to configure [nfpm](https://github.com/goreleaser/nfpm) to generate .deb and .rpm -- [./build/code-server-nfpm.sh](./build/code-server-nfpm.sh) - - Entrypoint script for code-server for .deb and .rpm -- [./build/code-server.service](./build/code-server.service) - - systemd user service packaged into the debs and rpms -- [./build/release-github-draft.sh](./build/release-github-draft.sh) (`yarn release:github-draft`) - - Uses [hub](https://github.com/github/hub) to create a draft release with a template description -- [./build/release-github-assets.sh](./build/release-github-assets.sh) (`yarn release:github-assets`) - - Downloads the release-package artifacts for the current commit from CI +- [./ci/build/test-static-release.sh](./build/test-static-release.sh) (`yarn test:static-release`) + - Ensures code-server in the `./release-static` directory works by installing an extension. +- [./ci/build/build-packages.sh](./build/build-packages.sh) (`yarn package`) + - Packages `./release-static` into a `.tar.gz` archive in `./release-packages`. + - If on linux, [nfpm](https://github.com/goreleaser/nfpm) is used to generate `.deb` and `.rpm`. +- [./ci/build/nfpm.yaml](./build/nfpm.yaml) + - Used to configure [nfpm](https://github.com/goreleaser/nfpm) to generate `.deb` and `.rpm`. +- [./ci/build/code-server-nfpm.sh](./build/code-server-nfpm.sh) + - Entrypoint script for code-server for `.deb` and .rpm`. +- [./ci/build/code-server.service](./build/code-server.service) + - systemd user service packaged into the `.deb` and `.rpm`. +- [./ci/build/release-github-draft.sh](./build/release-github-draft.sh) (`yarn release:github-draft`) + - Uses [hub](https://github.com/github/hub) to create a draft release with a template description. +- [./ci/build/release-github-assets.sh](./build/release-github-assets.sh) (`yarn release:github-assets`) + - Downloads the release-package artifacts for the current commit from CI. - Uses [hub](https://github.com/github/hub) to upload the artifacts to the release - specified in `package.json` + specified in `package.json`. +- [./ci/build/npm-postinstall.sh](./build/npm-postinstall.sh) + - Post install script for the npm package. + - Bundled by`yarn release`. ## release-container This directory contains the release docker container. - [./release-container/build.sh](./release-container/build.sh) - - Builds the release container - - Assumes debian releases are ready in `./release-packages` -- [./release-container/push.sh](./release-container/push.sh) - - Pushes the built release container to docker hub and updates the latest tag + - Builds the release container with the tag `codercom/code-server-$ARCH:$VERSION`. + - Assumes debian releases are ready in `./release-packages`. ## container @@ -103,21 +111,26 @@ This directory contains the container for CI. ## steps -This directory contains a few scripts used in CI. -Just helps avoid clobbering the CI configuration. +This directory contains the scripts used in CI. +Helps avoid clobbering the CI configuration. +- [./steps/fmt.sh](./steps/fmt.sh) + - Runs `yarn fmt` after ensuring VS Code is patched. +- [./steps/lint.sh](./steps/lint.sh) + - Runs `yarn lint` after ensuring VS Code is patched. - [./steps/test.sh](./steps/test.sh) - - Runs `yarn ci` after ensuring VS Code is patched + - Runs `yarn test` after ensuring VS Code is patched. - [./steps/release.sh](./steps/release.sh) - - Runs the full release process - - Generates the npm package at `./release` -- [./steps/static-release.sh](./steps/static-release.sh) - - Takes the output of the previous script and generates a static release and packages -- [./steps/lib.sh](./steps/lib.sh) - - Contains helpers to download artifacts from github actions workflow runs + - Runs the release process. + - Generates the npm package at `./release`. +- [./steps/release-static.sh](./steps/release-static.sh) + - Takes the output of the previous script and generates a static release and + release packages into `release-packages`. - [./steps/publish-npm.sh](./steps/publish-npm.sh) - - Grabs the `npm-package` release artifact for the current commit and publishes it on NPM -- [./steps/publish-docker.sh](./steps/publish-docker.sh) - - Grabs the `release-packages` release artifact for the current commit and - builds a docker image with it and publishes that onto docker hub with the - correct tag and updates latest + - Grabs the `npm-package` release artifact for the current commit and publishes it on npm. +- [./steps/build-docker-image.sh](./steps/build-docker-image.sh) + - Builds the docker image and then saves it into `./release-images/code-server-$ARCH-$VERSION.tar`. +- [./steps/push-docker-manifest.sh](./steps/push-docker-manifest.sh) + - Loads all images in `./release-images` and then builds and pushes a multi architecture + docker manifest for the amd64 and arm64 images to `codercom/code-server:$VERSION` and + `codercom/code-server:latest`. diff --git a/ci/build/build-packages.sh b/ci/build/build-packages.sh index 7dc65df0..95b0e0ae 100755 --- a/ci/build/build-packages.sh +++ b/ci/build/build-packages.sh @@ -8,30 +8,16 @@ main() { cd "$(dirname "${0}")/../.." source ./ci/lib.sh - export VERSION - VERSION="$(pkg_json_version)" - - local OS - OS="$(os)" - - export ARCH - ARCH="$(arch)" - - local archive_name="code-server-$VERSION-$OS-$ARCH" + local release_name="code-server-$VERSION-$OS-$ARCH" mkdir -p release-packages - local ext if [[ $OS == "linux" ]]; then - ext=".tar.gz" - tar -czf "release-packages/$archive_name$ext" --transform "s/^\.\/release-static/$archive_name/" ./release-static + tar -czf "release-packages/$release_name.tar.gz" --transform "s/^\.\/release-static/$release_name/" ./release-static else - mv ./release-static "./$archive_name" - ext=".zip" - zip -r "release-packages/$archive_name$ext" "./$archive_name" - mv "./$archive_name" ./release-static + tar -czf "release-packages/$release_name.tar.gz" -s "/^release-static/$release_name/" release-static fi - echo "done (release-packages/$archive_name)" + echo "done (release-packages/$release_name)" release_gcp @@ -42,9 +28,9 @@ main() { release_gcp() { mkdir -p "release-gcp/$VERSION" - cp "release-packages/$archive_name$ext" "./release-gcp/$VERSION/$OS-$ARCH$ext" + cp "release-packages/$release_name.tar.gz" "./release-gcp/$VERSION/$OS-$ARCH.tar.gz" mkdir -p "release-gcp/latest" - cp "./release-packages/$archive_name$ext" "./release-gcp/latest/$OS-$ARCH$ext" + cp "./release-packages/$release_name.tar.gz" "./release-gcp/latest/$OS-$ARCH.tar.gz" } # Generates deb and rpm packages. @@ -52,8 +38,9 @@ release_nfpm() { local nfpm_config nfpm_config=$(envsubst < ./ci/build/nfpm.yaml) - nfpm pkg -f <(echo "$nfpm_config") --target release-packages/code-server-"$VERSION-$ARCH.deb" - nfpm pkg -f <(echo "$nfpm_config") --target release-packages/code-server-"$VERSION-$ARCH.rpm" + # The underscores are convention for .deb. + nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server_${VERSION}_${ARCH}.deb" + nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server-$VERSION-$ARCH.rpm" } main "$@" diff --git a/ci/build/build-release.sh b/ci/build/build-release.sh index d96a466d..9acacd3a 100755 --- a/ci/build/build-release.sh +++ b/ci/build/build-release.sh @@ -8,7 +8,7 @@ MINIFY="${MINIFY-true}" main() { cd "$(dirname "${0}")/../.." - source ./ci/build/lib.sh + source ./ci/lib.sh VSCODE_SRC_PATH="lib/vscode" VSCODE_OUT_PATH="$RELEASE_PATH/lib/vscode" @@ -32,35 +32,32 @@ bundle_code_server() { mkdir -p "$RELEASE_PATH/src/browser/pages" rsync src/browser/pages/*.html "$RELEASE_PATH/src/browser/pages" - rsync yarn.lock "$RELEASE_PATH" - # Adds the commit to package.json jq --slurp '.[0] * .[1]' package.json <( cat << EOF { "commit": "$(git rev-parse HEAD)", "scripts": { - "postinstall": "cd lib/vscode && yarn --production && cd extensions && yarn --production" + "postinstall": "./postinstall.sh" } } EOF ) > "$RELEASE_PATH/package.json" + rsync yarn.lock "$RELEASE_PATH" + rsync ci/build/npm-postinstall.sh "$RELEASE_PATH/postinstall.sh" } bundle_vscode() { mkdir -p "$VSCODE_OUT_PATH" + rsync "$VSCODE_SRC_PATH/package.json" "$VSCODE_OUT_PATH" + rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH" + rsync "$VSCODE_SRC_PATH/node_modules" "$VSCODE_OUT_PATH" rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY+-min}/" "$VSCODE_OUT_PATH/out" rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions" - rm -Rf "$VSCODE_OUT_PATH/extensions/node_modules" - rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions" - rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions" - rsync "$VSCODE_SRC_PATH/extensions/postinstall.js" "$VSCODE_OUT_PATH/extensions" mkdir -p "$VSCODE_OUT_PATH/resources/linux" rsync "$VSCODE_SRC_PATH/resources/linux/code.png" "$VSCODE_OUT_PATH/resources/linux/code.png" - rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH" - # Adds the commit and date to product.json jq --slurp '.[0] * .[1]' "$VSCODE_SRC_PATH/product.json" <( cat << EOF @@ -71,12 +68,26 @@ bundle_vscode() { EOF ) > "$VSCODE_OUT_PATH/product.json" - # We remove the scripts field so that later on we can run - # yarn to fetch node_modules if necessary without build scripts - # being ran. - # We cannot use --no-scripts because we still want dependant package scripts to run - # for native modules to be rebuilt. - jq 'del(.scripts)' < "$VSCODE_SRC_PATH/package.json" > "$VSCODE_OUT_PATH/package.json" + pushd "$VSCODE_OUT_PATH" + yarn --production --frozen-lockfile --ignore-scripts + popd + + # We clear any native module builds. + local native_modules + mapfile -t native_modules < <(find "$VSCODE_OUT_PATH/node_modules" -name "binding.gyp" -exec dirname {} \;) + local nm + for nm in "${native_modules[@]}"; do + rm -R "$nm/build" + done + + # We have to rename node_modules to node_modules.bundled to avoid them being ignored by yarn. + local node_modules + mapfile -t node_modules < <(find "$VSCODE_OUT_PATH" -depth -name "node_modules") + local nm + for nm in "${node_modules[@]}"; do + rm -Rf "$nm.bundled" + mv "$nm" "$nm.bundled" + done } main "$@" diff --git a/ci/build/build-static-release.sh b/ci/build/build-static-release.sh index f2e28fa3..69075579 100755 --- a/ci/build/build-static-release.sh +++ b/ci/build/build-static-release.sh @@ -3,7 +3,7 @@ set -euo pipefail main() { cd "$(dirname "${0}")/../.." - source ./ci/build/lib.sh + source ./ci/lib.sh rsync "$RELEASE_PATH/" "$RELEASE_PATH-static" RELEASE_PATH+=-static @@ -19,7 +19,7 @@ main() { rsync "$node_path" "$RELEASE_PATH/lib/node" cd "$RELEASE_PATH" - yarn --production + yarn --production --frozen-lockfile } main "$@" diff --git a/ci/build/clean.sh b/ci/build/clean.sh index df8da6de..c57e0b43 100755 --- a/ci/build/clean.sh +++ b/ci/build/clean.sh @@ -3,10 +3,22 @@ set -euo pipefail main() { cd "$(dirname "${0}")/../.." + source ./ci/lib.sh - git clean -Xffd - git submodule foreach --recursive git clean -xffd - git submodule foreach --recursive git reset --hard + rm -Rf \ + out \ + release \ + release-static \ + release-packages \ + release-gcp \ + dist \ + .tsbuildinfo \ + .cache/out.tsbuildinfo + + pushd lib/vscode + git clean -xffd + git reset --hard + popd } main "$@" diff --git a/ci/build/code-server.service b/ci/build/code-server.service index 414f5451..a2f48e93 100644 --- a/ci/build/code-server.service +++ b/ci/build/code-server.service @@ -8,4 +8,4 @@ ExecStart=/usr/bin/code-server Restart=always [Install] -WantedBy=multi-user.target +WantedBy=default.target diff --git a/ci/build/lib.sh b/ci/build/lib.sh deleted file mode 100755 index f263adb8..00000000 --- a/ci/build/lib.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -source ./ci/lib.sh - -# RELEASE_PATH is the destination directory for the release from the root. -# Defaults to release -RELEASE_PATH="${RELEASE_PATH-release}" - -rsync() { - command rsync -a --del "$@" -} diff --git a/ci/build/npm-postinstall.sh b/ci/build/npm-postinstall.sh new file mode 100755 index 00000000..daca99d2 --- /dev/null +++ b/ci/build/npm-postinstall.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env sh +set -eu + +main() { + # Grabs the major version of node from $npm_config_user_agent which looks like + # yarn/1.21.1 npm/? node/v14.2.0 darwin x64 + major_node_version=$(echo "$npm_config_user_agent" | sed -n 's/.*node\/v\([^.]*\).*/\1/p') + if [ "$major_node_version" -lt 12 ]; then + echo "code-server currently requires at least node v12" + echo "We have detected that you are on node v$major_node_version" + echo "See https://github.com/cdr/code-server/issues/1633" + exit 1 + fi + + case "${npm_config_user_agent-}" in npm*) + # We are running under npm. + if [ "${npm_config_unsafe_perm-}" != "true" ]; then + echo "Please pass --unsafe-perm to npm to install code-server" + echo "Otherwise the postinstall script does not have permissions to run" + echo "See https://docs.npmjs.com/misc/config#unsafe-perm" + echo "See https://stackoverflow.com/questions/49084929/npm-sudo-global-installation-unsafe-perm" + exit 1 + fi + ;; + esac + + cd lib/vscode + + # We have to rename node_modules.bundled to node_modules. + # The bundled modules were renamed originally to avoid being ignored by yarn. + node_modules="$(find . -depth -name "node_modules.bundled")" + for nm in $node_modules; do + rm -Rf "${nm%.bundled}" + mv "$nm" "${nm%.bundled}" + done + + # $npm_config_global makes npm rebuild return without rebuilding. + unset npm_config_global + # Rebuilds native modules. + if ! npm rebuild; then + echo "You may not have the required dependencies to build the native modules." + echo "Please see https://github.com/cdr/code-server/blob/master/doc/npm.md" + exit 1 + fi +} + +main "$@" diff --git a/ci/build/release-github-assets.sh b/ci/build/release-github-assets.sh index 5f29b4b0..2388aad8 100755 --- a/ci/build/release-github-assets.sh +++ b/ci/build/release-github-assets.sh @@ -15,7 +15,7 @@ main() { for i in "${!assets[@]}"; do assets[$i]="--attach=${assets[$i]}" done - EDITOR=true hub release edit --draft "${assets[@]}" "v$(pkg_json_version)" + EDITOR=true hub release edit --draft "${assets[@]}" "v$VERSION" } main "$@" diff --git a/ci/build/release-github-draft.sh b/ci/build/release-github-draft.sh index fcd8e959..ef552437 100755 --- a/ci/build/release-github-draft.sh +++ b/ci/build/release-github-draft.sh @@ -9,8 +9,8 @@ main() { hub release create \ --file - \ - --draft "${assets[@]}" "v$(pkg_json_version)" << EOF -v$(pkg_json_version) + --draft "${assets[@]}" "v$VERSION" << EOF +v$VERSION VS Code v$(vscode_version) diff --git a/ci/container/Dockerfile b/ci/container/Dockerfile index 87578576..a609ae8a 100644 --- a/ci/container/Dockerfile +++ b/ci/container/Dockerfile @@ -34,8 +34,10 @@ RUN curl -sSL https://github.com/koalaman/shellcheck/releases/download/v0.7.1/sh # Install Go dependencies RUN ARCH="$(dpkg --print-architecture)" && \ - curl -sSL "https://dl.google.com/go/go1.14.2.linux-$ARCH.tar.gz" | tar -C /usr/local -xz + curl -sSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz ENV PATH=/usr/local/go/bin:/root/go/bin:$PATH ENV GO111MODULE=on RUN go get mvdan.cc/sh/v3/cmd/shfmt RUN go get github.com/goreleaser/nfpm/cmd/nfpm + +RUN curl -fsSL https://get.docker.com | sh diff --git a/ci/dev/diff-vscode.sh b/ci/dev/diff-vscode.sh new file mode 100755 index 00000000..98c955df --- /dev/null +++ b/ci/dev/diff-vscode.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +main() { + cd "$(dirname "$0")/../.." + + cd ./lib/vscode + git add -A + git diff HEAD > ../../ci/dev/vscode.patch +} + +main "$@" diff --git a/ci/dev/fmt.sh b/ci/dev/fmt.sh index f7c48c41..8e248823 100755 --- a/ci/dev/fmt.sh +++ b/ci/dev/fmt.sh @@ -21,6 +21,9 @@ main() { ) prettier --write --loglevel=warn $(git ls-files "${prettierExts[@]}") + doctoc --title '# FAQ' doc/FAQ.md > /dev/null + doctoc --title '# Setup Guide' doc/guide.md > /dev/null + if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then echo "Files need generation or are formatted incorrectly:" git -c color.ui=always status | grep --color=no '\[31m' diff --git a/ci/dev/patch-vscode.sh b/ci/dev/patch-vscode.sh new file mode 100755 index 00000000..cdc2691a --- /dev/null +++ b/ci/dev/patch-vscode.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail + +main() { + cd "$(dirname "$0")/../.." + + cd ./lib/vscode + git apply ../../ci/dev/vscode.patch +} + +main "$@" diff --git a/ci/dev/vscode.patch b/ci/dev/vscode.patch index ac70e7bf..9aa241fc 100644 --- a/ci/dev/vscode.patch +++ b/ci/dev/vscode.patch @@ -653,6 +653,19 @@ index 87a3b99c70..09e2c93172 100644 } // Node: AMD loader +diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts +index 266aa69fc6..e9b51f5fde 100644 +--- a/src/vs/platform/product/common/productService.ts ++++ b/src/vs/platform/product/common/productService.ts +@@ -25,6 +25,8 @@ export interface IBuiltInExtension { + export type ConfigurationSyncStore = { url: string, authenticationProviders: IStringDictionary<{ scopes: string[] }> }; + + export interface IProductConfiguration { ++ readonly codeServerVersion?: string; ++ + readonly version: string; + readonly date?: string; + readonly quality?: string; diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts index d0f6e6b18a..1966fd297d 100644 --- a/src/vs/platform/remote/browser/browserSocketFactory.ts @@ -1328,10 +1341,10 @@ index 0000000000..56331ff1fc +require('../../bootstrap-amd').load('vs/server/entry'); diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts new file mode 100644 -index 0000000000..d4771351de +index 0000000000..0a9c95d50e --- /dev/null +++ b/src/vs/server/ipc.d.ts -@@ -0,0 +1,116 @@ +@@ -0,0 +1,117 @@ +/** + * External interfaces for integration into code-server over IPC. No vs imports + * should be made in this file. @@ -1434,6 +1447,7 @@ index 0000000000..d4771351de + }; + readonly remoteUserDataUri: UriComponents; + readonly productConfiguration: { ++ codeServerVersion?: string; + readonly extensionsGallery?: { + readonly serviceUrl: string; + readonly itemUrl: string; @@ -3185,6 +3199,25 @@ index f2ca5011dd..4683e80a68 100644 } catch (e) { console.error('Could not rewrite csp'); } +diff --git a/src/vs/workbench/services/dialogs/browser/dialogService.ts b/src/vs/workbench/services/dialogs/browser/dialogService.ts +index 6b42535bff..88b7e3c3ea 100644 +--- a/src/vs/workbench/services/dialogs/browser/dialogService.ts ++++ b/src/vs/workbench/services/dialogs/browser/dialogService.ts +@@ -124,11 +124,12 @@ export class DialogService implements IDialogService { + async about(): Promise { + const detailString = (useAgo: boolean): string => { + return nls.localize('aboutDetail', +- "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", ++ "code-server: v{4}\n VS Code: v{0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", + this.productService.version || 'Unknown', + this.productService.commit || 'Unknown', + this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown', +- navigator.userAgent ++ navigator.userAgent, ++ this.productService.codeServerVersion || 'Unknown', + ); + }; + diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 7ed6e9e21a..223fa72662 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts diff --git a/ci/dev/vscode.sh b/ci/dev/vscode.sh index d9a67795..6c508747 100755 --- a/ci/dev/vscode.sh +++ b/ci/dev/vscode.sh @@ -15,7 +15,7 @@ main() { ( cd lib/vscode # Install VS Code dependencies. - yarn + yarn ${CI+--frozen-lockfile} ) } diff --git a/ci/lib.sh b/ci/lib.sh index 7c348d6f..a8b4d2e8 100755 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -27,6 +27,8 @@ os() { if echo "$ldd_output" | grep -iq musl; then os="alpine" fi + elif [[ $os == "darwin" ]]; then + os="macos" fi echo "$os" } @@ -73,6 +75,21 @@ download_artifact() { tmp_file="$(mktemp)" curl -sSL "$(get_artifact_url "$artifact_name")" > "$tmp_file" - unzip -o "$tmp_file" -d "$dst" + unzip -q -o "$tmp_file" -d "$dst" rm "$tmp_file" } + +rsync() { + command rsync -a --del "$@" +} + +VERSION="$(pkg_json_version)" +export VERSION +ARCH="$(arch)" +export ARCH +OS=$(os) +export OS + +# RELEASE_PATH is the destination directory for the release from the root. +# Defaults to release +RELEASE_PATH="${RELEASE_PATH-release}" diff --git a/ci/release-container/Dockerfile b/ci/release-container/Dockerfile index 4dbc4784..d81dec13 100644 --- a/ci/release-container/Dockerfile +++ b/ci/release-container/Dockerfile @@ -35,7 +35,7 @@ RUN ARCH="$(dpkg --print-architecture)" && \ printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml COPY release-packages/code-server*.deb /tmp/ -RUN dpkg -i /tmp/code-server*-$(dpkg --print-architecture).deb && rm /tmp/code-server*.deb +RUN dpkg -i /tmp/code-server*$(dpkg --print-architecture).deb && rm /tmp/code-server*.deb EXPOSE 8080 USER coder diff --git a/ci/release-container/build.sh b/ci/release-container/build.sh index 27941a9b..e91ea33c 100755 --- a/ci/release-container/build.sh +++ b/ci/release-container/build.sh @@ -4,11 +4,8 @@ set -euo pipefail main() { cd "$(dirname "$0")/../.." source ./ci/lib.sh - VERSION="$(pkg_json_version)" - imageTag="codercom/code-server:$VERSION" - - docker build -t "$imageTag" -f ./ci/release-container/Dockerfile . + docker build -t "codercom/code-server-$ARCH:$VERSION" -f ./ci/release-container/Dockerfile . } main "$@" diff --git a/ci/release-container/push.sh b/ci/release-container/push.sh deleted file mode 100755 index 0e44a4e4..00000000 --- a/ci/release-container/push.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - source ./ci/lib.sh - VERSION="$(pkg_json_version)" - - imageTag="codercom/code-server:$VERSION" - - docker push "$imageTag" - docker tag "$imageTag" codercom/code-server:latest - docker push codercom/code-server:latest -} - -main "$@" diff --git a/ci/steps/build-docker-image.sh b/ci/steps/build-docker-image.sh new file mode 100755 index 00000000..692fa40f --- /dev/null +++ b/ci/steps/build-docker-image.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +main() { + cd "$(dirname "$0")/../.." + source ./ci/lib.sh + + ./ci/release-container/build.sh + + mkdir -p release-images + docker save "codercom/code-server-$ARCH:$VERSION" > "release-images/code-server-$ARCH-$VERSION.tar" +} + +main "$@" diff --git a/ci/steps/fmt.sh b/ci/steps/fmt.sh new file mode 100755 index 00000000..5e323596 --- /dev/null +++ b/ci/steps/fmt.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +main() { + cd "$(dirname "$0")/../.." + + yarn --frozen-lockfile + + git submodule update --init + # We do not `yarn vscode` to make test.sh faster. + # If the patch fails to apply, then it's likely already applied + yarn vscode:patch &> /dev/null || true + + yarn fmt +} + +main "$@" diff --git a/ci/steps/lint.sh b/ci/steps/lint.sh new file mode 100755 index 00000000..b493e160 --- /dev/null +++ b/ci/steps/lint.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +main() { + cd "$(dirname "$0")/../.." + + yarn --frozen-lockfile + + git submodule update --init + # We do not `yarn vscode` to make test.sh faster. + # If the patch fails to apply, then it's likely already applied + yarn vscode:patch &> /dev/null || true + + yarn lint +} + +main "$@" diff --git a/ci/steps/publish-docker.sh b/ci/steps/publish-docker.sh deleted file mode 100755 index 12bf8111..00000000 --- a/ci/steps/publish-docker.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - source ./ci/lib.sh - - if [[ ${CI-} ]]; then - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - fi - - download_artifact release-packages ./release-packages - ./ci/release-container/build.sh - ./ci/release-container/push.sh -} - -main "$@" diff --git a/ci/steps/publish-npm.sh b/ci/steps/publish-npm.sh index 10865a61..be6161bf 100755 --- a/ci/steps/publish-npm.sh +++ b/ci/steps/publish-npm.sh @@ -11,7 +11,7 @@ main() { download_artifact npm-package ./release # https://github.com/actions/upload-artifact/issues/38 - chmod +x $(grep -rl '^#!/.\+' release) + chmod +x $(grep -rl '^#!/.*' release) yarn publish --non-interactive release } diff --git a/ci/steps/push-docker-manifest.sh b/ci/steps/push-docker-manifest.sh new file mode 100755 index 00000000..08d0fdac --- /dev/null +++ b/ci/steps/push-docker-manifest.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +main() { + cd "$(dirname "$0")/../.." + source ./ci/lib.sh + + download_artifact release-images ./release-images + if [[ ${CI-} ]]; then + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + fi + + for img in ./release-images/*; do + docker load -i "$img" + done + + # We have to ensure the amd64 and arm64 images exist on the remote registry + # in order to build the manifest. + # We don't put the arch in the tag to avoid polluting the main repository. + # These other repositories are private so they don't pollute our organization namespace. + docker push "codercom/code-server-amd64:$VERSION" + docker push "codercom/code-server-arm64:$VERSION" + + export DOCKER_CLI_EXPERIMENTAL=enabled + + docker manifest create "codercom/code-server:$VERSION" \ + "codercom/code-server-amd64:$VERSION" \ + "codercom/code-server-arm64:$VERSION" + docker manifest push --purge "codercom/code-server:$VERSION" + + docker manifest create "codercom/code-server:latest" \ + "codercom/code-server-amd64:$VERSION" \ + "codercom/code-server-arm64:$VERSION" + docker manifest push --purge "codercom/code-server:latest" +} + +main "$@" diff --git a/ci/steps/release-static.sh b/ci/steps/release-static.sh index 63c1b778..08a4a1fa 100755 --- a/ci/steps/release-static.sh +++ b/ci/steps/release-static.sh @@ -4,6 +4,9 @@ set -euo pipefail main() { cd "$(dirname "$0")/../.." + # https://github.com/actions/upload-artifact/issues/38 + chmod +x $(grep -rl '^#!/.*' release) + yarn release:static yarn test:static-release yarn package diff --git a/ci/steps/release.sh b/ci/steps/release.sh index 5c935522..94f1df8a 100755 --- a/ci/steps/release.sh +++ b/ci/steps/release.sh @@ -4,7 +4,7 @@ set -euo pipefail main() { cd "$(dirname "$0")/../.." - yarn + yarn --frozen-lockfile yarn vscode yarn build yarn build:vscode diff --git a/ci/steps/test.sh b/ci/steps/test.sh index 9430d107..801b2adc 100755 --- a/ci/steps/test.sh +++ b/ci/steps/test.sh @@ -4,14 +4,14 @@ set -euo pipefail main() { cd "$(dirname "$0")/../.." - yarn + yarn --frozen-lockfile git submodule update --init # We do not `yarn vscode` to make test.sh faster. # If the patch fails to apply, then it's likely already applied yarn vscode:patch &> /dev/null || true - yarn ci + yarn test } main "$@" diff --git a/doc/CONTRIBUTING.md b/doc/CONTRIBUTING.md index 37be0f7d..51609f94 100644 --- a/doc/CONTRIBUTING.md +++ b/doc/CONTRIBUTING.md @@ -1,16 +1,24 @@ # Contributing - [Detailed CI and build process docs](../ci) -- [Our VS Code Web docs](../src/node/app) + +## Requirements + +Please refer to [VS Code's prerequisites](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites). + +Differences: + +- We require a minimum of node v12 but later versions should work. +- We use [fnpm](https://github.com/goreleaser/nfpm) to build `.deb` and `.rpm` packages. +- The [CI container](../ci/container/Dockerfile) is a useful reference for all our dependencies. ## Development Workflow -- [VS Code prerequisites](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites) - ```shell yarn yarn vscode -yarn watch # Visit http://localhost:8080 once completed. +yarn watch +# Visit http://localhost:8080 once the build completed. ``` To develop inside of an isolated docker container: @@ -28,13 +36,8 @@ Any changes made to the source will be live reloaded. If changes are made to the patch and you've built previously you must manually reset VS Code then run `yarn vscode:patch`. -Some docs are available at [../src/node/app](../src/node/app) on how code-server -works internally. - ## Build -- [VS Code prerequisites](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites) - ```shell yarn yarn vscode @@ -43,5 +46,72 @@ yarn build:vscode yarn release cd release yarn --production -node . # Run the built JavaScript with Node. +# Runs the built JavaScript with Node. +node . ``` + +Now you can make it static and build packages with: + +``` +yarn release:static +yarn test:static-release +yarn package +# The static release is in ./release-static +# .deb, .rpm and the static archive are in ./release-packages +``` + +## Structure + +The `code-server` script serves an HTTP API to login and start a remote VS Code process. + +The CLI code is in [./src/node](./src/node) and the HTTP routes are implemented in +[./src/node/app](./src/node/app). + +Most of the meaty parts are in our VS Code patch which is described next. + +### VS Code Patch + +Back in v1 of code-server, we had an extensive patch of VS Code that split the codebase +into a frontend and server. The frontend consisted of all UI code and the server ran +the extensions and exposed an API to the frontend for file access and everything else +that the UI needed. + +This worked but eventually Microsoft added support to VS Code to run it in the web. +They have open sourced the frontend but have kept the server closed source. + +So in interest of piggy backing off their work, v2 and beyond use the VS Code +web frontend and fill in the server. This is contained in our +[./ci/dev/vscode.patch](../ci/dev/vscode.patch) under the path `src/vs/server`. + +Other notable changes in our patch include: + +- Add our own build file which includes our code and VS Code's web code. +- Allow multiple extension directories (both user and built-in). +- Modify the loader, websocket, webview, service worker, and asset requests to + use the URL of the page as a base (and TLS if necessary for the websocket). +- Send client-side telemetry through the server. +- Allow modification of the display language. +- Make it possible for us to load code on the client. +- Make extensions work in the browser. +- Make it possible to install extensions of any kind. +- Fix getting permanently disconnected when you sleep or hibernate for a while. +- Add connection type to web socket query parameters. + +Some known issues presently: + +- Creating custom VS Code extensions and debugging them doesn't work. +- Extension profiling and tips are currently disabled. + +As the web portion of VS Code matures, we'll be able to shrink and maybe even entirely +eliminate our patch. In the meantime, however, upgrading the VS Code version requires +ensuring that the patch still applies and has the intended effects. + +To generate a new patch run `yarn vscode:diff`. + +**note**: We have extension docs on the CI and build system at [./ci/README.md](../ci/README.md) + +If functionality doesn't depend on code from VS Code then it should be moved +into code-server otherwise it should be in the patch. + +In the future we'd like to run VS Code unit tests against our builds to ensure features +work as expected. diff --git a/doc/FAQ.md b/doc/FAQ.md index a4357560..6a933964 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -1,9 +1,32 @@ + + # FAQ +- [Questions?](#questions) +- [What's the deal with extensions?](#whats-the-deal-with-extensions) +- [Where are extensions stored?](#where-are-extensions-stored) +- [How is this different from VS Code Codespaces?](#how-is-this-different-from-vs-code-codespaces) +- [How should I expose code-server to the internet?](#how-should-i-expose-code-server-to-the-internet) +- [How do I securely access web services?](#how-do-i-securely-access-web-services) + - [Sub-domains](#sub-domains) + - [Sub-paths](#sub-paths) +- [Multi-tenancy](#multi-tenancy) +- [Docker in code-server docker container?](#docker-in-code-server-docker-container) +- [Collaboration](#collaboration) +- [How can I disable telemetry?](#how-can-i-disable-telemetry) +- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open) +- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server) +- [Heartbeat file](#heartbeat-file) +- [How does the config file work?](#how-does-the-config-file-work) +- [Enterprise](#enterprise) + + + ## Questions? -Please file all questions and support requests at https://www.reddit.com/r/codeserver/ -The issue tracker is only for bugs. +Please file all questions and support requests at https://www.reddit.com/r/codeserver/. + +The issue tracker is **only** for bugs. ## What's the deal with extensions? @@ -23,42 +46,59 @@ Issue [#1299](https://github.com/cdr/code-server/issues/1299) is a big one in ma better by allowing the community to submit extensions and repos to avoid waiting until the scraper finds an extension. -If an extension does not work, try to grab its VSIX from its Github releases or build it yourself and -copy it to the extensions folder. +If an extension is not available or does not work, you can grab its VSIX from its Github releases or +build it yourself. Then run the `Extensions: Install from VSIX` command in the Command Palette and +point to the .vsix file. -## How is this different from VS Code Online? +See below for installing an extension from the cli. -VS Code Online is a closed source managed service by Microsoft and only runs on Azure. +Feel free to file an issue to add a missing extension to the marketplace. -code-server is open source and can be freely run on any machine. +If you have your own custom marketplace, it is possible to point code-server to it by setting +`$SERVICE_URL` and `$ITEM_URL` to point to it. + +## Where are extensions stored? + +Defaults to `~/.local/share/code-server/extensions`. + +If the `XDG_DATA_HOME` environment variable is set the data directory will be +`$XDG_DATA_HOME/code-server/extensions`. In general we try to follow the XDG directory spec. + +You can install an extension on the CLI with: + +```bash +# From the Coder extension marketplace +code-server --install-extension ms-python.python + +# From a downloaded VSIX on the file system +code-server --install-extension downloaded-ms-python.python.vsix +``` + +## How is this different from VS Code Codespaces? + +VS Code Codespaces is a closed source and paid service by Microsoft. It also allows you to access +VS Code via the browser. + +However, code-server is free, open source and can be ran on any machine without any limitations. + +While you can self host environments with VS Code Codespaces, you still need to an Azure billing +account and you access VS Code via the Codespaces web dashboard instead of directly connecting to +your instance. ## How should I expose code-server to the internet? -By far the most secure method of using code-server is via -[sshcode](https://github.com/codercom/sshcode) as it runs code-server and then forwards -its port over SSH and requires no setup on your part other than having a working SSH server. +Please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server. -You can also forward your SSH key and GPG agent to the remote machine to securely access GitHub -and securely sign commits without duplicating your keys onto the the remote machine. - -1. https://developer.github.com/v3/guides/using-ssh-agent-forwarding/ -1. https://wiki.gnupg.org/AgentForwarding - -If you cannot use sshcode, then you will need to ensure there is some sort of authorization in -front of code-server and that you are using HTTPS to secure all connections. - -By default when listening externally, code-server enables password authentication using a -randomly generated password so you can use that. You can set the `PASSWORD` environment variable -to use your own instead. If you want to handle authentication yourself, use `--auth none` -to disable password authentication. +code-server only supports password authentication natively. **note**: code-server will rate limit password authentication attempts at 2 a minute and 12 an hour. -If you want to use external authentication you should handle this with a reverse -proxy using something like [oauth2_proxy](https://github.com/pusher/oauth2_proxy). +If you want to use external authentication (i.e sign in with Google) you should handle this +with a reverse proxy using something like [oauth2_proxy](https://github.com/pusher/oauth2_proxy). -For HTTPS, you can use a self signed certificate by passing in just `--cert` or pass in an existing -certificate by providing the path to `--cert` and the path to its key with `--cert-key`. +For HTTPS, you can use a self signed certificate by passing in just `--cert` or +pass in an existing certificate by providing the path to `--cert` and the path to +its key with `--cert-key`. If `code-server` has been passed a certificate it will also respond to HTTPS requests and will redirect all HTTP requests to HTTPS. Otherwise it will respond @@ -67,6 +107,8 @@ only to HTTP requests. You can use [Let's Encrypt](https://letsencrypt.org/) to get an SSL certificate for free. +Again, Please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server. + ## How do I securely access web services? code-server is capable of proxying to any port using either a subdomain or a @@ -96,16 +138,7 @@ ensure your reverse proxy forwards that information if you are using one. Just browse to `/proxy//`. -## x86 releases? - -node has dropped support for x86 and so we decided to as well. See -[nodejs/build/issues/885](https://github.com/nodejs/build/issues/885). - -## Alpine builds? - -Just install `libc-dev` and code-server should work. - -## Multi Tenancy +## Multi-tenancy If you want to run multiple code-server's on shared infrastructure, we recommend using virtual machines with a VM per user. This will easily allow users to run a docker daemon. If you want @@ -127,8 +160,9 @@ to make volume mounts in any other directory work. ## Collaboration -At the moment we have no plans for multi user collaboration on code-server but we understand there is strong -demand and will work on it when the time is right. +We understand the high demand but the team is swamped right now. + +You can follow progress at [#33](https://github.com/cdr/code-server/issues/33). ## How can I disable telemetry? @@ -157,21 +191,43 @@ code-server --log debug Once this is done, replicate the issue you're having then collect logging information from the following places: -1. stdout. -2. The most recently created directory in the `logs` directory (found in the - data directory; see below for how to find that). +1. stdout +2. The most recently created directory in the `~/.local/share/code-server/logs` directory 3. The browser console and network tabs. Additionally, collecting core dumps (you may need to enable them first) if code-server crashes can be helpful. -### Where is the data directory? +## Heartbeat file -If the `XDG_DATA_HOME` environment variable is set the data directory will be -`$XDG_DATA_HOME/code-server`. Otherwise: +`code-server` touches `~/.local/share/code-server/heartbeat` once a minute as long +as there is an active browser connection. -1. Unix: `~/.local/share/code-server` -1. Windows: `%APPDATA%\Local\code-server\Data` +If you want to shutdown `code-server` if there hasn't been an active connection in X minutes +you can do so by continuously checking the last modified time on the heartbeat file and if it is +older than X minutes, you should kill `code-server`. + +[#1636](https://github.com/cdr/code-server/issues/1636) will make the experience here better. + +## How does the config file work? + +When `code-server` starts up, it creates a default config file in `~/.config/code-server/config.yaml` that looks +like this: + +```yaml +bind-addr: 127.0.0.1:8080 +auth: password +password: mewkmdasosafuio3422 # This is randomly generated for each config.yaml +cert: false +``` + +Each key in the file maps directly to a `code-server` flag. Run `code-server --help` to see +a listing of all the flags. + +The default config here says to listen on the loopback IP port 8080, enable password authorization +and no TLS. Any flags passed to `code-server` will take priority over the config file. + +The `--config` flag or `$CODE_SERVER_CONFIG` can be used to change the config file's location. ## Enterprise diff --git a/doc/assets/droplet.svg b/doc/assets/droplet.svg deleted file mode 100644 index ecbb3f24..00000000 --- a/doc/assets/droplet.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - do-btn-blue-ghost - Created with Sketch. - - - - - - - - - - - - - - Create a Droplet - - - - - diff --git a/doc/guide.md b/doc/guide.md new file mode 100644 index 00000000..cc9cdf30 --- /dev/null +++ b/doc/guide.md @@ -0,0 +1,245 @@ + + +# Setup Guide + +- [1. Acquire a remote machine](#1-acquire-a-remote-machine) + - [Requirements](#requirements) + - [Google Cloud](#google-cloud) +- [2. Install code-server](#2-install-code-server) +- [3. Expose code-server](#3-expose-code-server) + - [SSH forwarding](#ssh-forwarding) + - [Let's Encrypt](#lets-encrypt) + - [Self Signed Certificate](#self-signed-certificate) + - [Change the password?](#change-the-password) + - [How do I securely access development web services?](#how-do-i-securely-access-development-web-services) + + + +This guide demonstrates how to setup and use code-server. +To reiterate, code-server lets you run VS Code on a remote server and then access it via a browser. + +See [README.md](../README.md) for a general overview and [FAQ.md](./FAQ.md) for further user docs. + +We'll walk you through acquiring a remote machine to run code-server on and then exposing `code-server` so you can +securely access it. + +## 1. Acquire a remote machine + +First, you need a machine to run code-server on. You can use a physical +machine you have lying around or use a VM on GCP/AWS. + +### Requirements + +For a good experience, we recommend at least: + +- 1 GB of RAM +- 2 cores + +You can use whatever linux distribution floats your boat but in this guide we assume Debian on Google Cloud. + +### Google Cloud + +For demonstration purposes, this guide assumes you're using a VM on GCP but you should be +able to easily use any machine or VM provider. + +You can sign up at https://console.cloud.google.com/getting-started. You'll get a 12 month \$300 +free trial. + +Once you've signed up and created a GCP project, create a new Compute Engine VM Instance. + +1. Navigate to `Compute Engine -> VM Instances` on the sidebar. +2. Now click `Create Instance` to create a new instance. +3. Name it whatever you want. +4. Choose the region closest to you based on [gcping.com](http://www.gcping.com). +5. Any zone is fine. +6. We'd recommend a `E2` series instance from the General-purpose family. + - Change the type to custom and set at least 2 cores and 2 GB of ram. + - Add more vCPUs and memory as you prefer, you can edit after creating the instance as well. + - https://cloud.google.com/compute/docs/machine-types#general_purpose +7. We highly recommend switching the persistent disk to a SSD of at least 32 GB. + - Click `Change` under `Boot Disk` and change the type to `SSD Persistent Disk` and the size + to `32`. + - You can always grow your disk later. + - The default OS of Debian 10 is fine. +8. Navigate to `Networking -> Network interfaces` and edit the existing interface + to use a static external IP. + - Click done to save network interface changes. +9. If you do not have a [project wide SSH key](https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#project-wide), navigate to `Security - > SSH Keys` and add your public key there. +10. Click create! + +Remember, you can shutdown your server when not in use to lower costs. +We highly recommend learning to use the [`gcloud`](https://cloud.google.com/sdk/gcloud) cli +to avoid the slow dashboard. + +## 2. Install code-server + +SSH into your instance and run the appropriate commands documented in [README.md](../README.md). + +Assuming Debian: + +```bash +curl -sSOL https://github.com/cdr/code-server/releases/download/3.3.0/code-server_3.3.0_amd64.deb +sudo dpkg -i code-server_3.3.0_amd64.deb +systemctl --user enable --now code-server +# Now code-server is running at http://127.0.0.1:8080 +# Your password is in ~/.config/code-server/config.yaml +``` + +## 3. Expose code-server + +**Never**, **ever** expose `code-server` directly to the internet without some form of authentication +and encryption as someone can completely takeover your machine with the terminal. + +There are several approaches to securely operating and exposing code-server. + +By default, code-server will enable password authentication which will +require you to copy the password from the code-server config file to login. You +can also set a custom password with `$PASSWORD`. + +**tip**: You can list the full set of code-server options with `code-server --help` + +### SSH forwarding + +We highly recommend this approach for not requiring any additional setup, you just need an +SSH server on your remote machine. The downside is you won't be able to access `code-server` +without an SSH client like an iPad. If that's important to you, skip to [Let's Encrypt](#lets-encrypt). + +Recommended reading: https://help.ubuntu.com/community/SSH/OpenSSH/PortForwarding. + +First, ssh into your instance and edit your code-server config file to disable password authentication. + +```bash +# Replaces "auth: password" with "auth: none" in the code-server config. +sed -i.bak 's/auth: password/auth: none/' ~/.config/code-server/config.yaml +``` + +Restart code-server with (assuming you followed the guide): + +```bash +systemctl --user restart code-server +``` + +Now forward local port 8080 to `127.0.0.1:8080` on the remote instance. + +```bash +# -N disables executing a remote shell +ssh -N -L 8080:127.0.0.1:8080 +``` + +Now if you access http://127.0.0.1:8080 locally, you should see code-server! + +If you want to make the SSH port forwarding persistent we recommend using +[mutagen](https://mutagen.io/documentation/introduction/installation). + +``` +# Same as the above SSH command but runs in the background continously. +# Add `mutagen daemon start` to your ~/.bashrc to start the mutagen daemon when you open a shell. +mutagen forward create --name=code-server tcp:127.0.0.1:8080 :tcp:127.0.0.1:8080 +``` + +We also recommend adding the following lines to your `~/.ssh/config` to quickly detect bricked SSH connections: + +```bash +Host * +ServerAliveInterval 5 +ExitOnForwardFailure yes +``` + +You can also forward your SSH key and GPG agent to the instance to securely access GitHub +and sign commits without copying your keys onto the instance. + +1. https://developer.github.com/v3/guides/using-ssh-agent-forwarding/ +2. https://wiki.gnupg.org/AgentForwarding + +### Let's Encrypt + +[Let's Encrypt](https://letsencrypt.org) is a great option if you want to access code-server on an iPad +or do not want to use SSH forwarding. This does require that the remote machine is exposed to the internet. + +Assuming you have been following the guide, edit your instance and checkmark the allow HTTP/HTTPS traffic options. + +1. You'll need to buy a domain name. We recommend [Google Domains](https://domains.google.com). +2. Add an A record to your domain with your instance's IP. +3. Install caddy https://caddyserver.com/docs/download#debian-ubuntu-raspbian. + +```bash +echo "deb [trusted=yes] https://apt.fury.io/caddy/ /" \ + | sudo tee -a /etc/apt/sources.list.d/caddy-fury.list +sudo apt update +sudo apt install caddy +``` + +4. Replace `/etc/caddy/Caddyfile` with sudo to look like this: + +``` +mydomain.com + +reverse_proxy 127.0.0.1:8080 +``` + +5. Reload caddy with: + +```bash +sudo systemctl reload caddy +``` + +Visit `https://` to access code-server. Congratulations! + +In a future release we plan to integrate Let's Encrypt directly with code-server to avoid +the dependency on caddy. + +### Self Signed Certificate + +**note:** Self signed certificates do not work with iPad and will cause a blank page. You'll +have to use [Let's Encrypt](#lets-encrypt) instead. + +Recommended reading: https://security.stackexchange.com/a/8112. + +We recommend this as a last resort as self signed certificates do not work with iPads and can +cause other bizarre issues. Not to mention all the warnings when you access code-server. +Only use this if: + +1. You do not want to buy a domain. +2. You cannot expose the remote machine to the internet. +3. You do not want to use SSH forwarding. + +ssh into your instance and edit your code-server config file to use a randomly generated self signed certificate: + +```bash +# Replaces "cert: false" with "cert: true" in the code-server config. +sed -i.bak 's/cert: false/cert: true/' ~/.config/code-server/config.yaml +# Replaces "bind-addr: 127.0.0.1:8080" with "bind-addr: 0.0.0.0:443" in the code-server config. +sed -i.bak 's/bind-addr: 127.0.0.1:8080/bind-addr: 0.0.0.0:443/' ~/.config/code-server/config.yaml +# Allows code-server to listen on port 443. +sudo setcap cap_net_bind_service=+ep /usr/lib/code-server/lib/node +``` + +Assuming you have been following the guide, restart code-server with: + +```bash +systemctl --user restart code-server +``` + +Edit your instance and checkmark the allow HTTPS traffic option. + +Visit `https://` to access code-server. +You'll get a warning when accessing but if you click through you should be good. + +To avoid the warnings, you can use [mkcert](https://mkcert.dev) to create a self signed certificate +trusted by your OS and then pass it into code-server via the `cert` and `cert-key` config +fields. + +### Change the password? + +Edit the code-server config file at `~/.config/code-server/config.yaml` and then restart +code-server with: + +```bash +systemctl --user restart code-server +``` + +### How do I securely access development web services? + +If you're working on a web service and want to access it locally, code-server can proxy it for you. + +See [FAQ.md](https://github.com/cdr/code-server/blob/master/doc/FAQ.md#how-do-i-securely-access-web-services). diff --git a/doc/npm.md b/doc/npm.md new file mode 100644 index 00000000..08704c0c --- /dev/null +++ b/doc/npm.md @@ -0,0 +1,34 @@ +# npm Install Requirements + +If you're installing the npm module you'll need certain dependencies to build +the native modules used by VS Code. + +You also need at least node v12 installed. See [#1633](https://github.com/cdr/code-server/issues/1633). + +## Ubuntu, Debian + +```bash +sudo apt-get install -y \ + build-essential \ + pkg-config \ + libx11-dev \ + libxkbfile-dev \ + libsecret-1-dev +``` + +## Fedora, Red Hat, SUSE + +```bash +sudo yum groupinstall -y 'Development Tools' +sudo yum config-manager --set-enabled PowerTools +sudo yum install -y python2 libsecret-devel libX11-devel libxkbfile-devel +npm config set python python2 +``` + +## macOS + +Install [Xcode](https://developer.apple.com/xcode/downloads/) and run: + +```bash +xcode-select --install +``` diff --git a/package.json b/package.json index 87696289..fbb114c9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-server", "license": "MIT", - "version": "3.3.0-rc.7", + "version": "3.3.0", "description": "Run VS Code on a remote server.", "homepage": "https://github.com/cdr/code-server", "bugs": { @@ -11,8 +11,8 @@ "scripts": { "clean": "./ci/build/clean.sh", "vscode": "./ci/dev/vscode.sh", - "vscode:patch": "cd ./lib/vscode && git apply ../../ci/dev/vscode.patch", - "vscode:diff": "cd ./lib/vscode && git diff HEAD > ../../ci/dev/vscode.patch", + "vscode:patch": "./ci/dev/patch-vscode.sh", + "vscode:diff": "./ci/dev/diff-vscode.sh", "build": "./ci/build/build-code-server.sh", "build:vscode": "./ci/build/build-vscode.sh", "release": "./ci/build/build-release.sh", @@ -45,6 +45,7 @@ "@types/ws": "^6.0.4", "@typescript-eslint/eslint-plugin": "^2.0.0", "@typescript-eslint/parser": "^2.0.0", + "doctoc": "^1.4.0", "eslint": "^6.2.0", "eslint-config-prettier": "^6.0.0", "eslint-plugin-import": "^2.18.2", @@ -52,7 +53,7 @@ "leaked-handles": "^5.2.0", "mocha": "^6.2.0", "parcel-bundler": "^1.12.4", - "prettier": "^1.18.2", + "prettier": "^2.0.5", "stylelint": "^13.0.0", "stylelint-config-recommended": "^3.0.0", "ts-node": "^8.4.1", @@ -91,5 +92,8 @@ "coder", "vscode-remote", "browser-ide" - ] + ], + "engines": { + "node": ">= 12" + } } diff --git a/src/browser/pages/vscode.html b/src/browser/pages/vscode.html index abfb102c..72c39824 100644 --- a/src/browser/pages/vscode.html +++ b/src/browser/pages/vscode.html @@ -98,7 +98,7 @@ END_PROD_ONLY -->