Compare commits

..

5 Commits

Author SHA1 Message Date
Asher
325181d414 fixup! Catch up changelog 2022-03-03 19:40:50 +00:00
Asher
7b2b0e0b21 Add release as valid semantic tag 2022-03-03 19:31:37 +00:00
Asher
ae83e049b9 Catch up changelog 2022-03-03 19:31:37 +00:00
Asher
b2ac660763 Rename VS Code to Code in changelog 2022-03-03 19:22:07 +00:00
Asher
7d5bade76c release: bump version to 4.1.0 2022-03-03 19:21:56 +00:00
77 changed files with 2225 additions and 2818 deletions

View File

@@ -29,9 +29,6 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: true
- name: Install Node.js v14
uses: actions/setup-node@v3
@@ -41,17 +38,21 @@ jobs:
- name: Install helm
uses: azure/setup-helm@v1.1
- name: Fetch dependencies from cache
id: cache-yarn
uses: actions/cache@v3
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
yarn-build-
# NOTE@jsjoeio
# disabling this until we can audit the build process
# and the usefulness of this step
# See: https://github.com/coder/code-server/issues/4287
# - name: Fetch dependencies from cache
# id: cache-yarn
# uses: actions/cache@v2
# with:
# path: "**/node_modules"
# key: yarn-build-${{ hashFiles('**/yarn.lock') }}
# restore-keys: |
# yarn-build-
- name: Install dependencies
if: steps.cache-yarn.outputs.cache-hit != 'true'
# if: steps.cache-yarn.outputs.cache-hit != 'true'
run: yarn --frozen-lockfile
- name: Run yarn fmt
@@ -70,9 +71,6 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: true
- name: Install Node.js v14
uses: actions/setup-node@v3
@@ -81,7 +79,7 @@ jobs:
- name: Fetch dependencies from cache
id: cache-yarn
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
@@ -104,53 +102,56 @@ jobs:
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
steps:
- name: Checkout repo
uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: true
- name: Install quilt
run: sudo apt update && sudo apt install quilt
- name: Patch Code
run: quilt push -a
- name: Install Node.js v14
uses: actions/setup-node@v3
with:
node-version: "14"
- name: Fetch dependencies from cache
id: cache-yarn
uses: actions/cache@v3
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
yarn-build-
# TODO@Teffen investigate why this omits code-oss-dev/node_modules
# - name: Fetch dependencies from cache
# id: cache-yarn
# uses: actions/cache@v2
# with:
# path: |
# "**/node_modules"
# "**/vendor/modules"
# "**/vendor/modules/code-oss-dev/node_modules"
# key: yarn-build-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('**/vendor/yarn.lock') }}
# restore-keys: |
# yarn-build-
- name: Install dependencies
if: steps.cache-yarn.outputs.cache-hit != 'true'
# if: steps.cache-yarn.outputs.cache-hit != 'true'
run: yarn --frozen-lockfile
- name: Build code-server
run: yarn build
# Get Code's git hash. When this changes it means the content is
# different and we need to rebuild.
- name: Get latest lib/vscode rev
# Parse the hash of the latest commit inside vendor/modules/code-oss-dev
# use this to avoid rebuilding it if nothing changed
# How it works: the `git log` command fetches the hash of the last commit
# that changed a file inside `vendor/modules/code-oss-dev`. If a commit changes any file in there,
# the hash returned will change, and we rebuild vscode. If the hash did not change,
# (for example, a change to `src/` or `docs/`), we reuse the same build as last time.
# This saves a lot of time in CI, as compiling VSCode can take anywhere from 5-10 minutes.
- name: Get latest vendor/modules/code-oss-dev rev
id: vscode-rev
run: echo "::set-output name=rev::$(git rev-parse HEAD:./lib/vscode)"
run: echo "::set-output name=rev::$(jq -r '.devDependencies["code-oss-dev"]' vendor/package.json | sed -r 's|.*#(.*)$|\1|')"
# We need to rebuild when we have a new version of Code or when any of
# the patches changed. Use VSCODE_CACHE_VERSION to force a rebuild.
- name: Fetch prebuilt Code package from cache
- name: Attempt to fetch vscode build from cache
id: cache-vscode
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: lib/vscode-reh-web-*
key: vscode-reh-package-${{ secrets.VSCODE_CACHE_VERSION }}-${{ steps.vscode-rev.outputs.rev }}-${{ hashFiles('patches/*.diff') }}
path: |
vendor/modules/code-oss-dev/.build
vendor/modules/code-oss-dev/out-build
vendor/modules/code-oss-dev/out-vscode-reh-web
vendor/modules/code-oss-dev/out-vscode-reh-web-min
key: vscode-reh-build-${{ steps.vscode-rev.outputs.rev }}
- name: Build vscode
if: steps.cache-vscode.outputs.cache-hit != 'true'
@@ -178,7 +179,7 @@ jobs:
run: tar -czf package.tar.gz release
- name: Upload npm package artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: npm-package
path: ./package.tar.gz
@@ -195,13 +196,9 @@ jobs:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/checkout@v3
- name: Download artifact
uses: actions/download-artifact@v3
- uses: actions/download-artifact@v3
id: download
with:
name: "npm-package"
@@ -228,10 +225,7 @@ jobs:
container: "centos:7"
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/checkout@v3
- name: Install Node.js v14
uses: actions/setup-node@v3
@@ -274,7 +268,7 @@ jobs:
run: yarn package
- name: Upload release artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: release-packages
path: ./release-packages
@@ -320,10 +314,7 @@ jobs:
NODE_VERSION: v14.17.4
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/checkout@v3
- name: Install Node.js v14
uses: actions/setup-node@v3
@@ -361,7 +352,7 @@ jobs:
run: yarn package ${NPM_CONFIG_ARCH}
- name: Upload release artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: release-packages
path: ./release-packages
@@ -372,10 +363,7 @@ jobs:
runs-on: macos-latest
timeout-minutes: 15
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/checkout@v3
- name: Install Node.js v14
uses: actions/setup-node@v3
@@ -405,7 +393,7 @@ jobs:
run: yarn package
- name: Upload release artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: release-packages
path: ./release-packages
@@ -420,11 +408,7 @@ jobs:
# since VS Code will load faster due to the bundling.
CODE_SERVER_TEST_ENTRY: "./release-packages/code-server-linux-amd64"
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: true
- uses: actions/checkout@v3
- name: Install Node.js v14
uses: actions/setup-node@v3
@@ -433,7 +417,7 @@ jobs:
- name: Fetch dependencies from cache
id: cache-yarn
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
@@ -466,7 +450,7 @@ jobs:
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: failed-test-videos
path: ./test/test-results
@@ -477,12 +461,10 @@ jobs:
trivy-scan-repo:
runs-on: ubuntu-20.04
steps:
- name: Checkout repo
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Run Trivy vulnerability scanner in repo mode
#Commit SHA for v0.0.17
uses: aquasecurity/trivy-action@296212627a1e693efa09c00adc3e03b2ba8edf18
with:
scan-type: "fs"
@@ -492,7 +474,6 @@ jobs:
template: "@/contrib/sarif.tpl"
output: "trivy-repo-results.sarif"
severity: "HIGH,CRITICAL"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v1
with:

View File

@@ -35,19 +35,6 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get version
id: version
run: echo "::set-output name=version::$(jq .version package.json)"
- name: Download artifact
uses: dawidd6/action-download-artifact@v2
id: download
with:
branch: v${{ steps.version.outputs.version }}
workflow_conclusion: completed
name: "release-packages"
path: release-packages
- name: Run ./ci/steps/docker-buildx-push.sh
run: ./ci/steps/docker-buildx-push.sh
env:

View File

@@ -17,24 +17,89 @@ permissions:
security-events: none
statuses: none
# Cancel in-progress runs for pull requests when developers push
# additional changes, and serialize builds in branches.
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
preview:
name: Docs preview
runs-on: ubuntu-20.04
environment: CI
# Only run if PR comes from base repo
# Reason: forks cannot access secrets and this will always fail
if: github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v3
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
- name: Set outputs
id: vars
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
- name: Checkout m
uses: actions/checkout@v3
with:
repository: coder/m
ref: refs/heads/master
ssh-key: ${{ secrets.READONLY_M_DEPLOY_KEY }}
submodules: true
fetch-depth: 0
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 14
- 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: |
code-server docs for PR #${{ github.event.number }} is ready! It will be updated on every commit.
* _Host_: https://coder.com/docs/code-server/${{ steps.vars.outputs.sha_short }}
* _Last deploy status_: success
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 }}

View File

@@ -23,16 +23,9 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Get version
id: version
run: echo "::set-output name=version::$(jq .version package.json)"
- name: Download artifact
uses: dawidd6/action-download-artifact@v2
- uses: actions/download-artifact@v3
id: download
with:
branch: v${{ steps.version.outputs.version }}
workflow_conclusion: completed
name: "npm-package"
path: release-npm-package
@@ -56,20 +49,11 @@ jobs:
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
- name: Checkout code-server
uses: actions/checkout@v3
- name: Checkout cdrci/homebrew-core
uses: actions/checkout@v3
with:
repository: cdrci/homebrew-core
path: homebrew-core
- uses: actions/checkout@v3
- name: Configure git
run: |
git config user.name github-actions
git config user.email github-actions@github.com
- name: Bump code-server homebrew version
env:
HOMEBREW_GITHUB_API_TOKEN: ${{secrets.HOMEBREW_GITHUB_API_TOKEN}}

View File

@@ -1,65 +0,0 @@
name: Trivy Nightly Docker Scan
on:
# Run scans if the workflow is modified, in order to test the
# workflow itself. This results in some spurious notifications,
# but seems okay for testing.
pull_request:
branches:
- main
paths:
- .github/workflows/trivy-docker.yaml
# Run scans against master whenever changes are merged.
push:
branches:
- main
paths:
- .github/workflows/trivy-docker.yaml
schedule:
# Run at 10:15 am UTC (3:15am PT/5:15am CT)
# Run at 0 minutes 0 hours of every day.
- cron: "15 10 * * *"
workflow_dispatch:
permissions:
actions: none
checks: none
contents: read
deployments: none
issues: none
packages: none
pull-requests: none
repository-projects: none
security-events: write
statuses: none
# Cancel in-progress runs for pull requests when developers push
# additional changes, and serialize builds in branches.
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
trivy-scan-image:
runs-on: ubuntu-20.04
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run Trivy vulnerability scanner in image mode
uses: aquasecurity/trivy-action@296212627a1e693efa09c00adc3e03b2ba8edf18
with:
image-ref: "docker.io/codercom/code-server:latest"
ignore-unfixed: true
format: "sarif"
output: "trivy-image-results.sarif"
severity: "HIGH,CRITICAL"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: "trivy-image-results.sarif"

9
.gitignore vendored
View File

@@ -8,17 +8,12 @@ release-packages/
release-gcp/
release-images/
node_modules
vendor/modules
node-*
/plugins
/lib/coder-cloud-agent
.home
coverage
**/.DS_Store
# Code packages itself here.
/lib/vscode-reh-web-*
# Failed e2e test videos are saved here
test/test-results
# Quilt's internal data.
/.pc

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "lib/vscode"]
path = lib/vscode
url = https://github.com/microsoft/vscode

View File

@@ -7,7 +7,7 @@ useTabs: false
overrides:
# Attempt to keep VScode's existing code style intact.
- files: "lib/vscode/**/*.ts"
- files: "vendor/modules/code-oss-dev/**/*.ts"
options:
# No limit defined upstream.
printWidth: 10000

View File

@@ -143,7 +143,7 @@
"description": "Static images and the manifest live here in `src/browser/media` (see the explorer)."
},
{
"directory": "lib/vscode",
"directory": "vendor/modules/code-oss-dev",
"line": 1,
"description": "code-server makes use of VS Code's frontend web/remote support. Most of the modifications implement the remote server since that portion of the code is closed source and not released with VS Code.\n\nWe also have a few bug fixes and have added some features (like client-side extensions). See [https://github.com/coder/code-server/blob/master/docs/CONTRIBUTING.md#modifications-to-vs-code](https://github.com/coder/code-server/blob/master/docs/CONTRIBUTING.md#modifications-to-vs-code) for a list.\n\nWe make an effort to keep the modifications as few as possible."
}

View File

@@ -20,34 +20,13 @@ VS Code v99.99.999
-->
## [4.2.0](https://github.com/coder/code-server/releases/tag/v4.2.0) - 2022-03-22
## [Unreleased](https://github.com/coder/code-server/releases)
Code v1.64.2
### Added
- Added tests for `handleArgsSocketCatchError`, `setDefaults` and
`optionDescriptions`.
Code v0.00.0
### Changed
- We switched from using the fork `coder/vscode` to a submodule of
`microsoft/vscode` + patches managed by `quilt` for how Code sits inside the
code-server codebase.
- Upgraded to Code 1.64.2.
### Fixed
- Update popup notification through `--disable-update-check` is now fixed.
- Fixed PWA icons not loading on iPad
- Fixed the homebrew release process. Our `cdrci` bot should now automatically
update the version as part of the release pipeline.
- Fixed titleBar color setting being ignored in PWA.
### Security
- Updated to `minimist-list`.
- Updated `cloud-agent` to `v0.2.4` which uses `nhooyr.io/webscoket` `v1.8.7`.
- Add here
## [4.1.0](https://github.com/coder/code-server/releases/tag/v4.1.0) - 2022-03-03

View File

@@ -50,11 +50,6 @@ release_nfpm() {
export NFPM_ARCH
# Code deletes some files from the extension node_modules directory which
# leaves broken symlinks in the corresponding .bin directory. nfpm will fail
# on these broken symlinks so clean them up.
rm -fr "./release-standalone/lib/vscode/extensions/node_modules/.bin"
PKG_FORMAT="deb"
NFPM_ARCH="$(get_nfpm_arch $PKG_FORMAT "$ARCH")"
nfpm_config="$(envsubst < ./ci/build/nfpm.yaml)"

View File

@@ -15,8 +15,8 @@ main() {
source ./ci/lib.sh
VSCODE_SRC_PATH="lib/vscode"
VSCODE_OUT_PATH="$RELEASE_PATH/lib/vscode"
VSCODE_SRC_PATH="vendor/modules/code-oss-dev"
VSCODE_OUT_PATH="$RELEASE_PATH/vendor/modules/code-oss-dev"
mkdir -p "$RELEASE_PATH"
@@ -25,7 +25,7 @@ main() {
rsync ./docs/README.md "$RELEASE_PATH"
rsync LICENSE.txt "$RELEASE_PATH"
rsync ./lib/vscode/ThirdPartyNotices.txt "$RELEASE_PATH"
rsync ./vendor/modules/code-oss-dev/ThirdPartyNotices.txt "$RELEASE_PATH"
}
bundle_code_server() {
@@ -66,10 +66,31 @@ EOF
bundle_vscode() {
mkdir -p "$VSCODE_OUT_PATH"
rsync ./lib/vscode-reh-web-*/ "$VSCODE_OUT_PATH"
rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH"
rsync "$VSCODE_SRC_PATH/out-vscode-reh-web${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
# Add the commit, date, our name, links, and enable telemetry. This just makes
# telemetry available; telemetry can still be disabled by flag or setting.
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
if [ "$KEEP_MODULES" = 0 ]; then
rm -Rf "$VSCODE_OUT_PATH/extensions/node_modules"
else
rsync "$VSCODE_SRC_PATH/node_modules/" "$VSCODE_OUT_PATH/node_modules"
fi
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/"
rsync "$VSCODE_SRC_PATH/resources/" "$VSCODE_OUT_PATH/resources/"
# TODO: We should look into using VS Code's packaging task (see
# gulpfile.reh.js). For now copy this directory into the right spot (for some
# reason VS Code uses a different path in production).
mkdir -p "$VSCODE_OUT_PATH/bin/helpers"
rsync "$VSCODE_SRC_PATH/resources/server/bin/helpers/" "$VSCODE_OUT_PATH/bin/helpers"
chmod +x "$VSCODE_OUT_PATH/bin/helpers/browser.sh"
# Add the commit and date and enable telemetry. This just makes telemetry
# available; telemetry can still be disabled by flag or setting.
jq --slurp '.[0] * .[1]' "$VSCODE_SRC_PATH/product.json" <(
cat << EOF
{
@@ -77,48 +98,15 @@ bundle_vscode() {
"commit": "$(cd "$VSCODE_SRC_PATH" && git rev-parse HEAD)",
"quality": "stable",
"date": $(jq -n 'now | todate'),
"codeServerVersion": "$VERSION",
"nameShort": "code-server",
"nameLong": "code-server",
"applicationName": "code-server",
"dataFolderName": ".code-server",
"win32MutexName": "codeserver",
"licenseUrl": "https://github.com/coder/code-server/blob/main/LICENSE.txt",
"win32DirName": "code-server",
"win32NameVersion": "code-server",
"win32AppUserModelId": "coder.code-server",
"win32ShellNameShort": "c&ode-server",
"darwinBundleIdentifier": "com.coder.code.server",
"linuxIconName": "com.coder.code.server",
"reportIssueUrl": "https://github.com/coder/code-server/issues/new",
"documentationUrl": "https://go.microsoft.com/fwlink/?LinkID=533484#vscode",
"keyboardShortcutsUrlMac": "https://go.microsoft.com/fwlink/?linkid=832143",
"keyboardShortcutsUrlLinux": "https://go.microsoft.com/fwlink/?linkid=832144",
"keyboardShortcutsUrlWin": "https://go.microsoft.com/fwlink/?linkid=832145",
"introductoryVideosUrl": "https://go.microsoft.com/fwlink/?linkid=832146",
"tipsAndTricksUrl": "https://go.microsoft.com/fwlink/?linkid=852118",
"newsletterSignupUrl": "https://www.research.net/r/vsc-newsletter",
"linkProtectionTrustedDomains": [
"https://open-vsx.org"
]
"codeServerVersion": "$VERSION"
}
EOF
) > "$VSCODE_OUT_PATH/product.json"
# Use the package.json for the web/remote server. It does not have the right
# version though so pull that from the main package.json. Also remove keytar
# since the web does not rely on it and that removes the dependency on
# libsecret.
jq --slurp '.[0] * {version: .[1].version} | del(.dependencies.keytar)' \
"$VSCODE_SRC_PATH/remote/package.json" \
"$VSCODE_SRC_PATH/package.json" > "$VSCODE_OUT_PATH/package.json"
rsync "$VSCODE_SRC_PATH/remote/yarn.lock" "$VSCODE_OUT_PATH/yarn.lock"
if [ "$KEEP_MODULES" = 0 ]; then
rm -Rf "$VSCODE_OUT_PATH/extensions/node_modules"
rm -Rf "$VSCODE_OUT_PATH/node_modules"
fi
# We remove the scripts field so that later on we can run
# yarn to fetch node_modules if necessary without build scripts running.
# We cannot use --no-scripts because we still want dependent package scripts to run.
jq 'del(.scripts)' < "$VSCODE_SRC_PATH/package.json" > "$VSCODE_OUT_PATH/package.json"
pushd "$VSCODE_OUT_PATH"
symlink_asar

View File

@@ -29,6 +29,12 @@ main() {
cd "$RELEASE_PATH"
yarn --production --frozen-lockfile
# HACK: the version of Typescript vscode 1.57 uses in extensions/
# leaves a few stray symlinks. Clean them up so nfpm does not fail.
# Remove this line when its no longer needed.
rm -fr "$RELEASE_PATH/vendor/modules/code-oss-dev/extensions/node_modules/.bin"
}
main "$@"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
# Builds vscode into lib/vscode/out-vscode.
# Builds vscode into vendor/modules/code-oss-dev/out-vscode.
# MINIFY controls whether a minified version of vscode is built.
MINIFY=${MINIFY-true}
@@ -9,7 +9,7 @@ MINIFY=${MINIFY-true}
main() {
cd "$(dirname "${0}")/../.."
cd lib/vscode
cd vendor/modules/code-oss-dev
# Any platform works since we have our own packaging step (for now).
yarn gulp "vscode-reh-web-linux-x64${MINIFY:+-min}"

View File

@@ -90,8 +90,8 @@ symlink_asar() {
}
vscode_yarn() {
echo 'Installing Code dependencies...'
cd lib/vscode
echo 'Installing vendor dependencies...'
cd vendor/modules/code-oss-dev
yarn --production --frozen-lockfile
symlink_asar

View File

@@ -9,15 +9,6 @@ set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
source ./ci/steps/steps-lib.sh
# NOTE@jsjoeio - only needed if we use the download_artifact
# because we talk to the GitHub API.
# Needed to use GitHub API
if ! is_env_var_set "GITHUB_TOKEN"; then
echo "GITHUB_TOKEN is not set. Cannot download npm release-packages without GitHub credentials."
exit 1
fi
download_artifact release-packages ./release-packages
local assets=(./release-packages/code-server*"$VERSION"*{.tar.gz,.deb,.rpm})

View File

@@ -19,7 +19,7 @@ main() {
"*.sh"
)
prettier --write --loglevel=warn $(
git ls-files "${prettierExts[@]}" | grep -v "lib/vscode" | grep -v 'helm-chart'
git ls-files "${prettierExts[@]}" | grep -v "lib/vscode" | grep -v "vendor/modules/code-oss-dev" | grep -v 'helm-chart'
)
doctoc --title '# FAQ' docs/FAQ.md > /dev/null

View File

@@ -4,10 +4,10 @@ set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js" | grep -v "lib/vscode")
stylelint $(git ls-files "*.css" | grep -v "lib/vscode")
eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js" | grep -v "vendor/modules/code-oss-dev" | grep -v "lib/vscode")
stylelint $(git ls-files "*.css" | grep -v "vendor/modules/code-oss-dev" | grep -v "lib/vscode")
tsc --noEmit --skipLibCheck
shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh" | grep -v "lib/vscode")
shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh" | grep -v "vendor/modules/code-oss-dev" | grep -v "lib/vscode")
if command -v helm && helm kubeval --help > /dev/null; then
helm kubeval ci/helm-chart
fi

View File

@@ -1,32 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail
# Install dependencies in $1.
install-deps() {
local args=(install)
if [[ ${CI-} ]]; then
args+=(--frozen-lockfile)
fi
# If there is no package.json then yarn will look upward and end up installing
# from the root resulting in an infinite loop (this can happen if you have not
# checked out the submodule yet for example).
if [[ ! -f "$1/package.json" ]]; then
echo "$1/package.json is missing; did you run git submodule update --init?"
exit 1
fi
pushd "$1"
echo "Installing dependencies for $PWD"
yarn "${args[@]}"
popd
}
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
install-deps test
install-deps test/e2e/extensions/test-extension
install-deps lib/vscode
pushd test
echo "Installing dependencies for $PWD"
yarn install
popd
local args=(install)
if [[ ${CI-} ]]; then
args+=(--frozen-lockfile)
fi
pushd test
echo "Installing dependencies for $PWD"
yarn "${args[@]}"
popd
pushd test/e2e/extensions/test-extension
echo "Installing dependencies for $PWD"
yarn "${args[@]}"
popd
pushd vendor
echo "Installing dependencies for $PWD"
# We install in 'modules' instead of 'node_modules' because VS Code's
# extensions use a webpack config which cannot differentiate between its own
# node_modules and itself being in a directory with the same name.
args+=(--modules-folder modules)
# We ignore scripts because NPM/Yarn's default behavior is to assume that
# devDependencies are not needed, and that even git repo based packages are
# assumed to be compiled. Because the default behavior for VS Code's
# `postinstall` assumes we're also compiled, this needs to be ignored.
args+=(--ignore-scripts)
yarn "${args[@]}"
# Finally, run the vendor `postinstall`
yarn run postinstall
popd
}
main "$@"

View File

@@ -37,7 +37,7 @@ main() {
exit 1
fi
if [[ ! -d $dir/lib/vscode/out ]]; then
if [[ ! -d $dir/vendor/modules/code-oss-dev/out ]]; then
echo >&2 "No VS Code build detected"
help
exit 1

View File

@@ -14,17 +14,11 @@ main() {
# Our code imports from `out` in order to work during development but if you
# have only built for production you will have not have this directory. In
# that case symlink `out` to a production build directory.
if [[ ! -e lib/vscode/out ]]; then
pushd lib
local out=(vscode-reh-web-*)
if [[ -d "${out[0]}" ]]; then
ln -s "../${out[0]}/out" ./vscode/out
else
echo "Could not find lib/vscode/out or lib/vscode-reh-web-*"
echo "Code must be built before running unit tests"
exit 1
fi
popd
local vscode="vendor/modules/code-oss-dev"
local link="$vscode/out"
local target="out-build"
if [[ ! -e $link ]] && [[ -d $vscode/$target ]]; then
ln -s "$target" "$link"
fi
# We must keep jest in a sub-directory. See ../../test/package.json for more

View File

@@ -14,7 +14,7 @@ class Watcher {
private rootPath = path.resolve(process.cwd())
private readonly paths = {
/** Path to uncompiled VS Code source. */
vscodeDir: path.join(this.rootPath, "lib/vscode"),
vscodeDir: path.join(this.rootPath, "vendor", "modules", "code-oss-dev"),
pluginDir: process.env.PLUGIN_DIR,
}

View File

@@ -15,9 +15,9 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 2.3.0
version: 2.2.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: 4.2.0
appVersion: 4.1.0

View File

@@ -6,7 +6,7 @@ replicaCount: 1
image:
repository: codercom/code-server
tag: '4.2.0'
tag: '4.1.0'
pullPolicy: Always
# Specifies one or more secrets to be used when pulling images from a

View File

@@ -14,7 +14,7 @@ pkg_json_version() {
}
vscode_version() {
jq -r .version lib/vscode/package.json
jq -r .version vendor/modules/code-oss-dev/package.json
}
os() {

View File

@@ -2,9 +2,7 @@
set -euo pipefail
main() {
REPO="homebrew-core"
GITHUB_USERNAME="cdrci"
UPSTREAM_USERNAME_AND_REPO="Homebrew/$REPO"
cd "$(dirname "$0")/../.."
# Only sourcing this so we get access to $VERSION
source ./ci/lib.sh
source ./ci/steps/steps-lib.sh
@@ -23,18 +21,25 @@ main() {
exit 1
fi
# NOTE: we need to make sure coderci/homebrew-core
# is up-to-date
# otherwise, brew bump-formula-pr will use an
# outdated base
echo "Cloning coderci/homebrew-core"
git clone https://github.com/coderci/homebrew-core.git
# Make sure the git clone step is successful
if ! directory_exists "$REPO"; then
echo "git clone failed. Cannot find $REPO directory."
if directory_exists "homebrew-core"; then
echo "git clone failed. Cannot find homebrew-core directory."
ls -la
exit 1
fi
echo "Changing into $REPO directory"
pushd "$REPO" && pwd
echo "Changing into homebrew-core directory"
pushd homebrew-core && pwd
echo "Adding $UPSTREAM_USERNAME_AND_REPO"
git remote add upstream "https://github.com/$UPSTREAM_USERNAME_AND_REPO.git"
echo "Adding Homebrew/homebrew-core"
git remote add upstream https://github.com/Homebrew/homebrew-core.git
# Make sure the git remote step is successful
if ! git config remote.upstream.url > /dev/null; then
@@ -45,22 +50,24 @@ main() {
fi
# TODO@jsjoeio - can I somehow check that this succeeded?
echo "Fetching upstream $UPSTREAM_USERNAME_AND_REPO commits"
git fetch upstream master
echo "Fetching upstream Homebrew/hombrew-core commits"
git fetch upstream
# TODO@jsjoeio - can I somehow check that this succeeded?
echo "Merging in latest $UPSTREAM_USERNAME_AND_REPO changes branch master"
echo "Merging in latest Homebrew/homebrew-core changes"
git merge upstream/master
echo "Pushing changes to coderci/homebrew-core fork on GitHub"
# GIT_ASKPASS lets us use the password when pushing without revealing it in the process list
# See: https://serverfault.com/a/912788
PATH_TO_GIT_ASKPASS="$HOME/git-askpass.sh"
# Source: https://serverfault.com/a/912788
# shellcheck disable=SC2016,SC2028
echo 'echo $HOMEBREW_GITHUB_API_TOKEN' > "$PATH_TO_GIT_ASKPASS"
echo 'echo $HOMEBREW_GITHUB_API_TOKEN' > "$PATH_TO_ASKPASS"
# Make sure the git-askpass.sh file creation is successful
if ! file_exists "$PATH_TO_GIT_ASKPASS"; then
if file_exists "$PATH_TO_GIT_ASKPASS"; then
echo "git-askpass.sh not found in $HOME."
ls -la "$HOME"
exit 1
@@ -70,20 +77,16 @@ main() {
chmod +x "$PATH_TO_GIT_ASKPASS"
# Make sure the git-askpass.sh file is executable
if ! is_executable "$PATH_TO_GIT_ASKPASS"; then
if is_executable "$PATH_TO_GIT_ASKPASS"; then
echo "$PATH_TO_GIT_ASKPASS is not executable."
ls -la "$PATH_TO_GIT_ASKPASS"
exit 1
fi
# NOTE: we need to make sure our fork is up-to-date
# otherwise, brew bump-formula-pr will use an
# outdated base
echo "Pushing changes to $GITHUB_USERNAME/$REPO fork on GitHub"
# Export the variables so git sees them
export HOMEBREW_GITHUB_API_TOKEN="$HOMEBREW_GITHUB_API_TOKEN"
export GIT_ASKPASS="$PATH_TO_GIT_ASKPASS"
git push "https://$GITHUB_USERNAME@github.com/$GITHUB_USERNAME/$REPO.git" --all
export GIT_ASKPASS="$PATH_TO_ASKPASS"
git push https://coder-oss@github.com/coder-oss/homebrew-core.git --all
# Find the docs for bump-formula-pr here
# https://github.com/Homebrew/brew/blob/master/Library/Homebrew/dev-cmd/bump-formula-pr.rb#L18
@@ -91,12 +94,21 @@ main() {
if ! output=$(brew bump-formula-pr --version="${VERSION}" code-server --no-browse --no-audit 2>&1); then
if [[ $output == *"Duplicate PRs should not be opened"* ]]; then
echo "$VERSION is already submitted"
exit 0
else
echo "$output"
exit 1
fi
fi
# Clean up and remove homebrew-core
popd
rm -rf homebrew-core
# Make sure homebrew-core is removed
if directory_exists "homebrew-core"; then
echo "rm -rf homebrew-core failed."
ls -la
fi
}
main "$@"

View File

@@ -4,9 +4,12 @@ set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
# NOTE@jsjoeio - this script assumes that you've downloaded
# the release-packages artifact to ./release-packages before
# running this docker buildx step
# ci/lib.sh sets VERSION and provides download_artifact here
source ./ci/lib.sh
# Download the release-packages artifact
download_artifact release-packages ./release-packages
docker buildx bake -f ci/release-image/docker-bake.hcl --push
}

View File

@@ -13,6 +13,14 @@ main() {
exit 1
fi
# NOTE@jsjoeio - only needed if we use the download_artifact
# because we talk to the GitHub API.
# Needed to use GitHub API
if ! is_env_var_set "GITHUB_TOKEN"; then
echo "GITHUB_TOKEN is not set. Cannot download npm release artifact without GitHub credentials."
exit 1
fi
## Publishing Information
# All the variables below are used to determine how we should publish
# the npm package. We also use this information for bumping the version.
@@ -43,13 +51,6 @@ main() {
exit 1
fi
# Check that we're using at least v7 of npm CLI
if ! command -v jq &> /dev/null; then
echo "Couldn't find jq"
echo "We need this in order to modify the package.json for dev builds."
exit 1
fi
# This allows us to publish to npm in CI workflows
if [[ ${CI-} ]]; then
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
@@ -85,10 +86,6 @@ main() {
# See: https://github.com/coder/code-server/pull/3935
echo "node_modules.asar" > release/.npmignore
# We use this to set the name of the package in the
# package.json
PACKAGE_NAME="code-server"
# NOTES:@jsjoeio
# We only need to run npm version for "development" and "staging".
# This is because our release:prep script automatically bumps the version
@@ -115,14 +112,12 @@ main() {
# Source: https://github.com/actions/checkout/issues/58#issuecomment-614041550
PR_NUMBER=$(echo "$GITHUB_REF" | awk 'BEGIN { FS = "/" } ; { print $3 }')
NPM_VERSION="$VERSION-$PR_NUMBER-$COMMIT_SHA"
PACKAGE_NAME="@coder/code-server-pr"
# This means the npm version will be tagged with "<pr number>"
# and installed when a user runs `yarn install code-server@<pr number>`
NPM_TAG="$PR_NUMBER"
fi
echo "using tag: $NPM_TAG"
echo "using package name: $PACKAGE_NAME"
# We modify the version in the package.json
# to be the current version + the PR number + commit SHA
@@ -130,14 +125,9 @@ main() {
# Example: "version": "4.0.1-4769-ad7b23cfe6ffd72914e34781ef7721b129a23040"
# Example: "version": "4.0.1-beta-ad7b23cfe6ffd72914e34781ef7721b129a23040"
pushd release
# NOTE@jsjoeio
# NOTE:@jsjoeio
# I originally tried to use `yarn version` but ran into issues and abandoned it.
npm version "$NPM_VERSION"
# NOTE@jsjoeio
# Use the development package name
# This is so we don't clutter the code-server versions on npm
# with development versions.
jq ".name |= \"$PACKAGE_NAME\"" package.json
popd
fi
@@ -151,10 +141,7 @@ main() {
return
fi
# NOTE@jsjoeio
# Since the dev builds are scoped to @coder
# We pass --access public to ensure npm knows it's not private.
yarn publish --non-interactive release --tag "$NPM_TAG" --access public
yarn publish --non-interactive release --tag "$NPM_TAG"
}
main "$@"

View File

@@ -7,8 +7,7 @@
- [Creating pull requests](#creating-pull-requests)
- [Commits and commit history](#commits-and-commit-history)
- [Development workflow](#development-workflow)
- [Version updates to Code](#version-updates-to-code)
- [Patching Code](#patching-code)
- [Updates to VS Code](#updates-to-vs-code)
- [Build](#build)
- [Help](#help)
- [Test](#test)
@@ -17,7 +16,7 @@
- [Integration tests](#integration-tests)
- [End-to-end tests](#end-to-end-tests)
- [Structure](#structure)
- [Modifications to Code](#modifications-to-code)
- [Modifications to VS Code](#modifications-to-vs-code)
- [Currently Known Issues](#currently-known-issues)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -45,8 +44,6 @@ Here is what is needed:
signature
verification](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification)
or follow [this tutorial](https://joeprevite.com/verify-commits-on-github)
- `quilt`
- Used to manage patches to Code
- `rsync` and `unzip`
- Used for code-server releases
- `bats`
@@ -60,7 +57,7 @@ If you're developing code-server on Linux, make sure you have installed or insta
sudo apt-get install build-essential g++ libx11-dev libxkbfile-dev libsecret-1-dev python-is-python3
```
These are required by Code. See [their Wiki](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites) for more information.
These are required by VS Code. See [their Wiki](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites) for more information.
## Creating pull requests
@@ -81,44 +78,41 @@ we'll guide you.
## Development workflow
The current development workflow is a bit tricky because we have this repo and we use our `coder/vscode` fork inside it with [`yarn link`](https://classic.yarnpkg.com/lang/en/docs/cli/link/).
Here are these steps you should follow to get your dev environment setup:
1. `git clone https://github.com/coder/code-server.git` - Clone `code-server`
2. `git submodule update --init` - Clone `vscode` submodule
3. `quilt push -a` - Apply patches to the `vscode` submodule.
4. `yarn` - Install dependencies
5. `yarn watch` - Launch code-server localhost:8080. code-server will be live
reloaded when changes are made; the browser needs to be refreshed manually.
2. `git clone https://github.com/coder/vscode.git` - Clone `vscode`
3. `cd vscode && yarn install` - install the dependencies in the `vscode` repo
4. `cd code-server && yarn install` - install the dependencies in the `code-server` repo
5. `cd vscode && yarn link` - use `yarn` to create a symlink to the `vscode` repo (`code-oss-dev` package)
6. `cd code-server && yarn link code-oss-dev --modules-folder vendor/modules` - links your local `vscode` repo (`code-oss-dev` package) inside your local version of code-server
7. `cd code-server && yarn watch` - this will spin up code-server on localhost:8080 which you can start developing. It will live reload changes to the source.
When pulling down changes that include modifications to the patches you will
need to apply them with `quilt`. If you pull down changes that update the
`vscode` submodule you will need to run `git submodule update --init` and
re-apply the patches.
### Updates to VS Code
### Version updates to Code
If changes are made and merged into `main` in the [`coder/vscode`](https://github.com/coder/vscode) repo, then you'll need to update the version in the `code-server` repo by following these steps:
1. Update the package tag listed in `vendor/package.json`:
```json
{
"devDependencies": {
"vscode": "coder/vscode#<latest-commit-sha>"
}
}
```
1. Update the `lib/vscode` submodule to the desired upstream version branch.
2. From the code-server **project root**, run `yarn install`.
3. Apply the patches (`quilt push -a`) or restore your stashed changes. At this
stage you may need to resolve conflicts. For example use `quilt push -f`,
manually apply the rejected portions, then `quilt refresh`.
4. Test code-server locally to make sure everything works.
5. Check the Node.js version that's used by Electron (which is shipped with VS
Then, test code-server locally to make sure everything works.
3. Check the Node.js version that's used by Electron (which is shipped with VS
Code. If necessary, update your version of Node.js to match.
6. Commit the updated submodule and patches to `code-server`.
7. Open a PR.
4. Open a PR
### Patching Code
0. You can go through the patch stack with `quilt push` and `quilt pop`.
1. Create a new patch (`quilt new {name}.diff`) or use an existing patch.
2. Add the file(s) you are patching (`quilt add [-P patch] {file}`). A file
**must** be added before you make changes to it.
3. Make your changes. Patches do not need to be independent of each other but
each patch must result in a working code-server without any broken in-between
states otherwise they are difficult to test and modify.
4. Add your changes to the patch (`quilt refresh`)
5. Add a comment in the patch about the reason for the patch and how to
reproduce the behavior it fixes or adds. Every patch should have an e2e test
as well.
> Watch for updates to
> `vendor/modules/code-oss-dev/src/vs/code/browser/workbench/workbench.html`. You may need to
> make changes to `src/browser/pages/vscode.html`.
### Build
@@ -214,46 +208,99 @@ code-server running locally. In CI, this is taken care of for you.
## Structure
The `code-server` script serves as an HTTP API for login and starting a remote
The `code-server` script serves as an HTTP API for login and starting a remote VS
Code process.
The CLI code is in [src/node](../src/node) and the HTTP routes are implemented
in [src/node/routes](../src/node/routes).
Most of the meaty parts are in the Code portion of the codebase under
[lib/vscode](../lib/vscode), which we describe next.
Most of the meaty parts are in the VS Code portion of the codebase under
[vendor/modules/code-oss-dev](../vendor/modules/code-oss-dev), which we describe next.
### Modifications to Code
### Modifications to VS Code
Our modifications to Code can be found in the [patches](../patches) directory.
We pull in Code as a submodule pointing to an upstream release branch.
In v1 of code-server, we had a patch of VS Code that split the codebase into a
front-end and a server. The front-end consisted of the UI code, while the server
ran the extensions and exposed an API to the front-end for file access and all
UI needs.
In v1 of code-server, we had Code as a submodule and used a single massive patch
that split the codebase into a front-end and a server. The front-end consisted
of the UI code, while the server ran the extensions and exposed an API to the
front-end for file access and all UI needs.
Over time, Microsoft added support to VS Code to run it on the web. They have
made the front-end open source, but not the server. As such, code-server v2 (and
later) uses the VS Code front-end and implements the server. We do this by using
a Git subtree to fork and modify VS Code. This code lives under
[vendor/modules/code-oss-dev](../vendor/modules/code-oss-dev).
Over time, Microsoft added support to Code to run it on the web. They had made
the front-end open source, but not the server. As such, code-server v2 (and
later) uses the Code front-end and implements the server. We did this by using a
Git subtree to fork and modify Code.
Some noteworthy changes in our version of VS Code include:
Microsoft eventually made the server open source and we were able to reduce our
changes significantly. Some time later we moved back to a submodule and patches
(managed by `quilt` this time instead of the mega-patch).
- Adding our build file, [`vendor/modules/code-oss-dev/coder.js`](../vendor/modules/code-oss-dev/coder.js), which includes build steps specific to code-server
- Node.js version detection changes in [`build/lib/node.ts`](../vendor/modules/code-oss-dev/build/lib/node.ts) and [`build/lib/util.ts`](../vendor/modules/code-oss-dev/build/lib/util.ts)
- Allowing extra extension directories
- Added extra arguments to [`src/vs/platform/environment/common/argv.ts`](../vendor/modules/code-oss-dev/src/vs/platform/environment/common/argv.ts) and to [`src/vs/platform/environment/node/argv.ts`](../vendor/modules/code-oss-dev/src/vs/platform/environment/node/argv.ts)
- Added extra environment state to [`src/vs/platform/environment/common/environment.ts`](../vendor/modules/code-oss-dev/src/vs/platform/environment/common/environment.ts);
- Added extra getters to [`src/vs/platform/environment/common/environmentService.ts`](../vendor/modules/code-oss-dev/src/vs/platform/environment/common/environmentService.ts)
- Added extra scanning paths to [`src/vs/platform/extensionManagement/node/extensionsScanner.ts`](../vendor/modules/code-oss-dev/src/vs/platform/extensionManagement/node/extensionsScanner.ts)
- Additions/removals from [`package.json`](../vendor/modules/code-oss-dev/package.json):
- Removing `electron`, `keytar` and `native-keymap` to avoid pulling in desktop dependencies during build on Linux
- Removing `gulp-azure-storage` and `gulp-tar` (unsued in our build process, may pull in outdated dependencies)
- Adding `proxy-agent`, `proxy-from-env` (for proxying) and `rimraf` (used during build/install steps)
- Adding our branding/custom URLs/version:
- [`product.json`](../vendor/modules/code-oss-dev/product.json)
- [`src/vs/base/common/product.ts`](../vendor/modules/code-oss-dev/src/vs/base/common/product.ts)
- [`src/vs/workbench/browser/parts/dialogs/dialogHandler.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts)
- [`src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts)
- [`src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts)
- Removing azure/macOS signing related dependencies from [`build/package.json`](../vendor/modules/code-oss-dev/build/package.json)
- Modifying `.gitignore` to allow us to add files to `src/vs/server` and modifying `.eslintignore` to ignore lint on the shared files below (we use different formatter settings than VS Code).
- Sharing some files with our codebase via symlinks:
- [`src/vs/base/common/ipc.d.ts`](../vendor/modules/code-oss-dev/src/vs/base/common/ipc.d.ts) points to [`typings/ipc.d.ts`](../typings/ipc.d.ts)
- [`src/vs/base/common/util.ts`](../vendor/modules/code-oss-dev/src/vs/base/common/util.ts) points to [`src/common/util.ts`](../src/common/util.ts)
- [`src/vs/base/node/proxy_agent.ts`](../vendor/modules/code-oss-dev/src/vs/base/node/proxy_agent.ts) points to [`src/node/proxy_agent.ts`](../src/node/proxy_agent.ts)
- Allowing socket changes by adding `setSocket` in [`src/vs/base/parts/ipc/common/ipc.net.ts`](../vendor/modules/code-oss-dev/src/vs/base/parts/ipc/common/ipc.net.ts)
- We use this for connection persistence in our server-side code.
- Added our server-side Node.JS code to `src/vs/server`.
- This code includes the logic to spawn the various services (extension host, terminal, etc.) and some glue
- Added [`src/vs/workbench/browser/client.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/browser/client.ts) to hold some server customizations.
- Includes the functionality for the Log Out command and menu item
- Also, imported and called `initialize` from the main web file, [`src/vs/workbench/browser/web.main.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/browser/web.main.ts)
- Added a (hopefully temporary) hotfix to [`src/vs/workbench/common/resources.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/common/resources.ts) to get context menu actions working for the Git integration.
- Added connection type to WebSocket query parameters in [`src/vs/platform/remote/common/remoteAgentConnection.ts`](../vendor/modules/code-oss-dev/src/vs/platform/remote/common/remoteAgentConnection.ts)
- Added `CODE_SERVER*` variables to the sanitization list in [`src/vs/base/common/processes.ts`](../vendor/modules/code-oss-dev/src/vs/base/common/processes.ts)
- Fix localization support:
- Added file [`src/vs/workbench/services/localizations/browser/localizationsService.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/services/localizations/browser/localizationsService.ts).
- Modified file [`src/vs/base/common/platform.ts`](../vendor/modules/code-oss-dev/src/vs/base/common/platform.ts)
- Modified file [`src/vs/base/node/languagePacks.js`](../vendor/modules/code-oss-dev/src/vs/base/node/languagePacks.js)
- Added code to allow server to inject settings to [`src/vs/platform/product/common/product.ts`](../vendor/modules/code-oss-dev/src/vs/platform/product/common/product.ts)
- Extension fixes:
- Avoid disabling extensions by extensionKind in [`src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts) (Needed for vscode-icons)
- Remove broken symlinks in [`extensions/postinstall.js`](../vendor/modules/code-oss-dev/extensions/postinstall.js)
- Add tip about extension gallery in [`src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts)
- Use our own server for GitHub authentication in [`extensions/github-authentication/src/githubServer.ts`](../vendor/modules/code-oss-dev/extensions/github-authentication/src/githubServer.ts)
- Settings persistence on the server in [`src/vs/workbench/services/environment/browser/environmentService.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/services/environment/browser/environmentService.ts)
- Add extension install fallback in [`src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts)
- Add proxy-agent monkeypatch and keep extension host indefinitely running in [`src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts)
- Patch build system to avoid removing extension dependencies for `yarn global add` users in [`build/lib/extensions.ts`](../vendor/modules/code-oss-dev/build/lib/extensions.ts)
- Allow all extensions to use proposed APIs in [`src/vs/workbench/services/environment/browser/environmentService.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/services/environment/browser/environmentService.ts)
- Make storage writes async to allow extensions to wait for them to complete in [`src/vs/platform/storage/common/storage.ts`](../vendor/modules/code-oss-dev/src/vs/platform/storage/common/storage.ts)
- Specify webview path in [`src/vs/code/browser/workbench/workbench.ts`](../vendor/modules/code-oss-dev/src/vs/code/browser/workbench/workbench.ts)
- URL readability improvements for folder/workspace in [`src/vs/code/browser/workbench/workbench.ts`](../vendor/modules/code-oss-dev/src/vs/code/browser/workbench/workbench.ts)
- Socket/Authority-related fixes (for remote proxying etc.):
- [`src/vs/code/browser/workbench/workbench.ts`](../vendor/modules/code-oss-dev/src/vs/code/browser/workbench/workbench.ts)
- [`src/vs/platform/remote/browser/browserSocketFactory.ts`](../vendor/modules/code-oss-dev/src/vs/platform/remote/browser/browserSocketFactory.ts)
- [`src/vs/base/common/network.ts`](../vendor/modules/code-oss-dev/src/vs/base/common/network.ts)
- Added code to write out IPC path in [`src/vs/workbench/api/node/extHostCLIServer.ts`](../vendor/modules/code-oss-dev/src/vs/workbench/api/node/extHostCLIServer.ts)
As the web portion of Code continues to mature, we'll be able to shrink and
possibly eliminate our patches. In the meantime, upgrading the Code version
requires us to ensure that our changes are still applied correctly and work as
intended. In the future, we'd like to run Code unit tests against our builds to
ensure that features work as expected.
As the web portion of VS Code matures, we'll be able to shrink and possibly
eliminate our modifications. In the meantime, upgrading the VS Code version requires
us to ensure that our changes are still applied and work as intended. In the future,
we'd like to run VS Code unit tests against our builds to ensure that features
work as expected.
> We have [extension docs](../ci/README.md) on the CI and build system.
If the functionality you're working on does NOT depend on code from Code, please
If the functionality you're working on does NOT depend on code from VS Code, please
move it out and into code-server.
### Currently Known Issues
- Creating custom Code extensions and debugging them doesn't work
- Creating custom VS Code extensions and debugging them doesn't work
- Extension profiling and tips are currently disabled

View File

@@ -164,7 +164,7 @@ If you're the current release manager, follow these steps:
### Publishing a release
1. Create a new branch called `v0.0.0` (replace 0s with actual version aka v4.2.0)
1. Create a release branch called `v0.0.0` but replace with new version
1. Run `yarn release:prep` and type in the new version (e.g., `3.8.1`)
1. GitHub Actions will generate the `npm-package`, `release-packages` and
`release-images` artifacts. You do not have to wait for this step to complete

View File

@@ -1,6 +1,6 @@
# code-server
[!["GitHub Discussions"](https://img.shields.io/badge/%20GitHub-%20Discussions-gray.svg?longCache=true&logo=github&colorB=purple)](https://github.com/coder/code-server/discussions) [!["Join us on Slack"](https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen)](https://coder.com/community) [![Twitter Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=social)](https://twitter.com/coderhq) [![codecov](https://codecov.io/gh/coder/code-server/branch/main/graph/badge.svg?token=5iM9farjnC)](https://codecov.io/gh/coder/code-server) [![See v4.2.0 docs](https://img.shields.io/static/v1?label=Docs&message=see%20v4.2.0%20&color=blue)](https://github.com/coder/code-server/tree/v4.2.0/docs)
[!["GitHub Discussions"](https://img.shields.io/badge/%20GitHub-%20Discussions-gray.svg?longCache=true&logo=github&colorB=purple)](https://github.com/coder/code-server/discussions) [!["Join us on Slack"](https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen)](https://coder.com/community) [![Twitter Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=social)](https://twitter.com/coderhq) [![codecov](https://codecov.io/gh/coder/code-server/branch/main/graph/badge.svg?token=5iM9farjnC)](https://codecov.io/gh/coder/code-server) [![See v4.1.0 docs](https://img.shields.io/static/v1?label=Docs&message=see%20v4.1.0%20&color=blue)](https://github.com/coder/code-server/tree/v4.1.0/docs)
Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and
access it in the browser.

View File

@@ -60,6 +60,6 @@ As `code-server` is based on VS Code, you can follow the steps described on Duck
code-server --enable-proposed-api genuitecllc.codetogether
```
Another option would be to add a value in code-server's [config file](https://coder.com/docs/code-server/v4.2.0/FAQ#how-does-the-config-file-work).
Another option would be to add a value in code-server's [config file](https://coder.com/docs/code-server/v4.1.0/FAQ#how-does-the-config-file-work).
3. Refresh code-server and navigate to the CodeTogether icon in the sidebar to host or join a coding session.

View File

@@ -52,7 +52,7 @@ There are several approaches to operating and exposing code-server securely:
We highly recommend using [port forwarding via
SSH](https://help.ubuntu.com/community/SSH/OpenSSH/PortForwarding) to access
code-server. If you have an SSH server on your remote machine, this approach
doesn't require any additional setup at all.
doesn't required additional setup.
The downside to SSH forwarding, however, is that you can't access code-server
when using machines without SSH clients (such as iPads). If this applies to you,

View File

@@ -1,6 +1,6 @@
# code-server Helm Chart
[![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square)](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) [![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)](https://img.shields.io/badge/Type-application-informational?style=flat-square) [![AppVersion: 4.2.0](https://img.shields.io/badge/AppVersion-4.2.0-informational?style=flat-square)](https://img.shields.io/badge/AppVersion-4.2.0-informational?style=flat-square)
[![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square)](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) [![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)](https://img.shields.io/badge/Type-application-informational?style=flat-square) [![AppVersion: 4.1.0](https://img.shields.io/badge/AppVersion-4.1.0-informational?style=flat-square)](https://img.shields.io/badge/AppVersion-4.1.0-informational?style=flat-square)
[code-server](https://github.com/coder/code-server) code-server is VS Code running
on a remote server, accessible through the browser.
@@ -73,7 +73,7 @@ and their default values.
| hostnameOverride | string | `""` |
| image.pullPolicy | string | `"Always"` |
| image.repository | string | `"codercom/code-server"` |
| image.tag | string | `"4.2.0"` |
| image.tag | string | `"4.1.0"` |
| imagePullSecrets | list | `[]` |
| ingress.enabled | bool | `false` |
| nameOverride | string | `""` |

View File

@@ -1,5 +1,5 @@
{
"versions": ["v4.2.0"],
"versions": ["v4.1.0"],
"routes": [
{
"title": "Home",

Submodule lib/vscode deleted from f80445acd5

View File

@@ -1,7 +1,7 @@
{
"name": "code-server",
"license": "MIT",
"version": "4.2.0",
"version": "4.1.0",
"description": "Run VS Code on a remote server.",
"homepage": "https://github.com/coder/code-server",
"bugs": {
@@ -51,7 +51,7 @@
"@types/ws": "^8.0.0",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"audit-ci": "^6.0.0",
"audit-ci": "^5.0.0",
"codecov": "^3.8.3",
"doctoc": "^2.0.0",
"eslint": "^7.7.0",
@@ -69,7 +69,7 @@
},
"resolutions": {
"ansi-regex": "^5.0.1",
"normalize-package-data": "^4.0.0",
"normalize-package-data": "^3.0.0",
"doctoc/underscore": "^1.13.1",
"doctoc/**/trim": "^1.0.0",
"postcss": "^8.2.1",
@@ -81,8 +81,7 @@
"vm2": "^3.9.6",
"follow-redirects": "^1.14.8",
"node-fetch": "^2.6.7",
"nanoid": "^3.1.31",
"minimist": "npm:minimist-lite@2.2.0"
"nanoid": "^3.1.31"
},
"dependencies": {
"@coder/logger": "1.1.16",
@@ -128,6 +127,7 @@
"testEnvironment": "node",
"testPathIgnorePatterns": [
"/node_modules/",
"/vendor/",
"/lib/",
"/out/",
"test/e2e"
@@ -158,7 +158,7 @@
"<rootDir>/release-npm-package",
"<rootDir>/release-gcp",
"<rootDir>/release-images",
"<rootDir>/lib"
"<rootDir>/vendor"
],
"moduleNameMapper": {
"^.+\\.(css|less)$": "<rootDir>/test/utils/cssStub.ts"

View File

@@ -1,305 +0,0 @@
Add base path support
Some users will host code-server behind a path-rewriting reverse proxy, for
example domain.tld/my/base/path. This patch adds support for that since Code
assumes everything is on / by default.
To test this serve code-server behind a reverse proxy with a path like /code.
Index: code-server/lib/vscode/src/vs/base/common/network.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/base/common/network.ts
+++ code-server/lib/vscode/src/vs/base/common/network.ts
@@ -151,8 +151,10 @@ class RemoteAuthoritiesImpl {
}
return URI.from({
scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,
- authority: `${host}:${port}`,
- path: `/vscode-remote-resource`,
+ authority: platform.isWeb ? window.location.host : `${host}:${port}`,
+ path: platform.isWeb
+ ? URI.joinPath(URI.parse(window.location.href), `/vscode-remote-resource`).path
+ : `/vscode-remote-resource`,
query
});
}
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
@@ -11,8 +11,8 @@
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Code">
- <link rel="apple-touch-icon" sizes="192x192" href="/_static/src/browser/media/pwa-icon-192.png" />
- <link rel="apple-touch-icon" sizes="512x512" href="/_static/src/browser/media/pwa-icon-512.png" />
+ <link rel="apple-touch-icon" sizes="192x192" href="{{BASE}}/_static/src/browser/media/pwa-icon-192.png" />
+ <link rel="apple-touch-icon" sizes="512x512" href="{{BASE}}/_static/src/browser/media/pwa-icon-512.png" />
<!-- Disable pinch zooming -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
@@ -27,23 +27,26 @@
<meta id="vscode-workbench-builtin-extensions" data-settings="{{WORKBENCH_BUILTIN_EXTENSIONS}}">
<!-- Workbench Icon/Manifest/CSS -->
- <link rel="icon" href="/_static/src/browser/media/favicon-dark-support.svg" />
- <link rel="alternate icon" href="/_static/src/browser/media/favicon.ico" />
- <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
+ <link rel="icon" href="{{BASE}}/_static/src/browser/media/favicon-dark-support.svg" />
+ <link rel="alternate icon" href="{{BASE}}/_static/src/browser/media/favicon.ico" />
+ <link rel="manifest" href="{{VS_BASE}}/manifest.json" crossorigin="use-credentials" />
</head>
<body aria-label="">
</body>
<!-- Startup (do not modify order of script tags!) -->
- <script src="./static/out/vs/loader.js"></script>
- <script src="./static/out/vs/webPackagePaths.js"></script>
+ <script src="{{VS_BASE}}/static/out/vs/loader.js"></script>
+ <script src="{{VS_BASE}}/static/out/vs/webPackagePaths.js"></script>
<script>
Object.keys(self.webPackagePaths).map(function (key, index) {
- self.webPackagePaths[key] = `${window.location.origin}/static/remote/web/node_modules/${key}/${self.webPackagePaths[key]}`;
+ self.webPackagePaths[key] = new URL(
+ `{{VS_BASE}}/static/remote/web/node_modules/${key}/${self.webPackagePaths[key]}`,
+ window.location,
+ ).toString();
});
require.config({
- baseUrl: `${window.location.origin}/static/out`,
+ baseUrl: new URL(`{{VS_BASE}}/static/out`, window.location).toString(),
recordStats: true,
trustedTypesPolicy: window.trustedTypes?.createPolicy('amdLoader', {
createScriptURL(value) {
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.html
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
@@ -11,8 +11,8 @@
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Code">
- <link rel="apple-touch-icon" sizes="192x192" href="/_static/src/browser/media/pwa-icon-192.png" />
- <link rel="apple-touch-icon" sizes="512x512" href="/_static/src/browser/media/pwa-icon-512.png" />
+ <link rel="apple-touch-icon" sizes="192x192" href="{{BASE}}/_static/src/browser/media/pwa-icon-192.png" />
+ <link rel="apple-touch-icon" sizes="512x512" href="{{BASE}}/_static/src/browser/media/pwa-icon-512.png" />
<!-- Disable pinch zooming -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
@@ -24,10 +24,10 @@
<meta id="vscode-workbench-auth-session" data-settings="{{WORKBENCH_AUTH_SESSION}}">
<!-- Workbench Icon/Manifest/CSS -->
- <link rel="icon" href="/_static/src/browser/media/favicon-dark-support.svg" />
- <link rel="alternate icon" href="/_static/src/browser/media/favicon.ico" />
- <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
- <link data-name="vs/workbench/workbench.web.main" rel="stylesheet" href="./static/out/vs/workbench/workbench.web.main.css">
+ <link rel="icon" href="{{BASE}}/_static/src/browser/media/favicon-dark-support.svg" />
+ <link rel="alternate icon" href="{{BASE}}/_static/src/browser/media/favicon.ico" />
+ <link rel="manifest" href="{{VS_BASE}}/manifest.json" crossorigin="use-credentials" />
+ <link data-name="vs/workbench/workbench.web.main" rel="stylesheet" href="{{VS_BASE}}/static/out/vs/workbench/workbench.web.main.css">
</head>
@@ -35,14 +35,17 @@
</body>
<!-- Startup (do not modify order of script tags!) -->
- <script src="./static/out/vs/loader.js"></script>
- <script src="./static/out/vs/webPackagePaths.js"></script>
+ <script src="{{VS_BASE}}/static/out/vs/loader.js"></script>
+ <script src="{{VS_BASE}}/static/out/vs/webPackagePaths.js"></script>
<script>
Object.keys(self.webPackagePaths).map(function (key, index) {
- self.webPackagePaths[key] = `${window.location.origin}/static/node_modules/${key}/${self.webPackagePaths[key]}`;
+ self.webPackagePaths[key] = new URL(
+ `{{VS_BASE}}/static/node_modules/${key}/${self.webPackagePaths[key]}`,
+ window.location,
+ ).toString();
});
require.config({
- baseUrl: `${window.location.origin}/static/out`,
+ baseUrl: new URL(`{{VS_BASE}}/static/out`, window.location).toString(),
recordStats: true,
trustedTypesPolicy: window.trustedTypes?.createPolicy('amdLoader', {
createScriptURL(value) {
@@ -55,7 +58,7 @@
<script>
performance.mark('code/willLoadWorkbenchMain');
</script>
- <script src="./static/out/vs/workbench/workbench.web.main.nls.js"></script>
- <script src="./static/out/vs/workbench/workbench.web.main.js"></script>
- <script src="./static/out/vs/code/browser/workbench/workbench.js"></script>
+ <script src="{{VS_BASE}}/static/out/vs/workbench/workbench.web.main.nls.js"></script>
+ <script src="{{VS_BASE}}/static/out/vs/workbench/workbench.web.main.js"></script>
+ <script src="{{VS_BASE}}/static/out/vs/code/browser/workbench/workbench.js"></script>
</html>
Index: code-server/lib/vscode/src/vs/platform/remote/browser/browserSocketFactory.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/remote/browser/browserSocketFactory.ts
+++ code-server/lib/vscode/src/vs/platform/remote/browser/browserSocketFactory.ts
@@ -274,7 +274,7 @@ export class BrowserSocketFactory implem
connect(host: string, port: number, query: string, debugLabel: string, callback: IConnectCallback): void {
const webSocketSchema = (/^https:/.test(window.location.href) ? 'wss' : 'ws');
- const socket = this._webSocketFactory.create(`${webSocketSchema}://${/:/.test(host) ? `[${host}]` : host}:${port}/?${query}&skipWebSocketFrames=false`, debugLabel);
+ const socket = this._webSocketFactory.create(`${webSocketSchema}://${window.location.host}${window.location.pathname}?${query}&skipWebSocketFrames=false`, debugLabel);
const errorListener = socket.onError((err) => callback(err, undefined));
socket.onOpen(() => {
errorListener.dispose();
@@ -282,6 +282,3 @@ export class BrowserSocketFactory implem
});
}
}
-
-
-
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -252,7 +252,10 @@ export class WebClientServer {
return res.end();
}
- const remoteAuthority = req.headers.host;
+ // It is not possible to reliably detect the remote authority on the server
+ // in all cases. Set this to something invalid to make sure we catch code
+ // that is using this when it should not.
+ const remoteAuthority = 'remote';
function escapeAttribute(value: string): string {
return value.replace(/"/g, '&quot;');
@@ -272,6 +275,8 @@ export class WebClientServer {
accessToken: this._environmentService.args['github-auth'],
scopes: [['user:email'], ['repo']]
} : undefined;
+ const base = relativeRoot(getOriginalUrl(req))
+ const vscodeBase = relativePath(getOriginalUrl(req))
const data = (await util.promisify(fs.readFile)(filePath)).toString()
.replace('{{WORKBENCH_WEB_CONFIGURATION}}', escapeAttribute(JSON.stringify({
remoteAuthority,
@@ -279,6 +284,7 @@ export class WebClientServer {
developmentOptions: { enableSmokeTestDriver: this._environmentService.driverHandle === 'web' ? true : undefined },
settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined,
productConfiguration: <Partial<IProductConfiguration>>{
+ rootEndpoint: base,
extensionsGallery: this._webExtensionResourceUrlTemplate ? {
...this._productService.extensionsGallery,
'resourceUrlTemplate': this._webExtensionResourceUrlTemplate.with({
@@ -289,7 +295,9 @@ export class WebClientServer {
} : undefined
}
})))
- .replace('{{WORKBENCH_AUTH_SESSION}}', () => authSessionInfo ? escapeAttribute(JSON.stringify(authSessionInfo)) : '');
+ .replace('{{WORKBENCH_AUTH_SESSION}}', () => authSessionInfo ? escapeAttribute(JSON.stringify(authSessionInfo)) : '')
+ .replace(/{{BASE}}/g, base)
+ .replace(/{{VS_BASE}}/g, vscodeBase);
const cspDirectives = [
'default-src \'self\';',
@@ -368,3 +376,70 @@ export class WebClientServer {
return res.end(data);
}
}
+
+/**
+ * Remove extra slashes in a URL.
+ *
+ * This is meant to fill the job of `path.join` so you can concatenate paths and
+ * then normalize out any extra slashes.
+ *
+ * If you are using `path.join` you do not need this but note that `path` is for
+ * file system paths, not URLs.
+ */
+export const normalizeUrlPath = (url: string, keepTrailing = false): string => {
+ return url.replace(/\/\/+/g, "/").replace(/\/+$/, keepTrailing ? "/" : "")
+}
+
+/**
+ * Get the relative path that will get us to the root of the page. For each
+ * slash we need to go up a directory. Will not have a trailing slash.
+ *
+ * For example:
+ *
+ * / => .
+ * /foo => .
+ * /foo/ => ./..
+ * /foo/bar => ./..
+ * /foo/bar/ => ./../..
+ *
+ * All paths must be relative in order to work behind a reverse proxy since we
+ * we do not know the base path. Anything that needs to be absolute (for
+ * example cookies) must get the base path from the frontend.
+ *
+ * All relative paths must be prefixed with the relative root to ensure they
+ * work no matter the depth at which they happen to appear.
+ *
+ * For Express `req.originalUrl` should be used as they remove the base from the
+ * standard `url` property making it impossible to get the true depth.
+ */
+export const relativeRoot = (originalUrl: string): string => {
+ const depth = (originalUrl.split("?", 1)[0].match(/\//g) || []).length
+ return normalizeUrlPath("./" + (depth > 1 ? "../".repeat(depth - 1) : ""))
+}
+
+/**
+ * Get the relative path to the current resource.
+ *
+ * For example:
+ *
+ * / => .
+ * /foo => ./foo
+ * /foo/ => .
+ * /foo/bar => ./bar
+ * /foo/bar/ => .
+ */
+export const relativePath = (originalUrl: string): string => {
+ const parts = originalUrl.split("?", 1)[0].split("/")
+ return normalizeUrlPath("./" + parts[parts.length - 1])
+}
+
+/**
+ * code-server serves Code using Express. Express removes the base from the url
+ * and puts the original in `originalUrl` so we must use this to get the correct
+ * depth. Code is not aware it is behind Express so the types do not match. We
+ * may want to continue moving code into Code and eventually remove the Express
+ * wrapper or move the web server back into code-server.
+ */
+export const getOriginalUrl = (req: http.IncomingMessage): string => {
+ return (req as any).originalUrl || req.url
+}
Index: code-server/lib/vscode/src/vs/base/common/product.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/base/common/product.ts
+++ code-server/lib/vscode/src/vs/base/common/product.ts
@@ -32,6 +32,7 @@ export type ExtensionVirtualWorkspaceSup
export interface IProductConfiguration {
readonly codeServerVersion?: string
+ readonly rootEndpoint?: string
readonly version: string;
readonly date?: string;
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
@@ -504,6 +504,7 @@ function doCreateUri(path: string, query
});
}
+ path = (window.location.pathname + "/" + path).replace(/\/\/+/g, "/")
return URI.parse(window.location.href).with({ path, query });
}
@@ -515,7 +516,7 @@ function doCreateUri(path: string, query
if (!configElement || !configElementAttribute) {
throw new Error('Missing web configuration element');
}
- const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = JSON.parse(configElementAttribute);
+ const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = { ...JSON.parse(configElementAttribute), remoteAuthority: location.host }
// Create workbench
create(document.body, {

View File

@@ -1,19 +0,0 @@
Add connection type to web sockets
This allows the backend to distinguish them. In our case we use them to count a
single "open" of Code so we need to be able to distinguish between web sockets
from two instances and two web sockets used in a single instance.
Index: code-server/lib/vscode/src/vs/platform/remote/common/remoteAgentConnection.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/remote/common/remoteAgentConnection.ts
+++ code-server/lib/vscode/src/vs/platform/remote/common/remoteAgentConnection.ts
@@ -231,7 +231,7 @@ async function connectToRemoteExtensionH
let socket: ISocket;
try {
- socket = await createSocket(options.logService, options.socketFactory, options.host, options.port, `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, `renderer-${connectionTypeToString(connectionType)}-${options.reconnectionToken}`, timeoutCancellationToken);
+ socket = await createSocket(options.logService, options.socketFactory, options.host, options.port, `type=${connectionTypeToString(connectionType)}&reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, `renderer-${connectionTypeToString(connectionType)}-${options.reconnectionToken}`, timeoutCancellationToken);
} catch (error) {
options.logService.error(`${logPrefix} socketFactory.connect() failed or timed out. Error:`);
options.logService.error(error);

View File

@@ -1,265 +0,0 @@
Add display language support
This likely needs tweaking if we want to upstream.
Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/serverServices.ts
+++ code-server/lib/vscode/src/vs/server/node/serverServices.ts
@@ -198,6 +198,9 @@ export async function setupServerService
const channel = new ExtensionManagementChannel(extensionManagementService, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority));
socketServer.registerChannel('extensions', channel);
+ const localizationsChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(ILocalizationsService));
+ socketServer.registerChannel('localizations', localizationsChannel);
+
const encryptionChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(IEncryptionMainService));
socketServer.registerChannel('encryption', encryptionChannel);
Index: code-server/lib/vscode/src/vs/base/common/platform.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/base/common/platform.ts
+++ code-server/lib/vscode/src/vs/base/common/platform.ts
@@ -83,6 +83,17 @@ if (typeof navigator === 'object' && !is
_isWeb = true;
_locale = navigator.language;
_language = _locale;
+
+ const el = typeof document !== 'undefined' && document.getElementById('vscode-remote-nls-configuration');
+ const rawNlsConfig = el && el.getAttribute('data-settings');
+ if (rawNlsConfig) {
+ try {
+ const nlsConfig: NLSConfig = JSON.parse(rawNlsConfig);
+ _locale = nlsConfig.locale;
+ _translationsConfigFile = nlsConfig._translationsConfigFile;
+ _language = nlsConfig.availableLanguages['*'] || LANGUAGE_DEFAULT;
+ } catch (error) { /* Oh well. */ }
+ }
}
// Native environment
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.html
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
@@ -23,6 +23,9 @@
<!-- Workbench Auth Session -->
<meta id="vscode-workbench-auth-session" data-settings="{{WORKBENCH_AUTH_SESSION}}">
+ <!-- NLS Configuration -->
+ <meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}">
+
<!-- Workbench Icon/Manifest/CSS -->
<link rel="icon" href="{{BASE}}/_static/src/browser/media/favicon-dark-support.svg" />
<link rel="alternate icon" href="{{BASE}}/_static/src/browser/media/favicon.ico" />
@@ -38,6 +41,27 @@
<script src="{{VS_BASE}}/static/out/vs/loader.js"></script>
<script src="{{VS_BASE}}/static/out/vs/webPackagePaths.js"></script>
<script>
+ let nlsConfig
+ try {
+ nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings"))
+ if (nlsConfig._resolvedLanguagePackCoreLocation) {
+ const bundles = Object.create(null)
+ nlsConfig.loadBundle = (bundle, _language, cb) => {
+ const result = bundles[bundle]
+ if (result) {
+ return cb(undefined, result)
+ }
+ const path = nlsConfig._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json"
+ fetch(`{{VS_BASE}}/vscode-remote-resource?path=${encodeURIComponent(path)}`)
+ .then((response) => response.json())
+ .then((json) => {
+ bundles[bundle] = json
+ cb(undefined, json)
+ })
+ .catch(cb)
+ }
+ }
+ } catch (error) { /* Probably fine. */ }
Object.keys(self.webPackagePaths).map(function (key, index) {
self.webPackagePaths[key] = new URL(
`{{VS_BASE}}/static/remote/web/node_modules/${key}/${self.webPackagePaths[key]}`,
@@ -52,7 +76,8 @@
return value;
}
}),
- paths: self.webPackagePaths
+ paths: self.webPackagePaths,
+ 'vs/nls': nlsConfig,
});
</script>
<script>
Index: code-server/lib/vscode/src/vs/platform/environment/common/environmentService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/environment/common/environmentService.ts
+++ code-server/lib/vscode/src/vs/platform/environment/common/environmentService.ts
@@ -105,7 +105,7 @@ export abstract class AbstractNativeEnvi
return URI.file(join(vscodePortable, 'argv.json'));
}
- return joinPath(this.userHome, this.productService.dataFolderName, 'argv.json');
+ return joinPath(this.appSettingsHome, 'argv.json');
}
@memoize
Index: code-server/lib/vscode/src/vs/server/node/remoteLanguagePacks.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/remoteLanguagePacks.ts
+++ code-server/lib/vscode/src/vs/server/node/remoteLanguagePacks.ts
@@ -30,6 +30,12 @@ export function getNLSConfiguration(lang
if (InternalNLSConfiguration.is(value)) {
value._languagePackSupport = true;
}
+ // If the configuration has no results keep trying since code-server
+ // doesn't restart when a language is installed so this result would
+ // persist (the plugin might not be installed yet for example).
+ if (value.locale !== 'en' && value.locale !== 'en-us' && Object.keys(value.availableLanguages).length === 0) {
+ _cache.delete(key);
+ }
return value;
});
_cache.set(key, result);
@@ -44,3 +50,43 @@ export namespace InternalNLSConfiguratio
return candidate && typeof candidate._languagePackId === 'string';
}
}
+
+/**
+ * The code below is copied from from src/main.js.
+ */
+
+export const getLocaleFromConfig = async (argvResource: string): Promise<string> => {
+ try {
+ const content = stripComments(await fs.promises.readFile(argvResource, 'utf8'));
+ return JSON.parse(content).locale;
+ } catch (error) {
+ if (error.code !== "ENOENT") {
+ console.warn(error)
+ }
+ return 'en';
+ }
+};
+
+const stripComments = (content: string): string => {
+ const regexp = /('(?:[^\\']*(?:\\.)?)*')|('(?:[^\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g;
+
+ return content.replace(regexp, (match, _m1, _m2, m3, m4) => {
+ // Only one of m1, m2, m3, m4 matches
+ if (m3) {
+ // A block comment. Replace with nothing
+ return '';
+ } else if (m4) {
+ // A line comment. If it ends in \r?\n then keep it.
+ const length_1 = m4.length;
+ if (length_1 > 2 && m4[length_1 - 1] === '\n') {
+ return m4[length_1 - 2] === '\r' ? '\r\n' : '\n';
+ }
+ else {
+ return '';
+ }
+ } else {
+ // We match a string
+ return match;
+ }
+ });
+};
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -26,6 +26,7 @@ import { URI } from 'vs/base/common/uri'
import { streamToBuffer } from 'vs/base/common/buffer';
import { IProductConfiguration } from 'vs/base/common/product';
import { isString } from 'vs/base/common/types';
+import { getLocaleFromConfig, getNLSConfiguration } from 'vs/server/node/remoteLanguagePacks';
const textMimeType = {
'.html': 'text/html',
@@ -277,6 +278,8 @@ export class WebClientServer {
} : undefined;
const base = relativeRoot(getOriginalUrl(req))
const vscodeBase = relativePath(getOriginalUrl(req))
+ const locale = this._environmentService.args.locale || await getLocaleFromConfig(this._environmentService.argvResource.fsPath);
+ const nlsConfiguration = await getNLSConfiguration(locale, this._environmentService.userDataPath)
const data = (await util.promisify(fs.readFile)(filePath)).toString()
.replace('{{WORKBENCH_WEB_CONFIGURATION}}', escapeAttribute(JSON.stringify({
remoteAuthority,
@@ -301,7 +304,8 @@ export class WebClientServer {
})))
.replace('{{WORKBENCH_AUTH_SESSION}}', () => authSessionInfo ? escapeAttribute(JSON.stringify(authSessionInfo)) : '')
.replace(/{{BASE}}/g, base)
- .replace(/{{VS_BASE}}/g, vscodeBase);
+ .replace(/{{VS_BASE}}/g, vscodeBase)
+ .replace(/{{NLS_CONFIGURATION}}/g, () => escapeAttribute(JSON.stringify(nlsConfiguration)));
const cspDirectives = [
'default-src \'self\';',
Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
+++ code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
@@ -14,6 +14,7 @@ export const serverOptions: OptionDescri
/* ----- code-server ----- */
'disable-update-check': { type: 'boolean' },
'auth': { type: 'string' },
+ 'locale': { type: 'string' },
/* ----- server setup ----- */
@@ -90,6 +91,7 @@ export interface ServerParsedArgs {
/* ----- code-server ----- */
'disable-update-check'?: boolean;
'auth'?: string
+ 'locale'?: string
/* ----- server setup ----- */
Index: code-server/lib/vscode/src/vs/workbench/services/localizations/browser/localizationsService.ts
===================================================================
--- /dev/null
+++ code-server/lib/vscode/src/vs/workbench/services/localizations/browser/localizationsService.ts
@@ -0,0 +1,28 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Coder Technologies. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
+import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
+import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
+import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
+
+/**
+ * Add localizations service for the browser.
+ * @author coder
+ */
+
+// @ts-ignore: interface is implemented via proxy
+export class LocalizationsService implements ILocalizationsService {
+
+ declare readonly _serviceBrand: undefined;
+
+ constructor(
+ @IRemoteAgentService remoteAgentService: IRemoteAgentService,
+ ) {
+ return ProxyChannel.toService<ILocalizationsService>(remoteAgentService.getConnection()!.getChannel('localizations'));
+ }
+}
+
+registerSingleton(ILocalizationsService, LocalizationsService, true);
Index: code-server/lib/vscode/src/vs/workbench/workbench.web.main.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/workbench.web.main.ts
+++ code-server/lib/vscode/src/vs/workbench/workbench.web.main.ts
@@ -109,6 +109,10 @@ registerSingleton(ICustomEndpointTelemet
//#region --- workbench contributions
+// Localizations
+import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
+import 'vs/workbench/services/localizations/browser/localizationsService';
+
// Output
import 'vs/workbench/contrib/output/common/outputChannelModelService';

View File

@@ -1,118 +0,0 @@
Use our own GitHub auth relay server
Microsoft's does not work with self-hosted instances so we run our own.
Also add an extra set of scopes so that tokens provided via --github-auth will
work for the PR extension.
Index: code-server/lib/vscode/extensions/github-authentication/src/githubServer.ts
===================================================================
--- code-server.orig/lib/vscode/extensions/github-authentication/src/githubServer.ts
+++ code-server/lib/vscode/extensions/github-authentication/src/githubServer.ts
@@ -17,7 +17,7 @@ const localize = nls.loadMessageBundle()
const CLIENT_ID = '01ab8ac9400c4e429b23';
const NETWORK_ERROR = 'network error';
-const AUTH_RELAY_SERVER = 'vscode-auth.github.com';
+const AUTH_RELAY_SERVER = 'auth.code-server.dev';
// const AUTH_RELAY_STAGING_SERVER = 'client-auth-staging-14a768b.herokuapp.com';
class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler {
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -274,7 +274,7 @@ export class WebClientServer {
id: generateUuid(),
providerId: 'github',
accessToken: this._environmentService.args['github-auth'],
- scopes: [['user:email'], ['repo']]
+ scopes: [['read:user', 'user:email', 'repo'], ['user:email'], ['repo']]
} : undefined;
const base = relativeRoot(getOriginalUrl(req))
const vscodeBase = relativePath(getOriginalUrl(req))
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
@@ -17,6 +17,7 @@ import { isFolderToOpen, isWorkspaceToOp
import { create, ICredentialsProvider, IURLCallbackProvider, IWorkbenchConstructionOptions, IWorkspace, IWorkspaceProvider } from 'vs/workbench/workbench.web.main';
import { posix } from 'vs/base/common/path';
import { ltrim } from 'vs/base/common/strings';
+import { equals as arrayEquals } from 'vs/base/common/arrays';
interface ICredential {
service: string;
@@ -24,6 +25,13 @@ interface ICredential {
password: string;
}
+interface IToken {
+ accessToken: string
+ account?: { label: string }
+ id: string
+ scopes: string[]
+}
+
class LocalStorageCredentialsProvider implements ICredentialsProvider {
private static readonly CREDENTIALS_STORAGE_KEY = 'credentials.provider';
@@ -51,6 +59,58 @@ class LocalStorageCredentialsProvider im
scopes,
accessToken: authSessionInfo!.accessToken
}))));
+
+ // Add tokens for extensions to use. This works for extensions like the
+ // pull requests one or GitLens.
+ const extensionId = `vscode.${authSessionInfo.providerId}-authentication`;
+ const service = `${product.urlProtocol}${extensionId}`;
+ const account = `${authSessionInfo.providerId}.auth`;
+ // Oddly the scopes need to match exactly so we cannot just have one token
+ // with all the scopes, instead we have to duplicate the token for each
+ // expected set of scopes.
+ const tokens: IToken[] = authSessionInfo.scopes.map((scopes) => ({
+ id: authSessionInfo!.id,
+ scopes: scopes.sort(), // Sort for comparing later.
+ accessToken: authSessionInfo!.accessToken,
+ }));
+ this.getPassword(service, account).then((raw) => {
+ let existing: {
+ content: IToken[]
+ } | undefined;
+
+ if (raw) {
+ try {
+ const json = JSON.parse(raw);
+ json.content = JSON.parse(json.content);
+ existing = json;
+ } catch (error) {
+ console.log(error);
+ }
+ }
+
+ // Keep tokens for account and scope combinations we do not have in case
+ // there is an extension that uses scopes we have not accounted for (in
+ // these cases the user will need to manually authenticate the extension
+ // through the UI) or the user has tokens for other accounts.
+ if (existing?.content) {
+ existing.content = existing.content.filter((existingToken) => {
+ const scopes = existingToken.scopes.sort();
+ return !(tokens.find((token) => {
+ return arrayEquals(scopes, token.scopes)
+ && token.account?.label === existingToken.account?.label;
+ }))
+ })
+ }
+
+ return this.setPassword(service, account, JSON.stringify({
+ extensionId,
+ ...(existing || {}),
+ content: JSON.stringify([
+ ...tokens,
+ ...(existing?.content || []),
+ ])
+ }));
+ })
}
}

View File

@@ -1,57 +0,0 @@
Add a notification when accessing code-server in an insecure context
This is done because otherwise when things like the clipboard do not work users
may think code-server is broken. Ideally there would be a notification at the
point where these things are used instead of this though.
To test access over something like an HTTP domain or an IP address (not
localhost).
Index: code-server/lib/vscode/src/vs/workbench/browser/client.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/client.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/client.ts
@@ -1,7 +1,10 @@
import { Disposable } from 'vs/base/common/lifecycle';
+import { localize } from 'vs/nls';
+import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
export class CodeServerClient extends Disposable {
constructor (
+ @INotificationService private notificationService: INotificationService,
) {
super();
}
@@ -42,5 +45,32 @@ export class CodeServerClient extends Di
}
});
}
+
+ if (!window.isSecureContext) {
+ this.notificationService.notify({
+ severity: Severity.Warning,
+ message: localize(
+ 'insecureContext',
+ "{0} is being accessed in an insecure context. Web views, the clipboard, and other functionality may not work as expected.",
+ 'code-server',
+ ),
+ actions: {
+ primary: [
+ {
+ id: 'understand',
+ label: localize('confirmInsecure', "I understand"),
+ tooltip: '',
+ class: undefined,
+ enabled: true,
+ checked: true,
+ dispose: () => undefined,
+ run: () => {
+ return Promise.resolve();
+ },
+ },
+ ],
+ },
+ });
+ }
}
}

View File

@@ -1,269 +0,0 @@
Prepare Code for integration with code-server
1. We already have the arguments so allow passing them in. There is also a
slight change in a few directories to preserve the directory structure we
have been using and to not override passed-in arguments.
2. Modify the terminal environment to filter out code-server environment variables.
3. Add the code-server version to the help dialog.
4. Add ready events for use in an iframe.
5. Add our icons.
6. Remove sourcemap host since we cannot upload ours there.
Index: code-server/lib/vscode/src/vs/server/node/server.main.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/server.main.ts
+++ code-server/lib/vscode/src/vs/server/node/server.main.ts
@@ -12,7 +12,7 @@ import { createServer as doCreateServer,
import { parseArgs, ErrorReporter } from 'vs/platform/environment/node/argv';
import { join, dirname } from 'vs/base/common/path';
import { performance } from 'perf_hooks';
-import { serverOptions } from 'vs/server/node/serverEnvironmentService';
+import { serverOptions, ServerParsedArgs } from 'vs/server/node/serverEnvironmentService';
import product from 'vs/platform/product/common/product';
import * as perf from 'vs/base/common/performance';
@@ -33,37 +33,42 @@ const errorReporter: ErrorReporter = {
}
};
-const args = parseArgs(process.argv.slice(2), serverOptions, errorReporter);
+function parse(): ServerParsedArgs {
+ return parseArgs(process.argv.slice(2), serverOptions, errorReporter);
+}
-const REMOTE_DATA_FOLDER = args['server-data-dir'] || process.env['VSCODE_AGENT_FOLDER'] || join(os.homedir(), product.serverDataFolderName || '.vscode-remote');
-const USER_DATA_PATH = join(REMOTE_DATA_FOLDER, 'data');
-const APP_SETTINGS_HOME = join(USER_DATA_PATH, 'User');
-const GLOBAL_STORAGE_HOME = join(APP_SETTINGS_HOME, 'globalStorage');
-const MACHINE_SETTINGS_HOME = join(USER_DATA_PATH, 'Machine');
-args['user-data-dir'] = USER_DATA_PATH;
-const APP_ROOT = dirname(FileAccess.asFileUri('', require).fsPath);
-const BUILTIN_EXTENSIONS_FOLDER_PATH = join(APP_ROOT, 'extensions');
-args['builtin-extensions-dir'] = BUILTIN_EXTENSIONS_FOLDER_PATH;
-args['extensions-dir'] = args['extensions-dir'] || join(REMOTE_DATA_FOLDER, 'extensions');
-
-[REMOTE_DATA_FOLDER, args['extensions-dir'], USER_DATA_PATH, APP_SETTINGS_HOME, MACHINE_SETTINGS_HOME, GLOBAL_STORAGE_HOME].forEach(f => {
- try {
- if (!fs.existsSync(f)) {
- fs.mkdirSync(f, { mode: 0o700 });
- }
- } catch (err) { console.error(err); }
-});
+function createDirs(args: ServerParsedArgs): string {
+ const REMOTE_DATA_FOLDER = args['server-data-dir'] || args['user-data-dir'] || process.env['VSCODE_AGENT_FOLDER'] || join(os.homedir(), product.serverDataFolderName || '.vscode-remote');
+ const USER_DATA_PATH = args['user-data-dir'] || join(REMOTE_DATA_FOLDER, 'data');
+ const APP_SETTINGS_HOME = join(USER_DATA_PATH, 'User');
+ const GLOBAL_STORAGE_HOME = join(APP_SETTINGS_HOME, 'globalStorage');
+ const MACHINE_SETTINGS_HOME = join(USER_DATA_PATH, 'Machine');
+ args['user-data-dir'] = USER_DATA_PATH;
+ const APP_ROOT = dirname(FileAccess.asFileUri('', require).fsPath);
+ const BUILTIN_EXTENSIONS_FOLDER_PATH = args['builtin-extensions-dir'] || join(APP_ROOT, 'extensions');
+ args['builtin-extensions-dir'] = BUILTIN_EXTENSIONS_FOLDER_PATH;
+ args['extensions-dir'] = args['extensions-dir'] || join(REMOTE_DATA_FOLDER, 'extensions');
+
+ [REMOTE_DATA_FOLDER, args['extensions-dir'], USER_DATA_PATH, APP_SETTINGS_HOME, MACHINE_SETTINGS_HOME, GLOBAL_STORAGE_HOME].forEach(f => {
+ try {
+ if (!fs.existsSync(f)) {
+ fs.mkdirSync(f, { mode: 0o700 });
+ }
+ } catch (err) { console.error(err); }
+ });
+ return REMOTE_DATA_FOLDER
+}
/**
* invoked by server-main.js
*/
-export function spawnCli() {
- runCli(args, REMOTE_DATA_FOLDER, serverOptions);
+export function spawnCli(args = parse()): Promise<void> {
+ return runCli(args, createDirs(args), serverOptions);
}
/**
* invoked by server-main.js
*/
-export function createServer(address: string | net.AddressInfo | null): Promise<IServerAPI> {
- return doCreateServer(address, args, REMOTE_DATA_FOLDER);
+export function createServer(address: string | net.AddressInfo | null, args = parse()): Promise<IServerAPI> {
+ return doCreateServer(address, args, createDirs(args));
}
Index: code-server/lib/vscode/src/vs/base/common/processes.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/base/common/processes.ts
+++ code-server/lib/vscode/src/vs/base/common/processes.ts
@@ -111,6 +111,8 @@ export function sanitizeProcessEnvironme
/^VSCODE_(?!SHELL_LOGIN).+$/,
/^SNAP(|_.*)$/,
/^GDK_PIXBUF_.+$/,
+ /^CODE_SERVER_.+$/,
+ /^CS_.+$/,
];
const envKeys = Object.keys(env);
envKeys
Index: code-server/lib/vscode/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts
@@ -144,11 +144,12 @@ export class BrowserDialogHandler implem
async about(): Promise<void> {
const detailString = (useAgo: boolean): string => {
return localize('aboutDetail',
- "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
+ "code-server: v{4}\nCode: {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'
);
};
Index: code-server/lib/vscode/src/vs/workbench/browser/client.ts
===================================================================
--- /dev/null
+++ code-server/lib/vscode/src/vs/workbench/browser/client.ts
@@ -0,0 +1,46 @@
+import { Disposable } from 'vs/base/common/lifecycle';
+
+export class CodeServerClient extends Disposable {
+ constructor (
+ ) {
+ super();
+ }
+
+ async startup(): Promise<void> {
+ // Emit ready events
+ const event = new CustomEvent('ide-ready');
+ window.dispatchEvent(event);
+
+ if (parent) {
+ // Tell the parent loading has completed.
+ parent.postMessage({ event: 'loaded' }, '*');
+
+ // Proxy or stop proxing events as requested by the parent.
+ const listeners = new Map<string, (event: Event) => void>();
+
+ window.addEventListener('message', parentEvent => {
+ const eventName = parentEvent.data.bind || parentEvent.data.unbind;
+ if (eventName) {
+ const oldListener = listeners.get(eventName);
+ if (oldListener) {
+ document.removeEventListener(eventName, oldListener);
+ }
+ }
+
+ if (parentEvent.data.bind && parentEvent.data.prop) {
+ const listener = (event: Event) => {
+ parent?.postMessage(
+ {
+ event: parentEvent.data.event,
+ [parentEvent.data.prop]: event[parentEvent.data.prop as keyof Event],
+ },
+ window.location.origin,
+ );
+ };
+ listeners.set(parentEvent.data.bind, listener);
+ document.addEventListener(parentEvent.data.bind, listener);
+ }
+ });
+ }
+ }
+}
Index: code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/web.main.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
@@ -69,6 +69,7 @@ import { ICredentialsService } from 'vs/
import { IndexedDB } from 'vs/base/browser/indexedDB';
import { BrowserCredentialsService } from 'vs/workbench/services/credentials/browser/credentialsService';
import { IWorkspace } from 'vs/workbench/services/host/browser/browserHostService';
+import { CodeServerClient } from 'vs/workbench/browser/client';
export class BrowserMain extends Disposable {
@@ -103,6 +104,9 @@ export class BrowserMain extends Disposa
// Startup
const instantiationService = workbench.startup();
+ const codeServerClient = this._register(instantiationService.createInstance(CodeServerClient));
+ await codeServerClient.startup();
+
// Window
this._register(instantiationService.createInstance(BrowserWindow));
Index: code-server/lib/vscode/src/vs/base/common/product.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/base/common/product.ts
+++ code-server/lib/vscode/src/vs/base/common/product.ts
@@ -31,6 +31,8 @@ export type ExtensionVirtualWorkspaceSup
};
export interface IProductConfiguration {
+ readonly codeServerVersion?: string
+
readonly version: string;
readonly date?: string;
readonly quality?: string;
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
@@ -11,7 +11,8 @@
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Code">
- <link rel="apple-touch-icon" href="/code-192.png" />
+ <link rel="apple-touch-icon" sizes="192x192" href="/_static/src/browser/media/pwa-icon-192.png" />
+ <link rel="apple-touch-icon" sizes="512x512" href="/_static/src/browser/media/pwa-icon-512.png" />
<!-- Disable pinch zooming -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
@@ -26,7 +27,8 @@
<meta id="vscode-workbench-builtin-extensions" data-settings="{{WORKBENCH_BUILTIN_EXTENSIONS}}">
<!-- Workbench Icon/Manifest/CSS -->
- <link rel="icon" href="/favicon.ico" type="image/x-icon" />
+ <link rel="icon" href="/_static/src/browser/media/favicon-dark-support.svg" />
+ <link rel="alternate icon" href="/_static/src/browser/media/favicon.ico" />
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
</head>
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.html
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
@@ -11,7 +11,8 @@
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Code">
- <link rel="apple-touch-icon" href="/code-192.png" />
+ <link rel="apple-touch-icon" sizes="192x192" href="/_static/src/browser/media/pwa-icon-192.png" />
+ <link rel="apple-touch-icon" sizes="512x512" href="/_static/src/browser/media/pwa-icon-512.png" />
<!-- Disable pinch zooming -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
@@ -23,7 +24,8 @@
<meta id="vscode-workbench-auth-session" data-settings="{{WORKBENCH_AUTH_SESSION}}">
<!-- Workbench Icon/Manifest/CSS -->
- <link rel="icon" href="/favicon.ico" type="image/x-icon" />
+ <link rel="icon" href="/_static/src/browser/media/favicon-dark-support.svg" />
+ <link rel="alternate icon" href="/_static/src/browser/media/favicon.ico" />
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
<link data-name="vs/workbench/workbench.web.main" rel="stylesheet" href="./static/out/vs/workbench/workbench.web.main.css">
Index: code-server/lib/vscode/build/gulpfile.reh.js
===================================================================
--- code-server.orig/lib/vscode/build/gulpfile.reh.js
+++ code-server/lib/vscode/build/gulpfile.reh.js
@@ -365,7 +365,7 @@ function packageTask(type, platform, arc
const minifyTask = task.define(`minify-vscode-${type}`, task.series(
optimizeTask,
util.rimraf(`out-vscode-${type}-min`),
- common.minifyTask(`out-vscode-${type}`, `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`)
+ common.minifyTask(`out-vscode-${type}`, ``)
));
gulp.task(minifyTask);

View File

@@ -1,32 +0,0 @@
Remove last opened functionality
This conflicts with our own handling of the last opened workspace. If we wanted
to switch to this we would need to pass through the disable-last-opened flag and
respect it here then remove our own redirction code that handles this.
Our version might be better anyway since it puts the workspace in the URL.
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
@@ -350,19 +350,6 @@ class WorkspaceProvider implements IWork
workspace = { folderUri: URI.revive(config.folderUri) };
} else if (config.workspaceUri) {
workspace = { workspaceUri: URI.revive(config.workspaceUri) };
- } else {
- workspace = (() => {
- const lastWorkspaceRaw = window.localStorage.getItem(WorkspaceProvider.LAST_WORKSPACE_STORAGE_KEY);
- if (lastWorkspaceRaw) {
- try {
- return parse(lastWorkspaceRaw); // use marshalling#parse() to revive potential URIs
- } catch (error) {
- // Ignore
- }
- }
-
- return undefined;
- })();
}
}

View File

@@ -1,66 +0,0 @@
Make storage local to the remote server
This solves two problems:
1. Extensions running in the browser (like Vim) might use these paths
directly instead of using the file service and most likely can't write
to `/User` on disk.
2. Settings will be stored in the file system instead of in browser
storage. Using browser storage makes sharing or seeding settings
between browsers difficult. We may want to revisit this once/if we get
settings sync.
Unfortunately this does not affect state which uses a separate method with
IndexedDB and does not appear nearly as easy to redirect to disk.
To test install the Vim extension and make sure something that uses file storage
works (history recall for example) and change settings from the UI and on disk
while making sure they appear on the other side.
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -289,6 +289,7 @@ export class WebClientServer {
enableSmokeTestDriver: this._environmentService.driverHandle === 'web' ? true : undefined,
logLevel: this._logService.getLevel(),
},
+ userDataPath: this._environmentService.userDataPath,
settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined,
productConfiguration: <Partial<IProductConfiguration>>{
rootEndpoint: base,
Index: code-server/lib/vscode/src/vs/workbench/browser/web.api.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/web.api.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/web.api.ts
@@ -205,6 +205,11 @@ export interface IWorkbenchConstructionO
*/
readonly configurationDefaults?: Record<string, any>;
+ /**
+ * Path to the user data directory.
+ */
+ readonly userDataPath?: string
+
//#endregion
Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
+++ code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
@@ -126,7 +126,14 @@ export class BrowserWorkbenchEnvironment
get logFile(): URI { return joinPath(this.logsHome, 'window.log'); }
@memoize
- get userRoamingDataHome(): URI { return URI.file('/User').with({ scheme: Schemas.userData }); }
+ get userRoamingDataHome(): URI { return joinPath(URI.file(this.userDataPath).with({ scheme: Schemas.vscodeRemote }), 'User'); }
+
+ get userDataPath(): string {
+ if (!this.options.userDataPath) {
+ throw new Error('userDataPath was not provided to the browser');
+ }
+ return this.options.userDataPath;
+ }
@memoize
get settingsResource(): URI { return joinPath(this.userRoamingDataHome, 'settings.json'); }

View File

@@ -1,21 +0,0 @@
Propagate the log level to the client
This can be tested by using `--log trace`. You should see plenty of debug and
trace logs in the console.
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -285,7 +285,10 @@ export class WebClientServer {
remoteAuthority,
webviewEndpoint: vscodeBase + '/static/out/vs/workbench/contrib/webview/browser/pre',
_wrapWebWorkerExtHostInIframe,
- developmentOptions: { enableSmokeTestDriver: this._environmentService.driverHandle === 'web' ? true : undefined },
+ developmentOptions: {
+ enableSmokeTestDriver: this._environmentService.driverHandle === 'web' ? true : undefined,
+ logLevel: this._logService.getLevel(),
+ },
settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined,
productConfiguration: <Partial<IProductConfiguration>>{
rootEndpoint: base,

View File

@@ -1,107 +0,0 @@
Add a logout command and menu item
This will only show if you have authentication enabled.
This has e2e tests but are currently disabled and need to be fixed.
Index: code-server/lib/vscode/src/vs/base/common/product.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/base/common/product.ts
+++ code-server/lib/vscode/src/vs/base/common/product.ts
@@ -34,6 +34,7 @@ export interface IProductConfiguration {
readonly codeServerVersion?: string
readonly rootEndpoint?: string
readonly updateEndpoint?: string
+ readonly logoutEndpoint?: string
readonly version: string;
readonly date?: string;
Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
+++ code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
@@ -13,6 +13,7 @@ import { IEnvironmentService, INativeEnv
export const serverOptions: OptionDescriptions<ServerParsedArgs> = {
/* ----- code-server ----- */
'disable-update-check': { type: 'boolean' },
+ 'auth': { type: 'string' },
/* ----- server setup ----- */
@@ -88,6 +89,7 @@ export const serverOptions: OptionDescri
export interface ServerParsedArgs {
/* ----- code-server ----- */
'disable-update-check'?: boolean;
+ 'auth'?: string
/* ----- server setup ----- */
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -287,6 +287,7 @@ export class WebClientServer {
productConfiguration: <Partial<IProductConfiguration>>{
rootEndpoint: base,
updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined,
+ logoutEndpoint: this._environmentService.args['auth'] ? base + '/logout' : undefined,
extensionsGallery: {
...this._productService.extensionsGallery,
'resourceUrlTemplate': this._webExtensionResourceUrlTemplate ? this._webExtensionResourceUrlTemplate.with({
Index: code-server/lib/vscode/src/vs/workbench/browser/client.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/client.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/client.ts
@@ -1,11 +1,15 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
+import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
+import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IProductService } from 'vs/platform/product/common/productService';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
export class CodeServerClient extends Disposable {
+ static LOGOUT_COMMAND_ID = 'code-server.logout';
+
constructor (
@ILogService private logService: ILogService,
@INotificationService private notificationService: INotificationService,
@@ -82,6 +86,10 @@ export class CodeServerClient extends Di
if (this.productService.updateEndpoint) {
this.checkUpdates(this.productService.updateEndpoint)
}
+
+ if (this.productService.logoutEndpoint) {
+ this.addLogoutCommand(this.productService.logoutEndpoint);
+ }
}
private checkUpdates(updateEndpoint: string) {
@@ -133,4 +141,25 @@ export class CodeServerClient extends Di
updateLoop();
}
+
+ private addLogoutCommand(logoutEndpoint: string) {
+ CommandsRegistry.registerCommand(CodeServerClient.LOGOUT_COMMAND_ID, () => {
+ const logoutUrl = new URL(logoutEndpoint, window.location.href);
+ // Cookies must be set with absolute paths and must use the same path to
+ // be unset (we set it on the root) so send the relative root and the
+ // current href so the backend can derive the absolute path to the root.
+ logoutUrl.searchParams.set('base', this.productService.rootEndpoint || ".");
+ logoutUrl.searchParams.set('href', window.location.href);
+ window.location.assign(logoutUrl);
+ });
+
+ for (const menuId of [MenuId.CommandPalette, MenuId.MenubarHomeMenu]) {
+ MenuRegistry.appendMenuItem(menuId, {
+ command: {
+ id: CodeServerClient.LOGOUT_COMMAND_ID,
+ title: localize('logout', "Sign out of {0}", 'code-server'),
+ },
+ });
+ }
+ }
}

View File

@@ -1,53 +0,0 @@
Add Open VSX default and an env var for marketplace, fix old marketplace
Our old marketplace only supports `serviceUrl` but this causes the marketplace
to be disabled entirely so this moves the template var check to fix that.
This can be tested by setting EXTENSIONS_GALLERY set to:
'{"serviceUrl": "https://extensions.coder.com/api"}'
Index: code-server/lib/vscode/src/vs/platform/product/common/product.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/product/common/product.ts
+++ code-server/lib/vscode/src/vs/platform/product/common/product.ts
@@ -45,7 +45,14 @@ else if (typeof require?.__$__nodeRequir
}
Object.assign(product, {
- version: pkg.version
+ version: pkg.version,
+ extensionsGallery: env.EXTENSIONS_GALLERY ? JSON.parse(env.EXTENSIONS_GALLERY) : (product.extensionsGallery || {
+ serviceUrl: "https://open-vsx.org/vscode/gallery",
+ itemUrl: "https://open-vsx.org/vscode/item",
+ resourceUrlTemplate: "https://open-vsx.org/vscode/asset/{publisher}/{name}/{version}/Microsoft.VisualStudio.Code.WebResources/{path}",
+ controlUrl: "",
+ recommendationsUrl: "",
+ }),
});
}
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -285,14 +285,14 @@ export class WebClientServer {
settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined,
productConfiguration: <Partial<IProductConfiguration>>{
rootEndpoint: base,
- extensionsGallery: this._webExtensionResourceUrlTemplate ? {
+ extensionsGallery: {
...this._productService.extensionsGallery,
- 'resourceUrlTemplate': this._webExtensionResourceUrlTemplate.with({
+ 'resourceUrlTemplate': this._webExtensionResourceUrlTemplate ? this._webExtensionResourceUrlTemplate.with({
scheme: 'http',
authority: remoteAuthority,
path: `web-extension-resource/${this._webExtensionResourceUrlTemplate.authority}${this._webExtensionResourceUrlTemplate.path}`
- }).toString(true)
- } : undefined
+ }).toString(true) : undefined
+ },
}
})))
.replace('{{WORKBENCH_AUTH_SESSION}}', () => authSessionInfo ? escapeAttribute(JSON.stringify(authSessionInfo)) : '')

View File

@@ -1,106 +0,0 @@
Patch the Node version to use the current version of Node
Previously it would use the yarnrc which results in builds that cannot run with
the version of Node they were built with because the native modules are
targeting the wrong version.
One way test this is to build in a fresh Docker container, run the build, then
try opening the built-in terminal.
Index: code-server/lib/vscode/build/gulpfile.reh.js
===================================================================
--- code-server.orig/lib/vscode/build/gulpfile.reh.js
+++ code-server/lib/vscode/build/gulpfile.reh.js
@@ -122,9 +122,7 @@ const serverWithWebEntryPoints = [
];
function getNodeVersion() {
- const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8');
- const target = /^target "(.*)"$/m.exec(yarnrc)[1];
- return target;
+ return process.versions.node;
}
const nodeVersion = getNodeVersion();
Index: code-server/lib/vscode/build/lib/node.js
===================================================================
--- code-server.orig/lib/vscode/build/lib/node.js
+++ code-server/lib/vscode/build/lib/node.js
@@ -7,9 +7,7 @@ Object.defineProperty(exports, "__esModu
const path = require("path");
const fs = require("fs");
const root = path.dirname(path.dirname(__dirname));
-const yarnrcPath = path.join(root, 'remote', '.yarnrc');
-const yarnrc = fs.readFileSync(yarnrcPath, 'utf8');
-const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)[1];
+const version = process.versions.node;
const platform = process.platform;
const arch = platform === 'darwin' ? 'x64' : process.arch;
const node = platform === 'win32' ? 'node.exe' : 'node';
Index: code-server/lib/vscode/build/lib/node.ts
===================================================================
--- code-server.orig/lib/vscode/build/lib/node.ts
+++ code-server/lib/vscode/build/lib/node.ts
@@ -7,9 +7,7 @@ import * as path from 'path';
import * as fs from 'fs';
const root = path.dirname(path.dirname(__dirname));
-const yarnrcPath = path.join(root, 'remote', '.yarnrc');
-const yarnrc = fs.readFileSync(yarnrcPath, 'utf8');
-const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)![1];
+const version = process.versions.node;
const platform = process.platform;
const arch = platform === 'darwin' ? 'x64' : process.arch;
Index: code-server/lib/vscode/build/lib/util.js
===================================================================
--- code-server.orig/lib/vscode/build/lib/util.js
+++ code-server/lib/vscode/build/lib/util.js
@@ -298,9 +298,7 @@ function streamToPromise(stream) {
}
exports.streamToPromise = streamToPromise;
function getElectronVersion() {
- const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8');
- const target = /^target "(.*)"$/m.exec(yarnrc)[1];
- return target;
+ return process.versions.node;
}
exports.getElectronVersion = getElectronVersion;
function acquireWebNodePaths() {
Index: code-server/lib/vscode/build/lib/util.ts
===================================================================
--- code-server.orig/lib/vscode/build/lib/util.ts
+++ code-server/lib/vscode/build/lib/util.ts
@@ -371,9 +371,7 @@ export function streamToPromise(stream:
}
export function getElectronVersion(): string {
- const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8');
- const target = /^target "(.*)"$/m.exec(yarnrc)![1];
- return target;
+ return process.versions.node;
}
export function acquireWebNodePaths() {
@@ -455,4 +453,3 @@ export function buildWebNodePaths(outDir
result.taskName = 'build-web-node-paths';
return result;
}
-
Index: code-server/lib/vscode/remote/.yarnrc
===================================================================
--- code-server.orig/lib/vscode/remote/.yarnrc
+++ /dev/null
@@ -1,3 +0,0 @@
-disturl "http://nodejs.org/dist"
-target "14.16.0"
-runtime "node"
Index: code-server/lib/vscode/.yarnrc
===================================================================
--- code-server.orig/lib/vscode/.yarnrc
+++ /dev/null
@@ -1,4 +0,0 @@
-disturl "https://electronjs.org/headers"
-target "13.5.2"
-runtime "electron"
-build_from_source "true"

View File

@@ -1,26 +0,0 @@
Replace rimraf with fs.rmSync in postinstall
The postinstall gets ran when you install with npm but rimraf is a development
dependency so it will not exist.
Index: code-server/lib/vscode/extensions/postinstall.js
===================================================================
--- code-server.orig/lib/vscode/extensions/postinstall.js
+++ code-server/lib/vscode/extensions/postinstall.js
@@ -8,7 +8,6 @@
const fs = require('fs');
const path = require('path');
-const rimraf = require('rimraf');
const root = path.join(__dirname, 'node_modules', 'typescript');
@@ -21,7 +20,7 @@ function processRoot() {
if (!toKeep.has(name)) {
const filePath = path.join(root, name);
console.log(`Removed ${filePath}`);
- rimraf.sync(filePath);
+ fs.rmSync(filePath, { recursive: true });
}
}
}

View File

@@ -1,36 +0,0 @@
Unconditionally enable the proposed API
To test run an extension that uses the proposed API.
We also override isProposedApiEnabled in case an extension does not declare the
APIs it needs correctly (the Jupyter extension had this issue).
Index: code-server/lib/vscode/src/vs/workbench/services/extensions/common/abstractExtensionService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/extensions/common/abstractExtensionService.ts
+++ code-server/lib/vscode/src/vs/workbench/services/extensions/common/abstractExtensionService.ts
@@ -1134,7 +1134,7 @@ class ProposedApiController {
this._envEnabledExtensions = new Set((_environmentService.extensionEnabledProposedApi ?? []).map(id => ExtensionIdentifier.toKey(id)));
- this._envEnablesProposedApiForAll =
+ this._envEnablesProposedApiForAll = true ||
!_environmentService.isBuilt || // always allow proposed API when running out of sources
(_environmentService.isExtensionDevelopment && productService.quality !== 'stable') || // do not allow proposed API against stable builds when developing an extension
(this._envEnabledExtensions.size === 0 && Array.isArray(_environmentService.extensionEnabledProposedApi)); // always allow proposed API if --enable-proposed-api is provided without extension ID
Index: code-server/lib/vscode/src/vs/workbench/services/extensions/common/extensions.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/extensions/common/extensions.ts
+++ code-server/lib/vscode/src/vs/workbench/services/extensions/common/extensions.ts
@@ -135,10 +135,7 @@ export interface IExtensionHost {
}
export function isProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): boolean {
- if (!extension.enabledApiProposals) {
- return false;
- }
- return extension.enabledApiProposals.includes(proposal);
+ return true
}
export function checkProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): void {

View File

@@ -1,104 +0,0 @@
Add VSCODE_PROXY_URI environment variable
This can be used by extensions to open a port and access it through the proxy.
It is available in the terminal as well.
This can be tested using printenv in the terminal and by using the
codeServerTest.proxyUri command through the test extension (copy it into your
extensions, use --extensions-dir, or symlink it).
This has e2e tests.
Index: code-server/lib/vscode/src/vs/base/common/product.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/base/common/product.ts
+++ code-server/lib/vscode/src/vs/base/common/product.ts
@@ -35,6 +35,7 @@ export interface IProductConfiguration {
readonly rootEndpoint?: string
readonly updateEndpoint?: string
readonly logoutEndpoint?: string
+ readonly proxyEndpointTemplate?: string
readonly version: string;
readonly date?: string;
Index: code-server/lib/vscode/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
+++ code-server/lib/vscode/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
@@ -7,7 +7,7 @@ import { Emitter } from 'vs/base/common/
import { Disposable } from 'vs/base/common/lifecycle';
import { RemoteAuthorities } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
-import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
+import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolvedOptions, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService {
@@ -20,7 +20,7 @@ export class RemoteAuthorityResolverServ
private readonly _connectionToken: string | undefined;
private readonly _connectionTokens: Map<string, string>;
- constructor(connectionToken: string | undefined, resourceUriProvider: ((uri: URI) => URI) | undefined) {
+ constructor(connectionToken: string | undefined, resourceUriProvider: ((uri: URI) => URI) | undefined, private readonly proxyEndpointTemplate?: string) {
super();
this._cache = new Map<string, ResolverResult>();
this._connectionToken = connectionToken;
@@ -59,12 +59,17 @@ export class RemoteAuthorityResolverServ
private _doResolveAuthority(authority: string): ResolverResult {
const connectionToken = this._connectionTokens.get(authority) || this._connectionToken;
+ let options: ResolvedOptions | undefined
+ if (this.proxyEndpointTemplate) {
+ const proxyUrl = new URL(this.proxyEndpointTemplate, window.location.href);
+ options = { extensionHostEnv: { VSCODE_PROXY_URI: decodeURIComponent(proxyUrl.toString()) }}
+ }
if (authority.indexOf(':') >= 0) {
const pieces = authority.split(':');
- return { authority: { authority, host: pieces[0], port: parseInt(pieces[1], 10), connectionToken } };
+ return { authority: { authority, host: pieces[0], port: parseInt(pieces[1], 10), connectionToken }, options };
}
const port = (/^https:/.test(window.location.href) ? 443 : 80);
- return { authority: { authority, host: authority, port: port, connectionToken } };
+ return { authority: { authority, host: authority, port: port, connectionToken }, options };
}
_clearResolvedAuthority(authority: string): void {
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -288,6 +288,7 @@ export class WebClientServer {
rootEndpoint: base,
updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined,
logoutEndpoint: this._environmentService.args['auth'] ? base + '/logout' : undefined,
+ proxyEndpointTemplate: base + '/proxy/{{port}}',
extensionsGallery: {
...this._productService.extensionsGallery,
'resourceUrlTemplate': this._webExtensionResourceUrlTemplate ? this._webExtensionResourceUrlTemplate.with({
Index: code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/web.main.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
@@ -179,7 +179,7 @@ export class BrowserMain extends Disposa
// Remote
const connectionToken = environmentService.options.connectionToken || getCookieValue(connectionTokenCookieName);
- const remoteAuthorityResolverService = new RemoteAuthorityResolverService(connectionToken, this.configuration.resourceUriProvider);
+ const remoteAuthorityResolverService = new RemoteAuthorityResolverService(connectionToken, this.configuration.resourceUriProvider, this.configuration.productConfiguration?.proxyEndpointTemplate);
serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService);
// Signing
Index: code-server/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts
@@ -388,7 +388,7 @@ export function createTerminalEnvironmen
// Sanitize the environment, removing any undesirable VS Code and Electron environment
// variables
- sanitizeProcessEnvironment(env, 'VSCODE_IPC_HOOK_CLI');
+ sanitizeProcessEnvironment(env, 'VSCODE_IPC_HOOK_CLI', 'VSCODE_PROXY_URI');
// Merge config (settings) and ShellLaunchConfig environments
mergeEnvironments(env, allowedEnvFromConfig);

View File

@@ -1,20 +0,0 @@
integration.diff
node-version.diff
base-path.diff
proposed-api.diff
marketplace.diff
webview.diff
insecure-notification.diff
update-check.diff
logout.diff
store-socket.diff
proxy-uri.diff
display-language.diff
github-auth.diff
unique-db.diff
post-install.diff
log-level.diff
local-storage.diff
service-worker.diff
last-opened.diff
connection-type.diff

View File

@@ -1,67 +0,0 @@
Add a service worker
To test try installing code-server as a PWA.
Index: code-server/lib/vscode/src/vs/base/common/product.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/base/common/product.ts
+++ code-server/lib/vscode/src/vs/base/common/product.ts
@@ -36,6 +36,10 @@ export interface IProductConfiguration {
readonly updateEndpoint?: string
readonly logoutEndpoint?: string
readonly proxyEndpointTemplate?: string
+ readonly serviceWorker?: {
+ readonly path: string;
+ readonly scope: string;
+ }
readonly version: string;
readonly date?: string;
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -296,6 +296,10 @@ export class WebClientServer {
updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined,
logoutEndpoint: this._environmentService.args['auth'] ? base + '/logout' : undefined,
proxyEndpointTemplate: base + '/proxy/{{port}}',
+ serviceWorker: {
+ scope: vscodeBase + '/',
+ path: base + '/_static/out/browser/serviceWorker.js',
+ },
extensionsGallery: {
...this._productService.extensionsGallery,
'resourceUrlTemplate': this._webExtensionResourceUrlTemplate ? this._webExtensionResourceUrlTemplate.with({
Index: code-server/lib/vscode/src/vs/workbench/browser/client.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/client.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/client.ts
@@ -90,6 +90,10 @@ export class CodeServerClient extends Di
if (this.productService.logoutEndpoint) {
this.addLogoutCommand(this.productService.logoutEndpoint);
}
+
+ if (this.productService.serviceWorker) {
+ await this.registerServiceWorker(this.productService.serviceWorker);
+ }
}
private checkUpdates(updateEndpoint: string) {
@@ -162,4 +166,17 @@ export class CodeServerClient extends Di
});
}
}
+
+ private async registerServiceWorker(serviceWorker: { path: string; scope: string }) {
+ if (typeof navigator !== 'undefined' && 'serviceWorker' in navigator) {
+ try {
+ await navigator.serviceWorker.register(serviceWorker.path, {
+ scope: serviceWorker.scope,
+ });
+ this.logService.info('[Service Worker] registered');
+ } catch (error: any) {
+ this.logService.error('[Service Worker] registration', error as Error);
+ }
+ }
+ }
}

View File

@@ -1,31 +0,0 @@
Store a static reference to the IPC socket
This lets us use it to open files inside code-server from outside of
code-server.
Index: code-server/lib/vscode/src/vs/workbench/api/node/extHostExtensionService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/api/node/extHostExtensionService.ts
+++ code-server/lib/vscode/src/vs/workbench/api/node/extHostExtensionService.ts
@@ -2,7 +2,9 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-
+import { promises as fs } from 'fs';
+import * as os from 'os'
+import * as path from 'vs/base/common/path';
import * as performance from 'vs/base/common/performance';
import { createApiFactoryAndRegisterActors } from 'vs/workbench/api/common/extHost.api.impl';
import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor';
@@ -69,6 +71,10 @@ export class ExtHostExtensionService ext
if (this._initData.remote.isRemote && this._initData.remote.authority) {
const cliServer = this._instaService.createInstance(CLIServer);
process.env['VSCODE_IPC_HOOK_CLI'] = cliServer.ipcHandlePath;
+
+ fs.writeFile(path.join(os.tmpdir(), 'vscode-ipc'), cliServer.ipcHandlePath).catch((error) => {
+ this._logService.error(error);
+ });
}
// Module loading tricks

View File

@@ -1,63 +0,0 @@
Prevent state collisions
Previously if you opened different workspaces that had the same filesystem path
(for example if you have /home/coder on two different machines that are both
accessed through the same host) they would conflict with each other. This
ensures that different browser paths will be unique (for example /workspace1 and
/workspace2).
The easiest way to test is to open files in the same workspace using both / and
/vscode and make sure they are not interacting with each other.
It should also migrate old databases which can be tested by opening in an old
code-server.
This has e2e tests.
Index: code-server/lib/vscode/src/vs/platform/storage/browser/storageService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/storage/browser/storageService.ts
+++ code-server/lib/vscode/src/vs/platform/storage/browser/storageService.ts
@@ -13,6 +13,7 @@ import { InMemoryStorageDatabase, isStor
import { ILogService } from 'vs/platform/log/common/log';
import { AbstractStorageService, IS_NEW_KEY, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
+import { hash } from 'vs/base/common/hash';
export class BrowserStorageService extends AbstractStorageService {
@@ -36,7 +37,11 @@ export class BrowserStorageService exten
}
private getId(scope: StorageScope): string {
- return scope === StorageScope.GLOBAL ? 'global' : this.payload.id;
+ // Add a unique ID based on the current path for per-workspace databases.
+ // This prevents workspaces on different machines that share the same domain
+ // and file path from colliding (since it does not appear IndexedDB can be
+ // scoped to a path) as long as they are hosted on different paths.
+ return scope === StorageScope.GLOBAL ? 'global' : (this.payload.id + '-' + hash(location.pathname.toString().replace(/\/$/, "")).toString(16));
}
protected async doInitialize(): Promise<void> {
@@ -75,6 +80,21 @@ export class BrowserStorageService exten
const firstWorkspaceOpen = this.workspaceStorage.getBoolean(IS_NEW_KEY);
if (firstWorkspaceOpen === undefined) {
this.workspaceStorage.set(IS_NEW_KEY, true);
+ // Migrate the old database.
+ let db: IIndexedDBStorageDatabase | undefined
+ try {
+ db = await IndexedDBStorageDatabase.create({ id: this.payload.id }, this.logService)
+ const items = await db.getItems()
+ for (const [key, value] of items) {
+ this.workspaceStorage.set(key, value);
+ }
+ } catch (error) {
+ this.logService.error(`[IndexedDB Storage ${this.payload.id}] migrate error: ${toErrorMessage(error)}`);
+ } finally {
+ if (db) {
+ db.close()
+ }
+ }
} else if (firstWorkspaceOpen) {
this.workspaceStorage.set(IS_NEW_KEY, false);
}

View File

@@ -1,132 +0,0 @@
Add a notification that lets you know when an update is out
The easiest way to test this is probably to change the version in your
package.json and delete the last notification storage item.
Index: code-server/lib/vscode/src/vs/workbench/browser/client.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/client.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/client.ts
@@ -1,10 +1,16 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
+import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
+import { IProductService } from 'vs/platform/product/common/productService';
+import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
export class CodeServerClient extends Disposable {
constructor (
+ @ILogService private logService: ILogService,
@INotificationService private notificationService: INotificationService,
+ @IProductService private productService: IProductService,
+ @IStorageService private storageService: IStorageService,
) {
super();
}
@@ -72,5 +78,59 @@ export class CodeServerClient extends Di
},
});
}
+
+ if (this.productService.updateEndpoint) {
+ this.checkUpdates(this.productService.updateEndpoint)
+ }
+ }
+
+ private checkUpdates(updateEndpoint: string) {
+ const getUpdate = async (updateCheckEndpoint: string): Promise<void> => {
+ this.logService.debug('Checking for update...');
+
+ const response = await fetch(updateCheckEndpoint, {
+ headers: { Accept: 'application/json' },
+ });
+ if (!response.ok) {
+ throw new Error(response.statusText);
+ }
+ const json = await response.json();
+ if (json.error) {
+ throw new Error(json.error);
+ }
+ if (json.isLatest) {
+ return;
+ }
+
+ const lastNoti = this.storageService.getNumber('csLastUpdateNotification', StorageScope.GLOBAL);
+ if (lastNoti) {
+ // Only remind them again after 1 week.
+ const timeout = 1000 * 60 * 60 * 24 * 7;
+ const threshold = lastNoti + timeout;
+ if (Date.now() < threshold) {
+ return;
+ }
+ }
+
+ this.storageService.store('csLastUpdateNotification', Date.now(), StorageScope.GLOBAL, StorageTarget.MACHINE);
+
+ this.notificationService.notify({
+ severity: Severity.Info,
+ message: `[code-server v${json.latest}](https://github.com/cdr/code-server/releases/tag/v${json.latest}) has been released!`,
+ });
+ };
+
+ const updateLoop = (): void => {
+ getUpdate(updateEndpoint)
+ .catch(error => {
+ this.logService.debug(`failed to check for update: ${error}`);
+ })
+ .finally(() => {
+ // Check again every 6 hours.
+ setTimeout(updateLoop, 1000 * 60 * 60 * 6);
+ });
+ };
+
+ updateLoop();
}
}
Index: code-server/lib/vscode/src/vs/base/common/product.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/base/common/product.ts
+++ code-server/lib/vscode/src/vs/base/common/product.ts
@@ -33,6 +33,7 @@ export type ExtensionVirtualWorkspaceSup
export interface IProductConfiguration {
readonly codeServerVersion?: string
readonly rootEndpoint?: string
+ readonly updateEndpoint?: string
readonly version: string;
readonly date?: string;
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -286,6 +286,7 @@ export class WebClientServer {
settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined,
productConfiguration: <Partial<IProductConfiguration>>{
rootEndpoint: base,
+ updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined,
extensionsGallery: {
...this._productService.extensionsGallery,
'resourceUrlTemplate': this._webExtensionResourceUrlTemplate ? this._webExtensionResourceUrlTemplate.with({
Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
+++ code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
@@ -11,6 +11,8 @@ import { refineServiceDecorator } from '
import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
export const serverOptions: OptionDescriptions<ServerParsedArgs> = {
+ /* ----- code-server ----- */
+ 'disable-update-check': { type: 'boolean' },
/* ----- server setup ----- */
@@ -84,6 +86,8 @@ export const serverOptions: OptionDescri
};
export interface ServerParsedArgs {
+ /* ----- code-server ----- */
+ 'disable-update-check'?: boolean;
/* ----- server setup ----- */

View File

@@ -1,46 +0,0 @@
Serve webviews from the same origin
Normally webviews are served from vscode-webview.net but we would rather them be
self-hosted.
When doing this CSP will block resources (for example when viewing images) so
add 'self' to the CSP to fix that.
Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
+++ code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
@@ -240,7 +240,7 @@ export class BrowserWorkbenchEnvironment
@memoize
get webviewExternalEndpoint(): string {
- const endpoint = this.options.webviewEndpoint
+ const endpoint = (this.options.webviewEndpoint && new URL(this.options.webviewEndpoint, window.location.toString()).toString())
|| this.productService.webviewContentExternalBaseUrlTemplate
|| 'https://{{uuid}}.vscode-webview.net/{{quality}}/{{commit}}/out/vs/workbench/contrib/webview/browser/pre/';
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -280,6 +280,7 @@ export class WebClientServer {
const data = (await util.promisify(fs.readFile)(filePath)).toString()
.replace('{{WORKBENCH_WEB_CONFIGURATION}}', escapeAttribute(JSON.stringify({
remoteAuthority,
+ webviewEndpoint: vscodeBase + '/static/out/vs/workbench/contrib/webview/browser/pre',
_wrapWebWorkerExtHostInIframe,
developmentOptions: { enableSmokeTestDriver: this._environmentService.driverHandle === 'web' ? true : undefined },
settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined,
Index: code-server/lib/vscode/src/vs/workbench/api/common/shared/webview.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/api/common/shared/webview.ts
+++ code-server/lib/vscode/src/vs/workbench/api/common/shared/webview.ts
@@ -25,7 +25,7 @@ export const webviewResourceBaseHost = '
export const webviewRootResourceAuthority = `vscode-resource.${webviewResourceBaseHost}`;
-export const webviewGenericCspSource = `https://*.${webviewResourceBaseHost}`;
+export const webviewGenericCspSource = `'self' https://*.${webviewResourceBaseHost}`;
/**
* Construct a uri that can load resources inside a webview

View File

@@ -1,14 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
self.addEventListener("install", () => {
console.debug("[Service Worker] installed")
})
self.addEventListener("activate", (event: any) => {
event.waitUntil((self as any).clients.claim())
console.debug("[Service Worker] activated")
})
self.addEventListener("fetch", () => {
// Without this event handler we won't be recognized as a PWA.
})

View File

@@ -22,35 +22,40 @@ export interface App extends Disposable {
server: http.Server
}
export const listen = async (server: http.Server, { host, port, socket, "socket-mode": mode }: ListenOptions) => {
if (socket) {
try {
await fs.unlink(socket)
} catch (error: any) {
handleArgsSocketCatchError(error)
}
}
await new Promise<void>(async (resolve, reject) => {
const listen = (server: http.Server, { host, port, socket, "socket-mode": mode }: ListenOptions) => {
return new Promise<void>(async (resolve, reject) => {
server.on("error", reject)
const onListen = () => {
// Promise resolved earlier so this is an unrelated error.
server.off("error", reject)
server.on("error", (err) => util.logError(logger, "http server error", err))
resolve()
if (socket && mode) {
fs.chmod(socket, mode)
.then(resolve)
.catch((err) => {
util.logError(logger, "socket chmod", err)
reject(err)
})
} else {
resolve()
}
}
if (socket) {
try {
await fs.unlink(socket)
} catch (error: any) {
handleArgsSocketCatchError(error)
}
server.listen(socket, onListen)
} else {
// [] is the correct format when using :: but Node errors with them.
server.listen(port, host.replace(/^\[|\]$/g, ""), onListen)
}
})
// NOTE@jsjoeio: we need to chmod after the server is finished
// listening. Otherwise, the socket may not have been created yet.
if (socket && mode) {
await fs.chmod(socket, mode)
}
}
/**
@@ -133,6 +138,6 @@ export const handleServerError = (resolved: boolean, err: Error, reject: (err: E
*/
export const handleArgsSocketCatchError = (error: any) => {
if (!isNodeJSErrnoException(error) || error.code !== "ENOENT") {
throw Error(error.message ? error.message : error)
logger.error(error.message ? error.message : error)
}
}

View File

@@ -31,33 +31,13 @@ export enum LogLevel {
export class OptionalString extends Optional<string> {}
/**
* Code flags provided by the user.
*/
export interface UserProvidedCodeArgs {
"disable-telemetry"?: boolean
force?: boolean
"user-data-dir"?: string
"enable-proposed-api"?: string[]
"extensions-dir"?: string
"builtin-extensions-dir"?: string
"install-extension"?: string[]
"uninstall-extension"?: string[]
"list-extensions"?: boolean
"locate-extension"?: string[]
"show-versions"?: boolean
category?: string
"github-auth"?: string
"disable-update-check"?: boolean
}
/**
* Arguments that the user explicitly provided on the command line. All
* arguments must be optional.
*
* For arguments with defaults see DefaultedArgs.
*/
export interface UserProvidedArgs extends UserProvidedCodeArgs {
export interface UserProvidedArgs {
config?: string
auth?: AuthType
password?: string
@@ -65,6 +45,7 @@ export interface UserProvidedArgs extends UserProvidedCodeArgs {
cert?: OptionalString
"cert-host"?: string
"cert-key"?: string
"disable-update-check"?: boolean
enable?: string[]
help?: boolean
host?: string
@@ -85,6 +66,21 @@ export interface UserProvidedArgs extends UserProvidedCodeArgs {
verbose?: boolean
/* Positional arguments. */
_?: string[]
// VS Code flags.
"disable-telemetry"?: boolean
force?: boolean
"user-data-dir"?: string
"enable-proposed-api"?: string[]
"extensions-dir"?: string
"builtin-extensions-dir"?: string
"install-extension"?: string[]
"uninstall-extension"?: string[]
"list-extensions"?: boolean
"locate-extension"?: string[]
"show-versions"?: boolean
category?: string
"github-auth"?: string
}
interface Option<T> {
@@ -124,11 +120,11 @@ type OptionType<T> = T extends boolean
? "string[]"
: "unknown"
export type Options<T> = {
type Options<T> = {
[P in keyof T]: Option<OptionType<T[P]>>
}
export const options: Options<Required<UserProvidedArgs>> = {
const options: Options<Required<UserProvidedArgs>> = {
auth: { type: AuthType, description: "The type of authentication to use." },
password: {
type: "string",
@@ -239,8 +235,8 @@ export const options: Options<Required<UserProvidedArgs>> = {
},
}
export const optionDescriptions = (opts: Partial<Options<Required<UserProvidedArgs>>> = options): string[] => {
const entries = Object.entries(opts).filter(([, v]) => !!v.description)
export const optionDescriptions = (): string[] => {
const entries = Object.entries(options).filter(([, v]) => !!v.description)
const widths = entries.reduce(
(prev, [k, v]) => ({
long: k.length > prev.long ? k.length : prev.long,
@@ -765,37 +761,14 @@ export const shouldOpenInExistingInstance = async (args: UserProvidedArgs): Prom
return undefined
}
/**
* Arguments for running Code's server.
*
* A subset of ../../lib/vscode/src/vs/server/node/serverEnvironmentService.ts:90
*/
export interface CodeArgs extends UserProvidedCodeArgs {
"accept-server-license-terms"?: boolean
"connection-token"?: string
help: boolean
port?: string
version: boolean
"without-connection-token"?: boolean
"without-browser-env-var"?: boolean
compatibility: string
}
/**
* Types for ../../lib/vscode/src/vs/server/node/server.main.ts:65.
*/
export type SpawnCodeCli = (args: CodeArgs) => Promise<void>
/**
* Convert our arguments to VS Code server arguments.
*/
export const toCodeArgs = async (args: DefaultedArgs): Promise<CodeArgs> => {
export const toVsCodeArgs = async (args: DefaultedArgs): Promise<CodeServerLib.ServerParsedArgs> => {
return {
"connection-token": "0000",
...args,
"accept-server-license-terms": true,
// This seems to be used to make the connection token flags optional (when
// set to 1.63) but we have always included them.
compatibility: "1.64",
/** Type casting. */
help: !!args.help,
version: !!args.version,

View File

@@ -16,14 +16,14 @@ export function getPackageJson(relativePath: string): JSONSchemaForNPMPackageJso
return pkg
}
export const rootPath = path.resolve(__dirname, "../..")
export const vsRootPath = path.join(rootPath, "lib/vscode")
const PACKAGE_JSON = "package.json"
const pkg = getPackageJson(`${rootPath}/${PACKAGE_JSON}`)
const codePkg = getPackageJson(`${vsRootPath}/${PACKAGE_JSON}`) || { version: "0.0.0" }
const pkg = getPackageJson("../../package.json")
const codePkg = getPackageJson("../../vendor/modules/code-oss-dev/package.json")
export const pkgName = pkg.name || "code-server"
export const version = pkg.version || "development"
export const commit = pkg.commit || "development"
export const rootPath = path.resolve(__dirname, "../..")
export const vsRootPath = path.join(rootPath, "vendor/modules/code-oss-dev")
export const codeVersion = codePkg.version || "development"
export const tmpdir = path.join(os.tmpdir(), "code-server")
export const isDevMode = commit === "development"

View File

@@ -1,7 +1,7 @@
import { logger } from "@coder/logger"
import { optionDescriptions, parse, readConfigFile, setDefaults, shouldOpenInExistingInstance } from "./cli"
import { getVersionString, getVersionJsonString } from "./constants"
import { openInExistingInstance, runCodeServer, runCodeCli, shouldSpawnCliProcess } from "./main"
import { openInExistingInstance, runCodeServer, runVsCodeCli, shouldSpawnCliProcess } from "./main"
import { isChild, wrapper } from "./wrapper"
async function entry(): Promise<void> {
@@ -48,7 +48,7 @@ async function entry(): Promise<void> {
if (shouldSpawnCliProcess(args)) {
logger.debug("Found VS Code arguments; spawning VS Code CLI")
return runCodeCli(args)
return runVsCodeCli(args)
}
const socketPath = await shouldOpenInExistingInstance(cliArgs)

View File

@@ -5,7 +5,7 @@ import path from "path"
import { Disposable } from "../common/emitter"
import { plural } from "../common/util"
import { createApp, ensureAddress } from "./app"
import { AuthType, DefaultedArgs, Feature, SpawnCodeCli, toCodeArgs, UserProvidedArgs } from "./cli"
import { AuthType, DefaultedArgs, Feature, toVsCodeArgs, UserProvidedArgs } from "./cli"
import { coderCloudBind } from "./coder_cloud"
import { commit, version } from "./constants"
import { register } from "./routes"
@@ -24,46 +24,27 @@ export const shouldSpawnCliProcess = (args: UserProvidedArgs): boolean => {
}
/**
* This is copy of OpenCommandPipeArgs from
* ../../lib/vscode/src/vs/workbench/api/node/extHostCLIServer.ts:15
*
* Arguments supported by Code's socket. It can be used to perform actions from
* the CLI in a running instance of Code (for example to open a file).
*
* TODO: Can we import this (and other types) directly?
* This is useful when an CLI arg should be passed to VS Code directly,
* such as when managing extensions.
* @deprecated This should be removed when code-server merges with lib/vscode.
*/
export interface OpenCommandPipeArgs {
type: "open"
fileURIs?: string[]
folderURIs: string[]
forceNewWindow?: boolean
diffMode?: boolean
addMode?: boolean
gotoLineMode?: boolean
forceReuseWindow?: boolean
waitMarkerFilePath?: string
}
export const runVsCodeCli = async (args: DefaultedArgs): Promise<void> => {
logger.debug("Running VS Code CLI")
/**
* Run Code's CLI for things like managing extensions.
*/
export const runCodeCli = async (args: DefaultedArgs): Promise<void> => {
logger.debug("Running Code CLI")
// See ../../lib/vscode/src/vs/server/node/server.main.ts:65.
const spawnCli = await loadAMDModule<SpawnCodeCli>("vs/server/node/server.main", "spawnCli")
// See ../../vendor/modules/code-oss-dev/src/vs/server/main.js.
const spawnCli = await loadAMDModule<CodeServerLib.SpawnCli>("vs/server/remoteExtensionHostAgent", "spawnCli")
try {
await spawnCli(await toCodeArgs(args))
await spawnCli(await toVsCodeArgs(args))
} catch (error: any) {
logger.error("Got error from Code", error)
logger.error("Got error from VS Code", error)
}
process.exit(0)
}
export const openInExistingInstance = async (args: DefaultedArgs, socketPath: string): Promise<void> => {
const pipeArgs: OpenCommandPipeArgs & { fileURIs: string[] } = {
const pipeArgs: CodeServerLib.OpenCommandPipeArgs & { fileURIs: string[] } = {
type: "open",
folderURIs: [],
fileURIs: [],
@@ -95,12 +76,12 @@ export const openInExistingInstance = async (args: DefaultedArgs, socketPath: st
},
(response) => {
response.on("data", (message) => {
logger.debug("got message from Code", field("message", message.toString()))
logger.debug("got message from VS Code", field("message", message.toString()))
})
},
)
vscode.on("error", (error: unknown) => {
logger.error("got error from Code", field("error", error))
logger.error("got error from VS Code", field("error", error))
})
vscode.write(JSON.stringify(pipeArgs))
vscode.end()

View File

@@ -129,14 +129,6 @@ export const register = async (app: App, args: DefaultedArgs): Promise<Disposabl
express.static(rootPath, {
cacheControl: commit !== "development",
fallthrough: false,
setHeaders: (res, path, stat) => {
// The service worker is served from a sub-path on the static route so
// this is required to allow it to register a higher scope (by default
// the browser only allows it to register from its own path or lower).
if (path.endsWith("/serviceWorker.js")) {
res.setHeader("Service-Worker-Allowed", "/")
}
},
}),
)

View File

@@ -1,34 +1,19 @@
import { logger } from "@coder/logger"
import * as express from "express"
import * as http from "http"
import * as net from "net"
import * as path from "path"
import { WebsocketRequest } from "../../../typings/pluginapi"
import { logError } from "../../common/util"
import { CodeArgs, toCodeArgs } from "../cli"
import { toVsCodeArgs } from "../cli"
import { isDevMode } from "../constants"
import { authenticated, ensureAuthenticated, redirect, replaceTemplates, self } from "../http"
import { authenticated, ensureAuthenticated, redirect, self } from "../http"
import { SocketProxyProvider } from "../socket"
import { isFile, loadAMDModule } from "../util"
import { Router as WsRouter } from "../wsRouter"
/**
* This is the API of Code's web client server. code-server delegates requests
* to Code here.
*/
export interface IServerAPI {
handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>
handleUpgrade(req: http.IncomingMessage, socket: net.Socket): void
handleServerError(err: Error): void
dispose(): void
}
// Types for ../../../lib/vscode/src/vs/server/node/server.main.ts:72.
export type CreateServer = (address: string | net.AddressInfo | null, args: CodeArgs) => Promise<IServerAPI>
import { errorHandler } from "./errors"
export class CodeServerRouteWrapper {
/** Assigned in `ensureCodeServerLoaded` */
private _codeServerMain!: IServerAPI
private _codeServerMain!: CodeServerLib.IServerAPI
private _wsRouterWrapper = WsRouter()
private _socketProxyProvider = new SocketProxyProvider()
public router = express.Router()
@@ -39,32 +24,6 @@ export class CodeServerRouteWrapper {
//#region Route Handlers
private manifest: express.Handler = async (req, res, next) => {
res.writeHead(200, { "Content-Type": "application/manifest+json" })
return res.end(
replaceTemplates(
req,
JSON.stringify(
{
name: "code-server",
short_name: "code-server",
start_url: ".",
display: "fullscreen",
description: "Run Code on a remote server.",
icons: [192, 512].map((size) => ({
src: `{{BASE}}/_static/src/browser/media/pwa-icon-${size}.png`,
type: "image/png",
sizes: `${size}x${size}`,
})),
},
null,
2,
),
),
)
}
private $root: express.Handler = async (req, res, next) => {
const isAuthenticated = await authenticated(req)
const NO_FOLDER_OR_WORKSPACE_QUERY = !req.query.folder && !req.query.workspace
@@ -122,6 +81,17 @@ export class CodeServerRouteWrapper {
}
private $proxyRequest: express.Handler = async (req, res, next) => {
// We allow certain errors to propagate so that other routers may handle requests
// outside VS Code
const requestErrorHandler = (error: any) => {
if (error instanceof Error && ["EntryNotFound", "FileNotFound", "HttpError"].includes(error.message)) {
next()
}
errorHandler(error, req, res, next)
}
req.once("error", requestErrorHandler)
this._codeServerMain.handleRequest(req, res)
}
@@ -147,14 +117,18 @@ export class CodeServerRouteWrapper {
const { args } = req
// See ../../../lib/vscode/src/vs/server/node/server.main.ts:72.
const createVSServer = await loadAMDModule<CreateServer>("vs/server/node/server.main", "createServer")
/**
* @file ../../../vendor/modules/code-oss-dev/src/vs/server/main.js
*/
const createVSServer = await loadAMDModule<CodeServerLib.CreateServer>(
"vs/server/remoteExtensionHostAgent",
"createServer",
)
try {
this._codeServerMain = await createVSServer(null, {
...(await toCodeArgs(args)),
...(await toVsCodeArgs(args)),
// TODO: Make the browser helper script work.
"without-connection-token": true,
"without-browser-env-var": true,
})
} catch (error) {
@@ -170,7 +144,6 @@ export class CodeServerRouteWrapper {
constructor() {
this.router.get("/", this.ensureCodeServerLoaded, this.$root)
this.router.get(/manifest.json$/, this.manifest)
this.router.all("*", ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyRequest)
this._wsRouterWrapper.ws("/", ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyWebsocket)
}

View File

@@ -55,6 +55,10 @@ describe("code-server", true, [], {}, () => {
expect(await codeServerPage.isEditorVisible()).toBe(true)
})
test("should always have a connection", async ({ codeServerPage }) => {
expect(await codeServerPage.isConnected()).toBe(true)
})
test("should show the Integrated Terminal", async ({ codeServerPage }) => {
await codeServerPage.focusTerminal()
expect(await codeServerPage.page.isVisible("#terminal")).toBe(true)

View File

@@ -20,14 +20,14 @@ class Context {
public canceled(): boolean {
return this._canceled
}
public finished(): boolean {
return this._done
public done(): void {
this._done = true
}
public cancel(): void {
this._canceled = true
}
public finish(): void {
this._done = true
public finish(): boolean {
return this._done
}
}
@@ -43,7 +43,7 @@ export class CodeServer {
name: string,
private readonly args: string[],
private readonly env: NodeJS.ProcessEnv,
private _workspaceDir: Promise<string> | string | undefined,
private readonly _workspaceDir: Promise<string> | string | undefined,
private readonly entry = process.env.CODE_SERVER_TEST_ENTRY || ".",
) {
this.logger = logger.named(name)
@@ -64,7 +64,7 @@ export class CodeServer {
/**
* The workspace directory code-server opens with.
*/
get workspaceDir(): Promise<string> | string {
get workspaceDir(): Promise<string> {
if (!this._workspaceDir) {
this._workspaceDir = tmpdir(workspaceDir)
}
@@ -198,7 +198,7 @@ export class CodeServerPage {
private readonly authenticated: boolean,
) {
this.page.on("console", (message) => {
this.codeServer.logger.debug(message.text())
this.codeServer.logger.debug(message)
})
this.page.on("pageerror", (error) => {
logError(this.codeServer.logger, "page", error)
@@ -241,13 +241,14 @@ export class CodeServerPage {
this.codeServer.logger.debug("Waiting for editor to be ready...")
const editorIsVisible = await this.isEditorVisible()
const editorIsConnected = await this.isConnected()
let reloadCount = 0
// Occassionally code-server timeouts in Firefox
// we're not sure why
// but usually a reload or two fixes it
// TODO@jsjoeio @oxy look into Firefox reconnection/timeout issues
while (!editorIsVisible) {
while (!editorIsVisible && !editorIsConnected) {
// When a reload happens, we want to wait for all resources to be
// loaded completely. Hence why we use that instead of DOMContentLoaded
// Read more: https://thisthat.dev/dom-content-loaded-vs-load/
@@ -255,7 +256,7 @@ export class CodeServerPage {
// Give it an extra second just in case it's feeling extra slow
await this.page.waitForTimeout(1000)
reloadCount += 1
if (await this.isEditorVisible()) {
if ((await this.isEditorVisible()) && (await this.isConnected())) {
this.codeServer.logger.debug(`editor became ready after ${reloadCount} reloads`)
break
}
@@ -279,6 +280,23 @@ export class CodeServerPage {
return visible
}
/**
* Checks if the editor is visible
*/
async isConnected() {
this.codeServer.logger.debug("Waiting for network idle...")
await this.page.waitForLoadState("networkidle")
const host = new URL(await this.codeServer.address()).host
// NOTE: This seems to be pretty brittle between version changes.
const hostSelector = `[aria-label="remote ${host}"]`
this.codeServer.logger.debug(`Waiting selector: ${hostSelector}`)
await this.page.waitForSelector(hostSelector)
return await this.page.isVisible(hostSelector)
}
/**
* Focuses Integrated Terminal
* by using "Terminal: Focus Terminal"
@@ -308,13 +326,13 @@ export class CodeServerPage {
* Wait for a tab to open for the specified file.
*/
async waitForTab(file: string): Promise<void> {
await this.page.waitForSelector(`.tab :text("${path.basename(file)}")`)
return this.page.waitForSelector(`.tab :text("${path.basename(file)}")`)
}
/**
* See if the specified tab is open.
*/
async tabIsVisible(file: string): Promise<boolean> {
async tabIsVisible(file: string): Promise<void> {
return this.page.isVisible(`.tab :text("${path.basename(file)}")`)
}
@@ -350,8 +368,8 @@ export class CodeServerPage {
try {
await this.page.waitForSelector(`${selector}:not(:focus-within)`)
} catch (error) {
if (!ctx.finished()) {
this.codeServer.logger.debug(`${selector} navigation: ${(error as any).message || error}`)
if (!ctx.done()) {
this.codeServer.logger.debug(`${selector} navigation: ${error.message || error}`)
}
}
return false
@@ -405,7 +423,7 @@ export class CodeServerPage {
return false
}
} catch (error) {
logger.debug(`navigation: ${(error as any).message || error}`)
logger.debug(`navigation: ${error.message || error}`)
return false
}
}
@@ -418,7 +436,7 @@ export class CodeServerPage {
// time we lose focus or there is an error.
let attempts = 1
let context = new Context()
while (!(await Promise.race([openThenWaitClose(context), navigate(context)]))) {
while (!(await Promise.race([openThenWaitClose(), navigate(context)]))) {
++attempts
logger.debug("closed, retrying (${attempt}/∞)")
context.cancel()

View File

@@ -3,7 +3,7 @@ import { promises } from "fs"
import * as http from "http"
import * as https from "https"
import * as path from "path"
import { createApp, ensureAddress, handleArgsSocketCatchError, handleServerError, listen } from "../../../src/node/app"
import { createApp, ensureAddress, handleArgsSocketCatchError, handleServerError } from "../../../src/node/app"
import { OptionalString, setDefaults } from "../../../src/node/cli"
import { generateCertificate } from "../../../src/node/util"
import { clean, mockLogger, getAvailablePort, tmpdir } from "../../utils/helpers"
@@ -201,33 +201,31 @@ describe("handleArgsSocketCatchError", () => {
})
it("should log an error if its not an NodeJS.ErrnoException", () => {
const message = "other message"
const error = new Error(message)
const error = new Error()
expect(() => {
handleArgsSocketCatchError(error)
}).toThrowError(error)
handleArgsSocketCatchError(error)
expect(logger.error).toHaveBeenCalledTimes(1)
expect(logger.error).toHaveBeenCalledWith(error)
})
it("should log an error if its not an NodeJS.ErrnoException (and the error has a message)", () => {
const errorMessage = "handleArgsSocketCatchError Error"
const error = new Error(errorMessage)
expect(() => {
handleArgsSocketCatchError(error)
}).toThrowError(error)
handleArgsSocketCatchError(error)
expect(logger.error).toHaveBeenCalledTimes(1)
expect(logger.error).toHaveBeenCalledWith(errorMessage)
})
it("should not log an error if its a NodeJS.ErrnoException", () => {
const code = "ENOENT"
const error: NodeJS.ErrnoException = new Error(code)
error.code = code
it("should not log an error if its a iNodeJS.ErrnoException", () => {
const error: NodeJS.ErrnoException = new Error()
error.code = "ENOENT"
handleArgsSocketCatchError(error)
expect(() => {
handleArgsSocketCatchError(error)
}).not.toThrowError()
expect(logger.error).toHaveBeenCalledTimes(0)
})
it("should log an error if the code is not ENOENT (and the error has a message)", () => {
@@ -236,50 +234,19 @@ describe("handleArgsSocketCatchError", () => {
error.code = "EACCESS"
error.message = errorMessage
expect(() => {
handleArgsSocketCatchError(error)
}).toThrowError(error)
handleArgsSocketCatchError(error)
expect(logger.error).toHaveBeenCalledTimes(1)
expect(logger.error).toHaveBeenCalledWith(errorMessage)
})
it("should log an error if the code is not ENOENT", () => {
const code = "EACCESS"
const error: NodeJS.ErrnoException = new Error(code)
error.code = code
const error: NodeJS.ErrnoException = new Error()
error.code = "EACCESS"
expect(() => {
handleArgsSocketCatchError(error)
}).toThrowError(error)
})
})
describe("listen", () => {
let tmpDirPath: string
let mockServer: http.Server
const testName = "listen"
beforeEach(async () => {
await clean(testName)
mockLogger()
tmpDirPath = await tmpdir(testName)
mockServer = http.createServer()
})
afterEach(() => {
mockServer.close()
jest.clearAllMocks()
})
it("should throw an error if a directory is passed in instead of a file", async () => {
const errorMessage = "EISDIR: illegal operation on a directory, unlink"
const port = await getAvailablePort()
const mockArgs = { port, host: "0.0.0.0", socket: tmpDirPath }
try {
await listen(mockServer, mockArgs)
} catch (error) {
expect(error).toBeInstanceOf(Error)
expect((error as any).message).toMatch(errorMessage)
}
handleArgsSocketCatchError(error)
expect(logger.error).toHaveBeenCalledTimes(1)
expect(logger.error).toHaveBeenCalledWith(error)
})
})

View File

@@ -12,12 +12,7 @@ import {
setDefaults,
shouldOpenInExistingInstance,
splitOnFirstEquals,
toCodeArgs,
optionDescriptions,
options,
Options,
AuthType,
OptionalString,
toVsCodeArgs,
} from "../../../src/node/cli"
import { shouldSpawnCliProcess } from "../../../src/node/main"
import { generatePassword, paths } from "../../../src/node/util"
@@ -199,15 +194,6 @@ describe("parser", () => {
expect(logger.level).toEqual(Level.Trace)
})
it("should set valid log level env var", async () => {
process.env.LOG_LEVEL = "error"
const defaults = await setDefaults(parse([]))
expect(defaults).toEqual({
...defaults,
log: "error",
})
})
it("should ignore invalid log level env var", async () => {
process.env.LOG_LEVEL = "bogus"
const defaults = await setDefaults(parse([]))
@@ -727,11 +713,11 @@ describe("readSocketPath", () => {
})
})
describe("toCodeArgs", () => {
describe("toVsCodeArgs", () => {
const vscodeDefaults = {
...defaults,
"connection-token": "0000",
"accept-server-license-terms": true,
compatibility: "1.64",
help: false,
port: "8080",
version: false,
@@ -744,7 +730,7 @@ describe("toCodeArgs", () => {
})
it("should convert empty args", async () => {
expect(await toCodeArgs(await setDefaults(parse([])))).toStrictEqual({
expect(await toVsCodeArgs(await setDefaults(parse([])))).toStrictEqual({
...vscodeDefaults,
})
})
@@ -752,103 +738,9 @@ describe("toCodeArgs", () => {
it("should ignore regular file", async () => {
const file = path.join(await tmpdir(testName), "file")
await fs.writeFile(file, "foobar")
expect(await toCodeArgs(await setDefaults(parse([file])))).toStrictEqual({
expect(await toVsCodeArgs(await setDefaults(parse([file])))).toStrictEqual({
...vscodeDefaults,
_: [file],
})
})
})
describe("optionDescriptions", () => {
it("should return the descriptions of all the available options", () => {
const expectedOptionDescriptions = Object.entries(options)
.flat()
.filter((item: any) => {
if (item.description) {
return item.description
}
})
.map((item: any) => item.description)
const actualOptionDescriptions = optionDescriptions()
// We need both the expected and the actual
// Both of these are string[]
// We then loop through the expectedOptionDescriptions
// and check that this expectedDescription exists in the
// actualOptionDescriptions
// To do that we need to loop through actualOptionDescriptions
// and make sure we have a substring match
expectedOptionDescriptions.forEach((expectedDescription) => {
const exists = actualOptionDescriptions.find((desc) => {
if (
desc.replace(/\n/g, " ").replace(/ /g, "").includes(expectedDescription.replace(/\n/g, " ").replace(/ /g, ""))
) {
return true
}
return false
})
expect(exists).toBeTruthy()
})
})
it("should visually align multiple options", () => {
const opts: Partial<Options<Required<UserProvidedArgs>>> = {
"cert-key": { type: "string", path: true, description: "Path to certificate key when using non-generated cert." },
"cert-host": {
type: "string",
description: "Hostname to use when generating a self signed certificate.",
},
"disable-update-check": {
type: "boolean",
description:
"Disable update check. Without this flag, code-server checks every 6 hours against the latest github release and \n" +
"then notifies you once every week that a new release is available.",
},
}
expect(optionDescriptions(opts)).toStrictEqual([
" --cert-key Path to certificate key when using non-generated cert.",
" --cert-host Hostname to use when generating a self signed certificate.",
` --disable-update-check Disable update check. Without this flag, code-server checks every 6 hours against the latest github release and
then notifies you once every week that a new release is available.`,
])
})
it("should add all valid options for enumerated types", () => {
const opts: Partial<Options<Required<UserProvidedArgs>>> = {
auth: { type: AuthType, description: "The type of authentication to use." },
}
expect(optionDescriptions(opts)).toStrictEqual([" --auth The type of authentication to use. [password, none]"])
})
it("should show if an option is deprecated", () => {
const opts: Partial<Options<Required<UserProvidedArgs>>> = {
link: {
type: OptionalString,
description: `
Securely bind code-server via our cloud service with the passed name. You'll get a URL like
https://hostname-username.coder.co at which you can easily access your code-server instance.
Authorization is done via GitHub.
`,
deprecated: true,
},
}
expect(optionDescriptions(opts)).toStrictEqual([
` --link (deprecated) Securely bind code-server via our cloud service with the passed name. You'll get a URL like
https://hostname-username.coder.co at which you can easily access your code-server instance.
Authorization is done via GitHub.`,
])
})
it("should show newlines in description", () => {
const opts: Partial<Options<Required<UserProvidedArgs>>> = {
"install-extension": {
type: "string[]",
description:
"Install or update a VS Code extension by id or vsix. The identifier of an extension is `${publisher}.${name}`.\n" +
"To install a specific version provide `@${version}`. For example: 'vscode.csharp@1.2.3'.",
},
}
expect(optionDescriptions(opts)).toStrictEqual([
` --install-extension Install or update a VS Code extension by id or vsix. The identifier of an extension is \`\${publisher}.\${name}\`.
To install a specific version provide \`@\${version}\`. For example: 'vscode.csharp@1.2.3'.`,
])
})
})

View File

@@ -1,7 +1,6 @@
import { logger } from "@coder/logger"
import path from "path"
import * as semver from "semver"
import { mockLogger } from "../../utils/helpers"
import * as semver from "semver"
describe("constants", () => {
let constants: typeof import("../../../src/node/constants")
@@ -16,21 +15,19 @@ describe("constants", () => {
}
const mockCodePackageJson = {
name: "mock-vscode",
name: "mock-code-oss-dev",
version: "1.2.3",
}
beforeAll(() => {
jest.clearAllMocks()
mockLogger()
jest.mock(path.resolve(__dirname, "../../../package.json"), () => mockPackageJson, { virtual: true })
jest.mock(path.resolve(__dirname, "../../../lib/vscode/package.json"), () => mockCodePackageJson, {
virtual: true,
})
jest.mock("../../../package.json", () => mockPackageJson, { virtual: true })
jest.mock("../../../vendor/modules/code-oss-dev/package.json", () => mockCodePackageJson, { virtual: true })
constants = require("../../../src/node/constants")
})
afterAll(() => {
jest.clearAllMocks()
jest.resetModules()
})
@@ -94,7 +91,7 @@ describe("constants", () => {
const packageJson = constants.getPackageJson("../../package.json")
expect(packageJson).toStrictEqual(mockPackageJson)
const codePackageJson = constants.getPackageJson("../../lib/vscode/package.json")
const codePackageJson = constants.getPackageJson("../../vendor/modules/code-oss-dev/package.json")
expect(codePackageJson).toStrictEqual(mockCodePackageJson)
})
})
@@ -105,19 +102,17 @@ describe("constants", () => {
name: "mock-code-server",
}
const mockCodePackageJson = {
name: "mock-vscode",
name: "mock-code-oss-dev",
}
beforeAll(() => {
jest.clearAllMocks()
jest.mock(path.resolve(__dirname, "../../../package.json"), () => mockPackageJson, { virtual: true })
jest.mock(path.resolve(__dirname, "../../../lib/vscode/package.json"), () => mockCodePackageJson, {
virtual: true,
})
jest.mock("../../../package.json", () => mockPackageJson, { virtual: true })
jest.mock("../../../vendor/modules/code-oss-dev/package.json", () => mockCodePackageJson, { virtual: true })
constants = require("../../../src/node/constants")
})
afterAll(() => {
jest.clearAllMocks()
jest.resetModules()
})

View File

@@ -103,7 +103,7 @@ describe("vscode", () => {
it("should do nothing when nothing is passed in", async () => {
codeServer = await integration.setup(["--auth=none"], "")
const resp = await codeServer.fetch("/", undefined)
let resp = await codeServer.fetch("/", undefined)
expect(resp.status).toBe(200)
const url = new URL(resp.url)

View File

@@ -20,7 +20,7 @@
"./node_modules/@types",
"./typings",
"./test/node_modules/@types",
"./lib/vscode/src/vs/server/@types"
"./vendor/modules/code-oss-dev/src/vs/server/@types"
],
"downlevelIteration": true
},

12
vendor/package.json vendored Normal file
View File

@@ -0,0 +1,12 @@
{
"name": "vendor",
"version": "1.0.0",
"license": "MIT",
"private": true,
"scripts": {
"postinstall": "./postinstall.sh"
},
"devDependencies": {
"code-oss-dev": "coder/vscode#94384412221f432c15bb679315c49964925090be"
}
}

10
vendor/postinstall.sh vendored Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
echo 'Installing VS Code dependencies...'
cd modules/code-oss-dev
yarn install --frozen-lockfile
}
main "$@"

1494
vendor/yarn.lock vendored Normal file

File diff suppressed because it is too large Load Diff

185
yarn.lock
View File

@@ -751,6 +751,15 @@ array.prototype.flat@^1.2.4:
define-properties "^1.1.3"
es-abstract "^1.18.0-next.1"
array.prototype.flatmap@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446"
integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==
dependencies:
call-bind "^1.0.0"
define-properties "^1.1.3"
es-abstract "^1.19.0"
arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
@@ -768,19 +777,20 @@ astral-regex@^2.0.0:
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
audit-ci@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/audit-ci/-/audit-ci-6.0.0.tgz#78b71ac2aa754218b16e224ef3aa649cfe3063f8"
integrity sha512-ZoJxM4FQvaWdabQvqA44PTg64Bm/a8B9dnL/ft33lygoQuKh+Oa0hwdc/VLsq/zrhNCC12uSUnnfYvgxgZLurw==
audit-ci@^5.0.0:
version "5.1.2"
resolved "https://registry.yarnpkg.com/audit-ci/-/audit-ci-5.1.2.tgz#2e9a6c23c8511d8f79f6fde18d042ebc1bdec881"
integrity sha512-FNBbo4ycoHxcS7ruNNkq3LB+fZ4UWDd0QUNAva7Ae/F/Y45BBA7ZfHPSr5Fr+tS2+eqSwxToeFRRnw2Tp2PE8Q==
dependencies:
JSONStream "^1.3.5"
array.prototype.flatmap "^1.2.5"
cross-spawn "^7.0.3"
escape-string-regexp "^4.0.0"
event-stream "4.0.1"
jju "^1.4.0"
readline-transform "1.0.0"
semver "^7.0.0"
yargs "^17.0.0"
yargs "^16.0.0"
autoprefixer@^9.8.6:
version "9.8.6"
@@ -1431,6 +1441,32 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2:
string.prototype.trimstart "^1.0.4"
unbox-primitive "^1.0.0"
es-abstract@^1.19.0:
version "1.19.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3"
integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==
dependencies:
call-bind "^1.0.2"
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
get-intrinsic "^1.1.1"
get-symbol-description "^1.0.0"
has "^1.0.3"
has-symbols "^1.0.2"
internal-slot "^1.0.3"
is-callable "^1.2.4"
is-negative-zero "^2.0.1"
is-regex "^1.1.4"
is-shared-array-buffer "^1.0.1"
is-string "^1.0.7"
is-weakref "^1.0.1"
object-inspect "^1.11.0"
object-keys "^1.1.1"
object.assign "^4.1.2"
string.prototype.trimend "^1.0.4"
string.prototype.trimstart "^1.0.4"
unbox-primitive "^1.0.1"
es-to-primitive@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
@@ -1942,7 +1978,7 @@ get-caller-file@^2.0.5:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.0.2, get-intrinsic@^1.1.1:
get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
@@ -1956,6 +1992,14 @@ get-stdin@^8.0.0:
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53"
integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==
get-symbol-description@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
dependencies:
call-bind "^1.0.2"
get-intrinsic "^1.1.1"
get-uri@3:
version "3.0.2"
resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c"
@@ -2098,6 +2142,13 @@ has-symbols@^1.0.1, has-symbols@^1.0.2:
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
has-tostringtag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
dependencies:
has-symbols "^1.0.2"
has-unicode@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -2110,12 +2161,12 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
hosted-git-info@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-5.0.0.tgz#df7a06678b4ebd722139786303db80fdf302ea56"
integrity sha512-rRnjWu0Bxj+nIfUOkz0695C0H6tRrN5iYIzYejb0tDEefe2AekHu/U5Kn9pEie5vsJqpNQU02az7TGSH3qpz4Q==
hosted-git-info@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.0.tgz#9f06639a90beff66cacae6e77f8387b431d61ddc"
integrity sha512-fqhGdjk4av7mT9fU/B01dUtZ+WZSc/XEXMoLXDVZukiQRXxeHSSz3AqbeWRJHtF8EQYHlAgB1NSAHU0Cm7aqZA==
dependencies:
lru-cache "^7.5.1"
lru-cache "^6.0.0"
html-tags@^3.1.0:
version "3.1.0"
@@ -2278,6 +2329,15 @@ ini@^1.3.5:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
internal-slot@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
dependencies:
get-intrinsic "^1.1.0"
has "^1.0.3"
side-channel "^1.0.4"
ip@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
@@ -2333,6 +2393,11 @@ is-callable@^1.1.4, is-callable@^1.2.3:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e"
integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==
is-callable@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
is-core-module@^2.2.0, is-core-module@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1"
@@ -2340,13 +2405,6 @@ is-core-module@^2.2.0, is-core-module@^2.4.0:
dependencies:
has "^1.0.3"
is-core-module@^2.8.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
dependencies:
has "^1.0.3"
is-date-object@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
@@ -2419,16 +2477,36 @@ is-regex@^1.1.2:
call-bind "^1.0.2"
has-symbols "^1.0.1"
is-regex@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
dependencies:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
is-regexp@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d"
integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==
is-shared-array-buffer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6"
integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==
is-string@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
is-string@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
dependencies:
has-tostringtag "^1.0.0"
is-symbol@^1.0.2, is-symbol@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
@@ -2446,6 +2524,13 @@ is-unicode-supported@^0.1.0:
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
is-weakref@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2"
integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==
dependencies:
call-bind "^1.0.0"
is-whitespace-character@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7"
@@ -2655,11 +2740,6 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
lru-cache@^7.5.1:
version "7.5.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.5.1.tgz#660a134c2c3c015aa453b03df55d2a9f0c216a0f"
integrity sha512-q1TS8IqKvcg3aScamKCHpepSrHF537Ww7nHahBOxhDu9D2YoBXAsj/7uFdZFj1xJr9LmyeJ62AdyofCHafUbIA==
make-dir@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@@ -2826,10 +2906,10 @@ minimist-options@4.1.0:
is-plain-obj "^1.1.0"
kind-of "^6.0.3"
minimist@^1.2.0, minimist@^1.2.5, "minimist@npm:minimist-lite@2.2.0", minimist@~1.2.5:
version "2.2.0"
resolved "https://registry.yarnpkg.com/minimist-lite/-/minimist-lite-2.2.0.tgz#43992acac6bb17e78acb6eee784d1da2f7cc3216"
integrity sha512-o9M0Iz5ELqCT4NzeaZHBBlV4+ruOGGWV6lVxFoghC6Wvp4W6ECbBBpmDRHdk72O/sMh3QT0c/0XDKhtGlztRZw==
minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
minipass@^3.0.0:
version "3.1.3"
@@ -2920,15 +3000,15 @@ nopt@^5.0.0:
dependencies:
abbrev "1"
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0, normalize-package-data@^3.0.0, normalize-package-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-4.0.0.tgz#1122d5359af21d4cd08718b92b058a658594177c"
integrity sha512-m+GL22VXJKkKbw62ZaBBjv8u6IE3UI4Mh5QakIqs3fWiKe0Xyi6L97hakwZK41/LD4R/2ly71Bayx0NLMwLA/g==
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0, normalize-package-data@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.1.tgz#98dc56dfe6755d99b1c53f046e1e3d2dde55a1c7"
integrity sha512-D/ttLdxo71msR4FF3VgSwK4blHfE3/vGByz1NCeE7/Dh8reQOKNJJjk5L10mLq9jxa+ZHzT1/HLgxljzbXE7Fw==
dependencies:
hosted-git-info "^5.0.0"
is-core-module "^2.8.1"
semver "^7.3.5"
validate-npm-package-license "^3.0.4"
hosted-git-info "^4.0.0"
resolve "^1.17.0"
semver "^7.3.2"
validate-npm-package-license "^3.0.1"
normalize-range@^0.1.2:
version "0.1.2"
@@ -2960,6 +3040,11 @@ object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-inspect@^1.11.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1"
integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==
object-inspect@^1.9.0:
version "1.10.2"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.2.tgz#b6385a3e2b7cae0b5eafcf90cddf85d128767f30"
@@ -3603,7 +3688,7 @@ resolve-from@^5.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
resolve@^1.13.1, resolve@^1.20.0:
resolve@^1.13.1, resolve@^1.17.0, resolve@^1.20.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
@@ -3670,7 +3755,7 @@ semver@^6.0.0, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.0.0, semver@^7.1.3, semver@^7.2.1, semver@^7.3.5:
semver@^7.0.0, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
@@ -4262,7 +4347,7 @@ typescript@^4.4.0-dev.20210528:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.2.tgz#6d618640d430e3569a1dfb44f7d7e600ced3ee86"
integrity sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==
unbox-primitive@^1.0.0:
unbox-primitive@^1.0.0, unbox-primitive@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"
integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==
@@ -4408,7 +4493,7 @@ v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0:
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
validate-npm-package-license@^3.0.4:
validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
@@ -4581,28 +4666,28 @@ yaml@^1.10.0:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"
integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==
yargs-parser@^20.2.2:
version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
yargs-parser@^20.2.3:
version "20.2.7"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a"
integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==
yargs-parser@^21.0.0:
version "21.0.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35"
integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==
yargs@^17.0.0:
version "17.3.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9"
integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==
yargs@^16.0.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
dependencies:
cliui "^7.0.2"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
string-width "^4.2.0"
y18n "^5.0.5"
yargs-parser "^21.0.0"
yargs-parser "^20.2.2"
yarn@^1.22.4:
version "1.22.11"