Compare commits
2 Commits
main
...
3835-lib-p
Author | SHA1 | Date |
---|---|---|
Teffen Ellis | cd28362fb7 | |
Teffen Ellis | 2504f6fce4 |
|
@ -3,4 +3,9 @@ root = true
|
|||
[*]
|
||||
indent_style = space
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# The indent size used in the `package.json` file cannot be changed
|
||||
# https://github.com/npm/npm/pull/3180#issuecomment-16336516
|
||||
[{*.yml,*.yaml,package.json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
|
|
@ -36,8 +36,11 @@ rules:
|
|||
import/order:
|
||||
[error, { alphabetize: { order: "asc" }, groups: [["builtin", "external", "internal"], "parent", "sibling"] }]
|
||||
no-async-promise-executor: off
|
||||
# This isn't a real module, just types, which apparently doesn't resolve.
|
||||
import/no-unresolved: [error, { ignore: ["express-serve-static-core"] }]
|
||||
|
||||
settings:
|
||||
import/resolver:
|
||||
typescript:
|
||||
alwaysTryTypes: true
|
||||
# Does not work with CommonJS unfortunately.
|
||||
import/ignore:
|
||||
- env-paths
|
||||
- xdg-basedir
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
* @coder/code-server-reviewers
|
||||
* @cdr/code-server-reviewers
|
||||
|
||||
ci/helm-chart/ @Matthew-Beckett @alexgorbatchev
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Report a bug and help us improve
|
||||
title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
Hi there! 👋
|
||||
|
||||
Thanks for reporting a bug.
|
||||
|
||||
Please search for existing issues before filing, as they may contain additional
|
||||
information about the problem and descriptions of workarounds. Provide as much
|
||||
information as you can, so that we can reproduce the issue. Otherwise, we may
|
||||
not be able to help diagnose the problem, and may close the issue as
|
||||
unreproducible or incomplete. For visual defects, please include screenshots to
|
||||
help us understand the issue.
|
||||
-->
|
||||
|
||||
## OS/Web Information
|
||||
|
||||
- Web Browser:
|
||||
- Local OS:
|
||||
- Remote OS:
|
||||
- Remote Architecture:
|
||||
- `code-server --version`:
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
## Expected
|
||||
|
||||
<!-- What should happen? -->
|
||||
|
||||
## Actual
|
||||
|
||||
<!-- What actually happens? -->
|
||||
|
||||
## Logs
|
||||
|
||||
<!--
|
||||
First run code-server with at least debug logging (or trace to be really
|
||||
thorough) by setting the --log flag or the LOG_LEVEL environment variable. -vvv
|
||||
and --verbose are aliases for --log trace. For example:
|
||||
|
||||
code-server --log debug
|
||||
|
||||
Once this is done, replicate the issue you're having then collect logging
|
||||
information from the following places:
|
||||
|
||||
1. The most recent files from ~/.local/share/code-server/coder-logs.
|
||||
2. The browser console.
|
||||
3. The browser network tab.
|
||||
|
||||
Additionally, collecting core dumps (you may need to enable them first) if
|
||||
code-server crashes can be helpful.
|
||||
-->
|
||||
|
||||
<!--
|
||||
If you're having issues with installation please include the installation logs
|
||||
i.e. the output of `yarn global add code-server` if you installed with `yarn`
|
||||
-->
|
||||
|
||||
## Screenshot
|
||||
|
||||
<!-- Ideally provide a screenshot, gif, video or screen recording. -->
|
||||
|
||||
## Notes
|
||||
|
||||
<!-- If you can reproduce the issue on vanilla VS Code,
|
||||
please file the issue at the VS Code repository instead. -->
|
||||
|
||||
This issue can be reproduced in VS Code: Yes/No
|
|
@ -1,86 +0,0 @@
|
|||
name: Bug report
|
||||
description: File a bug report
|
||||
title: "[Bug]: "
|
||||
labels: ["bug", "triage"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue already exists for the bug you encountered.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: OS/Web Information
|
||||
description: |
|
||||
examples:
|
||||
- **Web Browser**: Chrome
|
||||
- **Local OS**: macOS
|
||||
- **Remote OS**: Ubuntu
|
||||
- **Remote Architecture**: amd64
|
||||
- **`code-server --version`**: 4.0.1
|
||||
value: |
|
||||
- Web Browser:
|
||||
- Local OS:
|
||||
- Remote OS:
|
||||
- Remote Architecture:
|
||||
- `code-server --version`:
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: |
|
||||
1. open code-server
|
||||
2. install extension
|
||||
3. run command
|
||||
value: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected
|
||||
description: What should happen?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Actual
|
||||
description: What actually happens?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs
|
||||
description: Run code-server with the --verbose flag and then paste any relevant logs from the server, from the browser console and/or the browser network tab. For issues with installation, include installation logs (i.e. output of `yarn global add code-server`).
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshot/Video
|
||||
description: Please include a screenshot, gif or screen recording of your issue.
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Does this issue happen in VS Code?
|
||||
description: Please try reproducing this issue in VS Code
|
||||
options:
|
||||
- label: I cannot reproduce this in VS Code.
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Are you accessing code-server over HTTPS?
|
||||
description: code-server relies on service workers for many features. Double-check that you are using HTTPS.
|
||||
options:
|
||||
- label: I am using HTTPS.
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Notes
|
||||
description: Please include any addition notes that will help us resolve this issue.
|
||||
validations:
|
||||
required: false
|
|
@ -1,8 +1,8 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Question?
|
||||
url: https://github.com/coder/code-server/discussions/new?category_id=22503114
|
||||
- name: Question
|
||||
url: https://github.com/cdr/code-server/discussions/new?category_id=22503114
|
||||
about: Ask the community for help on our GitHub Discussions board
|
||||
- name: code-server Slack Community
|
||||
about: Need immediate help or just want to talk? Hop in our Slack. Note - this Slack is not actively monitored by code-server maintainers.
|
||||
- name: Chat
|
||||
about: Need immediate help or just want to talk? Hop in our Slack
|
||||
url: https://cdr.co/join-community
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
---
|
||||
name: Documentation improvement
|
||||
about: Suggest a documentation improvement
|
||||
title: "[Docs]: "
|
||||
title: ""
|
||||
labels: "docs"
|
||||
assignees: "@jsjoeio"
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
## What is your suggestion?
|
||||
|
||||
## How will this improve the docs?
|
||||
|
||||
## Are you interested in submitting a PR for this?
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
name: Extension request
|
||||
about: Request an extension missing from the code-server marketplace
|
||||
title: ""
|
||||
labels: extension-request
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
<!--
|
||||
Details on the code-server extension marketplace are at
|
||||
|
||||
https://github.com/cdr/code-server/blob/master/docs/FAQ.md#whats-the-deal-with-extensions
|
||||
|
||||
Please fill in the issue template!
|
||||
-->
|
||||
|
||||
- [ ] Extension name:
|
||||
- [ ] Extension GitHub or homepage:
|
|
@ -1,15 +1,13 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea to improve code-server
|
||||
title: "[Feat]: "
|
||||
labels: enhancement
|
||||
about: Suggest an idea
|
||||
title: ""
|
||||
labels: feature
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
## What is your suggestion?
|
||||
<!--
|
||||
Please search for existing issues before filing.
|
||||
|
||||
## Why do you want this feature?
|
||||
|
||||
## Are there any workarounds to get this functionality today?
|
||||
|
||||
## Are you interested in submitting a PR for this?
|
||||
Please describe the feature as clearly as possible!
|
||||
-->
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
name: Release
|
||||
about: "*For maintainers only*"
|
||||
title: "release: 0.0.0"
|
||||
labels: ""
|
||||
assignees: "@cdr/code-server-reviewers"
|
||||
---
|
||||
|
||||
<!-- Maintainer: fill out the checklist -->
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Assign to next release manager
|
||||
- [ ] Close previous release milestone
|
||||
- [ ] Create next release milestone
|
||||
- [ ] Associate issue with next release milestone
|
|
@ -8,14 +8,6 @@ coverage:
|
|||
range: "40...70"
|
||||
status:
|
||||
patch: off
|
||||
notify:
|
||||
slack:
|
||||
default:
|
||||
url: secret:v1::tXC7VwEIKYjNU8HRgRv2GdKOSCt5UzpykKZb+o1eCDqBgb2PEqwE3A26QUPYMLo4BO2qtrJhFIvwhUvlPwyzDCNGoNiuZfXr0UeZZ0y1TcZu672R/NBNMwEPO/e1Ye0pHxjzKHnuH7HqbjFucox/RBQLtiL3J56SWGE3JtbkC6o=
|
||||
threshold: 1%
|
||||
only_pulls: false
|
||||
branches:
|
||||
- "main"
|
||||
|
||||
parsers:
|
||||
gcov:
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
|
||||
|
||||
# Number of days of inactivity before a closed issue or pull request is locked
|
||||
daysUntilLock: 90
|
||||
|
||||
# Skip issues and pull requests created before a given timestamp. Timestamp must
|
||||
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
|
||||
skipCreatedBefore: false
|
||||
|
||||
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
|
||||
exemptLabels: []
|
||||
|
||||
# Label to add before locking, such as `outdated`. Set to `false` to disable
|
||||
lockLabel: false
|
||||
|
||||
# Comment to post before locking. Set to `false` to disable
|
||||
lockComment: >
|
||||
This thread has been automatically locked since there has not been
|
||||
any recent activity after it was closed. Please open a new issue for
|
||||
related bugs.
|
||||
|
||||
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
||||
setLockReason: true
|
||||
# Limit to only `issues` or `pulls`
|
||||
# only: issues
|
||||
|
||||
# Optionally, specify configuration settings just for `issues` or `pulls`
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - help-wanted
|
||||
# lockLabel: outdated
|
||||
|
||||
# pulls:
|
||||
# daysUntilLock: 30
|
||||
|
||||
# Repository to extend settings from
|
||||
# _extends: repo
|
|
@ -19,6 +19,18 @@ labels:
|
|||
action: comment
|
||||
delay: 5s
|
||||
message: "Thanks for making your first contribution! :slightly_smiling_face:"
|
||||
extension-request:
|
||||
action: close
|
||||
delay: 5s
|
||||
comment: >
|
||||
Thanks for opening an extension request!
|
||||
We are currently in the process of switching extension
|
||||
marketplaces and transitioning over to [Open VSX](https://open-vsx.org/).
|
||||
Once https://github.com/eclipse/openvsx/issues/249 is implemented, we
|
||||
can fully make this transition. Therefore, we are no longer accepting
|
||||
new requests for extension requests. We suggest installing the VSIX
|
||||
file and then installing into code-server as a temporary workaround.
|
||||
See [docs](https://github.com/cdr/code-server/blob/main/docs/FAQ.md#installing-vsix-extensions-via-the-command-line) for more info.
|
||||
"upstream:vscode":
|
||||
action: close
|
||||
delay: 5s
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
###############################################################################
|
||||
# This file configures "Semantic Pull Requests", which is documented here:
|
||||
# https://github.com/zeke/semantic-pull-requests
|
||||
###############################################################################
|
||||
|
||||
# Scopes are optionally supplied after a 'type'. For example, in
|
||||
#
|
||||
# feat(docs): autostart ui
|
||||
#
|
||||
# '(docs)' is the scope. Scopes are used to signify where the change occurred.
|
||||
scopes:
|
||||
# docs: changes to the code-server documentation.
|
||||
- docs
|
||||
|
||||
# vendor: changes to vendored dependencies.
|
||||
- vendor
|
||||
|
||||
# deps: changes to code-server's dependencies.
|
||||
- deps
|
||||
|
||||
# cs: changes to code specific to code-server.
|
||||
- cs
|
||||
|
||||
# cli: changes to the command-line interface.
|
||||
- cli
|
||||
|
||||
# We only check that the PR title is semantic. The PR title is automatically
|
||||
# applied to the "Squash & Merge" flow as the suggested commit message, so this
|
||||
# should suffice unless someone drastically alters the message in that flow.
|
||||
titleOnly: true
|
||||
|
||||
# Types are the 'tag' types in a commit or PR title. For example, in
|
||||
#
|
||||
# chore: fix thing
|
||||
#
|
||||
# 'chore' is the type.
|
||||
types:
|
||||
# A build of any kind.
|
||||
- build
|
||||
|
||||
# A user-facing change that corrects a defect in code-server.
|
||||
- fix
|
||||
|
||||
# Any code task that is ignored for changelog purposes. Examples include
|
||||
# devbin scripts and internal-only configurations.
|
||||
- chore
|
||||
|
||||
# Any work performed on CI.
|
||||
- ci
|
||||
|
||||
# Work that directly implements or supports the implementation of a feature.
|
||||
- feat
|
||||
|
||||
# A refactor changes code structure without any behavioral change.
|
||||
- refactor
|
||||
|
||||
# A git revert for any style of commit.
|
||||
- revert
|
||||
|
||||
# Adding tests of any kind. Should be separate from feature or fix
|
||||
# implementations. For example, if a commit adds a fix + test, it's a fix
|
||||
# commit. If a commit is simply bumping coverage, it's a test commit.
|
||||
- test
|
|
@ -19,6 +19,8 @@ jobs:
|
|||
name: Pre-build checks
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
|
@ -31,21 +33,17 @@ jobs:
|
|||
- name: Install helm
|
||||
uses: azure/setup-helm@v1.1
|
||||
|
||||
# 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: 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
|
||||
|
@ -56,11 +54,15 @@ jobs:
|
|||
run: yarn lint
|
||||
if: success()
|
||||
|
||||
- name: Upload coverage report to Codecov
|
||||
run: yarn coverage
|
||||
if: success()
|
||||
|
||||
audit-ci:
|
||||
name: Run audit-ci
|
||||
needs: prebuild
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
|
@ -92,8 +94,6 @@ jobs:
|
|||
needs: prebuild
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
|
@ -142,25 +142,14 @@ jobs:
|
|||
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 }}
|
||||
vendor/modules/code-oss-dev/out-vscode
|
||||
vendor/modules/code-oss-dev/out-vscode-min
|
||||
key: vscode-build-${{ steps.vscode-rev.outputs.rev }}
|
||||
|
||||
- name: Build vscode
|
||||
if: steps.cache-vscode.outputs.cache-hit != 'true'
|
||||
run: yarn build:vscode
|
||||
|
||||
# Our code imports code from VS Code's `out` directory meaning VS Code
|
||||
# must be built before running these tests.
|
||||
# TODO: Move to its own step?
|
||||
- name: Run code-server unit tests
|
||||
run: yarn test:unit
|
||||
if: success()
|
||||
|
||||
- name: Upload coverage report to Codecov
|
||||
run: yarn coverage
|
||||
if: success()
|
||||
|
||||
# The release package does not contain any native modules
|
||||
# and is neutral to architecture/os/libc version.
|
||||
- name: Create release package
|
||||
|
@ -177,33 +166,6 @@ jobs:
|
|||
name: npm-package
|
||||
path: ./package.tar.gz
|
||||
|
||||
npm:
|
||||
# the npm-package gets uploaded as an artifact in Build
|
||||
# so we need that to complete before this runs
|
||||
needs: build
|
||||
# This environment "npm" requires someone from
|
||||
# coder/code-server-reviewers to approve the PR before this job runs.
|
||||
environment: npm
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/download-artifact@v2
|
||||
id: download
|
||||
with:
|
||||
name: "npm-package"
|
||||
path: release-npm-package
|
||||
|
||||
- name: Run ./ci/steps/publish-npm.sh
|
||||
run: yarn publish:npm
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
# NOTE@jsjoeio
|
||||
# NPM_ENVIRONMENT intentionally not set here.
|
||||
# Instead, itis determined in publish-npm.sh script
|
||||
# using GITHUB environment variables
|
||||
|
||||
# TODO: cache building yarn --production
|
||||
# possibly 2m30s of savings(?)
|
||||
# this requires refactoring our release scripts
|
||||
|
@ -317,7 +279,7 @@ jobs:
|
|||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install cross-compiler
|
||||
run: sudo apt update && sudo apt install $PACKAGE
|
||||
run: sudo apt install $PACKAGE
|
||||
env:
|
||||
PACKAGE: ${{ format('g++-{0}', matrix.prefix) }}
|
||||
|
||||
|
@ -405,6 +367,9 @@ jobs:
|
|||
with:
|
||||
node-version: "14"
|
||||
|
||||
- name: Install playwright OS dependencies
|
||||
run: npx playwright install-deps
|
||||
|
||||
- name: Fetch dependencies from cache
|
||||
id: cache-yarn
|
||||
uses: actions/cache@v2
|
||||
|
@ -430,10 +395,17 @@ jobs:
|
|||
if: steps.cache-yarn.outputs.cache-hit != 'true'
|
||||
run: yarn --frozen-lockfile
|
||||
|
||||
- name: Install Playwright OS dependencies
|
||||
# HACK: this shouldn't need to exist, but put it here anyway
|
||||
# in an attempt to solve Playwright cache failures.
|
||||
- name: Reinstall playwright
|
||||
if: steps.cache-yarn.outputs.cache-hit == 'true'
|
||||
run: |
|
||||
./test/node_modules/.bin/playwright install-deps
|
||||
./test/node_modules/.bin/playwright install
|
||||
cd test/
|
||||
rm -r node_modules/playwright
|
||||
yarn install --check-files
|
||||
|
||||
- name: Run end-to-end tests
|
||||
run: yarn test:unit
|
||||
|
||||
- name: Run end-to-end tests
|
||||
run: yarn test:e2e
|
||||
|
@ -455,7 +427,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
- name: Run Trivy vulnerability scanner in repo mode
|
||||
#Commit SHA for v0.0.17
|
||||
uses: aquasecurity/trivy-action@a7a829a4345428ddd92ca57b18257440f6a18c90
|
||||
uses: aquasecurity/trivy-action@8eccb5539730451af599c84f444c6d6cf0fc2bb0
|
||||
with:
|
||||
scan-type: "fs"
|
||||
scan-ref: "."
|
||||
|
|
|
@ -6,15 +6,13 @@ on:
|
|||
workflow_dispatch:
|
||||
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
docker-images:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
@ -22,13 +20,9 @@ jobs:
|
|||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Run ./ci/steps/docker-buildx-push.sh
|
||||
run: ./ci/steps/docker-buildx-push.sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
|
|
@ -21,7 +21,6 @@ jobs:
|
|||
preview:
|
||||
name: Docs preview
|
||||
runs-on: ubuntu-20.04
|
||||
environment: CI
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.9.1
|
||||
|
@ -29,9 +28,9 @@ jobs:
|
|||
- name: Checkout m
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: coder/m
|
||||
repository: cdr/m
|
||||
ref: refs/heads/master
|
||||
ssh-key: ${{ secrets.READONLY_M_DEPLOY_KEY }}
|
||||
token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
|
@ -5,12 +5,10 @@ on:
|
|||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "install.sh"
|
||||
- "installer.sh"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "install.sh"
|
||||
|
||||
jobs:
|
||||
ubuntu:
|
||||
|
|
|
@ -6,7 +6,7 @@ on:
|
|||
workflow_dispatch:
|
||||
|
||||
release:
|
||||
types: [released]
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
# NOTE: this job requires curl, jq and yarn
|
||||
|
@ -16,18 +16,11 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/download-artifact@v2
|
||||
id: download
|
||||
with:
|
||||
name: "npm-package"
|
||||
path: release-npm-package
|
||||
|
||||
- name: Publish npm package and tag with "latest"
|
||||
run: yarn publish:npm
|
||||
- name: Run ./ci/steps/publish-npm.sh
|
||||
run: ./ci/steps/publish-npm.sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_ENVIRONMENT: "production"
|
||||
|
||||
homebrew:
|
||||
# The newest version of code-server needs to be available on npm when this runs
|
||||
|
|
|
@ -5,14 +5,10 @@ on:
|
|||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "**.sh"
|
||||
- "**.bats"
|
||||
- "installer.sh"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "**.sh"
|
||||
- "**.bats"
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
|
|
@ -12,6 +12,7 @@ vendor/modules
|
|||
node-*
|
||||
/plugins
|
||||
/lib/coder-cloud-agent
|
||||
/lib/linkup
|
||||
.home
|
||||
coverage
|
||||
**/.DS_Store
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
{
|
||||
"file": "src/node/heart.ts",
|
||||
"line": 7,
|
||||
"description": "code-server's heart beats to indicate recent activity.\n\nAlso documented here: [https://github.com/coder/code-server/blob/master/docs/FAQ.md#heartbeat-file](https://github.com/coder/code-server/blob/master/docs/FAQ.md#heartbeat-file)"
|
||||
"description": "code-server's heart beats to indicate recent activity.\n\nAlso documented here: [https://github.com/cdr/code-server/blob/master/docs/FAQ.md#heartbeat-file](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#heartbeat-file)"
|
||||
},
|
||||
{
|
||||
"file": "src/node/socket.ts",
|
||||
|
@ -80,12 +80,12 @@
|
|||
{
|
||||
"file": "src/node/routes/domainProxy.ts",
|
||||
"line": 18,
|
||||
"description": "code-server provides a built-in proxy to help in developing web-based applications. This is the code for the domain-based proxy.\n\nAlso documented here: [https://github.com/coder/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/coder/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services)"
|
||||
"description": "code-server provides a built-in proxy to help in developing web-based applications. This is the code for the domain-based proxy.\n\nAlso documented here: [https://github.com/cdr/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services)"
|
||||
},
|
||||
{
|
||||
"file": "src/node/routes/pathProxy.ts",
|
||||
"line": 19,
|
||||
"description": "Here is the path-based version of the proxy.\n\nAlso documented here: [https://github.com/coder/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/coder/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services)"
|
||||
"description": "Here is the path-based version of the proxy.\n\nAlso documented here: [https://github.com/cdr/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services)"
|
||||
},
|
||||
{
|
||||
"file": "src/node/proxy.ts",
|
||||
|
@ -95,7 +95,7 @@
|
|||
{
|
||||
"file": "src/node/routes/health.ts",
|
||||
"line": 5,
|
||||
"description": "A simple endpoint that lets you see if code-server is up.\n\nAlso documented here: [https://github.com/coder/code-server/blob/master/docs/FAQ.md#healthz-endpoint](https://github.com/coder/code-server/blob/master/docs/FAQ.md#healthz-endpoint)"
|
||||
"description": "A simple endpoint that lets you see if code-server is up.\n\nAlso documented here: [https://github.com/cdr/code-server/blob/master/docs/FAQ.md#healthz-endpoint](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#healthz-endpoint)"
|
||||
},
|
||||
{
|
||||
"file": "src/node/routes/login.ts",
|
||||
|
@ -145,7 +145,7 @@
|
|||
{
|
||||
"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."
|
||||
"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/cdr/code-server/blob/master/docs/CONTRIBUTING.md#modifications-to-vs-code](https://github.com/cdr/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."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
{
|
||||
"file": "src/node/app.ts",
|
||||
"line": 62,
|
||||
"description": "## That's it!\n\n\nThat's all there is to it! When this tour ends, your terminal session may stop, but just use `yarn watch` to start developing from here on out!\n\n\nIf you haven't already, be sure to check out these resources:\n- [Tour: Contributing](command:codetour.startTourByTitle?[\"Contributing\")\n- [Docs: FAQ.md](https://github.com/coder/code-server/blob/master/docs/FAQ.md)\n- [Docs: CONTRIBUTING.md](https://github.com/coder/code-server/blob/master/docs/CONTRIBUTING.md)\n- [Community: GitHub Discussions](https://github.com/coder/code-server/discussions)\n- [Community: Slack](https://community.coder.com)"
|
||||
"description": "## That's it!\n\n\nThat's all there is to it! When this tour ends, your terminal session may stop, but just use `yarn watch` to start developing from here on out!\n\n\nIf you haven't already, be sure to check out these resources:\n- [Tour: Contributing](command:codetour.startTourByTitle?[\"Contributing\")\n- [Docs: FAQ.md](https://github.com/cdr/code-server/blob/master/docs/FAQ.md)\n- [Docs: CONTRIBUTING.md](https://github.com/cdr/code-server/blob/master/docs/CONTRIBUTING.md)\n- [Community: GitHub Discussions](https://github.com/cdr/code-server/discussions)\n- [Community: Slack](https://community.coder.com)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
214
CHANGELOG.md
214
CHANGELOG.md
|
@ -1,161 +1,175 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
<!--
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
This should be updated on every PR.
|
||||
|
||||
<!-- Example:
|
||||
We copy from here into the release notes.
|
||||
|
||||
## [9.99.999] - 9090-09-09
|
||||
-->
|
||||
|
||||
VS Code v99.99.999
|
||||
<!--
|
||||
Add next version above previous version but below this line using the template
|
||||
|
||||
### Changed
|
||||
### Added
|
||||
### Deprecated
|
||||
### Removed
|
||||
### Fixed
|
||||
### Security
|
||||
|
||||
-->
|
||||
|
||||
## [Unreleased](https://github.com/coder/code-server/releases)
|
||||
## Next Version
|
||||
|
||||
VS Code v0.00.0
|
||||
|
||||
### Changed
|
||||
### New Features
|
||||
|
||||
- Add here
|
||||
- item
|
||||
|
||||
## [4.0.2](https://github.com/coder/code-server/releases/tag/v4.0.2) - 2022-01-27
|
||||
### Bug Fixes
|
||||
|
||||
VS Code v1.63.0
|
||||
- fix(socket): did this thing #321 @githubuser
|
||||
|
||||
### Fixed
|
||||
### Documentation
|
||||
|
||||
- Unset the `BROWSER` environment variable. This fixes applications that hard
|
||||
exit when trying to spawn the helper script `BROWSER` points to because the
|
||||
file is missing. While we do include the script now we are leaving the
|
||||
variable omitted because the script does not work yet.
|
||||
- item
|
||||
|
||||
## [4.0.1](https://github.com/coder/code-server/releases/tag/v4.0.1) - 2022-01-04
|
||||
### Development
|
||||
|
||||
VS Code v1.63.0
|
||||
- item
|
||||
|
||||
code-server has been rebased on upstream's newly open-sourced server
|
||||
implementation (#4414).
|
||||
-->
|
||||
|
||||
### Changed
|
||||
## Next Version
|
||||
|
||||
- Web socket compression has been made the default (when supported). This means
|
||||
the `--enable` flag will no longer take `permessage-deflate` as an option.
|
||||
- The static endpoint can no longer reach outside code-server. However the
|
||||
vscode-remote-resource endpoint still can.
|
||||
- OpenVSX has been made the default marketplace.
|
||||
- The last opened folder/workspace is no longer stored separately in the
|
||||
settings file (we rely on the already-existing query object instead).
|
||||
- The marketplace override environment variables `SERVICE_URL` and `ITEM_URL`
|
||||
have been replaced with a single `EXTENSIONS_GALLERY` variable that
|
||||
corresponds to `extensionsGallery` in VS Code's `product.json`.
|
||||
VS Code v0.00.0
|
||||
|
||||
### Added
|
||||
### New Features
|
||||
|
||||
- `VSCODE_PROXY_URI` env var for use in the terminal and extensions.
|
||||
- item
|
||||
|
||||
### Removed
|
||||
### Bug Fixes
|
||||
|
||||
- Extra extension directories have been removed. The `--extra-extensions-dir`
|
||||
and `--extra-builtin-extensions-dir` flags will no longer be accepted.
|
||||
- The `--install-source` flag has been removed.
|
||||
- Fix logout when using a base path (#3608)
|
||||
|
||||
### Deprecated
|
||||
### Documentation
|
||||
|
||||
- `--link` is now deprecated (#4562).
|
||||
- docs: add Pomerium #3424 @desimone
|
||||
- docs: fix confusing sentence in pull requests section #3460 @shiv-tyagi
|
||||
- docs: remove toc from changelog @oxy @jsjoeio
|
||||
- docs(MAINTAINING): add information about CHANGELOG #3467 @jsjoeio
|
||||
- docs: move release process to MAINTAINING.md #3441 @oxy @Prashant168
|
||||
- docs: format 'Caddy' from guide.md @PisecesPeng
|
||||
|
||||
### Security
|
||||
### Development
|
||||
|
||||
- We fixed a XSS vulnerability by escaping HTML from messages in the error page (#4430).
|
||||
- chore: cross-compile docker images with buildx #3166 @oxy
|
||||
- chore: update node to v14 #3458 @oxy
|
||||
- chore: update .gitignore #3557 @cuining
|
||||
- fix: use sufficient computational effort for password hash #3422 @jsjoeio
|
||||
- docs(CONTRIBUTING): add section on testing #3629 @jsjoeio
|
||||
|
||||
## [3.12.0](https://github.com/coder/code-server/releases/tag/v3.12.0) - 2021-09-15
|
||||
### Development
|
||||
|
||||
VS Code v1.60.0
|
||||
- fix(publish): update cdrci fork in brew-bump.sh #3468 @jsjoeio
|
||||
- chore(dev): migrate away from parcel #3578 @jsjoeio
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade VS Code to 1.60.0.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix logout when using a base path (#3608).
|
||||
|
||||
## [3.11.1](https://github.com/coder/code-server/releases/tag/v3.11.1) - 2021-08-06
|
||||
|
||||
Undocumented (see releases page).
|
||||
|
||||
## [3.11.0](https://github.com/coder/code-server/releases/tag/v3.11.0) - 2021-06-14
|
||||
|
||||
Undocumented (see releases page).
|
||||
|
||||
## [3.10.2](https://github.com/coder/code-server/releases/tag/v3.10.2) - 2021-05-21
|
||||
## 3.10.2
|
||||
|
||||
VS Code v1.56.1
|
||||
|
||||
### Added
|
||||
### New Features
|
||||
|
||||
- Support `extraInitContainers` in helm chart values (#3393).
|
||||
- feat: support `extraInitContainers` in helm chart values #3393 @strowk
|
||||
- feat: change `extraContainers` to support templating in helm chart #3393 @strowk
|
||||
|
||||
### Changed
|
||||
### Bug Fixes
|
||||
|
||||
- Change `extraContainers` to support templating in helm chart (#3393).
|
||||
- fix: use correct command to Open Folder on Welcome page #3437 @jsjoeio
|
||||
|
||||
### Fixed
|
||||
### Development
|
||||
|
||||
- Fix "Open Folder" on welcome page (#3437).
|
||||
- fix(ci): update brew-bump.sh to update remote first #3438 @jsjoeio
|
||||
|
||||
## [3.10.1](https://github.com/coder/code-server/releases/tag/v3.10.1) - 2021-05-17
|
||||
## 3.10.1
|
||||
|
||||
VS Code v1.56.1
|
||||
|
||||
### Fixed
|
||||
### Bug Fixes
|
||||
|
||||
- Check the logged user instead of $USER (#3330).
|
||||
- Fix broken node_modules.asar symlink in npm package (#3355).
|
||||
- Update cloud agent to fix version issue (#3342).
|
||||
- fix: Check the logged user instead of $USER #3330 @videlanicolas
|
||||
- fix: Fix broken node_modules.asar symlink in npm package #3355 @code-asher
|
||||
- fix: Update cloud agent to fix version issue #3342 @oxy
|
||||
|
||||
### Changed
|
||||
### Documentation
|
||||
|
||||
- Use xdgBasedir.runtime instead of tmp (#3304).
|
||||
- docs(install): add raspberry pi section #3376 @jsjoeio
|
||||
- docs(maintaining): add pull requests section #3378 @jsjoeio
|
||||
- docs(maintaining): add merge strategies section #3379 @jsjoeio
|
||||
- refactor: move default PR template #3375 @jsjoeio
|
||||
- docs(contributing): add commits section #3377 @jsjoeio
|
||||
|
||||
## [3.10.0](https://github.com/coder/code-server/releases/tag/v3.10.0) - 2021-05-10
|
||||
### Development
|
||||
|
||||
- chore: ignore updates to microsoft/playwright-github-action
|
||||
- fix(socket): use xdgBasedir.runtime instead of tmp #3304 @jsjoeio
|
||||
- fix(ci): re-enable trivy-scan-repo #3368 @jsjoeio
|
||||
|
||||
## 3.10.0
|
||||
|
||||
VS Code v1.56.0
|
||||
|
||||
### Changed
|
||||
### New Features
|
||||
|
||||
- Update to VS Code 1.56.0 (#3269).
|
||||
- Minor connections refactor (#3178). Improves connection stability.
|
||||
- Use ptyHostService (#3308). This brings us closer to upstream VS Code.
|
||||
- feat: minor connections refactor #3178 @code-asher
|
||||
- feat(security): add code-scanning with CodeQL #3229 @jsjoeio
|
||||
- feat(ci): add trivy job for security #3261 @jsjoeio
|
||||
- feat(vscode): update to version 1.56.0 #3269 @oxy
|
||||
- feat: use ptyHostService #3308 @code-asher
|
||||
|
||||
### Added
|
||||
### Bug Fixes
|
||||
|
||||
- Add flag for toggling permessage-deflate (#3286). The default is off so
|
||||
compression will no longer be used by default. Use the --enable flag to
|
||||
toggle it back on.
|
||||
- fix(socket): did this thing #321 @githubuser
|
||||
- fix(login): rate limiter shouldn't count successful logins #3141 @jsjoeio
|
||||
- chore(lib/vscode): update netmask #3187 @oxy
|
||||
- chore(deps): update dependencies with CVEs #3223 @oxy
|
||||
- fix: refactor logout #3277 @code-asher
|
||||
- fix: add flag for toggling permessage-deflate #3286 @code-asher
|
||||
- fix: make sure directories exist #3309 @code-asher
|
||||
|
||||
### Fixed
|
||||
### Documentation
|
||||
|
||||
- Make rate limiter not count against successful logins (#3141).
|
||||
- Refactor logout (#3277). This fixes logging out in some scenarios.
|
||||
- Make sure directories exist (#3309). This fixes some errors on startup.
|
||||
- docs(FAQ): add mention of sysbox #3087 @bpmct
|
||||
- docs: add security policy #3148 @jsjoeio
|
||||
- docs(guide.md): add `caddy` example for serving from sub-path #3217 @catthehacker
|
||||
- docs: revamp debugging section #3224 @code-asher
|
||||
- docs(readme): refactor to use codecov shield #3227 @jsjoeio
|
||||
- docs(maintaining): use milestones over boards #3228 @jsjoeio
|
||||
- docs(faq): add entry for accessing OSX folders #3247 @bpmct
|
||||
- docs(termux): add workaround for Android backspace issue #3251 @jsjoeio
|
||||
- docs(maintaining): add triage to workflow #3284 @jsjoeio
|
||||
- docs(security): add section for tools #3287 @jsjoeio
|
||||
- docs(maintaining): add versioning #3288 @jsjoeio
|
||||
- docs: add changelog #3337 @jsjoeio
|
||||
|
||||
### Security
|
||||
### Development
|
||||
|
||||
- Update dependencies with CVEs (#3223).
|
||||
- fix(update-vscode): add check/docs for git-subtree #3129 @oxy
|
||||
- refactor(testing): migrate to playwright-test from jest-playwright #3133 @jsjoeio
|
||||
- refactor(ci): remove unmaintained CI images and update release workflow #3147 @oxy
|
||||
- chore(ci): migrate from hub to gh #3168 @oxy
|
||||
- feat(testing): add e2e tests for code-server and terminal #3169 @jsjoeio
|
||||
- chore(ranger): fix syntax for extension-request #3172 @oxy
|
||||
- feat(testing): add codecov to generate test coverage reports #3194 @jsjoeio
|
||||
- feat(testing): add tests for registerServiceWorker #3200 @jsjoeio
|
||||
- refactor(testing): fix flaky terminal test #3230 @jsjoeio
|
||||
- chore: ignore 15.x @types/node updates #3244 @jsjoeio
|
||||
- chore(build): compile vscode+extensions in parallel #3250 @oxy
|
||||
- fix(deps): remove eslint-plugin-jest-playwright #3260 @jsjoeio
|
||||
- fix(testing): reduce flakiness of terminal.test.ts and use 1 worker for e2e tests #3263 @jsjoeio
|
||||
- feat(testing): add isConnected check #3271 @jsjoeio
|
||||
- feat(testing): add test for src/node/constants.ts #3290 @jsjoeio
|
||||
- feat: test static route #3297 @code-asher
|
||||
- refactor(ci): split audit from prebuild #3298 @oxy
|
||||
- chore(lib/vscode): cleanup/update build deps #3314 @oxy
|
||||
- fix(build): download correct cloud-agent for arch #3331 @oxy
|
||||
- fix: xmldom and underscore #3332 @oxy
|
||||
|
||||
## Previous versions
|
||||
|
||||
This was added with `3.10.0`, which means any previous versions are not
|
||||
documented in the changelog.
|
||||
This was added with `3.10.0`, which means any previous versions are not documented in the changelog.
|
||||
|
||||
To see those, please visit the [Releases page](https://github.com/coder/code-server/releases).
|
||||
To see those, please visit the [Releases page](https://github.com/cdr/code-server/releases).
|
||||
|
|
|
@ -20,16 +20,23 @@ main() {
|
|||
source ./ci/lib.sh
|
||||
OS="$(uname | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
mkdir -p ./lib
|
||||
|
||||
if ! [ -f ./lib/coder-cloud-agent ]; then
|
||||
echo "Downloading the cloud agent..."
|
||||
|
||||
set +e
|
||||
curl -fsSL "https://github.com/coder/cloud-agent/releases/latest/download/cloud-agent-$OS-$ARCH" -o ./lib/coder-cloud-agent
|
||||
curl -fsSL "https://github.com/cdr/cloud-agent/releases/latest/download/cloud-agent-$OS-$ARCH" -o ./lib/coder-cloud-agent
|
||||
chmod +x ./lib/coder-cloud-agent
|
||||
set -e
|
||||
fi
|
||||
|
||||
if ! [ -f ./lib/linkup ]; then
|
||||
echo "Downloading Link agent..."
|
||||
|
||||
set +e
|
||||
curl -fsSL "https://storage.googleapis.com/coder-link-releases/latest/linkup-$OS-$ARCH" -o ./lib/linkup
|
||||
chmod +x ./lib/linkup
|
||||
set -e
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
|
@ -61,13 +61,14 @@ EOF
|
|||
rsync node_modules/ "$RELEASE_PATH/node_modules"
|
||||
mkdir -p "$RELEASE_PATH/lib"
|
||||
rsync ./lib/coder-cloud-agent "$RELEASE_PATH/lib"
|
||||
rsync ./lib/linkup "$RELEASE_PATH/lib"
|
||||
fi
|
||||
}
|
||||
|
||||
bundle_vscode() {
|
||||
mkdir -p "$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"
|
||||
rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
|
||||
|
||||
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
|
||||
if [ "$KEEP_MODULES" = 0 ]; then
|
||||
|
@ -79,15 +80,9 @@ bundle_vscode() {
|
|||
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"
|
||||
mkdir -p "$VSCODE_OUT_PATH/resources/"{linux,web}
|
||||
rsync "$VSCODE_SRC_PATH/resources/linux/" "$VSCODE_OUT_PATH/resources/linux/"
|
||||
rsync "$VSCODE_SRC_PATH/resources/web/" "$VSCODE_OUT_PATH/resources/web/"
|
||||
|
||||
# Add the commit and date and enable telemetry. This just makes telemetry
|
||||
# available; telemetry can still be disabled by flag or setting.
|
||||
|
@ -95,10 +90,8 @@ bundle_vscode() {
|
|||
cat << EOF
|
||||
{
|
||||
"enableTelemetry": true,
|
||||
"commit": "$(cd "$VSCODE_SRC_PATH" && git rev-parse HEAD)",
|
||||
"quality": "stable",
|
||||
"date": $(jq -n 'now | todate'),
|
||||
"codeServerVersion": "$VERSION"
|
||||
"commit": "$(git rev-parse HEAD)",
|
||||
"date": $(jq -n 'now | todate')
|
||||
}
|
||||
EOF
|
||||
) > "$VSCODE_OUT_PATH/product.json"
|
||||
|
|
|
@ -11,8 +11,13 @@ main() {
|
|||
|
||||
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}"
|
||||
yarn gulp compile-build compile-extensions-build compile-extension-media compile-web
|
||||
|
||||
yarn gulp optimize --gulpfile ./coder.js
|
||||
|
||||
if [[ $MINIFY ]]; then
|
||||
yarn gulp minify --gulpfile ./coder.js
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
|
@ -5,7 +5,7 @@ set -eu
|
|||
# Runs code-server with the bundled node binary.
|
||||
|
||||
_realpath() {
|
||||
# See https://github.com/coder/code-server/issues/1537 on why no realpath or readlink -f.
|
||||
# See https://github.com/cdr/code-server/issues/1537 on why no realpath or readlink -f.
|
||||
|
||||
script="$1"
|
||||
cd "$(dirname "$script")"
|
||||
|
@ -16,7 +16,7 @@ _realpath() {
|
|||
&& cat package.json | grep -q '^ "name": "code-server",$'; then
|
||||
echo "***** Please use the script in bin/code-server instead!" >&2
|
||||
echo "***** This script will soon be removed!" >&2
|
||||
echo "***** See the release notes at https://github.com/coder/code-server/releases/tag/v3.4.0" >&2
|
||||
echo "***** See the release notes at https://github.com/cdr/code-server/releases/tag/v3.4.0" >&2
|
||||
fi
|
||||
|
||||
script="$(readlink "$(basename "$script")")"
|
||||
|
|
|
@ -8,7 +8,7 @@ maintainer: "Anmol Sethi <hi@nhooyr.io>"
|
|||
description: |
|
||||
Run VS Code in the browser.
|
||||
vendor: "Coder"
|
||||
homepage: "https://github.com/coder/code-server"
|
||||
homepage: "https://github.com/cdr/code-server"
|
||||
license: "MIT"
|
||||
|
||||
contents:
|
||||
|
|
|
@ -57,18 +57,21 @@ main() {
|
|||
esac
|
||||
|
||||
OS="$(uname | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
mkdir -p ./lib
|
||||
|
||||
if curl -fsSL "https://github.com/coder/cloud-agent/releases/latest/download/cloud-agent-$OS-$ARCH" -o ./lib/coder-cloud-agent; then
|
||||
if curl -fsSL "https://github.com/cdr/cloud-agent/releases/latest/download/cloud-agent-$OS-$ARCH" -o ./lib/coder-cloud-agent; then
|
||||
chmod +x ./lib/coder-cloud-agent
|
||||
else
|
||||
echo "Failed to download cloud agent; --link will not work"
|
||||
fi
|
||||
|
||||
if curl -fsSL "https://storage.googleapis.com/coder-link-releases/latest/linkup-$OS-$ARCH" -o ./lib/linkup; then
|
||||
chmod +x ./lib/linkup
|
||||
else
|
||||
echo "Failed to download Link agent; the Link extension will not work"
|
||||
fi
|
||||
|
||||
if ! vscode_yarn; then
|
||||
echo "You may not have the required dependencies to build the native modules."
|
||||
echo "Please see https://github.com/coder/code-server/blob/master/docs/npm.md"
|
||||
echo "Please see https://github.com/cdr/code-server/blob/master/docs/npm.md"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ main() {
|
|||
download_artifact release-packages ./release-packages
|
||||
local assets=(./release-packages/code-server*"$VERSION"*{.tar.gz,.deb,.rpm})
|
||||
|
||||
EDITOR=true gh release upload "v$VERSION" "${assets[@]}" --clobber
|
||||
EDITOR=true gh release upload "v$VERSION" "${assets[@]}"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
|
@ -83,14 +83,14 @@ main() {
|
|||
echo -e "Great! We'll prep a PR for updating to $CODE_SERVER_VERSION_TO_UPDATE\n"
|
||||
$CMD rg -g '!yarn.lock' -g '!*.svg' -g '!CHANGELOG.md' --files-with-matches --fixed-strings "${CODE_SERVER_CURRENT_VERSION}" | $CMD xargs sd "$CODE_SERVER_CURRENT_VERSION" "$CODE_SERVER_VERSION_TO_UPDATE"
|
||||
|
||||
$CMD git commit --no-verify -am "chore(release): bump version to $CODE_SERVER_VERSION_TO_UPDATE"
|
||||
$CMD git commit -am "chore(release): bump version to $CODE_SERVER_VERSION_TO_UPDATE"
|
||||
|
||||
# This runs from the root so that's why we use this path vs. ../../
|
||||
RELEASE_TEMPLATE_STRING=$(cat ./.github/PULL_REQUEST_TEMPLATE/release_template.md)
|
||||
|
||||
echo -e "\nOpening a draft PR on GitHub"
|
||||
# To read about these flags, visit the docs: https://cli.github.com/manual/gh_pr_create
|
||||
$CMD gh pr create --base main --title "release: $CODE_SERVER_VERSION_TO_UPDATE" --body "$RELEASE_TEMPLATE_STRING" --reviewer @coder/code-server-reviewers --repo coder/code-server --draft --assignee "@me"
|
||||
$CMD gh pr create --base main --title "release: $CODE_SERVER_VERSION_TO_UPDATE" --body "$RELEASE_TEMPLATE_STRING" --reviewer @cdr/code-server-reviewers --repo cdr/code-server --draft --assignee "@me"
|
||||
|
||||
# Open PR in browser
|
||||
$CMD gh pr view --web
|
||||
|
|
|
@ -3,48 +3,35 @@ set -euo pipefail
|
|||
|
||||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
source ./ci/lib.sh
|
||||
|
||||
pushd test
|
||||
echo "Installing dependencies for $PWD"
|
||||
echo "Installing code-server test dependencies..."
|
||||
|
||||
cd test
|
||||
yarn install
|
||||
popd
|
||||
cd ..
|
||||
|
||||
local args=(install)
|
||||
if [[ ${CI-} ]]; then
|
||||
args+=(--frozen-lockfile)
|
||||
fi
|
||||
cd vendor
|
||||
echo "Installing vendor dependencies..."
|
||||
|
||||
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
|
||||
# * 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.
|
||||
#
|
||||
# * 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)
|
||||
# assumed to be compiled. Because the default behavior for VS Code's `postinstall`
|
||||
# assumes we're also compiled, this needs to be ignored.
|
||||
|
||||
local args=(install --modules-folder modules --ignore-scripts)
|
||||
|
||||
if [[ ${CI-} ]]; then
|
||||
args+=("--frozen-lockfile")
|
||||
fi
|
||||
|
||||
yarn "${args[@]}"
|
||||
|
||||
# Finally, run the vendor `postinstall`
|
||||
yarn run postinstall
|
||||
|
||||
popd
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
|
@ -1,23 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
help() {
|
||||
echo >&2 " You can build with 'yarn watch' or you can build a release"
|
||||
echo >&2 " For example: 'yarn build && yarn build:vscode && KEEP_MODULES=1 yarn release'"
|
||||
echo >&2 " Then 'CODE_SERVER_TEST_ENTRY=./release yarn test:e2e'"
|
||||
echo >&2 " You can manually run that release with 'node ./release'"
|
||||
}
|
||||
|
||||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
source ./ci/lib.sh
|
||||
|
||||
pushd test/e2e/extensions/test-extension
|
||||
echo "Building test extension"
|
||||
yarn build
|
||||
popd
|
||||
|
||||
local dir="$PWD"
|
||||
if [[ ! ${CODE_SERVER_TEST_ENTRY-} ]]; then
|
||||
echo "Set CODE_SERVER_TEST_ENTRY to test another build of code-server"
|
||||
|
@ -33,13 +21,13 @@ main() {
|
|||
# wrong (native modules version issues, incomplete build, etc).
|
||||
if [[ ! -d $dir/out ]]; then
|
||||
echo >&2 "No code-server build detected"
|
||||
help
|
||||
echo >&2 "You can build it with 'yarn build' or 'yarn watch'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d $dir/vendor/modules/code-oss-dev/out ]]; then
|
||||
echo >&2 "No VS Code build detected"
|
||||
help
|
||||
echo >&2 "You can build it with 'yarn build:vscode' or 'yarn watch'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
@ -3,27 +3,12 @@ set -euo pipefail
|
|||
|
||||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
source ./ci/lib.sh
|
||||
|
||||
echo "Building test plugin"
|
||||
pushd test/unit/node/test-plugin
|
||||
cd test/unit/node/test-plugin
|
||||
make -s out/index.js
|
||||
popd
|
||||
|
||||
# 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.
|
||||
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
|
||||
# information. We must also run it from the root otherwise coverage will not
|
||||
# include our source files.
|
||||
cd "$OLDPWD"
|
||||
CS_DISABLE_PLUGINS=true ./test/node_modules/.bin/jest "$@"
|
||||
}
|
||||
|
||||
|
|
265
ci/dev/watch.ts
265
ci/dev/watch.ts
|
@ -1,140 +1,149 @@
|
|||
import { spawn, fork, ChildProcess } from "child_process"
|
||||
import * as cp from "child_process"
|
||||
import * as path from "path"
|
||||
import { onLine, OnLineCallback } from "../../src/node/util"
|
||||
|
||||
interface DevelopmentCompilers {
|
||||
[key: string]: ChildProcess | undefined
|
||||
vscode: ChildProcess
|
||||
vscodeWebExtensions: ChildProcess
|
||||
codeServer: ChildProcess
|
||||
plugins: ChildProcess | undefined
|
||||
}
|
||||
|
||||
class Watcher {
|
||||
private rootPath = path.resolve(process.cwd())
|
||||
private readonly paths = {
|
||||
/** Path to uncompiled VS Code source. */
|
||||
vscodeDir: path.join(this.rootPath, "vendor", "modules", "code-oss-dev"),
|
||||
pluginDir: process.env.PLUGIN_DIR,
|
||||
}
|
||||
|
||||
//#region Web Server
|
||||
|
||||
/** Development web server. */
|
||||
private webServer: ChildProcess | undefined
|
||||
|
||||
private reloadWebServer = (): void => {
|
||||
if (this.webServer) {
|
||||
this.webServer.kill()
|
||||
}
|
||||
|
||||
// Pass CLI args, save for `node` and the initial script name.
|
||||
const args = process.argv.slice(2)
|
||||
this.webServer = fork(path.join(this.rootPath, "out/node/entry.js"), args)
|
||||
const { pid } = this.webServer
|
||||
|
||||
this.webServer.on("exit", () => console.log("[Code Server]", `Web process ${pid} exited`))
|
||||
|
||||
console.log("\n[Code Server]", `Spawned web server process ${pid}`)
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Compilers
|
||||
|
||||
private readonly compilers: DevelopmentCompilers = {
|
||||
codeServer: spawn("tsc", ["--watch", "--pretty", "--preserveWatchOutput"], { cwd: this.rootPath }),
|
||||
vscode: spawn("yarn", ["watch"], { cwd: this.paths.vscodeDir }),
|
||||
vscodeWebExtensions: spawn("yarn", ["watch-web"], { cwd: this.paths.vscodeDir }),
|
||||
plugins: this.paths.pluginDir ? spawn("yarn", ["build", "--watch"], { cwd: this.paths.pluginDir }) : undefined,
|
||||
}
|
||||
|
||||
public async initialize(): Promise<void> {
|
||||
for (const event of ["SIGINT", "SIGTERM"]) {
|
||||
process.on(event, () => this.dispose(0))
|
||||
}
|
||||
|
||||
for (const [processName, devProcess] of Object.entries(this.compilers)) {
|
||||
if (!devProcess) continue
|
||||
|
||||
devProcess.on("exit", (code) => {
|
||||
console.log(`[${processName}]`, "Terminated unexpectedly")
|
||||
this.dispose(code)
|
||||
})
|
||||
|
||||
if (devProcess.stderr) {
|
||||
devProcess.stderr.on("data", (d: string | Uint8Array) => process.stderr.write(d))
|
||||
}
|
||||
}
|
||||
|
||||
onLine(this.compilers.vscode, this.parseVSCodeLine)
|
||||
onLine(this.compilers.codeServer, this.parseCodeServerLine)
|
||||
|
||||
if (this.compilers.plugins) {
|
||||
onLine(this.compilers.plugins, this.parsePluginLine)
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Line Parsers
|
||||
|
||||
private parseVSCodeLine: OnLineCallback = (strippedLine, originalLine) => {
|
||||
if (!strippedLine.length) return
|
||||
|
||||
console.log("[VS Code]", originalLine)
|
||||
|
||||
if (strippedLine.includes("Finished compilation with")) {
|
||||
console.log("[VS Code] ✨ Finished compiling! ✨", "(Refresh your web browser ♻️)")
|
||||
this.reloadWebServer()
|
||||
}
|
||||
}
|
||||
|
||||
private parseCodeServerLine: OnLineCallback = (strippedLine, originalLine) => {
|
||||
if (!strippedLine.length) return
|
||||
|
||||
console.log("[Compiler][Code Server]", originalLine)
|
||||
|
||||
if (strippedLine.includes("Watching for file changes")) {
|
||||
console.log("[Compiler][Code Server]", "Finished compiling!", "(Refresh your web browser ♻️)")
|
||||
this.reloadWebServer()
|
||||
}
|
||||
}
|
||||
|
||||
private parsePluginLine: OnLineCallback = (strippedLine, originalLine) => {
|
||||
if (!strippedLine.length) return
|
||||
|
||||
console.log("[Compiler][Plugin]", originalLine)
|
||||
|
||||
if (strippedLine.includes("Watching for file changes...")) {
|
||||
this.reloadWebServer()
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Utilities
|
||||
|
||||
private dispose(code: number | null): void {
|
||||
for (const [processName, devProcess] of Object.entries(this.compilers)) {
|
||||
console.log(`[${processName}]`, "Killing...\n")
|
||||
devProcess?.removeAllListeners()
|
||||
devProcess?.kill()
|
||||
}
|
||||
process.exit(typeof code === "number" ? code : 0)
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
import { onLine } from "../../src/node/util"
|
||||
|
||||
async function main(): Promise<void> {
|
||||
try {
|
||||
const watcher = new Watcher()
|
||||
await watcher.initialize()
|
||||
await watcher.watch()
|
||||
} catch (error: any) {
|
||||
console.error(error.message)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
class Watcher {
|
||||
private readonly rootPath = path.resolve(__dirname, "../..")
|
||||
private readonly vscodeSourcePath = path.join(this.rootPath, "vendor/modules/code-oss-dev")
|
||||
|
||||
private static log(message: string, skipNewline = false): void {
|
||||
process.stdout.write(message)
|
||||
if (!skipNewline) {
|
||||
process.stdout.write("\n")
|
||||
}
|
||||
}
|
||||
|
||||
public async watch(): Promise<void> {
|
||||
let server: cp.ChildProcess | undefined
|
||||
const restartServer = (): void => {
|
||||
if (server) {
|
||||
server.kill()
|
||||
}
|
||||
const s = cp.fork(path.join(this.rootPath, "out/node/entry.js"), process.argv.slice(2))
|
||||
console.log(`[server] spawned process ${s.pid}`)
|
||||
s.on("exit", () => console.log(`[server] process ${s.pid} exited`))
|
||||
server = s
|
||||
}
|
||||
|
||||
const vscode = cp.spawn("yarn", ["watch"], { cwd: this.vscodeSourcePath })
|
||||
|
||||
const vscodeWebExtensions = cp.spawn("yarn", ["watch-web"], { cwd: this.vscodeSourcePath })
|
||||
|
||||
const tsc = cp.spawn("tsc", ["--watch", "--pretty", "--preserveWatchOutput"], { cwd: this.rootPath })
|
||||
const plugin = process.env.PLUGIN_DIR
|
||||
? cp.spawn("yarn", ["build", "--watch"], { cwd: process.env.PLUGIN_DIR })
|
||||
: undefined
|
||||
|
||||
const cleanup = (code?: number | null): void => {
|
||||
Watcher.log("killing vs code watcher")
|
||||
vscode.removeAllListeners()
|
||||
vscode.kill()
|
||||
|
||||
Watcher.log("killing vs code web extension watcher")
|
||||
vscodeWebExtensions.removeAllListeners()
|
||||
vscodeWebExtensions.kill()
|
||||
|
||||
Watcher.log("killing tsc")
|
||||
tsc.removeAllListeners()
|
||||
tsc.kill()
|
||||
|
||||
if (plugin) {
|
||||
Watcher.log("killing plugin")
|
||||
plugin.removeAllListeners()
|
||||
plugin.kill()
|
||||
}
|
||||
|
||||
if (server) {
|
||||
Watcher.log("killing server")
|
||||
server.removeAllListeners()
|
||||
server.kill()
|
||||
}
|
||||
|
||||
Watcher.log("killing watch")
|
||||
process.exit(code || 0)
|
||||
}
|
||||
|
||||
process.on("SIGINT", () => cleanup())
|
||||
process.on("SIGTERM", () => cleanup())
|
||||
|
||||
vscode.on("exit", (code) => {
|
||||
Watcher.log("vs code watcher terminated unexpectedly")
|
||||
cleanup(code)
|
||||
})
|
||||
|
||||
vscodeWebExtensions.on("exit", (code) => {
|
||||
Watcher.log("vs code extension watcher terminated unexpectedly")
|
||||
cleanup(code)
|
||||
})
|
||||
|
||||
tsc.on("exit", (code) => {
|
||||
Watcher.log("tsc terminated unexpectedly")
|
||||
cleanup(code)
|
||||
})
|
||||
|
||||
if (plugin) {
|
||||
plugin.on("exit", (code) => {
|
||||
Watcher.log("plugin terminated unexpectedly")
|
||||
cleanup(code)
|
||||
})
|
||||
}
|
||||
|
||||
vscodeWebExtensions.stderr.on("data", (d) => process.stderr.write(d))
|
||||
vscode.stderr.on("data", (d) => process.stderr.write(d))
|
||||
tsc.stderr.on("data", (d) => process.stderr.write(d))
|
||||
|
||||
if (plugin) {
|
||||
plugin.stderr.on("data", (d) => process.stderr.write(d))
|
||||
}
|
||||
|
||||
let startingVscode = false
|
||||
let startedVscode = false
|
||||
onLine(vscode, (line, original) => {
|
||||
console.log("[vscode]", original)
|
||||
// Wait for watch-client since "Finished compilation" will appear multiple
|
||||
// times before the client starts building.
|
||||
if (!startingVscode && line.includes("Starting watch-client")) {
|
||||
startingVscode = true
|
||||
} else if (startingVscode && line.includes("Finished compilation")) {
|
||||
if (startedVscode) {
|
||||
restartServer()
|
||||
}
|
||||
startedVscode = true
|
||||
}
|
||||
})
|
||||
|
||||
onLine(tsc, (line, original) => {
|
||||
// tsc outputs blank lines; skip them.
|
||||
if (line !== "") {
|
||||
console.log("[tsc]", original)
|
||||
}
|
||||
if (line.includes("Watching for file changes")) {
|
||||
restartServer()
|
||||
}
|
||||
})
|
||||
|
||||
if (plugin) {
|
||||
onLine(plugin, (line, original) => {
|
||||
// tsc outputs blank lines; skip them.
|
||||
if (line !== "") {
|
||||
console.log("[plugin]", original)
|
||||
}
|
||||
if (line.includes("Watching for file changes")) {
|
||||
restartServer()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
apiVersion: v2
|
||||
name: code-server
|
||||
description: A Helm chart for coder/code-server
|
||||
description: A Helm chart for cdr/code-server
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
|
@ -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.1.0
|
||||
version: 1.0.3
|
||||
|
||||
# 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.0.2
|
||||
appVersion: 3.12.0
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "code-server.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "code-server.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward --namespace {{ .Release.Namespace }} service/{{ include "code-server.fullname" . }} 8080:http
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
||||
|
||||
Administrator credentials:
|
||||
|
|
|
@ -21,7 +21,6 @@ spec:
|
|||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }}
|
||||
{{- if .Values.hostnameOverride }}
|
||||
hostname: {{ .Values.hostnameOverride }}
|
||||
{{- end }}
|
||||
|
@ -143,12 +142,6 @@ spec:
|
|||
secretName: {{ .secretName }}
|
||||
defaultMode: {{ .defaultMode }}
|
||||
{{- end }}
|
||||
{{- range .Values.extraConfigmapMounts }}
|
||||
- name: {{ .name }}
|
||||
configMap:
|
||||
name: {{ .configMap }}
|
||||
defaultMode: {{ .defaultMode }}
|
||||
{{- end }}
|
||||
{{- range .Values.extraVolumeMounts }}
|
||||
- name: {{ .name }}
|
||||
{{- if .existingClaim }}
|
||||
|
|
|
@ -18,9 +18,6 @@ metadata:
|
|||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.ingressClassName }}
|
||||
ingressClassName: {{ .Values.ingress.ingressClassName }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
|
|
|
@ -6,15 +6,10 @@ replicaCount: 1
|
|||
|
||||
image:
|
||||
repository: codercom/code-server
|
||||
tag: '4.0.2'
|
||||
tag: '3.12.0'
|
||||
pullPolicy: Always
|
||||
|
||||
# Specifies one or more secrets to be used when pulling images from a
|
||||
# private container repository
|
||||
# https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry
|
||||
imagePullSecrets: []
|
||||
# - name: registry-creds
|
||||
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
hostnameOverride: ""
|
||||
|
@ -33,6 +28,14 @@ podAnnotations: {}
|
|||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
|
@ -40,12 +43,13 @@ service:
|
|||
ingress:
|
||||
enabled: false
|
||||
#annotations:
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
#hosts:
|
||||
# - host: code-server.example.loc
|
||||
# paths:
|
||||
# - /
|
||||
ingressClassName: ""
|
||||
|
||||
#tls:
|
||||
# - secretName: code-server
|
||||
# hosts:
|
||||
|
@ -123,6 +127,10 @@ persistence:
|
|||
# existingClaim: ""
|
||||
# hostPath: /data
|
||||
|
||||
serviceAccount:
|
||||
create: true
|
||||
name:
|
||||
|
||||
## Enable an Specify container in extraContainers.
|
||||
## This is meant to allow adding code-server dependencies, like docker-dind.
|
||||
extraContainers: |
|
||||
|
|
|
@ -10,13 +10,11 @@ RUN apt-get update \
|
|||
man \
|
||||
nano \
|
||||
git \
|
||||
git-lfs \
|
||||
procps \
|
||||
openssh-client \
|
||||
sudo \
|
||||
vim.tiny \
|
||||
lsb-release \
|
||||
&& git lfs install \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# https://wiki.debian.org/Locale#Manually
|
||||
|
|
|
@ -18,4 +18,4 @@ if [ "${DOCKER_USER-}" ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
exec dumb-init /usr/bin/code-server "$@"
|
||||
dumb-init /usr/bin/code-server "$@"
|
||||
|
|
|
@ -10,23 +10,23 @@ main() {
|
|||
echo "Checking environment variables"
|
||||
|
||||
# We need VERSION to bump the brew formula
|
||||
if ! is_env_var_set "VERSION"; then
|
||||
if is_env_var_set "VERSION"; then
|
||||
echo "VERSION is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We need HOMEBREW_GITHUB_API_TOKEN to push up commits
|
||||
if ! is_env_var_set "HOMEBREW_GITHUB_API_TOKEN"; then
|
||||
if is_env_var_set "HOMEBREW_GITHUB_API_TOKEN"; then
|
||||
echo "HOMEBREW_GITHUB_API_TOKEN is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# NOTE: we need to make sure coderci/homebrew-core
|
||||
# NOTE: we need to make sure cdrci/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
|
||||
echo "Cloning cdrci/homebrew-core"
|
||||
git clone https://github.com/cdrci/homebrew-core.git
|
||||
|
||||
# Make sure the git clone step is successful
|
||||
if directory_exists "homebrew-core"; then
|
||||
|
@ -57,7 +57,7 @@ main() {
|
|||
echo "Merging in latest Homebrew/homebrew-core changes"
|
||||
git merge upstream/master
|
||||
|
||||
echo "Pushing changes to coderci/homebrew-core fork on GitHub"
|
||||
echo "Pushing changes to cdrci/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
|
||||
|
@ -86,7 +86,7 @@ main() {
|
|||
# Export the variables so git sees them
|
||||
export HOMEBREW_GITHUB_API_TOKEN="$HOMEBREW_GITHUB_API_TOKEN"
|
||||
export GIT_ASKPASS="$PATH_TO_ASKPASS"
|
||||
git push https://coder-oss@github.com/coder-oss/homebrew-core.git --all
|
||||
git push https://cdr-oss@github.com/cdr-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
|
||||
|
|
|
@ -1,15 +1,36 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# See if this version already exists on Docker Hub.
|
||||
function version_exists() {
|
||||
local output
|
||||
output=$(curl --silent "https://index.docker.io/v1/repositories/codercom/code-server/tags/$VERSION")
|
||||
if [[ $output == "Tag not found" ]]; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
# ci/lib.sh sets VERSION and provides download_artifact here
|
||||
source ./ci/lib.sh
|
||||
|
||||
if version_exists; then
|
||||
echo "$VERSION is already pushed"
|
||||
return
|
||||
fi
|
||||
|
||||
# Download the release-packages artifact
|
||||
download_artifact release-packages ./release-packages
|
||||
|
||||
# Login to Docker
|
||||
if [[ ${CI-} ]]; then
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
fi
|
||||
|
||||
docker buildx bake -f ci/release-image/docker-bake.hcl --push
|
||||
}
|
||||
|
||||
|
|
|
@ -4,144 +4,27 @@ set -euo pipefail
|
|||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
source ./ci/lib.sh
|
||||
source ./ci/steps/steps-lib.sh
|
||||
|
||||
## Authentication tokens
|
||||
# Needed to publish on NPM
|
||||
if ! is_env_var_set "NPM_TOKEN"; then
|
||||
echo "NPM_TOKEN is not set. Cannot publish to npm without credentials."
|
||||
exit 1
|
||||
# npm view won't exit with non-zero so we have to check the output.
|
||||
local hasVersion
|
||||
hasVersion=$(npm view "code-server@$VERSION" version)
|
||||
if [[ $hasVersion == "$VERSION" ]]; then
|
||||
echo "$VERSION is already published"
|
||||
return
|
||||
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.
|
||||
# This is because npm won't publish your package unless it's a new version.
|
||||
# i.e. for development, we bump the version to <current version>-<pr number>-<commit sha>
|
||||
# example: "version": "4.0.1-4769-ad7b23cfe6ffd72914e34781ef7721b129a23040"
|
||||
# We need the current package.json VERSION
|
||||
if ! is_env_var_set "VERSION"; then
|
||||
echo "VERSION is not set. Cannot publish to npm without VERSION."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We use this to grab the PR_NUMBER
|
||||
if ! is_env_var_set "GITHUB_REF"; then
|
||||
echo "GITHUB_REF is not set. Are you running this locally? We rely on values provided by GitHub."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We use this when setting NPM_VERSION
|
||||
if ! is_env_var_set "GITHUB_SHA"; then
|
||||
echo "GITHUB_SHA is not set. Are you running this locally? We rely on values provided by GitHub."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We use this to determine the NPM_ENVIRONMENT
|
||||
if ! is_env_var_set "GITHUB_EVENT_NAME"; then
|
||||
echo "GITHUB_EVENT_NAME is not set. Are you running this locally? We rely on values provided by GitHub."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# This allows us to publish to npm in CI workflows
|
||||
if [[ ${CI-} ]]; then
|
||||
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
|
||||
fi
|
||||
|
||||
## Environment
|
||||
# This string is used to determine how we should tag the npm release.
|
||||
# Environment can be one of three choices:
|
||||
# "development" - this means we tag with the PR number, allowing
|
||||
# a developer to install this version with `yarn add code-server@<pr-number>`
|
||||
# "staging" - this means we tag with `beta`, allowing
|
||||
# a developer to install this version with `yarn add code-server@beta`
|
||||
# "production" - this means we tag with `latest` (default), allowing
|
||||
# a developer to install this version with `yarn add code-server@latest`
|
||||
if ! is_env_var_set "NPM_ENVIRONMENT"; then
|
||||
echo "NPM_ENVIRONMENT is not set. Determining in script based on GITHUB environment variables."
|
||||
|
||||
if [[ "$GITHUB_EVENT_NAME" == 'push' && "$GITHUB_REF" == 'refs/heads/main' ]]; then
|
||||
NPM_ENVIRONMENT="staging"
|
||||
else
|
||||
NPM_ENVIRONMENT="development"
|
||||
fi
|
||||
|
||||
echo "Using npm environment: $NPM_ENVIRONMENT"
|
||||
fi
|
||||
|
||||
# NOTE@jsjoeio - this script assumes we have the artifact downloaded on disk
|
||||
# That happens in CI as a step before we run this.
|
||||
download_artifact npm-package ./release-npm-package
|
||||
# https://github.com/actions/upload-artifact/issues/38
|
||||
tar -xzf release-npm-package/package.tar.gz
|
||||
|
||||
# Ignore symlink when publishing npm package
|
||||
# See: https://github.com/coder/code-server/pull/3935
|
||||
# See: https://github.com/cdr/code-server/pull/3935
|
||||
echo "node_modules.asar" > release/.npmignore
|
||||
|
||||
# NOTES:@jsjoeio
|
||||
# We only need to run npm version for "development" and "staging".
|
||||
# This is because our release:prep script automatically bumps the version
|
||||
# in the package.json and we commit it as part of the release PR.
|
||||
if [[ "$NPM_ENVIRONMENT" == "production" ]]; then
|
||||
NPM_VERSION="$VERSION"
|
||||
# This means the npm version will be published as "stable"
|
||||
# and installed when a user runs `yarn install code-server`
|
||||
NPM_TAG="latest"
|
||||
else
|
||||
COMMIT_SHA="$GITHUB_SHA"
|
||||
echo "Not a production environment"
|
||||
echo "Found environment: $NPM_ENVIRONMENT"
|
||||
echo "Manually bumping npm version..."
|
||||
|
||||
if [[ "$NPM_ENVIRONMENT" == "staging" ]]; then
|
||||
NPM_VERSION="$VERSION-beta-$COMMIT_SHA"
|
||||
# This means the npm version will be tagged with "beta"
|
||||
# and installed when a user runs `yarn install code-server@beta`
|
||||
NPM_TAG="beta"
|
||||
fi
|
||||
|
||||
if [[ "$NPM_ENVIRONMENT" == "development" ]]; then
|
||||
# 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"
|
||||
# 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"
|
||||
|
||||
# We modify the version in the package.json
|
||||
# to be the current version + the PR number + commit SHA
|
||||
# or we use current version + beta + commit SHA
|
||||
# Example: "version": "4.0.1-4769-ad7b23cfe6ffd72914e34781ef7721b129a23040"
|
||||
# Example: "version": "4.0.1-beta-ad7b23cfe6ffd72914e34781ef7721b129a23040"
|
||||
pushd release
|
||||
# NOTE:@jsjoeio
|
||||
# I originally tried to use `yarn version` but ran into issues and abandoned it.
|
||||
npm version "$NPM_VERSION"
|
||||
popd
|
||||
fi
|
||||
|
||||
# We need to make sure we haven't already published the version.
|
||||
# This is because npm view won't exit with non-zero so we have
|
||||
# to check the output.
|
||||
local hasVersion
|
||||
hasVersion=$(npm view "code-server@$NPM_VERSION" version)
|
||||
if [[ $hasVersion == "$NPM_VERSION" ]]; then
|
||||
echo "$NPM_VERSION is already published"
|
||||
return
|
||||
fi
|
||||
|
||||
yarn publish --non-interactive release --tag "$NPM_TAG"
|
||||
yarn publish --non-interactive release
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
|
@ -3,16 +3,13 @@
|
|||
# Contributing
|
||||
|
||||
- [Requirements](#requirements)
|
||||
- [Linux-specific requirements](#linux-specific-requirements)
|
||||
- [Creating pull requests](#creating-pull-requests)
|
||||
- [Commits and commit history](#commits-and-commit-history)
|
||||
- [Development workflow](#development-workflow)
|
||||
- [Updates to VS Code](#updates-to-vs-code)
|
||||
- [Build](#build)
|
||||
- [Help](#help)
|
||||
- [Test](#test)
|
||||
- [Test](#test)
|
||||
- [Unit tests](#unit-tests)
|
||||
- [Script tests](#script-tests)
|
||||
- [Integration tests](#integration-tests)
|
||||
- [End-to-end tests](#end-to-end-tests)
|
||||
- [Structure](#structure)
|
||||
|
@ -35,7 +32,7 @@ Here is what is needed:
|
|||
- [`git-lfs`](https://git-lfs.github.com)
|
||||
- [`yarn`](https://classic.yarnpkg.com/en/)
|
||||
- Used to install JS packages and run scripts
|
||||
- [`nfpm`](https://nfpm.goreleaser.com/)
|
||||
- [`nfpm`](https://classic.yarnpkg.com/en/)
|
||||
- Used to build `.deb` and `.rpm` packages
|
||||
- [`jq`](https://stedolan.github.io/jq/)
|
||||
- Used to build code-server releases
|
||||
|
@ -44,24 +41,16 @@ 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)
|
||||
- `build-essential` (Linux only - used by VS Code)
|
||||
- Get this by running `apt-get install -y build-essential`
|
||||
- `rsync` and `unzip`
|
||||
- Used for code-server releases
|
||||
- `bats`
|
||||
- Used to run script unit tests
|
||||
|
||||
### Linux-specific requirements
|
||||
|
||||
If you're developing code-server on Linux, make sure you have installed or install the following dependencies:
|
||||
|
||||
```shell
|
||||
sudo apt-get install build-essential g++ libx11-dev libxkbfile-dev libsecret-1-dev python-is-python3
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
Please create a [GitHub Issue](https://github.com/coder/code-server/issues) that
|
||||
Please create a [GitHub Issue](https://github.com/cdr/code-server/issues) that
|
||||
includes context for issues that you see. You can skip this if the proposed fix
|
||||
is minor.
|
||||
|
||||
|
@ -78,37 +67,31 @@ 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/).
|
||||
```shell
|
||||
yarn
|
||||
yarn watch
|
||||
# Visit http://localhost:8080 once the build is completed.
|
||||
```
|
||||
|
||||
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 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.
|
||||
`yarn watch` will live reload changes to the source.
|
||||
|
||||
### Updates to VS 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>"
|
||||
"vscode": "cdr/vscode#X.XX.X-code-server"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. From the code-server **project root**, run `yarn install`.
|
||||
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
|
||||
1. 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.
|
||||
4. Open a PR
|
||||
1. Open a PR
|
||||
|
||||
> Watch for updates to
|
||||
> `vendor/modules/code-oss-dev/src/vs/code/browser/workbench/workbench.html`. You may need to
|
||||
|
@ -146,18 +129,13 @@ yarn package
|
|||
> If you need your builds to support older distros, run the build commands
|
||||
> inside a Docker container with all the build requirements installed.
|
||||
|
||||
### Help
|
||||
### Test
|
||||
|
||||
If you get stuck or need help, you can always start a new GitHub Discussion [here](https://github.com/coder/code-server/discussions). One of the maintainers will respond and help you out.
|
||||
|
||||
## Test
|
||||
|
||||
There are four kinds of tests in code-server:
|
||||
There are three kinds of tests in code-server:
|
||||
|
||||
1. Unit tests
|
||||
2. Script tests
|
||||
3. Integration tests
|
||||
4. End-to-end tests
|
||||
2. Integration tests
|
||||
3. End-to-end tests
|
||||
|
||||
### Unit tests
|
||||
|
||||
|
@ -168,14 +146,6 @@ These live under [test/unit](../test/unit).
|
|||
|
||||
We use unit tests for functions and things that can be tested in isolation. The file structure is modeled closely after `/src` so it's easy for people to know where test files should live.
|
||||
|
||||
### Script tests
|
||||
|
||||
Our script tests are written in bash and run using [bats](https://github.com/bats-core/bats-core).
|
||||
|
||||
These tests live under `test/scripts`.
|
||||
|
||||
We use these to test anything related to our scripts (most of which live under `ci`).
|
||||
|
||||
### Integration tests
|
||||
|
||||
These are a work in progress. We build code-server and run a script called
|
||||
|
|
75
docs/FAQ.md
75
docs/FAQ.md
|
@ -26,8 +26,7 @@
|
|||
- [Can I use Docker in a code-server container?](#can-i-use-docker-in-a-code-server-container)
|
||||
- [How do I disable telemetry?](#how-do-i-disable-telemetry)
|
||||
- [What's the difference between code-server and Theia?](#whats-the-difference-between-code-server-and-theia)
|
||||
- [What's the difference between code-server and OpenVSCode-Server?](#whats-the-difference-between-code-server-and-openvscode-server)
|
||||
- [What's the difference between code-server and GitHub Codespaces?](#whats-the-difference-between-code-server-and-github-codespaces)
|
||||
- [What's the difference between code-server and VS Code Codespaces?](#whats-the-difference-between-code-server-and-vs-code-codespaces)
|
||||
- [Does code-server have any security login validation?](#does-code-server-have-any-security-login-validation)
|
||||
- [Are there community projects involving code-server?](#are-there-community-projects-involving-code-server)
|
||||
- [How do I change the port?](#how-do-i-change-the-port)
|
||||
|
@ -37,7 +36,7 @@
|
|||
## Questions?
|
||||
|
||||
Please file all questions and support requests at
|
||||
<https://github.com/coder/code-server/discussions>.
|
||||
<https://github.com/cdr/code-server/discussions>.
|
||||
|
||||
## How should I expose code-server to the internet?
|
||||
|
||||
|
@ -101,28 +100,32 @@ Service](https://cdn.vsassets.io/v/M146_20190123.39/_content/Microsoft-Visual-St
|
|||
> Visual Studio Products and Services.
|
||||
|
||||
Because of this, we can't offer any extensions on Microsoft's marketplace.
|
||||
Instead, we use the [Open-VSX extension gallery](https://open-vsx.org), which is also used by various other forks.
|
||||
It isn't perfect, but its getting better by the day with more and more extensions.
|
||||
|
||||
We also offer our own marketplace for open source extensions, but plan to
|
||||
deprecate it at a future date and completely migrate to Open-VSX.
|
||||
Instead, we've created a marketplace offering open-source extensions. The
|
||||
marketplace works by scraping GitHub for VS Code extensions and building them.
|
||||
|
||||
These are the closed-source extensions that are presently unavailable:
|
||||
|
||||
1. [Live Share](https://visualstudio.microsoft.com/services/live-share). We may
|
||||
implement something similar (see
|
||||
[#33](https://github.com/coder/code-server/issues/33))
|
||||
[#33](https://github.com/cdr/code-server/issues/33))
|
||||
1. [Remote Extensions (SSH, Containers,
|
||||
WSL)](https://github.com/microsoft/vscode-remote-release). We may implement
|
||||
these again at some point, see
|
||||
([#1315](https://github.com/coder/code-server/issues/1315)).
|
||||
([#1315](https://github.com/cdr/code-server/issues/1315)).
|
||||
|
||||
For more about the closed source portions of VS Code, see [vscodium/vscodium](https://github.com/VSCodium/vscodium#why-does-this-exist).
|
||||
|
||||
## How can I request an extension that's missing from the marketplace?
|
||||
|
||||
To add an extension to Open-VSX, please see [open-vsx/publish-extensions](https://github.com/open-vsx/publish-extensions).
|
||||
We no longer plan to add new extensions to our legacy extension gallery.
|
||||
We are in the process of transitioning to [Open VSX](https://open-vsx.org/).
|
||||
Once we've [implemented Open
|
||||
VSX](https://github.com/eclipse/openvsx/issues/249), we can finalize this
|
||||
transition. As such, we are not currently accepting new extension requests.
|
||||
|
||||
In the meantime, we suggest:
|
||||
|
||||
- [Switching to Open VSX](#how-do-i-configure-the-marketplace-url) now
|
||||
- Downloading and [installing the extension manually](#installing-an-extension-manually)
|
||||
|
||||
## How do I install an extension?
|
||||
|
||||
|
@ -155,19 +158,20 @@ You can also download extensions using the command line. For instance,
|
|||
downloading from OpenVSX can be done like this:
|
||||
|
||||
```shell
|
||||
code-server --install-extension <extension id>
|
||||
SERVICE_URL=https://open-vsx.org/vscode/gallery ITEM_URL=https://open-vsx.org/vscode/item code-server --install-extension <extension id>
|
||||
```
|
||||
|
||||
## How do I use my own extensions marketplace?
|
||||
|
||||
If you own a marketplace that implements the VS Code Extension Gallery API, you
|
||||
can point code-server to it by setting `$EXTENSIONS_GALLERY`.
|
||||
This corresponds directly with the `extensionsGallery` entry in in VS Code's `product.json`.
|
||||
can point code-server to it by setting `$SERVICE_URL` and `$ITEM_URL`. These correspond directly
|
||||
to `serviceUrl` and `itemUrl` in VS Code's `product.json`.
|
||||
|
||||
For example, to use the legacy Coder extensions marketplace:
|
||||
For example, to use [open-vsx.org](https://open-vsx.org), run:
|
||||
|
||||
```bash
|
||||
export EXTENSIONS_GALLERY='{"serviceUrl": "https://extensions.coder.com/api"}'
|
||||
export SERVICE_URL=https://open-vsx.org/vscode/gallery
|
||||
export ITEM_URL=https://open-vsx.org/vscode/item
|
||||
```
|
||||
|
||||
Though you can technically use Microsoft's marketplace in this manner, we
|
||||
|
@ -222,7 +226,7 @@ You may have to give Node.js full disk access, since it doesn't implement any of
|
|||
Privacy** > **Privacy** > **Full Disk Access**. Then, click the 🔒 to unlock,
|
||||
click **+**, and select the Node.js binary you located in the previous step.
|
||||
|
||||
See [#2794](https://github.com/coder/code-server/issues/2794) for additional context.
|
||||
See [#2794](https://github.com/cdr/code-server/issues/2794) for additional context.
|
||||
|
||||
## How do I direct server-side requests through a proxy?
|
||||
|
||||
|
@ -302,7 +306,7 @@ after a predetermined amount of time, you can do so by checking continuously for
|
|||
the last modified time on the heartbeat file. If it is older than X minutes (or
|
||||
whatever amount of time you'd like), you can kill code-server.
|
||||
|
||||
Eventually, [#1636](https://github.com/coder/code-server/issues/1636) will make
|
||||
Eventually, [#1636](https://github.com/cdr/code-server/issues/1636) will make
|
||||
this process better.
|
||||
|
||||
## How do I change the password?
|
||||
|
@ -373,31 +377,18 @@ for extensions.
|
|||
|
||||
Theia doesn't allow you to reuse your existing VS Code config.
|
||||
|
||||
## What's the difference between code-server and OpenVSCode-Server?
|
||||
## What's the difference between code-server and VS Code Codespaces?
|
||||
|
||||
code-server and OpenVSCode-Server both allow you to access VS Code via a
|
||||
browser. The two projects also use their own [forks of VS Code](https://github.com/coder/vscode) to
|
||||
leverage modern VS Code APIs and stay up to date with the upsteam version.
|
||||
Both code-server and VS Code Codespaces allow you to access VS Code via a
|
||||
browser.
|
||||
|
||||
However, OpenVSCode-Server is scoped at only making VS Code available in the web browser.
|
||||
code-server includes some other features:
|
||||
VS Code Codespaces, however, is a closed-source, paid service offered by
|
||||
Microsoft. While you can self-host environments with VS Code Codespaces, you
|
||||
still need an Azure billing account, and you must access VS Code via the
|
||||
Codespaces web dashboard instead of connecting directly to it.
|
||||
|
||||
- password auth
|
||||
- proxy web ports
|
||||
- certificate support
|
||||
- plugin API
|
||||
- settings sync (coming soon)
|
||||
|
||||
For more details, see [this discussion post](https://github.com/coder/code-server/discussions/4267#discussioncomment-1411583).
|
||||
|
||||
## What's the difference between code-server and GitHub Codespaces?
|
||||
|
||||
Both code-server and GitHub Codespaces allow you to access VS Code via a
|
||||
browser. GitHub Codespaces, however, is a closed-source, paid service offered by
|
||||
GitHub and Microsoft.
|
||||
|
||||
On the other hand, code-server is self-hosted, free, open-source, and
|
||||
can be run on any machine with few limitations.
|
||||
On the other hand, code-server is free, open-source, and can be run on any
|
||||
machine with few limitations.
|
||||
|
||||
## Does code-server have any security login validation?
|
||||
|
||||
|
@ -406,7 +397,7 @@ minute plus an additional twelve per hour.
|
|||
|
||||
## Are there community projects involving code-server?
|
||||
|
||||
Visit the [awesome-code-server](https://github.com/coder/awesome-code-server)
|
||||
Visit the [awesome-code-server](https://github.com/cdr/awesome-code-server)
|
||||
repository to view community projects and guides with code-server! Feel free to
|
||||
add your own!
|
||||
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
- [Docker](#docker)
|
||||
- [Homebrew](#homebrew)
|
||||
- [npm](#npm)
|
||||
- [Syncing with Upstream VS Code](#syncing-with-upstream-vs-code)
|
||||
- [Testing](#testing)
|
||||
- [Documentation](#documentation)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
|
@ -37,23 +35,23 @@ Current maintainers:
|
|||
- @TeffenEllis
|
||||
- @jsjoeio
|
||||
|
||||
Occasionally, other Coder employees may step in time to time to assist with code-server.
|
||||
Occassionally, other Coder employees may step in time to time to assist with code-server.
|
||||
|
||||
### Onboarding
|
||||
|
||||
To onboard a new maintainer to the project, please make sure to do the following:
|
||||
|
||||
- [ ] Add to [coder/code-server-reviewers](https://github.com/orgs/coder/teams/code-server-reviewers)
|
||||
- [ ] Add as Admin under [Repository Settings > Access](https://github.com/coder/code-server/settings/access)
|
||||
- [ ] Add to [cdr/code-server-reviewers](https://github.com/orgs/cdr/teams/code-server-reviewers)
|
||||
- [ ] Add as Admin under [Repository Settings > Access](https://github.com/cdr/code-server/settings/access)
|
||||
- [ ] Add to [npm Coder org](https://www.npmjs.com/org/coder)
|
||||
- [ ] Add as [AUR maintainer](https://aur.archlinux.org/packages/code-server/) (talk to Colin)
|
||||
- [ ] Introduce to community via Discussion (see [example](https://github.com/coder/code-server/discussions/3955))
|
||||
- [ ] Introduce to community via Discussion (see [example](https://github.com/cdr/code-server/discussions/3955))
|
||||
|
||||
### Offboarding
|
||||
|
||||
Very similar to Onboarding but Remove maintainer from all teams and revoke access. Please also do the following:
|
||||
|
||||
- [ ] Write farewell post via Discussion (see [example](https://github.com/coder/code-server/discussions/3933))
|
||||
- [ ] Write farewell post via Discussion (see [example](https://github.com/cdr/code-server/discussions/3933))
|
||||
|
||||
## Workflow
|
||||
|
||||
|
@ -64,7 +62,7 @@ contributing on day one.
|
|||
### Milestones
|
||||
|
||||
We operate mainly using
|
||||
[milestones](https://github.com/coder/code-server/milestones). This was heavily
|
||||
[milestones](https://github.com/cdr/code-server/milestones). This was heavily
|
||||
inspired by our friends over at [vscode](https://github.com/microsoft/vscode).
|
||||
|
||||
Here are the milestones we use and how we use them:
|
||||
|
@ -127,7 +125,8 @@ the issue.
|
|||
|
||||
### Merge strategies
|
||||
|
||||
For most things, we recommend the **squash and merge** strategy. There
|
||||
For most things, we recommend the **squash and merge** strategy. If you're
|
||||
updating `lib/vscode`, we suggest using the **rebase and merge** strategy. There
|
||||
may be times where **creating a merge commit** makes sense as well. Use your
|
||||
best judgment. If you're unsure, you can always discuss in the PR with the team.
|
||||
|
||||
|
@ -185,12 +184,12 @@ If you're the current release manager, follow these steps:
|
|||
artifacts, publish the NPM package from `npm-package`, and publish the Docker
|
||||
Hub image from `release-images`.
|
||||
1. Update the AUR package. Instructions for updating the AUR package are at
|
||||
[coder/code-server-aur](https://github.com/coder/code-server-aur).
|
||||
[cdr/code-server-aur](https://github.com/cdr/code-server-aur).
|
||||
1. Wait for the npm package to be published.
|
||||
|
||||
#### AUR
|
||||
|
||||
We publish to AUR as a package [here](https://aur.archlinux.org/packages/code-server/). This process is manual and can be done by following the steps in [this repo](https://github.com/coder/code-server-aur).
|
||||
We publish to AUR as a package [here](https://aur.archlinux.org/packages/code-server/). This process is manual and can be done by following the steps in [this repo](https://github.com/cdr/code-server-aur).
|
||||
|
||||
#### Docker
|
||||
|
||||
|
@ -202,7 +201,7 @@ This is currently automated with the release process.
|
|||
|
||||
We publish code-server on Homebrew [here](https://github.com/Homebrew/homebrew-core/blob/master/Formula/code-server.rb).
|
||||
|
||||
This is currently automated with the release process (but may fail occasionally). If it does, run this locally:
|
||||
This is currently automated with the release process (but may fail occassionally). If it does, run this locally:
|
||||
|
||||
```shell
|
||||
# Replace VERSION with version
|
||||
|
@ -215,40 +214,13 @@ We publish code-server as a npm package [here](https://www.npmjs.com/package/cod
|
|||
|
||||
This is currently automated with the release process.
|
||||
|
||||
## Syncing with Upstream VS Code
|
||||
|
||||
The VS Code portion of code-server lives under [`coder/vscode`](https://github.com/coder/vscode). To update VS Code for code-server, follow these steps:
|
||||
|
||||
1. `git checkout -b vscode-update` - Create a new branch locally based off `main`
|
||||
2. `git fetch upstream` - Fetch upstream (VS Code)'s latest branches
|
||||
3. `git merge upstream/release/1.64` - Merge it locally
|
||||
1. replace `1.64` with the version you're upgrading to
|
||||
1. If there are merge conflicts, commit first, then fix them locally.
|
||||
4. Open a PR merging your branch (`vscode-update`) into `main` and add the code-server review team
|
||||
|
||||
Ideally, our fork stays as close to upstream as possible. See the differences between our fork and upstream [here](https://github.com/microsoft/vscode/compare/main...coder:main).
|
||||
|
||||
## Testing
|
||||
|
||||
Our testing structure is laid out under our [Contributing docs](https://coder.com/docs/code-server/latest/CONTRIBUTING#test).
|
||||
|
||||
We hope to eventually hit 100% test coverage with our unit tests, and maybe one day our scripts (coverage not tracked currently).
|
||||
|
||||
If you're ever looking to add more tests, here are a few ways to get started:
|
||||
|
||||
- run `yarn test:unit` and look at the coverage chart. You'll see all the uncovered lines. This is a good place to start.
|
||||
- look at `test/scripts` to see which scripts are tested. We can always use more tests there.
|
||||
- look at `test/e2e`. We can always use more end-to-end tests.
|
||||
|
||||
Otherwise, talk to a current maintainer and ask which part of the codebase is lacking most when it comes to tests.
|
||||
|
||||
## Documentation
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
Our docs are hosted on [Vercel](https://vercel.com/). Vercel only shows logs in realtime, which means you need to have the logs open in one tab and reproduce your error in another tab. Since our logs are private to Coder the organization, you can only follow these steps if you're a Coder employee. Ask a maintainer for help if you need it.
|
||||
|
||||
Taking a real scenario, let's say you wanted to troubleshoot [this docs change](https://github.com/coder/code-server/pull/4042). Here is how you would do it:
|
||||
Taking a real scenario, let's say you wanted to troubleshoot [this docs change](https://github.com/cdr/code-server/pull/4042). Here is how you would do it:
|
||||
|
||||
1. Go to https://vercel.com/codercom/codercom
|
||||
2. Click "View Function Logs"
|
||||
|
|
|
@ -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.0.2 docs](https://img.shields.io/static/v1?label=Docs&message=see%20v4.0.2%20&color=blue)](https://github.com/coder/code-server/tree/v4.0.2/docs)
|
||||
[!["GitHub Discussions"](https://img.shields.io/badge/%20GitHub-%20Discussions-gray.svg?longCache=true&logo=github&colorB=purple)](https://github.com/cdr/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://cdr.co/join-community) [![Twitter Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=social)](https://twitter.com/coderhq) [![codecov](https://codecov.io/gh/cdr/code-server/branch/main/graph/badge.svg?token=5iM9farjnC)](https://codecov.io/gh/cdr/code-server) [![See v3.12.0 docs](https://img.shields.io/static/v1?label=Docs&message=see%20v3.12.0%20&color=blue)](https://github.com/cdr/code-server/tree/v3.12.0/docs)
|
||||
|
||||
Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and
|
||||
access it in the browser.
|
||||
|
@ -14,9 +14,6 @@ access it in the browser.
|
|||
- Preserve battery life when you're on the go; all intensive tasks run on your
|
||||
server
|
||||
|
||||
| 🔔 code-server is a free browser-based IDE while [Coder](https://coder.com/) is our enterprise developer workspace platform. For more information, visit [Coder.com](https://coder.com/docs/comparison)
|
||||
| ---
|
||||
|
||||
## Requirements
|
||||
|
||||
See [requirements](requirements.md) for minimum specs, as well as instructions
|
||||
|
@ -29,13 +26,13 @@ on how to set up a Google VM on which you can install code-server.
|
|||
There are three ways to get started:
|
||||
|
||||
1. Using the [install
|
||||
script](https://github.com/coder/code-server/blob/main/install.sh), which
|
||||
script](https://github.com/cdr/code-server/blob/main/install.sh), which
|
||||
automates most of the process. The script uses the system package manager if
|
||||
possible.
|
||||
2. Manually [installing
|
||||
code-server](https://coder.com/docs/code-server/latest/install)
|
||||
3. Using our one-click buttons and guides to [deploy code-server to a cloud
|
||||
provider](https://github.com/coder/deploy-code-server) ⚡
|
||||
provider](https://github.com/cdr/deploy-code-server) ⚡
|
||||
|
||||
If you use the install script, you can preview what occurs during the install
|
||||
process:
|
||||
|
@ -56,6 +53,10 @@ code-server.
|
|||
We also have an in-depth [setup and
|
||||
configuration](https://coder.com/docs/code-server/latest/guide) guide.
|
||||
|
||||
## TLS and authentication (beta)
|
||||
|
||||
To add TLS and authentication out of the box, use [code-server --link](https://coder.com/docs/code-server/latest/link).
|
||||
|
||||
## Questions?
|
||||
|
||||
See answers to [frequently asked
|
||||
|
|
|
@ -26,9 +26,9 @@ We use the following tools to help us stay on top of vulnerability mitigation.
|
|||
|
||||
Coder sponsors the development and maintenance of the code-server project. We will fix security issues within 90 days of receiving a report and publish the fix in a subsequent release. The code-server project does not provide backports or patch releases for security issues at this time.
|
||||
|
||||
| Version | Supported |
|
||||
| ------------------------------------------------------- | ------------------ |
|
||||
| [Latest](https://github.com/coder/code-server/releases) | :white_check_mark: |
|
||||
| Version | Supported |
|
||||
| ----------------------------------------------------- | ------------------ |
|
||||
| [Latest](https://github.com/cdr/code-server/releases) | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
# Running code-server using UserLAnd
|
||||
|
||||
1. Install UserLAnd from [Google Play](https://play.google.com/store/apps/details?id=tech.ula&hl=en_US&gl=US)
|
||||
2. Install an Ubuntu VM
|
||||
3. Start app
|
||||
4. Install Node.js, `curl` and `yarn` using `sudo apt install nodejs npm yarn curl -y`
|
||||
5. Install `nvm`:
|
||||
|
||||
```shell
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
||||
```
|
||||
|
||||
6. Exit the terminal using `exit` and then reopen the terminal
|
||||
7. Install and use Node.js 14:
|
||||
|
||||
```shell
|
||||
nvm install 14
|
||||
nvm use 14
|
||||
```
|
||||
|
||||
8. Install code-server globally on device with: `npm i -g code-server`
|
||||
9. Run code-server with `code-server`
|
||||
10. Access on localhost:8080 in your browser
|
|
@ -30,19 +30,15 @@ SERVICE_URL=https://open-vsx.org/vscode/gallery \
|
|||
|
||||
As `code-server` is based on VS Code, you can follow the steps described on Duckly's [Pair programming with VS Code](https://duckly.com/tools/vscode) page and skip the installation step.
|
||||
|
||||
## Code sharing using CodeTogether
|
||||
## Code sharing with CodeTogether
|
||||
|
||||
[CodeTogether](https://www.codetogether.com/) is a real-time cross-IDE replacement for Microsoft Live Share providing:
|
||||
[CodeTogether](https://www.codetogether.com/) is another service with cross-platform live collaborative features:
|
||||
|
||||
- Cross-IDE support - between VS Code, Eclipse, IntelliJ and IDEs based on them (browser or desktop)
|
||||
- Real-time editing - shared or individual cursors for pairing, mobbing, swarming, or whatever
|
||||
- P2P encrypted - servers can't decrypt the traffic ([Security Details](https://codetogether.com/download/security/))
|
||||
- SaaS or [On-premises](https://codetogether.com/on-premises/) options
|
||||
- Shared servers, terminals, and consoles
|
||||
- Unit Testing - with support for Red, Green, Refactor TDD
|
||||
- Joining via a web browser or your preferred IDE
|
||||
- Free unlimited 1 hour sessions with 4 participants
|
||||
- Multiple plans including [free or paid options](https://www.codetogether.com/pricing/)
|
||||
- Sharing ports,
|
||||
- Sharing, read/write terminals,
|
||||
- Joining via web browser or another IDE.
|
||||
|
||||
However, some of these are [paid options](https://www.codetogether.com/pricing/).
|
||||
|
||||
### Installing the CodeTogether extension
|
||||
|
||||
|
@ -60,6 +56,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.0.2/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/v3.12.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.
|
||||
|
|
415
docs/guide.md
415
docs/guide.md
|
@ -1,5 +1,396 @@
|
|||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
# Setup Guide
|
||||
|
||||
- [Expose code-server](#expose-code-server)
|
||||
- [Port forwarding via SSH](#port-forwarding-via-ssh)
|
||||
- [Using Let's Encrypt with Caddy](#using-lets-encrypt-with-caddy)
|
||||
- [Using Let's Encrypt with NGINX](#using-lets-encrypt-with-nginx)
|
||||
- [Using a self-signed certificate](#using-a-self-signed-certificate)
|
||||
- [External authentication](#external-authentication)
|
||||
- [HTTPS and self-signed certificates](#https-and-self-signed-certificates)
|
||||
- [Accessing web services](#accessing-web-services)
|
||||
- [Using a subdomain](#using-a-subdomain)
|
||||
- [Using a subpath](#using-a-subpath)
|
||||
- [Stripping `/proxy/<port>` from the request path](#stripping-proxyport-from-the-request-path)
|
||||
- [Proxying to create a React app](#proxying-to-create-a-react-app)
|
||||
- [Proxying to a Vue app](#proxying-to-a-vue-app)
|
||||
- [Setup Guide](#setup-guide)
|
||||
- [Expose code-server](#expose-code-server-1)
|
||||
- [Port forwarding via SSH](#port-forwarding-via-ssh-1)
|
||||
- [Using Let's Encrypt with Caddy](#using-lets-encrypt-with-caddy-1)
|
||||
- [Using Let's Encrypt with NGINX](#using-lets-encrypt-with-nginx-1)
|
||||
- [Using a self-signed certificate](#using-a-self-signed-certificate-1)
|
||||
- [External authentication](#external-authentication-1)
|
||||
- [HTTPS and self-signed certificates](#https-and-self-signed-certificates-1)
|
||||
- [Accessing web services](#accessing-web-services-1)
|
||||
- [Using a subdomain](#using-a-subdomain-1)
|
||||
- [Using a subpath](#using-a-subpath-1)
|
||||
- [Stripping `/proxy/<port>` from the request path](#stripping-proxyport-from-the-request-path-1)
|
||||
- [Proxying to create a React app](#proxying-to-create-a-react-app-1)
|
||||
- [Proxying to a Vue app](#proxying-to-a-vue-app-1)
|
||||
- [SSH into code-server on VS Code](#ssh-into-code-server-on-vs-code)
|
||||
- [Option 1: cloudflared tunnel](#option-1-cloudflared-tunnel)
|
||||
- [Option 2: ngrok tunnel](#option-2-ngrok-tunnel)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
This article will walk you through exposing code-server securely once you've
|
||||
completed the [installation process](install.md).
|
||||
|
||||
## Expose code-server
|
||||
|
||||
**Never** expose code-server directly to the internet without some form of
|
||||
authentication and encryption, otherwise someone can take over your machine via
|
||||
the terminal.
|
||||
|
||||
By default, code-server uses password authentication. As such, you must copy the
|
||||
password from code-server's config file to log in. To avoid exposing itself
|
||||
unnecessarily, code-server listens on `localhost`; this practice is fine for
|
||||
testing, but it doesn't work if you want to access code-server from a different
|
||||
machine.
|
||||
|
||||
> **Rate limits:** code-server rate limits password authentication attempts to
|
||||
> two per minute plus an additional twelve per hour.
|
||||
|
||||
There are several approaches to operating and exposing code-server securely:
|
||||
|
||||
- Port forwarding via SSH
|
||||
- Using Let's Encrypt with Caddy
|
||||
- Using Let's Encrypt with NGINX
|
||||
- Using a self-signed certificate
|
||||
|
||||
### Port forwarding via SSH
|
||||
|
||||
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 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,
|
||||
we recommend using another method, such as [Let's Encrypt](#let-encrypt) instead.
|
||||
|
||||
> To work properly, your environment should have WebSockets enabled, which
|
||||
> code-server uses to communicate between the browser and server.
|
||||
|
||||
1. SSH into your instance and edit the code-server config file to disable
|
||||
password authentication:
|
||||
|
||||
```console
|
||||
# Replaces "auth: password" with "auth: none" in the code-server config.
|
||||
sed -i.bak 's/auth: password/auth: none/' ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
2. Restart code-server:
|
||||
|
||||
```console
|
||||
sudo systemctl restart code-server@$USER
|
||||
```
|
||||
|
||||
3. Forward local port `8080` to `127.0.0.1:8080` on the remote instance by running the following command on your local machine:
|
||||
|
||||
```console
|
||||
# -N disables executing a remote shell
|
||||
ssh -N -L 8080:127.0.0.1:8080 [user]@<instance-ip>
|
||||
```
|
||||
|
||||
4. At this point, you can access code-server by pointing your web browser to `http://127.0.0.1:8080`.
|
||||
|
||||
5. If you'd like to make the port forwarding via SSH persistent, we recommend
|
||||
using [mutagen](https://mutagen.io/documentation/introduction/installation)
|
||||
to do so. Once you've installed mutagen, you can port forward as follows:
|
||||
|
||||
```console
|
||||
# This is the same as the above SSH command, but it runs in the background
|
||||
# continuously. Be sure to add `mutagen daemon start` to your ~/.bashrc to
|
||||
# start the mutagen daemon when you open a shell.
|
||||
|
||||
mutagen forward create --name=code-server tcp:127.0.0.1:8080 < instance-ip > :tcp:127.0.0.1:8080
|
||||
```
|
||||
|
||||
6. Optional, but highly recommended: add the following to `~/.ssh/config` so
|
||||
that you can detect bricked SSH connections:
|
||||
|
||||
```bash
|
||||
Host *
|
||||
ServerAliveInterval 5
|
||||
ExitOnForwardFailure yes
|
||||
```
|
||||
|
||||
> You can [forward your
|
||||
> SSH](https://developer.github.com/v3/guides/using-ssh-agent-forwarding/) and
|
||||
> [GPG agent](https://wiki.gnupg.org/AgentForwarding) to the instance to
|
||||
> securely access GitHub and sign commits without having to copy your keys.
|
||||
|
||||
### Using Let's Encrypt with Caddy
|
||||
|
||||
Using [Let's Encrypt](https://letsencrypt.org) is an option if you want to
|
||||
access code-server on an iPad or do not want to use SSH port forwarding.
|
||||
|
||||
1. This option requires that the remote machine be exposed to the internet. Make sure that your instance allows HTTP/HTTP traffic.
|
||||
|
||||
1. You'll need a domain name (if you don't have one, you can purchase one from
|
||||
[Google Domains](https://domains.google.com) or the domain service of your
|
||||
choice)). Once you have a domain name, add an A record to your domain that contains your
|
||||
instance's IP address.
|
||||
|
||||
1. Install [Caddy](https://caddyserver.com/docs/download#debian-ubuntu-raspbian):
|
||||
|
||||
```console
|
||||
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
|
||||
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/cfg/gpg/gpg.155B6D79CA56EA34.key' | sudo apt-key add -
|
||||
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/cfg/setup/config.deb.txt?distro=debian&version=any-version' | sudo tee -a /etc/apt/sources.list.d/caddy-stable.list
|
||||
sudo apt update
|
||||
sudo apt install caddy
|
||||
```
|
||||
|
||||
1. Replace `/etc/caddy/Caddyfile` using `sudo` so that the file looks like this:
|
||||
|
||||
```text
|
||||
mydomain.com
|
||||
|
||||
reverse_proxy 127.0.0.1:8080
|
||||
```
|
||||
|
||||
If you want to serve code-server from a sub-path, you can do so as follows:
|
||||
|
||||
```text
|
||||
mydomain.com/code/* {
|
||||
uri strip_prefix /code
|
||||
reverse_proxy 127.0.0.1:8080
|
||||
}
|
||||
```
|
||||
|
||||
Remember to replace `mydomain.com` with your domain name!
|
||||
|
||||
1. Reload Caddy:
|
||||
|
||||
```console
|
||||
sudo systemctl reload caddy
|
||||
```
|
||||
|
||||
At this point, you should be able to access code-server via
|
||||
`https://mydomain.com`.
|
||||
|
||||
### Using Let's Encrypt with NGINX
|
||||
|
||||
1. This option requires that the remote machine be exposed to the internet. Make sure that your instance allows HTTP/HTTP traffic.
|
||||
|
||||
1. You'll need a domain name (if you don't have one, you can purchase one from
|
||||
[Google Domains](https://domains.google.com) or the domain service of your
|
||||
choice)). Once you have a domain name, add an A record to your domain that contains your
|
||||
instance's IP address.
|
||||
|
||||
1. Install NGINX:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y nginx certbot python3-certbot-nginx
|
||||
```
|
||||
|
||||
1. Update `/etc/nginx/sites-available/code-server` using sudo with the following
|
||||
configuration:
|
||||
|
||||
```text
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name mydomain.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection upgrade;
|
||||
proxy_set_header Accept-Encoding gzip;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Be sure to replace `mydomain.com` with your domain name!
|
||||
|
||||
1. Enable the config:
|
||||
|
||||
```console
|
||||
sudo ln -s ../sites-available/code-server /etc/nginx/sites-enabled/code-server
|
||||
sudo certbot --non-interactive --redirect --agree-tos --nginx -d mydomain.com -m me@example.com
|
||||
```
|
||||
|
||||
Be sure to replace `me@example.com` with your actual email.
|
||||
|
||||
At this point, you should be able to access code-server via
|
||||
`https://mydomain.com`.
|
||||
|
||||
### Using a self-signed certificate
|
||||
|
||||
> Self signed certificates do not work with iPad; see [./ipad.md](./ipad.md) for
|
||||
> more information.
|
||||
|
||||
Before proceeding, we recommend familiarizing yourself with the [risks of
|
||||
self-signing a certificate for
|
||||
SSL](https://security.stackexchange.com/questions/8110).
|
||||
|
||||
We recommend self-signed certificates as a last resort, since self-signed
|
||||
certificates do not work with iPads and may cause unexpected issues with
|
||||
code-server. You should only proceed with this option if:
|
||||
|
||||
- You do not want to buy a domain or you cannot expose the remote machine to
|
||||
the internet
|
||||
- You do not want to use port forwarding via SSH
|
||||
|
||||
To use a self-signed certificate:
|
||||
|
||||
1. This option requires that the remote machine be exposed to the internet. Make
|
||||
sure that your instance allows HTTP/HTTP traffic.
|
||||
|
||||
1. SSH into your instance and edit your code-server config file to use a
|
||||
randomly generated self-signed certificate:
|
||||
|
||||
```console
|
||||
# Replaces "cert: false" with "cert: true" in the code-server config.
|
||||
sed -i.bak 's/cert: false/cert: true/' ~/.config/code-server/config.yaml
|
||||
# Replaces "bind-addr: 127.0.0.1:8080" with "bind-addr: 0.0.0.0:443" in the code-server config.
|
||||
sed -i.bak 's/bind-addr: 127.0.0.1:8080/bind-addr: 0.0.0.0:443/' ~/.config/code-server/config.yaml
|
||||
# Allows code-server to listen on port 443.
|
||||
sudo setcap cap_net_bind_service=+ep /usr/lib/code-server/lib/node
|
||||
```
|
||||
|
||||
1. Restart code-server:
|
||||
|
||||
```console
|
||||
sudo systemctl restart code-server@$USER
|
||||
```
|
||||
|
||||
At this point, you should be able to access code-server via
|
||||
`https://<your-instance-ip>`.
|
||||
|
||||
If you'd like to avoid the warnings displayed by code-server when using a
|
||||
self-signed certificate, you can use [mkcert](https://mkcert.dev) to create a
|
||||
self-signed certificate that's trusted by your operating system, then pass the
|
||||
certificate to code-server via the `cert` and `cert-key` config fields.
|
||||
|
||||
## External authentication
|
||||
|
||||
If you want to use external authentication mechanism (e.g., Sign in with
|
||||
Google), you can do this with a reverse proxy such as:
|
||||
|
||||
- [Pomerium](https://www.pomerium.io/guides/code-server.html)
|
||||
- [oauth2_proxy](https://github.com/pusher/oauth2_proxy)
|
||||
- [Cloudflare Access](https://teams.cloudflare.com/access)
|
||||
|
||||
## HTTPS and self-signed certificates
|
||||
|
||||
For HTTPS, you can use a self-signed certificate by:
|
||||
|
||||
- Passing in `--cert`
|
||||
- Passing in an existing certificate by providing the path to `--cert` and the
|
||||
path to the key with `--cert-key`
|
||||
|
||||
The self signed certificate will be generated to
|
||||
`~/.local/share/code-server/self-signed.crt`.
|
||||
|
||||
If you pass a certificate to code-server, it will respond to HTTPS requests and
|
||||
redirect all HTTP requests to HTTPS.
|
||||
|
||||
> You can use [Let's Encrypt](https://letsencrypt.org/) to get a TLS certificate
|
||||
> for free.
|
||||
|
||||
Note: if you set `proxy_set_header Host $host;` in your reverse proxy config, it will change the address displayed in the green section of code-server in the bottom left to show the correct address.
|
||||
|
||||
## Accessing web services
|
||||
|
||||
If you're working on web services and want to access it locally, code-server
|
||||
can proxy to any port using either a subdomain or a subpath, allowing you to
|
||||
securely access these services using code-server's built-in authentication.
|
||||
|
||||
### Using a subdomain
|
||||
|
||||
You will need a DNS entry that points to your server for each port you want to
|
||||
access. You can either set up a wildcard DNS entry for `*.<domain>` if your
|
||||
domain name registrar supports it, or you can create one for every port you want
|
||||
to access (`3000.<domain>`, `8080.<domain>`, etc).
|
||||
|
||||
You should also set up TLS certificates for these subdomains, either using a
|
||||
wildcard certificate for `*.<domain>` or individual certificates for each port.
|
||||
|
||||
To set your domain, start code-server with the `--proxy-domain` flag:
|
||||
|
||||
```console
|
||||
code-server --proxy-domain <domain>
|
||||
```
|
||||
|
||||
Now you can browse to `<port>.<domain>`. Note that this uses the host header, so
|
||||
ensure your reverse proxy (if you're using one) forwards that information.
|
||||
|
||||
### Using a subpath
|
||||
|
||||
Simply browse to `/proxy/<port>/`.
|
||||
|
||||
### Stripping `/proxy/<port>` from the request path
|
||||
|
||||
You may notice that the code-server proxy strips `/proxy/<port>` from the
|
||||
request path.
|
||||
|
||||
HTTP servers should use relative URLs to avoid the need to be coupled to the
|
||||
absolute path at which they are served. This means you must [use trailing
|
||||
slashes on all paths with
|
||||
subpaths](https://blog.cdivilly.com/2019/02/28/uri-trailing-slashes).
|
||||
|
||||
This reasoning is why the default behavior is to strip `/proxy/<port>` from the
|
||||
base path. If your application uses relative URLs and does not assume the
|
||||
absolute path at which it is being served, it will just work no matter what port
|
||||
you decide to serve it off or if you put it in behind code-server or any other
|
||||
proxy.
|
||||
|
||||
However, some prefer the cleaner aesthetic of no trailing slashes. Omitting the
|
||||
trailing slashes couples you to the base path, since you cannot use relative
|
||||
redirects correctly anymore. If you're okay with this tradeoff, use `/absproxy`
|
||||
instead and the path will be passed as is (e.g., `/absproxy/3000/my-app-path`).
|
||||
|
||||
### Proxying to create a React app
|
||||
|
||||
You must use `/absproxy/<port>` with `create-react-app` (see
|
||||
[#2565](https://github.com/cdr/code-server/issues/2565) and
|
||||
[#2222](https://github.com/cdr/code-server/issues/2222) for more information).
|
||||
You will need to inform `create-react-app` of the path at which you are serving
|
||||
via `$PUBLIC_URL` and webpack via `$WDS_SOCKET_PATH`:
|
||||
|
||||
```sh
|
||||
PUBLIC_URL=/absproxy/3000 \
|
||||
WDS_SOCKET_PATH=$PUBLIC_URL/sockjs-node \
|
||||
BROWSER=none yarn start
|
||||
```
|
||||
|
||||
You should then be able to visit `https://my-code-server-address.io/absproxy/3000` to see your app exposed through
|
||||
code-server!
|
||||
|
||||
> We highly recommend using the subdomain approach instead to avoid this class of issue.
|
||||
|
||||
### Proxying to a Vue app
|
||||
|
||||
Similar to the situation with React apps, you have to make a few modifications to proxy a Vue app.
|
||||
|
||||
1. add `vue.config.js`
|
||||
2. update the values to match this (you can use any free port):
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
devServer: {
|
||||
port: 3454,
|
||||
sockPath: "sockjs-node",
|
||||
},
|
||||
publicPath: "/absproxy/3454",
|
||||
}
|
||||
```
|
||||
|
||||
3. access app at `<code-server-root>/absproxy/3454` e.g. `http://localhost:8080/absproxy/3454`
|
||||
|
||||
Read more about `publicPath` in the [Vue.js docs](https://cli.vuejs.org/config/#publicpath)
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
# Setup Guide
|
||||
|
||||
- [Expose code-server](#expose-code-server)
|
||||
|
@ -7,7 +398,6 @@
|
|||
- [Using Let's Encrypt with Caddy](#using-lets-encrypt-with-caddy)
|
||||
- [Using Let's Encrypt with NGINX](#using-lets-encrypt-with-nginx)
|
||||
- [Using a self-signed certificate](#using-a-self-signed-certificate)
|
||||
- [TLS 1.3 and Safari](#tls-13-and-safari)
|
||||
- [External authentication](#external-authentication)
|
||||
- [HTTPS and self-signed certificates](#https-and-self-signed-certificates)
|
||||
- [Accessing web services](#accessing-web-services)
|
||||
|
@ -115,7 +505,7 @@ we recommend using another method, such as [Let's Encrypt](#let-encrypt) instead
|
|||
Using [Let's Encrypt](https://letsencrypt.org) is an option if you want to
|
||||
access code-server on an iPad or do not want to use SSH port forwarding.
|
||||
|
||||
1. This option requires that the remote machine be exposed to the internet. Make sure that your instance allows HTTP/HTTPS traffic.
|
||||
1. This option requires that the remote machine be exposed to the internet. Make sure that your instance allows HTTP/HTTP traffic.
|
||||
|
||||
1. You'll need a domain name (if you don't have one, you can purchase one from
|
||||
[Google Domains](https://domains.google.com) or the domain service of your
|
||||
|
@ -146,7 +536,7 @@ sudo apt install caddy
|
|||
mydomain.com/code/* {
|
||||
uri strip_prefix /code
|
||||
reverse_proxy 127.0.0.1:8080
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Remember to replace `mydomain.com` with your domain name!
|
||||
|
@ -162,7 +552,7 @@ At this point, you should be able to access code-server via
|
|||
|
||||
### Using Let's Encrypt with NGINX
|
||||
|
||||
1. This option requires that the remote machine be exposed to the internet. Make sure that your instance allows HTTP/HTTPS traffic.
|
||||
1. This option requires that the remote machine be exposed to the internet. Make sure that your instance allows HTTP/HTTP traffic.
|
||||
|
||||
1. You'll need a domain name (if you don't have one, you can purchase one from
|
||||
[Google Domains](https://domains.google.com) or the domain service of your
|
||||
|
@ -229,7 +619,7 @@ code-server. You should only proceed with this option if:
|
|||
To use a self-signed certificate:
|
||||
|
||||
1. This option requires that the remote machine be exposed to the internet. Make
|
||||
sure that your instance allows HTTP/HTTPS traffic.
|
||||
sure that your instance allows HTTP/HTTP traffic.
|
||||
|
||||
1. SSH into your instance and edit your code-server config file to use a
|
||||
randomly generated self-signed certificate:
|
||||
|
@ -257,13 +647,6 @@ self-signed certificate, you can use [mkcert](https://mkcert.dev) to create a
|
|||
self-signed certificate that's trusted by your operating system, then pass the
|
||||
certificate to code-server via the `cert` and `cert-key` config fields.
|
||||
|
||||
### TLS 1.3 and Safari
|
||||
|
||||
If you will be using Safari and your configuration does not allow anything less
|
||||
than TLS 1.3 you will need to add support for TLS 1.2 since Safari does not
|
||||
support TLS 1.3 for web sockets at the time of writing. If this is the case you
|
||||
should see OSSStatus: 9836 in the browser console.
|
||||
|
||||
## External authentication
|
||||
|
||||
If you want to use external authentication mechanism (e.g., Sign in with
|
||||
|
@ -294,7 +677,7 @@ Note: if you set `proxy_set_header Host $host;` in your reverse proxy config, it
|
|||
|
||||
## Accessing web services
|
||||
|
||||
If you're working on web services and want to access them locally, code-server
|
||||
If you're working on web services and want to access it locally, code-server
|
||||
can proxy to any port using either a subdomain or a subpath, allowing you to
|
||||
securely access these services using code-server's built-in authentication.
|
||||
|
||||
|
@ -345,8 +728,8 @@ instead and the path will be passed as is (e.g., `/absproxy/3000/my-app-path`).
|
|||
### Proxying to create a React app
|
||||
|
||||
You must use `/absproxy/<port>` with `create-react-app` (see
|
||||
[#2565](https://github.com/coder/code-server/issues/2565) and
|
||||
[#2222](https://github.com/coder/code-server/issues/2222) for more information).
|
||||
[#2565](https://github.com/cdr/code-server/issues/2565) and
|
||||
[#2222](https://github.com/cdr/code-server/issues/2222) for more information).
|
||||
You will need to inform `create-react-app` of the path at which you are serving
|
||||
via `$PUBLIC_URL` and webpack via `$WDS_SOCKET_PATH`:
|
||||
|
||||
|
@ -396,7 +779,7 @@ sudo apt update
|
|||
sudo apt install wget unzip openssh-server
|
||||
```
|
||||
|
||||
2. Start the SSH server and set the password for your user, if you haven't already. If you use [deploy-code-server](https://github.com/coder/deploy-code-server),
|
||||
2. Start the SSH server and set the password for your user, if you haven't already. If you use [deploy-code-server](https://github.com/cdr/deploy-code-server),
|
||||
|
||||
```bash
|
||||
sudo service ssh start
|
||||
|
|
10
docs/helm.md
10
docs/helm.md
|
@ -1,8 +1,8 @@
|
|||
# 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.0.2](https://img.shields.io/badge/AppVersion-4.0.2-informational?style=flat-square)](https://img.shields.io/badge/AppVersion-4.0.2-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: 3.12.0](https://img.shields.io/badge/AppVersion-3.12.0-informational?style=flat-square)](https://img.shields.io/badge/AppVersion-3.12.0-informational?style=flat-square)
|
||||
|
||||
[code-server](https://github.com/coder/code-server) code-server is VS Code running
|
||||
[code-server](https://github.com/cdr/code-server) code-server is VS Code running
|
||||
on a remote server, accessible through the browser.
|
||||
|
||||
This chart is community maintained by [@Matthew-Beckett](https://github.com/Matthew-Beckett) and [@alexgorbatchev](https://github.com/alexgorbatchev)
|
||||
|
@ -10,7 +10,7 @@ This chart is community maintained by [@Matthew-Beckett](https://github.com/Matt
|
|||
## Quickstart
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/coder/code-server
|
||||
$ git clone https://github.com/cdr/code-server
|
||||
$ cd code-server
|
||||
$ helm upgrade --install code-server ci/helm-chart
|
||||
```
|
||||
|
@ -30,7 +30,7 @@ package manager.
|
|||
To install the chart with the release name `code-server`:
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/coder/code-server
|
||||
$ git clone https://github.com/cdr/code-server
|
||||
$ cd code-server
|
||||
$ helm upgrade --install code-server ci/helm-chart
|
||||
```
|
||||
|
@ -73,7 +73,7 @@ and their default values.
|
|||
| hostnameOverride | string | `""` |
|
||||
| image.pullPolicy | string | `"Always"` |
|
||||
| image.repository | string | `"codercom/code-server"` |
|
||||
| image.tag | string | `"4.0.2"` |
|
||||
| image.tag | string | `"3.12.0"` |
|
||||
| imagePullSecrets | list | `[]` |
|
||||
| ingress.enabled | bool | `false` |
|
||||
| nameOverride | string | `""` |
|
||||
|
|
|
@ -30,7 +30,7 @@ operating systems.
|
|||
## install.sh
|
||||
|
||||
The easiest way to install code-server is to use our [install
|
||||
script](https://github.com/coder/code-server/blob/main/install.sh) for Linux, macOS and FreeBSD. The install script
|
||||
script](../install.sh) for Linux, macOS and FreeBSD. The install script
|
||||
[attempts to use the system package manager](#detection-reference) if possible.
|
||||
|
||||
You can preview what occurs during the install process:
|
||||
|
@ -67,7 +67,7 @@ code-server.
|
|||
|
||||
If you prefer to install code-server manually, despite the [detection
|
||||
references](#detection-reference) and `--dry-run` feature, then continue on for
|
||||
information on how to do this. The [`install.sh`](https://github.com/coder/code-server/blob/main/install.sh) script runs the
|
||||
information on how to do this. The [`install.sh`](../install.sh) script runs the
|
||||
_exact_ same commands presented in the rest of this document.
|
||||
|
||||
### Detection reference
|
||||
|
@ -104,7 +104,7 @@ We recommend installing with `yarn` or `npm` when:
|
|||
1. You're on Linux with `glibc` < v2.17, `glibcxx` < v3.4.18 on `amd64`, `glibc`
|
||||
< v2.23, or `glibcxx` < v3.4.21 on `arm64`.
|
||||
1. You're running Alpine Linux or are using a non-glibc libc. See
|
||||
[#1430](https://github.com/coder/code-server/issues/1430#issuecomment-629883198)
|
||||
[#1430](https://github.com/cdr/code-server/issues/1430#issuecomment-629883198)
|
||||
for more information.
|
||||
|
||||
Installing code-server with `yarn` or `npm` builds native modules on install.
|
||||
|
@ -114,7 +114,7 @@ This process requires C dependencies; see our guide on [installing with yarn and
|
|||
## Standalone releases
|
||||
|
||||
We publish self-contained `.tar.gz` archives for every release on
|
||||
[GitHub](https://github.com/coder/code-server/releases). The archives bundle the
|
||||
[GitHub](https://github.com/cdr/code-server/releases). The archives bundle the
|
||||
node binary and node modules.
|
||||
|
||||
We create the standalone releases using the [npm package](#yarn-npm), and we
|
||||
|
@ -127,7 +127,7 @@ requirement).
|
|||
To use a standalone release:
|
||||
|
||||
1. Download the latest release archive for your system from
|
||||
[GitHub](https://github.com/coder/code-server/releases).
|
||||
[GitHub](https://github.com/cdr/code-server/releases).
|
||||
2. Unpack the release.
|
||||
3. Run code-server by executing `./bin/code-server`.
|
||||
|
||||
|
@ -139,7 +139,7 @@ release on Linux:
|
|||
|
||||
```bash
|
||||
mkdir -p ~/.local/lib ~/.local/bin
|
||||
curl -fL https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-linux-amd64.tar.gz \
|
||||
curl -fL https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-linux-amd64.tar.gz \
|
||||
| tar -C ~/.local/lib -xz
|
||||
mv ~/.local/lib/code-server-$VERSION-linux-amd64 ~/.local/lib/code-server-$VERSION
|
||||
ln -s ~/.local/lib/code-server-$VERSION/bin/code-server ~/.local/bin/code-server
|
||||
|
@ -154,7 +154,7 @@ code-server
|
|||
> upgrade or [build with yarn](#yarn-npm).
|
||||
|
||||
```bash
|
||||
curl -fOL https://github.com/coder/code-server/releases/download/v$VERSION/code-server_$VERSION_amd64.deb
|
||||
curl -fOL https://github.com/cdr/code-server/releases/download/v$VERSION/code-server_$VERSION_amd64.deb
|
||||
sudo dpkg -i code-server_$VERSION_amd64.deb
|
||||
sudo systemctl enable --now code-server@$USER
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
|
@ -166,7 +166,7 @@ sudo systemctl enable --now code-server@$USER
|
|||
> with yarn](#yarn-npm).
|
||||
|
||||
```bash
|
||||
curl -fOL https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-amd64.rpm
|
||||
curl -fOL https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-amd64.rpm
|
||||
sudo rpm -i code-server-$VERSION-amd64.rpm
|
||||
sudo systemctl enable --now code-server@$USER
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
|
@ -228,9 +228,9 @@ You can install code-server using the [Helm package manager](https://coder.com/d
|
|||
|
||||
## Windows
|
||||
|
||||
We currently [do not publish Windows releases](https://github.com/coder/code-server/issues/1397). We recommend installing code-server onto Windows with [`yarn` or `npm`](#yarn-npm).
|
||||
We currently [do not publish Windows releases](https://github.com/cdr/code-server/issues/1397). We recommend installing code-server onto Windows with [`yarn` or `npm`](#yarn-npm).
|
||||
|
||||
> Note: You will also need to [build coder/cloud-agent manually](https://github.com/coder/cloud-agent/issues/17) if you would like to use `code-server --link` on Windows.
|
||||
> Note: You will also need to [build cdr/cloud-agent manually](https://github.com/cdr/cloud-agent/issues/17) if you would like to use `code-server --link` on Windows.
|
||||
|
||||
## Raspberry Pi
|
||||
|
||||
|
@ -245,7 +245,7 @@ information.
|
|||
## Cloud providers
|
||||
|
||||
We maintain [one-click apps and install scripts for cloud
|
||||
providers](https://github.com/coder/deploy-code-server) such as DigitalOcean,
|
||||
providers](https://github.com/cdr/deploy-code-server) such as DigitalOcean,
|
||||
Railway, Heroku, and Azure.
|
||||
|
||||
## Uninstall
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
# Using code-server on iOS with iSH
|
||||
|
||||
1. Install iSH from the [App Store](https://apps.apple.com/us/app/ish-shell/id1436902243)
|
||||
2. Install `curl` with `apk add curl`
|
||||
3. Install code-server with `curl -fsSL https://code-server.dev/install.sh | sh`
|
||||
4. Run code-server with `code-server`
|
||||
5. Access on localhost:8080 in your browser
|
14
docs/ipad.md
14
docs/ipad.md
|
@ -104,7 +104,7 @@ and tricks helpful:
|
|||
process](#access-code-server-with-a-self-signed-certificate-on-an-ipad)
|
||||
- Keyboard issues:
|
||||
- The keyboard disappear sometimes
|
||||
[#979](https://github.com/coder/code-server/issues/979)
|
||||
[#979](https://github.com/cdr/code-server/issues/979)
|
||||
- Some expectations regarding shortcuts may not be met:
|
||||
- `cmd + n` opens new browser window instead of new file, and it's difficult
|
||||
to set alternative as a workaround
|
||||
|
@ -112,18 +112,18 @@ and tricks helpful:
|
|||
- There's no escape key by default on the Magic Keyboard, so most users set
|
||||
the globe key to be an escape key
|
||||
- Trackpad scrolling does not work on iPadOS < 14.5
|
||||
([#1455](https://github.com/coder/code-server/issues/1455))
|
||||
([#1455](https://github.com/cdr/code-server/issues/1455))
|
||||
- [WebKit fix](https://bugs.webkit.org/show_bug.cgi?id=210071#c13)
|
||||
- Keyboard may lose focus in Safari / split view [#4182](https://github.com/coder/code-server/issues/4182)
|
||||
- Terminal text does not appear by default [#3824](https://github.com/coder/code-server/issues/3824)
|
||||
- Copy & paste in terminal does not work well with keyboard shortcuts [#3491](https://github.com/coder/code-server/issues/3491)
|
||||
- Keyboard may lose focus in Safari / split view [#4182](https://github.com/cdr/code-server/issues/4182)
|
||||
- Terminal text does not appear by default [#3824](https://github.com/cdr/code-server/issues/3824)
|
||||
- Copy & paste in terminal does not work well with keyboard shortcuts [#3491](https://github.com/cdr/code-server/issues/3491)
|
||||
- `ctrl+c` does not stop a long-running process in the browser
|
||||
- Tracking upstream issue here:
|
||||
[#114009](https://github.com/microsoft/vscode/issues/114009)
|
||||
- See [workaround](#ctrl-c-workaround)
|
||||
|
||||
Additionally, see [issues in the code-server repo that are tagged with the `os-ios`
|
||||
label](https://github.com/coder/code-server/issues?q=is%3Aopen+is%3Aissue+label%3Aos-ios)
|
||||
Additionally, see [issues in the code-server repo that are tagged with the iPad
|
||||
label](https://github.com/cdr/code-server/issues?q=is%3Aopen+is%3Aissue+label%3AiPad)
|
||||
for more information.
|
||||
|
||||
### Workaround for issue with `ctrl+c` not stopping a running process in the terminal
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
# code-server --link
|
||||
|
||||
> Note: This feature is no longer recommended due to instability. Stay tuned for a revised version.
|
||||
|
||||
Run code-server with the flag `--link` and you'll get TLS, authentication, and a dedicated URL
|
||||
Run code-server with the beta flag `--link` and you'll get TLS, authentication, and a dedicated URL
|
||||
for accessing your IDE out of the box.
|
||||
|
||||
```console
|
||||
$ code-server --link
|
||||
Proxying code-server, you can access your IDE at https://example.coder.co
|
||||
Proxying code-server, you can access your IDE at https://example.cdr.co
|
||||
```
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"versions": ["v4.0.2"],
|
||||
"versions": ["v3.12.0"],
|
||||
"routes": [
|
||||
{
|
||||
"title": "Home",
|
||||
|
@ -51,16 +51,6 @@
|
|||
"title": "Termux",
|
||||
"description": "How to install Termux to run code-server on an Android device.",
|
||||
"path": "./termux.md"
|
||||
},
|
||||
{
|
||||
"title": "iOS",
|
||||
"description": "How to use code-server on iOS with iSH.",
|
||||
"path": "./ios.md"
|
||||
},
|
||||
{
|
||||
"title": "Android",
|
||||
"description": "How to run code-server on an Android device using UserLAnd.",
|
||||
"path": "./android.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -73,7 +63,7 @@
|
|||
{
|
||||
"title": "Upgrade",
|
||||
"description": "How to upgrade code-server.",
|
||||
"icon": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.8049 2.19795C17.7385 2.1311 17.6587 2.07899 17.5708 2.04504C17.4829 2.01108 17.3889 1.99604 17.2948 2.00089C7.89216 2.49153 4.4188 10.8673 4.38528 10.9517C4.33624 11.0736 4.32406 11.2071 4.35028 11.3358C4.3765 11.4645 4.43995 11.5827 4.53274 11.6756L8.32449 15.4674C8.41787 15.5606 8.53669 15.6242 8.66606 15.6502C8.79543 15.6762 8.92959 15.6634 9.05174 15.6135C9.13552 15.5793 17.4664 12.0671 17.9986 2.7087C18.0039 2.61474 17.9895 2.5207 17.9561 2.4327C17.9227 2.3447 17.8712 2.26471 17.8049 2.19795ZM12.3314 9.56427C12.1439 9.75179 11.9051 9.87951 11.645 9.93126C11.385 9.98302 11.1154 9.9565 10.8704 9.85505C10.6254 9.7536 10.4161 9.58178 10.2687 9.36131C10.1214 9.14085 10.0428 8.88166 10.0428 8.6165C10.0428 8.35135 10.1214 8.09215 10.2687 7.87169C10.4161 7.65123 10.6254 7.47941 10.8704 7.37796C11.1154 7.27651 11.385 7.24998 11.645 7.30174C11.9051 7.3535 12.1439 7.48121 12.3314 7.66873C12.5827 7.92012 12.7239 8.26104 12.7239 8.6165C12.7239 8.97197 12.5827 9.31288 12.3314 9.56427Z\"/><path d=\"M2.74602 14.5444C2.92281 14.3664 3.133 14.2251 3.36454 14.1285C3.59608 14.0319 3.8444 13.9819 4.09529 13.9815C4.34617 13.9811 4.59466 14.0.12 4.82653 14.126C5.05839 14.2218 5.26907 14.3624 5.44647 14.5398C5.62386 14.7172 5.7645 14.9279 5.86031 15.1598C5.95612 15.3916 6.00522 15.6401 6.00479 15.891C6.00437 16.1419 5.95442 16.3902 5.85782 16.6218C5.76122 16.8533 5.61987 17.0635 5.44186 17.2403C4.69719 17.985 2 18.0004 2 18.0004C2 18.0004 2 15.2884 2.74602 14.5444Z\"/><path d=\"M8.9416 3.48269C7.99688 3.31826 7.02645 3.38371 6.11237 3.67352C5.19828 3.96332 4.36741 4.46894 3.68999 5.14765C3.33153 5.50944 3.01988 5.91477 2.76233 6.35415C2.68692 6.4822 2.6562 6.63169 2.67501 6.77911C2.69381 6.92652 2.76108 7.06351 2.86623 7.16853L4.1994 8.50238C5.43822 6.53634 7.04911 4.83119 8.9416 3.48269Z\"/><path d=\"M16.5181 11.0585C16.6825 12.0033 16.6171 12.9737 16.3273 13.8878C16.0375 14.8019 15.5318 15.6327 14.8531 16.3101C14.4914 16.6686 14.086 16.9803 13.6466 17.2378C13.5186 17.3132 13.3691 17.3439 13.2217 17.3251C13.0743 17.3063 12.9373 17.2391 12.8323 17.1339L11.4984 15.8007C13.4645 14.5619 15.1696 12.951 16.5181 11.0585Z\"/></svg>",
|
||||
"icon": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.8049 2.19795C17.7385 2.1311 17.6587 2.07899 17.5708 2.04504C17.4829 2.01108 17.3889 1.99604 17.2948 2.00089C7.89216 2.49153 4.4188 10.8673 4.38528 10.9517C4.33624 11.0736 4.32406 11.2071 4.35028 11.3358C4.3765 11.4645 4.43995 11.5827 4.53274 11.6756L8.32449 15.4674C8.41787 15.5606 8.53669 15.6242 8.66606 15.6502C8.79543 15.6762 8.92959 15.6634 9.05174 15.6135C9.13552 15.5793 17.4664 12.0671 17.9986 2.7087C18.0039 2.61474 17.9895 2.5207 17.9561 2.4327C17.9227 2.3447 17.8712 2.26471 17.8049 2.19795ZM12.3314 9.56427C12.1439 9.75179 11.9051 9.87951 11.645 9.93126C11.385 9.98302 11.1154 9.9565 10.8704 9.85505C10.6254 9.7536 10.4161 9.58178 10.2687 9.36131C10.1214 9.14085 10.0428 8.88166 10.0428 8.6165C10.0428 8.35135 10.1214 8.09215 10.2687 7.87169C10.4161 7.65123 10.6254 7.47941 10.8704 7.37796C11.1154 7.27651 11.385 7.24998 11.645 7.30174C11.9051 7.3535 12.1439 7.48121 12.3314 7.66873C12.5827 7.92012 12.7239 8.26104 12.7239 8.6165C12.7239 8.97197 12.5827 9.31288 12.3314 9.56427Z\"/><path d=\"M2.74602 14.5444C2.92281 14.3664 3.133 14.2251 3.36454 14.1285C3.59608 14.0319 3.8444 13.9819 4.09529 13.9815C4.34617 13.9811 4.59466 14.0302 4.82653 14.126C5.05839 14.2218 5.26907 14.3624 5.44647 14.5398C5.62386 14.7172 5.7645 14.9279 5.86031 15.1598C5.95612 15.3916 6.00522 15.6401 6.00479 15.891C6.00437 16.1419 5.95442 16.3902 5.85782 16.6218C5.76122 16.8533 5.61987 17.0635 5.44186 17.2403C4.69719 17.985 2 18.0004 2 18.0004C2 18.0004 2 15.2884 2.74602 14.5444Z\"/><path d=\"M8.9416 3.48269C7.99688 3.31826 7.02645 3.38371 6.11237 3.67352C5.19828 3.96332 4.36741 4.46894 3.68999 5.14765C3.33153 5.50944 3.01988 5.91477 2.76233 6.35415C2.68692 6.4822 2.6562 6.63169 2.67501 6.77911C2.69381 6.92652 2.76108 7.06351 2.86623 7.16853L4.1994 8.50238C5.43822 6.53634 7.04911 4.83119 8.9416 3.48269Z\"/><path d=\"M16.5181 11.0585C16.6825 12.0033 16.6171 12.9737 16.3273 13.8878C16.0375 14.8019 15.5318 15.6327 14.8531 16.3101C14.4914 16.6686 14.086 16.9803 13.6466 17.2378C13.5186 17.3132 13.3691 17.3439 13.2217 17.3251C13.0743 17.3063 12.9373 17.2391 12.8323 17.1339L11.4984 15.8007C13.4645 14.5619 15.1696 12.951 16.5181 11.0585Z\"/></svg>",
|
||||
"path": "./upgrade.md"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -27,7 +27,7 @@ which is currently `14.x`. VS Code also [lists Node.js
|
|||
requirements](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites).
|
||||
|
||||
Using other versions of Node.js [may lead to unexpected
|
||||
behavior](https://github.com/coder/code-server/issues/1633).
|
||||
behavior](https://github.com/cdr/code-server/issues/1633).
|
||||
|
||||
## Ubuntu, Debian
|
||||
|
||||
|
@ -100,7 +100,7 @@ yarn global bin
|
|||
# Or: npm config get prefix
|
||||
```
|
||||
|
||||
For help and additional troubleshooting, see [#1397](https://github.com/coder/code-server/issues/1397).
|
||||
For help and additional troubleshooting, see [#1397](https://github.com/cdr/code-server/issues/1397).
|
||||
|
||||
## Installing
|
||||
|
||||
|
@ -116,7 +116,7 @@ code-server
|
|||
## Troubleshooting
|
||||
|
||||
If you need further assistance, post on our [GitHub Discussions
|
||||
page](https://github.com/coder/code-server/discussions).
|
||||
page](https://github.com/cdr/code-server/discussions).
|
||||
|
||||
### Issues with Node.js after version upgrades
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ new Compute Engine VM instance:
|
|||
4. Choose the **region** that's closest to you based on [GCP
|
||||
ping](https://gcping.com/).
|
||||
5. Choose a **zone** (any option is fine).
|
||||
6. We recommend choosing an **E2 series instance** from the [general-purpose
|
||||
6. We recommend choose an **E2 series instance** from the [general-purpose
|
||||
family](https://cloud.google.com/compute/docs/machine-types#general_purpose).
|
||||
7. Change the instance type to **custom** and set at least **2 cores** and **2
|
||||
GB of RAM**. You can add more resources if desired, though you can also edit
|
||||
|
|
153
docs/termux.md
153
docs/termux.md
|
@ -5,144 +5,67 @@
|
|||
- [Install](#install)
|
||||
- [Upgrade](#upgrade)
|
||||
- [Known Issues](#known-issues)
|
||||
- [Git won't work in `/sdcard`](#git-wont-work-in-sdcard)
|
||||
- [Extra](#extra)
|
||||
- [Create a new user](#create-a-new-user)
|
||||
- [Install Go](#install-go)
|
||||
- [Install Python](#install-python)
|
||||
- [Search doesn't work](#search-doesnt-work)
|
||||
- [Backspace doesn't work](#backspace-doesnt-work)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
Termux is a terminal application and Linux environment that you can also use to
|
||||
run code-server from your Android phone.
|
||||
|
||||
## Install
|
||||
|
||||
1. Get [Termux](https://f-droid.org/en/packages/com.termux/) from **F-Droid**.
|
||||
2. Install Debian by running the following.
|
||||
- Run `termux-setup-storage` to allow storage access, or else code-server won't be able to read from `/sdcard`.\
|
||||
If you used the Andronix command then you may have to edit the `start-debian.sh` script to mount `/sdcard` just as simple as uncommenting the `command+=" -b /sdcard"` line.
|
||||
> The following command was extracted from [Andronix](https://andronix.app/) you can also use [proot-distro](https://github.com/termux/proot-distro).
|
||||
> After Debian is installed the `~ $` will change to `root@localhost`.
|
||||
|
||||
```bash
|
||||
pkg update -y && pkg install wget curl proot tar -y && wget https://raw.githubusercontent.com/AndronixApp/AndronixOrigin/master/Installer/Debian/debian.sh -O debian.sh && chmod +x debian.sh && bash debian.sh
|
||||
```
|
||||
|
||||
3. Run the following commands to setup Debian.
|
||||
|
||||
```bash
|
||||
apt update
|
||||
apt upgrade -y
|
||||
apt-get install nano vim sudo curl wget git -y
|
||||
```
|
||||
|
||||
4. Install [NVM](https://github.com/nvm-sh/nvm) by following the install guide in the README, just a curl/wget command.
|
||||
5. Set up NVM for multi-user. After installing NVM it automatically adds the necessary commands for it to work, but it will only work if you are logged in as root;
|
||||
|
||||
- Copy the lines NVM asks you to run after running the install script.
|
||||
- Run `nano /root/.bashrc` and comment out those lines by adding a `#` at the start.
|
||||
- Run `nano /etc/profile` and paste those lines at the end and make sure to replace `$HOME` with `/root`
|
||||
- Now run `exit` and start Debain again.
|
||||
|
||||
6. After following the instructions and setting up NVM you can now install the [required node version](https://coder.com/docs/code-server/latest/npm#nodejs-version) using `nvm install version_here`.
|
||||
7. To install `code-server` run the following.
|
||||
> To check the install process (Will not actually install code-server)
|
||||
> If it all looks good, you can install code-server by running the second command
|
||||
|
||||
```bash
|
||||
curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -fsSL https://code-server.dev/install.sh | sh
|
||||
```
|
||||
|
||||
8. You can now start code server by simply running `code-server`.
|
||||
|
||||
> Consider using a new user instead of root, read [here](https://www.howtogeek.com/124950/htg-explains-why-you-shouldnt-log-into-your-linux-system-as-root/) why using root is not recommended.\
|
||||
> Learn how to add a user [here](#create-a-new-user).
|
||||
1. Install Termux from [F-Droid](https://f-droid.org/en/packages/com.termux/).
|
||||
1. Make sure it's up-to-date: `apt update && apt upgrade`
|
||||
1. Install required packages: `apt install build-essential python git nodejs yarn`
|
||||
1. Install code-server: `yarn global add code-server`
|
||||
1. Run code-server: `code-server` and navigate to localhost:8080 in your browser
|
||||
|
||||
## Upgrade
|
||||
|
||||
1. Remove all previous installs `rm -rf ~/.local/lib/code-server-*`
|
||||
2. Run the install script again `curl -fsSL https://code-server.dev/install.sh | sh`
|
||||
To upgrade run: `yarn global upgrade code-server --latest`
|
||||
|
||||
## Known Issues
|
||||
|
||||
### Git won't work in `/sdcard`
|
||||
The following details known issues and suggested workarounds for using
|
||||
code-server with Termux.
|
||||
|
||||
Issue : Using git in the `/sdcard` directory will fail during cloning/commit/staging/etc...\
|
||||
Fix : None\
|
||||
Potential Workaround :
|
||||
### Search doesn't work
|
||||
|
||||
1. Create a soft-link from the debian-fs to your folder in `/sdcard`
|
||||
2. Use git from termux (preferred)
|
||||
There is a known issue with search not working on Android because it's missing
|
||||
`bin/rg` ([context](https://github.com/cdr/code-server/issues/1730#issuecomment-721515979)). To fix this:
|
||||
|
||||
## Extra
|
||||
1. Install `ripgrep` with `pkg`
|
||||
|
||||
### Create a new user
|
||||
```sh
|
||||
pkg install ripgrep
|
||||
```
|
||||
|
||||
To create a new user follow these simple steps -
|
||||
1. Make a soft link using `ln -s`
|
||||
|
||||
1. Create a new user by running `useradd username -m`.
|
||||
2. Change the password by running `passwd username`.
|
||||
3. Give your new user sudo access by runnning `visudo`, scroll down to `User privilege specification` and add the following line after root `username ALL=(ALL:ALL) ALL`.
|
||||
4. Now edit the `/etc/passwd` file with your commadline editor of choice and at the end of the line that specifies your user change `/bin/sh` to `/bin/bash`.
|
||||
5. Now switch users, by running `su - username`
|
||||
```sh
|
||||
# run this command inside the code-server directory
|
||||
ln -s $PREFIX/bin/rg ./vendor/modules/code-oss-dev/vscode-ripgrep/bin/rg
|
||||
```
|
||||
|
||||
- Remember the `-` betweeen `su` and username is required to execute `/etc/profile`,\
|
||||
since `/etc/profile` may have some necessary things to be executed you should always add a `-`.
|
||||
### Backspace doesn't work
|
||||
|
||||
### Install Go
|
||||
When using Android's on-screen keyboard, the backspace key doesn't work
|
||||
properly. This is a known upstream issue:
|
||||
|
||||
> From https://golang.org/doc/install
|
||||
- [Issues with backspace in Codespaces on Android (Surface Duo)](https://github.com/microsoft/vscode/issues/107602)
|
||||
- [Support mobile platforms](https://github.com/xtermjs/xterm.js/issues/1101)
|
||||
|
||||
1. Go to https://golang.org/dl/ and copy the download link for `linux arm` and run the following.
|
||||
There are two workarounds.
|
||||
|
||||
```bash
|
||||
wget download_link
|
||||
```
|
||||
**Option 1:** Modify keyboard dispatch settings
|
||||
|
||||
2. Extract the downloaded archive. (This step will erase all previous GO installs, make sure to create a backup if you have previously installed GO)
|
||||
1. Open the Command Palette
|
||||
2. Search for **Preferences: Open Settings (JSON)**
|
||||
3. Add `"keyboard.dispatch": "keyCode"`
|
||||
|
||||
```bash
|
||||
rm -rf /usr/local/go && tar -C /usr/local -xzf archive_name
|
||||
```
|
||||
The backspace button should work at this point.
|
||||
|
||||
3. Run `nano /etc/profile` and add the following line `export PATH=$PATH:/usr/local/go/bin`.
|
||||
4. Now run `exit` (depending on if you have switched users or not, you may have to run `exit` multiple times to get to normal termux shell) and start Debian again.
|
||||
5. Check if your install was successful by running `go version`
|
||||
_Thanks to @Nefomemes for the [suggestion](https://github.com/cdr/code-server/issues/1141#issuecomment-789463707)!_
|
||||
|
||||
### Install Python
|
||||
|
||||
> Run these commands as root
|
||||
|
||||
1. Run the following command to install required packages to build python.
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install make build-essential libssl-dev zlib1g-dev \
|
||||
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
|
||||
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
|
||||
```
|
||||
|
||||
2. Install [pyenv](https://github.com/pyenv/pyenv/) from [pyenv-installer](https://github.com/pyenv/pyenv-installer) by running.
|
||||
|
||||
```bash
|
||||
curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
|
||||
```
|
||||
|
||||
3. Run `nano /etc/profile` and add the following
|
||||
|
||||
```bash
|
||||
export PYENV_ROOT="/root/.pyenv"
|
||||
export PATH="/root/.pyenv/bin:$PATH"
|
||||
eval "$(pyenv init --path)"
|
||||
eval "$(pyenv virtualenv-init -)"
|
||||
```
|
||||
|
||||
4. Exit start Debian again.
|
||||
5. Run `pyenv versions` to list all installable versions.
|
||||
6. Run `pyenv install version` to install the desired python version.
|
||||
> The build process may take some time (an hour or 2 depending on your device).
|
||||
7. Run `touch /root/.pyenv/version && echo "your_version_here" > /root/.pyenv/version`
|
||||
8. (You may have to start Debian again) Run `python3 -V` to verify if PATH works or not.
|
||||
> If `python3` doesn't work but pyenv says that the install was successful in step 6 then try running `$PYENV_ROOT/versions/your_version/bin/python3`.
|
||||
**Option 2:** Use a Bluetooth keyboard.
|
||||
|
|
|
@ -28,8 +28,8 @@ This will show issues that:
|
|||
1. If more information is required, please ask the submitter and tag as
|
||||
`waiting-for-info` and wait.
|
||||
1. Finally, the issue should be moved into the
|
||||
[code-server](https://github.com/coder/code-server/projects/1) project where we
|
||||
[code-server](https://github.com/cdr/code-server/projects/1) project where we
|
||||
pick out issues to fix and track their progress.
|
||||
|
||||
We also use [milestones](https://github.com/coder/code-server/milestones) to track
|
||||
We also use [milestones](https://github.com/cdr/code-server/milestones) to track
|
||||
what issues are planned/or were closed for what release.
|
||||
|
|
25
install.sh
25
install.sh
|
@ -23,7 +23,7 @@ The remote host must have internet access.
|
|||
${not_curl_usage-}
|
||||
Usage:
|
||||
|
||||
$arg0 [--dry-run] [--version X.X.X] [--edge] [--method detect] \
|
||||
$arg0 [--dry-run] [--version X.X.X] [--method detect] \
|
||||
[--prefix ~/.local] [--rsh ssh] [user@host]
|
||||
|
||||
--dry-run
|
||||
|
@ -32,9 +32,6 @@ Usage:
|
|||
--version X.X.X
|
||||
Install a specific version instead of the latest.
|
||||
|
||||
--edge
|
||||
Install the latest edge version instead of the latest stable version.
|
||||
|
||||
--method [detect | standalone]
|
||||
Choose the installation method. Defaults to detect.
|
||||
- detect detects the system package manager and tries to use it.
|
||||
|
@ -74,13 +71,9 @@ EOF
|
|||
}
|
||||
|
||||
echo_latest_version() {
|
||||
if [ "${EDGE-}" ]; then
|
||||
version="$(curl -fsSL https://api.github.com/repos/coder/code-server/releases | awk 'match($0,/.*"html_url": "(.*\/releases\/tag\/.*)".*/)' | head -n 1 | awk -F '"' '{print $4}')"
|
||||
else
|
||||
# https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860
|
||||
version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/coder/code-server/releases/latest)"
|
||||
fi
|
||||
version="${version#https://github.com/coder/code-server/releases/tag/}"
|
||||
# https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860
|
||||
version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/cdr/code-server/releases/latest)"
|
||||
version="${version#https://github.com/cdr/code-server/releases/tag/}"
|
||||
version="${version#v}"
|
||||
echo "$version"
|
||||
}
|
||||
|
@ -142,7 +135,6 @@ main() {
|
|||
OPTIONAL \
|
||||
ALL_FLAGS \
|
||||
RSH_ARGS \
|
||||
EDGE \
|
||||
RSH
|
||||
|
||||
ALL_FLAGS=""
|
||||
|
@ -178,9 +170,6 @@ main() {
|
|||
--version=*)
|
||||
VERSION="$(parse_arg "$@")"
|
||||
;;
|
||||
--edge)
|
||||
EDGE=1
|
||||
;;
|
||||
--rsh)
|
||||
RSH="$(parse_arg "$@")"
|
||||
shift
|
||||
|
@ -351,7 +340,7 @@ install_deb() {
|
|||
echoh "Installing v$VERSION of the $ARCH deb package from GitHub."
|
||||
echoh
|
||||
|
||||
fetch "https://github.com/coder/code-server/releases/download/v$VERSION/code-server_${VERSION}_$ARCH.deb" \
|
||||
fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server_${VERSION}_$ARCH.deb" \
|
||||
"$CACHE_DIR/code-server_${VERSION}_$ARCH.deb"
|
||||
sudo_sh_c dpkg -i "$CACHE_DIR/code-server_${VERSION}_$ARCH.deb"
|
||||
|
||||
|
@ -362,7 +351,7 @@ install_rpm() {
|
|||
echoh "Installing v$VERSION of the $ARCH rpm package from GitHub."
|
||||
echoh
|
||||
|
||||
fetch "https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-$ARCH.rpm" \
|
||||
fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$ARCH.rpm" \
|
||||
"$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"
|
||||
sudo_sh_c rpm -i "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"
|
||||
|
||||
|
@ -388,7 +377,7 @@ install_standalone() {
|
|||
echoh "Installing v$VERSION of the $ARCH release from GitHub."
|
||||
echoh
|
||||
|
||||
fetch "https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-$OS-$ARCH.tar.gz" \
|
||||
fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$OS-$ARCH.tar.gz" \
|
||||
"$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz"
|
||||
|
||||
# -w only works if the directory exists so try creating it first. If this
|
||||
|
|
46
package.json
46
package.json
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "code-server",
|
||||
"license": "MIT",
|
||||
"version": "4.0.2",
|
||||
"version": "3.12.0",
|
||||
"description": "Run VS Code on a remote server.",
|
||||
"homepage": "https://github.com/coder/code-server",
|
||||
"homepage": "https://github.com/cdr/code-server",
|
||||
"bugs": {
|
||||
"url": "https://github.com/coder/code-server/issues"
|
||||
"url": "https://github.com/cdr/code-server/issues"
|
||||
},
|
||||
"repository": "https://github.com/coder/code-server",
|
||||
"repository": "https://github.com/cdr/code-server",
|
||||
"scripts": {
|
||||
"clean": "./ci/build/clean.sh",
|
||||
"build": "./ci/build/build-code-server.sh",
|
||||
|
@ -17,19 +17,18 @@
|
|||
"release:github-draft": "./ci/build/release-github-draft.sh",
|
||||
"release:github-assets": "./ci/build/release-github-assets.sh",
|
||||
"release:prep": "./ci/build/release-prep.sh",
|
||||
"test:e2e": "VSCODE_IPC_HOOK_CLI= ./ci/dev/test-e2e.sh",
|
||||
"test:e2e": "./ci/dev/test-e2e.sh",
|
||||
"test:standalone-release": "./ci/build/test-standalone-release.sh",
|
||||
"test:unit": "./ci/dev/test-unit.sh --forceExit --detectOpenHandles",
|
||||
"test:unit": "./ci/dev/test-unit.sh",
|
||||
"test:scripts": "./ci/dev/test-scripts.sh",
|
||||
"package": "./ci/build/build-packages.sh",
|
||||
"postinstall": "./ci/dev/postinstall.sh",
|
||||
"publish:npm": "./ci/steps/publish-npm.sh",
|
||||
"_audit": "./ci/dev/audit.sh",
|
||||
"fmt": "./ci/dev/fmt.sh",
|
||||
"lint": "./ci/dev/lint.sh",
|
||||
"test": "echo 'Run yarn test:unit or yarn test:e2e' && exit 1",
|
||||
"ci": "./ci/dev/ci.sh",
|
||||
"watch": "VSCODE_DEV=1 VSCODE_IPC_HOOK_CLI= NODE_OPTIONS='--max_old_space_size=32384 --trace-warnings' ts-node ./ci/dev/watch.ts",
|
||||
"watch": "VSCODE_IPC_HOOK_CLI= NODE_OPTIONS='--max_old_space_size=32384 --trace-warnings' ts-node ./ci/dev/watch.ts",
|
||||
"icons": "./ci/dev/gen_icons.sh",
|
||||
"coverage": "codecov"
|
||||
},
|
||||
|
@ -49,18 +48,18 @@
|
|||
"@types/split2": "^3.2.0",
|
||||
"@types/trusted-types": "^2.0.2",
|
||||
"@types/ws": "^8.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"audit-ci": "^5.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.7.0",
|
||||
"@typescript-eslint/parser": "^4.7.0",
|
||||
"audit-ci": "^4.0.0",
|
||||
"codecov": "^3.8.3",
|
||||
"doctoc": "^2.0.0",
|
||||
"eslint": "^7.7.0",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"eslint-import-resolver-typescript": "^2.5.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"prettier": "^2.2.1",
|
||||
"prettier-plugin-sh": "^0.8.0",
|
||||
"prettier-plugin-sh": "^0.7.1",
|
||||
"shellcheck": "^1.0.0",
|
||||
"stylelint": "^13.0.0",
|
||||
"stylelint-config-recommended": "^5.0.0",
|
||||
|
@ -76,12 +75,8 @@
|
|||
"browserslist": "^4.16.5",
|
||||
"safe-buffer": "^5.1.1",
|
||||
"vfile-message": "^2.0.2",
|
||||
"tar": "^6.1.9",
|
||||
"path-parse": "^1.0.7",
|
||||
"vm2": "^3.9.6",
|
||||
"follow-redirects": "^1.14.8",
|
||||
"node-fetch": "^2.6.7",
|
||||
"nanoid": "^3.1.31"
|
||||
"argon2/@mapbox/node-pre-gyp/tar": "^6.1.9",
|
||||
"path-parse": "^1.0.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coder/logger": "1.1.16",
|
||||
|
@ -96,12 +91,13 @@
|
|||
"limiter": "^1.1.5",
|
||||
"pem": "^1.14.2",
|
||||
"proxy-agent": "^5.0.0",
|
||||
"qs": "6.10.3",
|
||||
"rotating-file-stream": "^3.0.0",
|
||||
"proxy-from-env": "^1.1.0",
|
||||
"qs": "6.10.1",
|
||||
"rotating-file-stream": "^2.1.1",
|
||||
"safe-buffer": "^5.1.1",
|
||||
"safe-compare": "^1.1.4",
|
||||
"semver": "^7.1.3",
|
||||
"split2": "^4.0.0",
|
||||
"split2": "^3.2.2",
|
||||
"ws": "^8.0.0",
|
||||
"xdg-basedir": "^4.0.0",
|
||||
"yarn": "^1.22.4"
|
||||
|
@ -157,12 +153,10 @@
|
|||
"<rootDir>/release-standalone",
|
||||
"<rootDir>/release-npm-package",
|
||||
"<rootDir>/release-gcp",
|
||||
"<rootDir>/release-images",
|
||||
"<rootDir>/vendor"
|
||||
"<rootDir>/release-images"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"^.+\\.(css|less)$": "<rootDir>/test/utils/cssStub.ts"
|
||||
},
|
||||
"globalSetup": "<rootDir>/test/utils/globalUnitSetup.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
<div class="content">
|
||||
<form class="login-form" method="post">
|
||||
<input class="user" type="text" autocomplete="username" />
|
||||
<input id="base" type="hidden" name="base" value="{{BASE}}" />
|
||||
<input id="href" type="hidden" name="href" value="" />
|
||||
<div class="field">
|
||||
<input
|
||||
required
|
||||
|
@ -49,13 +47,5 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Inform the backend about the path since the proxy might have rewritten
|
||||
// it out of the headers and cookies must be set with absolute paths.
|
||||
const el = document.getElementById("href")
|
||||
if (el) {
|
||||
el.value = location.href
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -7,7 +7,7 @@ import { logger } from "@coder/logger"
|
|||
export type Callback<T, R = void | Promise<void>> = (t: T, p: Promise<void>) => R
|
||||
|
||||
export interface Disposable {
|
||||
dispose(): void | Promise<void>
|
||||
dispose(): void
|
||||
}
|
||||
|
||||
export interface Event<T> {
|
||||
|
|
|
@ -13,12 +13,8 @@ export enum HttpCode {
|
|||
* used in the HTTP response.
|
||||
*/
|
||||
export class HttpError extends Error {
|
||||
public constructor(message: string, public readonly statusCode: HttpCode, public readonly details?: object) {
|
||||
public constructor(message: string, public readonly status: HttpCode, public readonly details?: object) {
|
||||
super(message)
|
||||
this.name = this.constructor.name
|
||||
}
|
||||
}
|
||||
|
||||
export enum CookieKeys {
|
||||
Session = "code-server-session",
|
||||
}
|
||||
|
|
|
@ -23,12 +23,6 @@ export const generateUuid = (length = 24): string => {
|
|||
|
||||
/**
|
||||
* 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 normalize = (url: string, keepTrailing = false): string => {
|
||||
return url.replace(/\/\/+/g, "/").replace(/\/+$/, keepTrailing ? "/" : "")
|
||||
|
@ -41,6 +35,50 @@ export const trimSlashes = (url: string): string => {
|
|||
return url.replace(/^\/+|\/+$/g, "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a relative base against the window location. This is used for
|
||||
* anything that doesn't work with a relative path.
|
||||
*/
|
||||
export const resolveBase = (base?: string): string => {
|
||||
// After resolving the base will either start with / or be an empty string.
|
||||
if (!base || base.startsWith("/")) {
|
||||
return base ?? ""
|
||||
}
|
||||
const parts = location.pathname.split("/")
|
||||
parts[parts.length - 1] = base
|
||||
const url = new URL(location.origin + "/" + parts.join("/"))
|
||||
return normalize(url.pathname)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get client-side configuration embedded in the HTML or query params.
|
||||
*/
|
||||
export const getClientConfiguration = <T extends CodeServerLib.ClientConfiguration>(): T => {
|
||||
let config: T
|
||||
try {
|
||||
config = JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!)
|
||||
} catch (error) {
|
||||
config = {} as T
|
||||
}
|
||||
|
||||
// You can also pass options in stringified form to the options query
|
||||
// variable. Options provided here will override the ones in the options
|
||||
// element.
|
||||
const params = new URLSearchParams(location.search)
|
||||
const queryOpts = params.get("options")
|
||||
if (queryOpts) {
|
||||
config = {
|
||||
...config,
|
||||
...JSON.parse(queryOpts),
|
||||
}
|
||||
}
|
||||
|
||||
config.base = resolveBase(config.base)
|
||||
config.csStaticBase = resolveBase(config.csStaticBase)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the value in an array if it's not already an array. If the value is
|
||||
* undefined return an empty array.
|
||||
|
@ -56,7 +94,7 @@ export const arrayify = <T>(value?: T | T[]): T[] => {
|
|||
}
|
||||
|
||||
// TODO: Might make sense to add Error handling to the logger itself.
|
||||
export function logError(logger: { error: (msg: string) => void }, prefix: string, err: unknown): void {
|
||||
export function logError(logger: { error: (msg: string) => void }, prefix: string, err: Error | string): void {
|
||||
if (err instanceof Error) {
|
||||
logger.error(`${prefix}: ${err.message} ${err.stack}`)
|
||||
} else {
|
||||
|
|
|
@ -4,24 +4,13 @@ import express, { Express } from "express"
|
|||
import { promises as fs } from "fs"
|
||||
import http from "http"
|
||||
import * as httpolyglot from "httpolyglot"
|
||||
import { Disposable } from "../common/emitter"
|
||||
import * as util from "../common/util"
|
||||
import { DefaultedArgs } from "./cli"
|
||||
import { disposer } from "./http"
|
||||
import { isNodeJSErrnoException } from "./util"
|
||||
import { handleUpgrade } from "./wsRouter"
|
||||
|
||||
type ListenOptions = Pick<DefaultedArgs, "socket" | "port" | "host">
|
||||
|
||||
export interface App extends Disposable {
|
||||
/** Handles regular HTTP requests. */
|
||||
router: Express
|
||||
/** Handles websocket requests. */
|
||||
wsRouter: Express
|
||||
/** The underlying HTTP server. */
|
||||
server: http.Server
|
||||
}
|
||||
|
||||
const listen = (server: http.Server, { host, port, socket }: ListenOptions) => {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
server.on("error", reject)
|
||||
|
@ -52,9 +41,10 @@ const listen = (server: http.Server, { host, port, socket }: ListenOptions) => {
|
|||
/**
|
||||
* Create an Express app and an HTTP/S server to serve it.
|
||||
*/
|
||||
export const createApp = async (args: DefaultedArgs): Promise<App> => {
|
||||
const router = express()
|
||||
router.use(compression())
|
||||
export const createApp = async (args: DefaultedArgs): Promise<[Express, Express, http.Server]> => {
|
||||
const app = express()
|
||||
|
||||
app.use(compression())
|
||||
|
||||
const server = args.cert
|
||||
? httpolyglot.createServer(
|
||||
|
@ -62,38 +52,30 @@ export const createApp = async (args: DefaultedArgs): Promise<App> => {
|
|||
cert: args.cert && (await fs.readFile(args.cert.value)),
|
||||
key: args["cert-key"] && (await fs.readFile(args["cert-key"])),
|
||||
},
|
||||
router,
|
||||
app,
|
||||
)
|
||||
: http.createServer(router)
|
||||
|
||||
const dispose = disposer(server)
|
||||
: http.createServer(app)
|
||||
|
||||
await listen(server, args)
|
||||
|
||||
const wsRouter = express()
|
||||
handleUpgrade(wsRouter, server)
|
||||
const wsApp = express()
|
||||
handleUpgrade(wsApp, server)
|
||||
|
||||
return { router, wsRouter, server, dispose }
|
||||
return [app, wsApp, server]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address of a server as a string (protocol *is* included) while
|
||||
* ensuring there is one (will throw if there isn't).
|
||||
*
|
||||
* The address might be a URL or it might be a pipe or socket path.
|
||||
*/
|
||||
export const ensureAddress = (server: http.Server, protocol: string): URL | string => {
|
||||
export const ensureAddress = (server: http.Server): string => {
|
||||
const addr = server.address()
|
||||
|
||||
if (!addr) {
|
||||
throw new Error("Server has no address")
|
||||
throw new Error("server has no address")
|
||||
}
|
||||
|
||||
if (typeof addr !== "string") {
|
||||
return new URL(`${protocol}://${addr.address}:${addr.port}`)
|
||||
return `http://${addr.address}:${addr.port}`
|
||||
}
|
||||
|
||||
// If this is a string then it is a pipe or Unix socket.
|
||||
return addr
|
||||
}
|
||||
|
||||
|
|
224
src/node/cli.ts
224
src/node/cli.ts
|
@ -3,17 +3,7 @@ import { promises as fs } from "fs"
|
|||
import yaml from "js-yaml"
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
import {
|
||||
canConnect,
|
||||
generateCertificate,
|
||||
generatePassword,
|
||||
humanPath,
|
||||
paths,
|
||||
isNodeJSErrnoException,
|
||||
isFile,
|
||||
} from "./util"
|
||||
|
||||
const DEFAULT_SOCKET_PATH = path.join(os.tmpdir(), "vscode-ipc")
|
||||
import { canConnect, generateCertificate, generatePassword, humanPath, paths } from "./util"
|
||||
|
||||
export enum Feature {
|
||||
// No current experimental features!
|
||||
|
@ -39,13 +29,21 @@ export enum LogLevel {
|
|||
|
||||
export class OptionalString extends Optional<string> {}
|
||||
|
||||
/**
|
||||
* Arguments that the user explicitly provided on the command line. All
|
||||
* arguments must be optional.
|
||||
*
|
||||
* For arguments with defaults see DefaultedArgs.
|
||||
*/
|
||||
export interface UserProvidedArgs {
|
||||
export interface Args
|
||||
extends Pick<
|
||||
CodeServerLib.NativeParsedArgs,
|
||||
| "user-data-dir"
|
||||
| "enable-proposed-api"
|
||||
| "extensions-dir"
|
||||
| "builtin-extensions-dir"
|
||||
| "extra-extensions-dir"
|
||||
| "extra-builtin-extensions-dir"
|
||||
| "ignore-last-opened"
|
||||
| "locale"
|
||||
| "log"
|
||||
| "verbose"
|
||||
| "_"
|
||||
> {
|
||||
config?: string
|
||||
auth?: AuthType
|
||||
password?: string
|
||||
|
@ -53,40 +51,28 @@ export interface UserProvidedArgs {
|
|||
cert?: OptionalString
|
||||
"cert-host"?: string
|
||||
"cert-key"?: string
|
||||
"disable-telemetry"?: boolean
|
||||
"disable-update-check"?: boolean
|
||||
enable?: string[]
|
||||
help?: boolean
|
||||
host?: string
|
||||
locale?: string
|
||||
port?: number
|
||||
json?: boolean
|
||||
log?: LogLevel
|
||||
open?: boolean
|
||||
port?: number
|
||||
"bind-addr"?: string
|
||||
socket?: string
|
||||
version?: boolean
|
||||
force?: boolean
|
||||
"list-extensions"?: boolean
|
||||
"install-extension"?: string[]
|
||||
"show-versions"?: boolean
|
||||
"uninstall-extension"?: string[]
|
||||
"proxy-domain"?: string[]
|
||||
"reuse-window"?: boolean
|
||||
"new-window"?: boolean
|
||||
"ignore-last-opened"?: boolean
|
||||
link?: OptionalString
|
||||
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
|
||||
link?: OptionalString
|
||||
}
|
||||
|
||||
interface Option<T> {
|
||||
|
@ -105,9 +91,9 @@ interface Option<T> {
|
|||
description?: string
|
||||
|
||||
/**
|
||||
* If marked as deprecated, the option is marked as deprecated in help.
|
||||
* If marked as beta, the option is marked as beta in help.
|
||||
*/
|
||||
deprecated?: boolean
|
||||
beta?: boolean
|
||||
}
|
||||
|
||||
type OptionType<T> = T extends boolean
|
||||
|
@ -130,7 +116,7 @@ type Options<T> = {
|
|||
[P in keyof T]: Option<OptionType<T[P]>>
|
||||
}
|
||||
|
||||
const options: Options<Required<UserProvidedArgs>> = {
|
||||
const options: Options<Required<Args>> = {
|
||||
auth: { type: AuthType, description: "The type of authentication to use." },
|
||||
password: {
|
||||
type: "string",
|
||||
|
@ -164,7 +150,6 @@ const options: Options<Required<UserProvidedArgs>> = {
|
|||
enable: { type: "string[]" },
|
||||
help: { type: "boolean", short: "h", description: "Show this output." },
|
||||
json: { type: "boolean" },
|
||||
locale: { type: "string" }, // The preferred way to set the locale is via the UI.
|
||||
open: { type: "boolean", description: "Open in browser on startup. Does not work remotely." },
|
||||
|
||||
"bind-addr": {
|
||||
|
@ -188,10 +173,10 @@ const options: Options<Required<UserProvidedArgs>> = {
|
|||
"user-data-dir": { type: "string", path: true, description: "Path to the user data directory." },
|
||||
"extensions-dir": { type: "string", path: true, description: "Path to the extensions directory." },
|
||||
"builtin-extensions-dir": { type: "string", path: true },
|
||||
"extra-extensions-dir": { type: "string[]", path: true },
|
||||
"extra-builtin-extensions-dir": { type: "string[]", path: true },
|
||||
"list-extensions": { type: "boolean", description: "List installed VS Code extensions." },
|
||||
force: { type: "boolean", description: "Avoid prompts when installing VS Code extensions." },
|
||||
"locate-extension": { type: "string[]" },
|
||||
category: { type: "string" },
|
||||
"install-extension": {
|
||||
type: "string[]",
|
||||
description:
|
||||
|
@ -222,6 +207,7 @@ const options: Options<Required<UserProvidedArgs>> = {
|
|||
description: "Force to open a file or folder in an already opened window.",
|
||||
},
|
||||
|
||||
locale: { type: "string" },
|
||||
log: { type: LogLevel },
|
||||
verbose: { type: "boolean", short: "vvv", description: "Enable verbose logging." },
|
||||
|
||||
|
@ -229,10 +215,10 @@ const options: Options<Required<UserProvidedArgs>> = {
|
|||
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.
|
||||
https://hostname-username.cdr.co at which you can easily access your code-server instance.
|
||||
Authorization is done via GitHub.
|
||||
`,
|
||||
deprecated: true,
|
||||
beta: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -255,7 +241,7 @@ export const optionDescriptions = (): string[] => {
|
|||
.map((line, i) => {
|
||||
line = line.trim()
|
||||
if (i === 0) {
|
||||
return " ".repeat(widths.long - k.length) + (v.deprecated ? "(deprecated) " : "") + line
|
||||
return " ".repeat(widths.long - k.length) + (v.beta ? "(beta) " : "") + line
|
||||
}
|
||||
return " ".repeat(widths.long + widths.short + 6) + line
|
||||
})
|
||||
|
@ -278,16 +264,12 @@ export function splitOnFirstEquals(str: string): string[] {
|
|||
return split
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse arguments into UserProvidedArgs. This should not go beyond checking
|
||||
* that arguments are valid types and have values when required.
|
||||
*/
|
||||
export const parse = (
|
||||
argv: string[],
|
||||
opts?: {
|
||||
configFile?: string
|
||||
},
|
||||
): UserProvidedArgs => {
|
||||
): Args => {
|
||||
const error = (msg: string): Error => {
|
||||
if (opts?.configFile) {
|
||||
msg = `error reading ${opts.configFile}: ${msg}`
|
||||
|
@ -296,7 +278,7 @@ export const parse = (
|
|||
return new Error(msg)
|
||||
}
|
||||
|
||||
const args: UserProvidedArgs = {}
|
||||
const args: Args = { _: [] }
|
||||
let ended = false
|
||||
|
||||
for (let i = 0; i < argv.length; ++i) {
|
||||
|
@ -310,17 +292,17 @@ export const parse = (
|
|||
|
||||
// Options start with a dash and require a value if non-boolean.
|
||||
if (!ended && arg.startsWith("-")) {
|
||||
let key: keyof UserProvidedArgs | undefined
|
||||
let key: keyof Args | undefined
|
||||
let value: string | undefined
|
||||
if (arg.startsWith("--")) {
|
||||
const split = splitOnFirstEquals(arg.replace(/^--/, ""))
|
||||
key = split[0] as keyof UserProvidedArgs
|
||||
key = split[0] as keyof Args
|
||||
value = split[1]
|
||||
} else {
|
||||
const short = arg.replace(/^-/, "")
|
||||
const pair = Object.entries(options).find(([, v]) => v.short === short)
|
||||
if (pair) {
|
||||
key = pair[0] as keyof UserProvidedArgs
|
||||
key = pair[0] as keyof Args
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,10 +377,6 @@ export const parse = (
|
|||
}
|
||||
|
||||
// Everything else goes into _.
|
||||
if (typeof args._ === "undefined") {
|
||||
args._ = []
|
||||
}
|
||||
|
||||
args._.push(arg)
|
||||
}
|
||||
|
||||
|
@ -407,19 +385,11 @@ export const parse = (
|
|||
throw new Error("--cert-key is missing")
|
||||
}
|
||||
|
||||
logger.debug(() => [
|
||||
`parsed ${opts?.configFile ? "config" : "command line"}`,
|
||||
field("args", { ...args, password: undefined }),
|
||||
])
|
||||
logger.debug(() => ["parsed command line", field("args", { ...args, password: undefined })])
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
/**
|
||||
* User-provided arguments with defaults. The distinction between user-provided
|
||||
* args and defaulted args exists so we can tell the difference between end
|
||||
* values and what the user actually provided on the command line.
|
||||
*/
|
||||
export interface DefaultedArgs extends ConfigArgs {
|
||||
auth: AuthType
|
||||
cert?: {
|
||||
|
@ -433,8 +403,6 @@ export interface DefaultedArgs extends ConfigArgs {
|
|||
usingEnvHashedPassword: boolean
|
||||
"extensions-dir": string
|
||||
"user-data-dir": string
|
||||
/* Positional arguments. */
|
||||
_: []
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -442,7 +410,7 @@ export interface DefaultedArgs extends ConfigArgs {
|
|||
* with the defaults set. Arguments from the CLI are prioritized over config
|
||||
* arguments.
|
||||
*/
|
||||
export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: ConfigArgs): Promise<DefaultedArgs> {
|
||||
export async function setDefaults(cliArgs: Args, configArgs?: ConfigArgs): Promise<DefaultedArgs> {
|
||||
const args = Object.assign({}, configArgs || {}, cliArgs)
|
||||
|
||||
if (!args["user-data-dir"]) {
|
||||
|
@ -497,7 +465,7 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
|
|||
args.auth = AuthType.Password
|
||||
}
|
||||
|
||||
const addr = bindAddrFromAllSources(configArgs || {}, cliArgs)
|
||||
const addr = bindAddrFromAllSources(configArgs || { _: [] }, cliArgs)
|
||||
args.host = addr.host
|
||||
args.port = addr.port
|
||||
|
||||
|
@ -538,10 +506,6 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
|
|||
const proxyDomains = new Set((args["proxy-domain"] || []).map((d) => d.replace(/^\*\./, "")))
|
||||
args["proxy-domain"] = Array.from(proxyDomains)
|
||||
|
||||
if (typeof args._ === "undefined") {
|
||||
args._ = []
|
||||
}
|
||||
|
||||
return {
|
||||
...args,
|
||||
usingEnvPassword,
|
||||
|
@ -568,7 +532,7 @@ cert: false
|
|||
`
|
||||
}
|
||||
|
||||
interface ConfigArgs extends UserProvidedArgs {
|
||||
interface ConfigArgs extends Args {
|
||||
config: string
|
||||
}
|
||||
|
||||
|
@ -592,7 +556,7 @@ export async function readConfigFile(configPath?: string): Promise<ConfigArgs> {
|
|||
await fs.writeFile(configPath, defaultConfigFile(generatedPassword), {
|
||||
flag: "wx", // wx means to fail if the path exists.
|
||||
})
|
||||
logger.info(`Wrote default config file to ${humanPath(os.homedir(), configPath)}`)
|
||||
logger.info(`Wrote default config file to ${humanPath(configPath)}`)
|
||||
} catch (error: any) {
|
||||
// EEXIST is fine; we don't want to overwrite existing configurations.
|
||||
if (error.code !== "EEXIST") {
|
||||
|
@ -610,7 +574,7 @@ export async function readConfigFile(configPath?: string): Promise<ConfigArgs> {
|
|||
*/
|
||||
export function parseConfigFile(configFile: string, configPath: string): ConfigArgs {
|
||||
if (!configFile) {
|
||||
return { config: configPath }
|
||||
return { _: [], config: configPath }
|
||||
}
|
||||
|
||||
const config = yaml.load(configFile, {
|
||||
|
@ -657,7 +621,7 @@ interface Addr {
|
|||
* This function creates the bind address
|
||||
* using the CLI args.
|
||||
*/
|
||||
export function bindAddrFromArgs(addr: Addr, args: UserProvidedArgs): Addr {
|
||||
export function bindAddrFromArgs(addr: Addr, args: Args): Addr {
|
||||
addr = { ...addr }
|
||||
if (args["bind-addr"]) {
|
||||
addr = parseBindAddr(args["bind-addr"])
|
||||
|
@ -675,7 +639,7 @@ export function bindAddrFromArgs(addr: Addr, args: UserProvidedArgs): Addr {
|
|||
return addr
|
||||
}
|
||||
|
||||
function bindAddrFromAllSources(...argsConfig: UserProvidedArgs[]): Addr {
|
||||
function bindAddrFromAllSources(...argsConfig: Args[]): Addr {
|
||||
let addr: Addr = {
|
||||
host: "localhost",
|
||||
port: 8080,
|
||||
|
@ -688,92 +652,62 @@ function bindAddrFromAllSources(...argsConfig: UserProvidedArgs[]): Addr {
|
|||
return addr
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the socketPath based on path passed in.
|
||||
*
|
||||
* The one usually passed in is the DEFAULT_SOCKET_PATH.
|
||||
*
|
||||
* If it can't read the path, it throws an error and returns undefined.
|
||||
*/
|
||||
export async function readSocketPath(path: string): Promise<string | undefined> {
|
||||
try {
|
||||
return await fs.readFile(path, "utf8")
|
||||
} catch (error) {
|
||||
// If it doesn't exist, we don't care.
|
||||
// But if it fails for some reason, we should throw.
|
||||
// We want to surface that to the user.
|
||||
if (!isNodeJSErrnoException(error) || error.code !== "ENOENT") {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
export const shouldRunVsCodeCli = (args: Args): boolean => {
|
||||
// Create new interface with only Arg keys
|
||||
// keyof Args
|
||||
// Turn that into an array
|
||||
// Array<...>
|
||||
type ExtensionArgs = Array<keyof Args>
|
||||
const extensionRelatedArgs: ExtensionArgs = ["list-extensions", "install-extension", "uninstall-extension"]
|
||||
|
||||
const argKeys = Object.keys(args)
|
||||
|
||||
// If any of the extensionRelatedArgs are included in args
|
||||
// then we don't want to run the vscode cli
|
||||
return extensionRelatedArgs.some((arg) => argKeys.includes(arg))
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if it looks like the user is trying to open a file or folder in an
|
||||
* existing instance. The arguments here should be the arguments the user
|
||||
* explicitly passed on the command line, *NOT DEFAULTS* or the configuration.
|
||||
* explicitly passed on the command line, not defaults or the configuration.
|
||||
*/
|
||||
export const shouldOpenInExistingInstance = async (args: UserProvidedArgs): Promise<string | undefined> => {
|
||||
export const shouldOpenInExistingInstance = async (args: Args): Promise<string | undefined> => {
|
||||
// Always use the existing instance if we're running from VS Code's terminal.
|
||||
if (process.env.VSCODE_IPC_HOOK_CLI) {
|
||||
logger.debug("Found VSCODE_IPC_HOOK_CLI")
|
||||
return process.env.VSCODE_IPC_HOOK_CLI
|
||||
}
|
||||
|
||||
const readSocketPath = async (): Promise<string | undefined> => {
|
||||
try {
|
||||
return await fs.readFile(path.join(os.tmpdir(), "vscode-ipc"), "utf8")
|
||||
} catch (error: any) {
|
||||
if (error.code !== "ENOENT") {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
// If these flags are set then assume the user is trying to open in an
|
||||
// existing instance since these flags have no effect otherwise.
|
||||
const openInFlagCount = ["reuse-window", "new-window"].reduce((prev, cur) => {
|
||||
return args[cur as keyof UserProvidedArgs] ? prev + 1 : prev
|
||||
return args[cur as keyof Args] ? prev + 1 : prev
|
||||
}, 0)
|
||||
if (openInFlagCount > 0) {
|
||||
logger.debug("Found --reuse-window or --new-window")
|
||||
return readSocketPath(DEFAULT_SOCKET_PATH)
|
||||
return readSocketPath()
|
||||
}
|
||||
|
||||
// It's possible the user is trying to spawn another instance of code-server.
|
||||
// 1. Check if any unrelated flags are set (this should only run when
|
||||
// code-server is invoked exactly like this: `code-server my-file`).
|
||||
// 2. That a file or directory was passed.
|
||||
// 3. That the socket is active.
|
||||
if (Object.keys(args).length === 1 && typeof args._ !== "undefined" && args._.length > 0) {
|
||||
const socketPath = await readSocketPath(DEFAULT_SOCKET_PATH)
|
||||
// Check if any unrelated flags are set (check against one because `_` always
|
||||
// exists), that a file or directory was passed, and that the socket is
|
||||
// active.
|
||||
if (Object.keys(args).length === 1 && args._.length > 0) {
|
||||
const socketPath = await readSocketPath()
|
||||
if (socketPath && (await canConnect(socketPath))) {
|
||||
logger.debug("Found existing code-server socket")
|
||||
return socketPath
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert our arguments to VS Code server arguments.
|
||||
*/
|
||||
export const toVsCodeArgs = async (args: DefaultedArgs): Promise<CodeServerLib.ServerParsedArgs> => {
|
||||
let workspace = ""
|
||||
let folder = ""
|
||||
if (args._.length) {
|
||||
const lastEntry = path.resolve(args._[args._.length - 1])
|
||||
const entryIsFile = await isFile(lastEntry)
|
||||
if (entryIsFile && path.extname(lastEntry) === ".code-workspace") {
|
||||
workspace = lastEntry
|
||||
} else if (!entryIsFile) {
|
||||
folder = lastEntry
|
||||
}
|
||||
// Otherwise it is a regular file. Spawning VS Code with a file is not yet
|
||||
// supported but it can be done separately after code-server spawns.
|
||||
}
|
||||
|
||||
return {
|
||||
"connection-token": "0000",
|
||||
...args,
|
||||
workspace,
|
||||
folder,
|
||||
"accept-server-license-terms": true,
|
||||
/** Type casting. */
|
||||
help: !!args.help,
|
||||
version: !!args.version,
|
||||
port: args.port?.toString(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { spawn } from "child_process"
|
|||
import path from "path"
|
||||
import split2 from "split2"
|
||||
|
||||
// https://github.com/coder/coder-cloud
|
||||
// https://github.com/cdr/coder-cloud
|
||||
const coderCloudAgent = path.resolve(__dirname, "../../lib/coder-cloud-agent")
|
||||
|
||||
function runAgent(...args: string[]): Promise<void> {
|
||||
|
@ -33,11 +33,9 @@ function runAgent(...args: string[]): Promise<void> {
|
|||
})
|
||||
}
|
||||
|
||||
export function coderCloudBind(address: URL | string, serverName = ""): Promise<void> {
|
||||
if (typeof address === "string") {
|
||||
throw new Error("Cannot link socket paths")
|
||||
}
|
||||
|
||||
// Address needs to be in hostname:port format without the protocol.
|
||||
return runAgent("bind", `--code-server-addr=${address.host}`, serverName)
|
||||
export function coderCloudBind(csAddr: string, serverName = ""): Promise<void> {
|
||||
// addr needs to be in host:port format.
|
||||
// So we trim the protocol.
|
||||
csAddr = csAddr.replace(/^https?:\/\//, "")
|
||||
return runAgent("bind", `--code-server-addr=${csAddr}`, serverName)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { logger } from "@coder/logger"
|
||||
import type { JSONSchemaForNPMPackageJsonFiles } from "@schemastore/package"
|
||||
import { JSONSchemaForNPMPackageJsonFiles } from "@schemastore/package"
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
|
||||
|
@ -18,12 +18,9 @@ export function getPackageJson(relativePath: string): JSONSchemaForNPMPackageJso
|
|||
|
||||
const pkg = getPackageJson("../../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 tmpdir = path.join(os.tmpdir(), "code-server")
|
||||
export const isDevMode = commit === "development"
|
||||
export const httpProxyUri =
|
||||
process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
import { logger } from "@coder/logger"
|
||||
import { optionDescriptions, parse, readConfigFile, setDefaults, shouldOpenInExistingInstance } from "./cli"
|
||||
import {
|
||||
optionDescriptions,
|
||||
parse,
|
||||
readConfigFile,
|
||||
setDefaults,
|
||||
shouldOpenInExistingInstance,
|
||||
shouldRunVsCodeCli,
|
||||
} from "./cli"
|
||||
import { commit, version } from "./constants"
|
||||
import { openInExistingInstance, runCodeServer, runVsCodeCli, shouldSpawnCliProcess } from "./main"
|
||||
import { openInExistingInstance, runCodeServer, runVsCodeCli } from "./main"
|
||||
import { monkeyPatchProxyProtocols } from "./proxy_agent"
|
||||
import { isChild, wrapper } from "./wrapper"
|
||||
|
||||
async function entry(): Promise<void> {
|
||||
monkeyPatchProxyProtocols()
|
||||
|
||||
// There's no need to check flags like --help or to spawn in an existing
|
||||
// instance for the child process because these would have already happened in
|
||||
// the parent and the child wouldn't have been spawned. We also get the
|
||||
|
@ -14,8 +24,7 @@ async function entry(): Promise<void> {
|
|||
if (isChild(wrapper)) {
|
||||
const args = await wrapper.handshake()
|
||||
wrapper.preventExit()
|
||||
const server = await runCodeServer(args)
|
||||
wrapper.onDispose(() => server.dispose())
|
||||
await runCodeServer(args)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -27,8 +36,6 @@ async function entry(): Promise<void> {
|
|||
console.log("code-server", version, commit)
|
||||
console.log("")
|
||||
console.log(`Usage: code-server [options] [path]`)
|
||||
console.log(` - Opening a directory: code-server ./path/to/your/project`)
|
||||
console.log(` - Opening a saved workspace: code-server ./path/to/your/project.code-workspace`)
|
||||
console.log("")
|
||||
console.log("Options")
|
||||
optionDescriptions().forEach((description) => {
|
||||
|
@ -52,14 +59,12 @@ async function entry(): Promise<void> {
|
|||
return
|
||||
}
|
||||
|
||||
if (shouldSpawnCliProcess(args)) {
|
||||
logger.debug("Found VS Code arguments; spawning VS Code CLI")
|
||||
if (shouldRunVsCodeCli(args)) {
|
||||
return runVsCodeCli(args)
|
||||
}
|
||||
|
||||
const socketPath = await shouldOpenInExistingInstance(cliArgs)
|
||||
if (socketPath) {
|
||||
logger.debug("Trying to open in existing instance")
|
||||
return openInExistingInstance(args, socketPath)
|
||||
}
|
||||
|
||||
|
|
144
src/node/http.ts
144
src/node/http.ts
|
@ -1,48 +1,31 @@
|
|||
import { field, logger } from "@coder/logger"
|
||||
import * as express from "express"
|
||||
import * as expressCore from "express-serve-static-core"
|
||||
import * as http from "http"
|
||||
import * as net from "net"
|
||||
import * as qs from "qs"
|
||||
import { Disposable } from "../common/emitter"
|
||||
import { CookieKeys, HttpCode, HttpError } from "../common/http"
|
||||
import path from "path"
|
||||
import qs from "qs"
|
||||
import { HttpCode, HttpError } from "../common/http"
|
||||
import { normalize } from "../common/util"
|
||||
import { AuthType, DefaultedArgs } from "./cli"
|
||||
import { version as codeServerVersion } from "./constants"
|
||||
import { Heart } from "./heart"
|
||||
import { CoderSettings, SettingsProvider } from "./settings"
|
||||
import { UpdateProvider } from "./update"
|
||||
import { getPasswordMethod, IsCookieValidArgs, isCookieValid, sanitizeString, escapeHtml, escapeJSON } from "./util"
|
||||
|
||||
/**
|
||||
* Base options included on every page.
|
||||
*/
|
||||
export interface ClientConfiguration {
|
||||
codeServerVersion: string
|
||||
/** Relative path from this page to the root. No trailing slash. */
|
||||
base: string
|
||||
/** Relative path from this page to the static root. No trailing slash. */
|
||||
csStaticBase: string
|
||||
}
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Express {
|
||||
export interface Request {
|
||||
args: DefaultedArgs
|
||||
heart: Heart
|
||||
settings: SettingsProvider<CoderSettings>
|
||||
updater: UpdateProvider
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createClientConfiguration = (req: express.Request): ClientConfiguration => {
|
||||
const base = relativeRoot(req.originalUrl)
|
||||
export const createClientConfiguration = (req: express.Request): CodeServerLib.ClientConfiguration => {
|
||||
const base = relativeRoot(req)
|
||||
|
||||
return {
|
||||
base,
|
||||
csStaticBase: base + "/_static",
|
||||
csStaticBase: normalize(path.join(base, "_static/")),
|
||||
codeServerVersion,
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +38,7 @@ export const replaceTemplates = <T extends object>(
|
|||
content: string,
|
||||
extraOpts?: Omit<T, "base" | "csStaticBase" | "logLevel">,
|
||||
): string => {
|
||||
const serverOptions: ClientConfiguration = {
|
||||
const serverOptions: CodeServerLib.ClientConfiguration = {
|
||||
...createClientConfiguration(req),
|
||||
...extraOpts,
|
||||
}
|
||||
|
@ -98,7 +81,7 @@ export const authenticated = async (req: express.Request): Promise<boolean> => {
|
|||
const passwordMethod = getPasswordMethod(hashedPasswordFromArgs)
|
||||
const isCookieValidArgs: IsCookieValidArgs = {
|
||||
passwordMethod,
|
||||
cookieKey: sanitizeString(req.cookies[CookieKeys.Session]),
|
||||
cookieKey: sanitizeString(req.cookies.key),
|
||||
passwordFromArgs: req.args.password || "",
|
||||
hashedPasswordFromArgs: req.args["hashed-password"],
|
||||
}
|
||||
|
@ -113,34 +96,21 @@ export const authenticated = async (req: express.Request): Promise<boolean> => {
|
|||
|
||||
/**
|
||||
* 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:
|
||||
*
|
||||
* slash we need to go up a directory. 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
|
||||
export const relativeRoot = (req: express.Request): string => {
|
||||
const depth = (req.originalUrl.split("?", 1)[0].match(/\//g) || []).length
|
||||
return normalize("./" + (depth > 1 ? "../".repeat(depth - 1) : ""))
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect relatively to `/${to}`. Query variables on the current URI will be
|
||||
* preserved. `to` should be a simple path without any query parameters
|
||||
* Redirect relatively to `/${to}`. Query variables on the current URI will be preserved.
|
||||
* `to` should be a simple path without any query parameters
|
||||
* `override` will merge with the existing query (use `undefined` to unset).
|
||||
*/
|
||||
export const redirect = (
|
||||
|
@ -156,7 +126,7 @@ export const redirect = (
|
|||
}
|
||||
})
|
||||
|
||||
const relativePath = normalize(`${relativeRoot(req.originalUrl)}/${to}`, true)
|
||||
const relativePath = normalize(`${relativeRoot(req)}/${to}`, true)
|
||||
const queryString = qs.stringify(query)
|
||||
const redirectPath = `${relativePath}${queryString ? `?${queryString}` : ""}`
|
||||
logger.debug(`redirecting from ${req.originalUrl} to ${redirectPath}`)
|
||||
|
@ -209,89 +179,3 @@ export const getCookieDomain = (host: string, proxyDomains: string[]): string |
|
|||
logger.debug("got cookie doman", field("host", host))
|
||||
return host || undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a function capable of fully disposing an HTTP server.
|
||||
*/
|
||||
export function disposer(server: http.Server): Disposable["dispose"] {
|
||||
const sockets = new Set<net.Socket>()
|
||||
let cleanupTimeout: undefined | NodeJS.Timeout
|
||||
|
||||
server.on("connection", (socket) => {
|
||||
sockets.add(socket)
|
||||
|
||||
socket.on("close", () => {
|
||||
sockets.delete(socket)
|
||||
|
||||
if (cleanupTimeout && sockets.size === 0) {
|
||||
clearTimeout(cleanupTimeout)
|
||||
cleanupTimeout = undefined
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return () => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
// The whole reason we need this disposer is because close will not
|
||||
// actually close anything; it only prevents future connections then waits
|
||||
// until everything is closed.
|
||||
server.close((err) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
resolve()
|
||||
})
|
||||
|
||||
// If there are sockets remaining we might need to force close them or
|
||||
// this promise might never resolve.
|
||||
if (sockets.size > 0) {
|
||||
// Give sockets a chance to close up shop.
|
||||
cleanupTimeout = setTimeout(() => {
|
||||
cleanupTimeout = undefined
|
||||
|
||||
for (const socket of sockets.values()) {
|
||||
console.warn("a socket was left hanging")
|
||||
socket.destroy()
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the options for setting a cookie. The options must be identical for
|
||||
* setting and unsetting cookies otherwise they are considered separate.
|
||||
*/
|
||||
export const getCookieOptions = (req: express.Request): express.CookieOptions => {
|
||||
// Normally we set paths relatively. However browsers do not appear to allow
|
||||
// cookies to be set relatively which means we need an absolute path. We
|
||||
// cannot be guaranteed we know the path since a reverse proxy might have
|
||||
// rewritten it. That means we need to get the path from the frontend.
|
||||
|
||||
// The reason we need to set the path (as opposed to defaulting to /) is to
|
||||
// avoid code-server instances on different sub-paths clobbering each other or
|
||||
// from accessing each other's tokens (and to prevent other services from
|
||||
// accessing code-server's tokens).
|
||||
|
||||
// When logging in or out the request must include the href (the full current
|
||||
// URL of that page) and the relative path to the root as given to it by the
|
||||
// backend. Using these two we can determine the true absolute root.
|
||||
const url = new URL(
|
||||
req.query.base || req.body.base || "/",
|
||||
req.query.href || req.body.href || "http://" + (req.headers.host || "localhost"),
|
||||
)
|
||||
return {
|
||||
domain: getCookieDomain(url.host, req.args["proxy-domain"]),
|
||||
path: normalize(url.pathname) || "/",
|
||||
sameSite: "lax",
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full path to the current page, preserving any trailing slash.
|
||||
*/
|
||||
export const self = (req: express.Request): string => {
|
||||
return normalize(`${req.baseUrl}${req.originalUrl.endsWith("/") ? "/" : ""}`, true)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import { logger } from "@coder/logger"
|
||||
import { spawn } from "child_process"
|
||||
import path from "path"
|
||||
|
||||
export function startLink(port: number): Promise<void> {
|
||||
logger.debug(`running link targetting ${port}`)
|
||||
|
||||
const agent = spawn(path.resolve(__dirname, "../../lib/linkup"), ["--devurl", `code:${port}:code-server`], {
|
||||
shell: false,
|
||||
})
|
||||
return new Promise((res, rej) => {
|
||||
agent.on("error", rej)
|
||||
agent.on("close", (code) => {
|
||||
if (code !== 0) {
|
||||
return rej({
|
||||
message: `Link exited with ${code}`,
|
||||
})
|
||||
}
|
||||
res()
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,28 +1,15 @@
|
|||
import { field, logger } from "@coder/logger"
|
||||
import http from "http"
|
||||
import * as os from "os"
|
||||
import path from "path"
|
||||
import { Disposable } from "../common/emitter"
|
||||
import { plural } from "../common/util"
|
||||
import { createApp, ensureAddress } from "./app"
|
||||
import { AuthType, DefaultedArgs, Feature, toVsCodeArgs, UserProvidedArgs } from "./cli"
|
||||
import { AuthType, DefaultedArgs, Feature } from "./cli"
|
||||
import { coderCloudBind } from "./coder_cloud"
|
||||
import { commit, version } from "./constants"
|
||||
import { startLink } from "./link"
|
||||
import { register } from "./routes"
|
||||
import { humanPath, isFile, loadAMDModule, open } from "./util"
|
||||
|
||||
/**
|
||||
* Return true if the user passed an extension-related VS Code flag.
|
||||
*/
|
||||
export const shouldSpawnCliProcess = (args: UserProvidedArgs): boolean => {
|
||||
return (
|
||||
!!args["list-extensions"] ||
|
||||
!!args["install-extension"] ||
|
||||
!!args["uninstall-extension"] ||
|
||||
!!args["locate-extension"]
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is useful when an CLI arg should be passed to VS Code directly,
|
||||
* such as when managing extensions.
|
||||
|
@ -31,13 +18,12 @@ export const shouldSpawnCliProcess = (args: UserProvidedArgs): boolean => {
|
|||
export const runVsCodeCli = async (args: DefaultedArgs): Promise<void> => {
|
||||
logger.debug("Running VS Code CLI")
|
||||
|
||||
// See ../../vendor/modules/code-oss-dev/src/vs/server/main.js.
|
||||
const spawnCli = await loadAMDModule<CodeServerLib.SpawnCli>("vs/server/remoteExtensionHostAgent", "spawnCli")
|
||||
const cliProcessMain = await loadAMDModule<CodeServerLib.IMainCli["main"]>("vs/code/node/cliProcessMain", "main")
|
||||
|
||||
try {
|
||||
await spawnCli(await toVsCodeArgs(args))
|
||||
} catch (error: any) {
|
||||
logger.error("Got error from VS Code", error)
|
||||
await cliProcessMain(args)
|
||||
} catch (error) {
|
||||
logger.error("Got error from VS Code", field("error", error))
|
||||
}
|
||||
|
||||
process.exit(0)
|
||||
|
@ -51,9 +37,8 @@ export const openInExistingInstance = async (args: DefaultedArgs, socketPath: st
|
|||
forceReuseWindow: args["reuse-window"],
|
||||
forceNewWindow: args["new-window"],
|
||||
}
|
||||
const paths = args._ || []
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
const fp = path.resolve(paths[i])
|
||||
for (let i = 0; i < args._.length; i++) {
|
||||
const fp = path.resolve(args._[i])
|
||||
if (await isFile(fp)) {
|
||||
pipeArgs.fileURIs.push(fp)
|
||||
} else {
|
||||
|
@ -87,13 +72,11 @@ export const openInExistingInstance = async (args: DefaultedArgs, socketPath: st
|
|||
vscode.end()
|
||||
}
|
||||
|
||||
export const runCodeServer = async (
|
||||
args: DefaultedArgs,
|
||||
): Promise<{ dispose: Disposable["dispose"]; server: http.Server }> => {
|
||||
export const runCodeServer = async (args: DefaultedArgs): Promise<http.Server> => {
|
||||
logger.info(`code-server ${version} ${commit}`)
|
||||
|
||||
logger.info(`Using user-data-dir ${humanPath(os.homedir(), args["user-data-dir"])}`)
|
||||
logger.trace(`Using extensions-dir ${humanPath(os.homedir(), args["extensions-dir"])}`)
|
||||
logger.info(`Using user-data-dir ${humanPath(args["user-data-dir"])}`)
|
||||
logger.trace(`Using extensions-dir ${humanPath(args["extensions-dir"])}`)
|
||||
|
||||
if (args.auth === AuthType.Password && !args.password && !args["hashed-password"]) {
|
||||
throw new Error(
|
||||
|
@ -101,18 +84,12 @@ export const runCodeServer = async (
|
|||
)
|
||||
}
|
||||
|
||||
const app = await createApp(args)
|
||||
const protocol = args.cert ? "https" : "http"
|
||||
const serverAddress = ensureAddress(app.server, protocol)
|
||||
const disposeRoutes = await register(app, args)
|
||||
|
||||
logger.info(`Using config file ${humanPath(os.homedir(), args.config)}`)
|
||||
logger.info(
|
||||
`${protocol.toUpperCase()} server listening on ${serverAddress.toString()} ${
|
||||
args.link ? "(randomized by --link)" : ""
|
||||
}`,
|
||||
)
|
||||
const [app, wsApp, server] = await createApp(args)
|
||||
const serverAddress = ensureAddress(server)
|
||||
await register(app, wsApp, server, args)
|
||||
|
||||
logger.info(`Using config file ${humanPath(args.config)}`)
|
||||
logger.info(`HTTP server listening on ${serverAddress} ${args.link ? "(randomized by --link)" : ""}`)
|
||||
if (args.auth === AuthType.Password) {
|
||||
logger.info(" - Authentication is enabled")
|
||||
if (args.usingEnvPassword) {
|
||||
|
@ -120,14 +97,14 @@ export const runCodeServer = async (
|
|||
} else if (args.usingEnvHashedPassword) {
|
||||
logger.info(" - Using password from $HASHED_PASSWORD")
|
||||
} else {
|
||||
logger.info(` - Using password from ${humanPath(os.homedir(), args.config)}`)
|
||||
logger.info(` - Using password from ${humanPath(args.config)}`)
|
||||
}
|
||||
} else {
|
||||
logger.info(` - Authentication is disabled ${args.link ? "(disabled by --link)" : ""}`)
|
||||
}
|
||||
|
||||
if (args.cert) {
|
||||
logger.info(` - Using certificate for HTTPS: ${humanPath(os.homedir(), args.cert.value)}`)
|
||||
logger.info(` - Using certificate for HTTPS: ${humanPath(args.cert.value)}`)
|
||||
} else {
|
||||
logger.info(` - Not serving HTTPS ${args.link ? "(disabled by --link)" : ""}`)
|
||||
}
|
||||
|
@ -138,10 +115,19 @@ export const runCodeServer = async (
|
|||
}
|
||||
|
||||
if (args.link) {
|
||||
await coderCloudBind(serverAddress, args.link.value)
|
||||
await coderCloudBind(serverAddress.replace(/^https?:\/\//, ""), args.link.value)
|
||||
logger.info(" - Connected to cloud agent")
|
||||
}
|
||||
|
||||
try {
|
||||
const port = parseInt(serverAddress.split(":").pop() as string, 10)
|
||||
startLink(port).catch((ex) => {
|
||||
logger.debug("Link daemon exited!", field("error", ex))
|
||||
})
|
||||
} catch (error) {
|
||||
logger.debug("Failed to start link daemon!", error as any)
|
||||
}
|
||||
|
||||
if (args.enable && args.enable.length > 0) {
|
||||
logger.info("Enabling the following experimental features:")
|
||||
args.enable.forEach((feature) => {
|
||||
|
@ -157,20 +143,16 @@ export const runCodeServer = async (
|
|||
)
|
||||
}
|
||||
|
||||
if (args.open) {
|
||||
if (!args.socket && args.open) {
|
||||
// The web socket doesn't seem to work if browsing with 0.0.0.0.
|
||||
const openAddress = serverAddress.replace("://0.0.0.0", "://localhost")
|
||||
try {
|
||||
await open(serverAddress)
|
||||
logger.info(`Opened ${serverAddress}`)
|
||||
await open(openAddress)
|
||||
logger.info(`Opened ${openAddress}`)
|
||||
} catch (error) {
|
||||
logger.error("Failed to open", field("address", serverAddress.toString()), field("error", error))
|
||||
logger.error("Failed to open", field("address", openAddress), field("error", error))
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
server: app.server,
|
||||
dispose: async () => {
|
||||
disposeRoutes()
|
||||
await app.dispose()
|
||||
},
|
||||
}
|
||||
return server
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Coder Technologies. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import ProxyAgent from "proxy-agent"
|
||||
import { getProxyForUrl } from "proxy-from-env"
|
||||
|
||||
/**
|
||||
* This file has nothing to do with the code-server proxy.
|
||||
* It is to support $HTTP_PROXY, $HTTPS_PROXY and $NO_PROXY.
|
||||
*
|
||||
* - https://github.com/cdr/code-server/issues/124
|
||||
* - https://www.npmjs.com/package/proxy-agent
|
||||
* - https://www.npmjs.com/package/proxy-from-env
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* monkeyPatch patches the node http,https modules to route all requests through the
|
||||
* agent we get from the proxy-agent package.
|
||||
*
|
||||
* This approach only works if there is no code specifying an explicit agent when making
|
||||
* a request.
|
||||
*
|
||||
* None of our code ever passes in a explicit agent to the http,https modules.
|
||||
* VS Code's does sometimes but only when a user sets the http.proxy configuration.
|
||||
* See https://code.visualstudio.com/docs/setup/network#_legacy-proxy-server-support
|
||||
*
|
||||
* Even if they do, it's probably the same proxy so we should be fine! And those knobs
|
||||
* are deprecated anyway.
|
||||
*/
|
||||
export function monkeyPatchProxyProtocols(): void {
|
||||
if (!shouldEnableProxy()) {
|
||||
return
|
||||
}
|
||||
|
||||
const http = require("http")
|
||||
const https = require("https")
|
||||
|
||||
// If we do not pass in a proxy URL, proxy-agent will get the URL from the environment.
|
||||
// See https://www.npmjs.com/package/proxy-from-env.
|
||||
// Also see shouldEnableProxy.
|
||||
const pa = new ProxyAgent()
|
||||
http.globalAgent = pa
|
||||
https.globalAgent = pa
|
||||
}
|
||||
|
||||
const sampleUrls = [new URL("http://example.com"), new URL("https://example.com")]
|
||||
|
||||
// If they have $NO_PROXY set to example.com then this check won't work!
|
||||
// But that's drastically unlikely.
|
||||
export function shouldEnableProxy(): boolean {
|
||||
const testedProxyEndpoints = sampleUrls.map((url) => {
|
||||
return {
|
||||
url,
|
||||
proxyUrl: getProxyForUrl(url.toString()),
|
||||
}
|
||||
})
|
||||
|
||||
let shouldEnable = false
|
||||
|
||||
for (const { url, proxyUrl } of testedProxyEndpoints) {
|
||||
if (proxyUrl) {
|
||||
console.debug(`${url.protocol} -- Using "${proxyUrl}"`)
|
||||
shouldEnable = true
|
||||
}
|
||||
}
|
||||
|
||||
return shouldEnable
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { Request, Router } from "express"
|
||||
import { HttpCode, HttpError } from "../../common/http"
|
||||
import { authenticated, ensureAuthenticated, redirect, self } from "../http"
|
||||
import { normalize } from "../../common/util"
|
||||
import { authenticated, ensureAuthenticated, redirect } from "../http"
|
||||
import { proxy } from "../proxy"
|
||||
import { Router as WsRouter } from "../wsRouter"
|
||||
|
||||
|
@ -55,7 +56,7 @@ router.all("*", async (req, res, next) => {
|
|||
return next()
|
||||
}
|
||||
// Redirect all other pages to the login.
|
||||
const to = self(req)
|
||||
const to = normalize(`${req.baseUrl}${req.path}`)
|
||||
return redirect(req, res, "login", {
|
||||
to: to !== "/" ? to : undefined,
|
||||
})
|
||||
|
|
|
@ -6,38 +6,16 @@ import { WebsocketRequest } from "../../../typings/pluginapi"
|
|||
import { HttpCode } from "../../common/http"
|
||||
import { rootPath } from "../constants"
|
||||
import { replaceTemplates } from "../http"
|
||||
import { escapeHtml, getMediaMime } from "../util"
|
||||
|
||||
interface ErrorWithStatusCode {
|
||||
statusCode: number
|
||||
}
|
||||
|
||||
interface ErrorWithCode {
|
||||
code: string
|
||||
}
|
||||
|
||||
/** Error is network related. */
|
||||
export const errorHasStatusCode = (error: any): error is ErrorWithStatusCode => {
|
||||
return error && "statusCode" in error
|
||||
}
|
||||
|
||||
/** Error originates from file system. */
|
||||
export const errorHasCode = (error: any): error is ErrorWithCode => {
|
||||
return error && "code" in error
|
||||
}
|
||||
|
||||
const notFoundCodes = [404, "ENOENT", "EISDIR"]
|
||||
import { getMediaMime } from "../util"
|
||||
|
||||
const notFoundCodes = ["ENOENT", "EISDIR", "FileNotFound"]
|
||||
export const errorHandler: express.ErrorRequestHandler = async (err, req, res, next) => {
|
||||
let statusCode = 500
|
||||
|
||||
if (errorHasStatusCode(err)) {
|
||||
statusCode = err.statusCode
|
||||
} else if (errorHasCode(err) && notFoundCodes.includes(err.code)) {
|
||||
statusCode = HttpCode.NotFound
|
||||
if (notFoundCodes.includes(err.code)) {
|
||||
err.status = HttpCode.NotFound
|
||||
}
|
||||
|
||||
res.status(statusCode)
|
||||
const status = err.status ?? err.statusCode ?? 500
|
||||
res.status(status)
|
||||
|
||||
// Assume anything that explicitly accepts text/html is a user browsing a
|
||||
// page (as opposed to an xhr request). Don't use `req.accepts()` since
|
||||
|
@ -49,9 +27,9 @@ export const errorHandler: express.ErrorRequestHandler = async (err, req, res, n
|
|||
const content = await fs.readFile(resourcePath, "utf8")
|
||||
res.send(
|
||||
replaceTemplates(req, content)
|
||||
.replace(/{{ERROR_TITLE}}/g, statusCode.toString())
|
||||
.replace(/{{ERROR_HEADER}}/g, statusCode.toString())
|
||||
.replace(/{{ERROR_BODY}}/g, escapeHtml(err.message)),
|
||||
.replace(/{{ERROR_TITLE}}/g, status)
|
||||
.replace(/{{ERROR_HEADER}}/g, status)
|
||||
.replace(/{{ERROR_BODY}}/g, err.message),
|
||||
)
|
||||
} else {
|
||||
res.json({
|
||||
|
|
|
@ -2,21 +2,19 @@ import { logger } from "@coder/logger"
|
|||
import cookieParser from "cookie-parser"
|
||||
import * as express from "express"
|
||||
import { promises as fs } from "fs"
|
||||
import http from "http"
|
||||
import * as path from "path"
|
||||
import * as tls from "tls"
|
||||
import * as pluginapi from "../../../typings/pluginapi"
|
||||
import { Disposable } from "../../common/emitter"
|
||||
import { HttpCode, HttpError } from "../../common/http"
|
||||
import { plural } from "../../common/util"
|
||||
import { App } from "../app"
|
||||
import { AuthType, DefaultedArgs } from "../cli"
|
||||
import { commit, rootPath } from "../constants"
|
||||
import { commit, isDevMode, rootPath } from "../constants"
|
||||
import { Heart } from "../heart"
|
||||
import { ensureAuthenticated, redirect } from "../http"
|
||||
import { PluginAPI } from "../plugin"
|
||||
import { CoderSettings, SettingsProvider } from "../settings"
|
||||
import { UpdateProvider } from "../update"
|
||||
import { getMediaMime, paths } from "../util"
|
||||
import { wrapper } from "../wrapper"
|
||||
import * as apps from "./apps"
|
||||
import * as domainProxy from "./domainProxy"
|
||||
import { errorHandler, wsErrorHandler } from "./errors"
|
||||
|
@ -25,15 +23,20 @@ import * as login from "./login"
|
|||
import * as logout from "./logout"
|
||||
import * as pathProxy from "./pathProxy"
|
||||
import * as update from "./update"
|
||||
import { CodeServerRouteWrapper } from "./vscode"
|
||||
import { createVSServerRouter, VSServerResult } from "./vscode"
|
||||
|
||||
/**
|
||||
* Register all routes and middleware.
|
||||
*/
|
||||
export const register = async (app: App, args: DefaultedArgs): Promise<Disposable["dispose"]> => {
|
||||
export const register = async (
|
||||
app: express.Express,
|
||||
wsApp: express.Express,
|
||||
server: http.Server,
|
||||
args: DefaultedArgs,
|
||||
): Promise<void> => {
|
||||
const heart = new Heart(path.join(paths.data, "heartbeat"), async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
app.server.getConnections((error, count) => {
|
||||
server.getConnections((error, count) => {
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
|
@ -42,15 +45,15 @@ export const register = async (app: App, args: DefaultedArgs): Promise<Disposabl
|
|||
})
|
||||
})
|
||||
})
|
||||
server.on("close", () => {
|
||||
heart.dispose()
|
||||
})
|
||||
|
||||
app.router.disable("x-powered-by")
|
||||
app.wsRouter.disable("x-powered-by")
|
||||
app.disable("x-powered-by")
|
||||
wsApp.disable("x-powered-by")
|
||||
|
||||
app.router.use(cookieParser())
|
||||
app.wsRouter.use(cookieParser())
|
||||
|
||||
const settings = new SettingsProvider<CoderSettings>(path.join(args["user-data-dir"], "coder.json"))
|
||||
const updater = new UpdateProvider("https://api.github.com/repos/coder/code-server/releases/latest", settings)
|
||||
app.use(cookieParser())
|
||||
wsApp.use(cookieParser())
|
||||
|
||||
const common: express.RequestHandler = (req, _, next) => {
|
||||
// /healthz|/healthz/ needs to be excluded otherwise health checks will make
|
||||
|
@ -62,16 +65,14 @@ export const register = async (app: App, args: DefaultedArgs): Promise<Disposabl
|
|||
// Add common variables routes can use.
|
||||
req.args = args
|
||||
req.heart = heart
|
||||
req.settings = settings
|
||||
req.updater = updater
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
app.router.use(common)
|
||||
app.wsRouter.use(common)
|
||||
app.use(common)
|
||||
wsApp.use(common)
|
||||
|
||||
app.router.use(async (req, res, next) => {
|
||||
app.use(async (req, res, next) => {
|
||||
// If we're handling TLS ensure all requests are redirected to HTTPS.
|
||||
// TODO: This does *NOT* work if you have a base path since to specify the
|
||||
// protocol we need to specify the whole path.
|
||||
|
@ -89,80 +90,85 @@ export const register = async (app: App, args: DefaultedArgs): Promise<Disposabl
|
|||
next()
|
||||
})
|
||||
|
||||
app.router.use("/", domainProxy.router)
|
||||
app.wsRouter.use("/", domainProxy.wsRouter.router)
|
||||
app.use("/", domainProxy.router)
|
||||
wsApp.use("/", domainProxy.wsRouter.router)
|
||||
|
||||
app.router.all("/proxy/(:port)(/*)?", (req, res) => {
|
||||
app.all("/proxy/(:port)(/*)?", (req, res) => {
|
||||
pathProxy.proxy(req, res)
|
||||
})
|
||||
app.wsRouter.get("/proxy/(:port)(/*)?", async (req) => {
|
||||
wsApp.get("/proxy/(:port)(/*)?", async (req) => {
|
||||
await pathProxy.wsProxy(req as pluginapi.WebsocketRequest)
|
||||
})
|
||||
// These two routes pass through the path directly.
|
||||
// So the proxied app must be aware it is running
|
||||
// under /absproxy/<someport>/
|
||||
app.router.all("/absproxy/(:port)(/*)?", (req, res) => {
|
||||
app.all("/absproxy/(:port)(/*)?", (req, res) => {
|
||||
pathProxy.proxy(req, res, {
|
||||
passthroughPath: true,
|
||||
})
|
||||
})
|
||||
app.wsRouter.get("/absproxy/(:port)(/*)?", async (req) => {
|
||||
wsApp.get("/absproxy/(:port)(/*)?", async (req) => {
|
||||
await pathProxy.wsProxy(req as pluginapi.WebsocketRequest, {
|
||||
passthroughPath: true,
|
||||
})
|
||||
})
|
||||
|
||||
let pluginApi: PluginAPI
|
||||
if (!process.env.CS_DISABLE_PLUGINS) {
|
||||
const workingDir = args._ && args._.length > 0 ? path.resolve(args._[args._.length - 1]) : undefined
|
||||
pluginApi = new PluginAPI(logger, process.env.CS_PLUGIN, process.env.CS_PLUGIN_PATH, workingDir)
|
||||
const pluginApi = new PluginAPI(logger, process.env.CS_PLUGIN, process.env.CS_PLUGIN_PATH, workingDir)
|
||||
await pluginApi.loadPlugins()
|
||||
pluginApi.mount(app.router, app.wsRouter)
|
||||
app.router.use("/api/applications", ensureAuthenticated, apps.router(pluginApi))
|
||||
pluginApi.mount(app, wsApp)
|
||||
app.use("/api/applications", ensureAuthenticated, apps.router(pluginApi))
|
||||
wrapper.onDispose(() => pluginApi.dispose())
|
||||
}
|
||||
|
||||
app.router.use(express.json())
|
||||
app.router.use(express.urlencoded({ extended: true }))
|
||||
app.use(express.json())
|
||||
app.use(express.urlencoded({ extended: true }))
|
||||
|
||||
app.router.use(
|
||||
app.use(
|
||||
"/_static",
|
||||
express.static(rootPath, {
|
||||
cacheControl: commit !== "development",
|
||||
fallthrough: false,
|
||||
}),
|
||||
)
|
||||
|
||||
app.router.use("/healthz", health.router)
|
||||
app.wsRouter.use("/healthz", health.wsRouter.router)
|
||||
app.use("/healthz", health.router)
|
||||
wsApp.use("/healthz", health.wsRouter.router)
|
||||
|
||||
if (args.auth === AuthType.Password) {
|
||||
app.router.use("/login", login.router)
|
||||
app.router.use("/logout", logout.router)
|
||||
app.use("/login", login.router)
|
||||
app.use("/logout", logout.router)
|
||||
} else {
|
||||
app.router.all("/login", (req, res) => redirect(req, res, "/", {}))
|
||||
app.router.all("/logout", (req, res) => redirect(req, res, "/", {}))
|
||||
app.all("/login", (req, res) => redirect(req, res, "/", {}))
|
||||
app.all("/logout", (req, res) => redirect(req, res, "/", {}))
|
||||
}
|
||||
|
||||
app.router.use("/update", update.router)
|
||||
app.use("/update", update.router)
|
||||
|
||||
const vsServerRouteHandler = new CodeServerRouteWrapper()
|
||||
|
||||
// Note that the root route is replaced in Coder Enterprise by the plugin API.
|
||||
for (const routePrefix of ["/vscode", "/"]) {
|
||||
app.router.use(routePrefix, vsServerRouteHandler.router)
|
||||
app.wsRouter.use(routePrefix, vsServerRouteHandler.wsRouter)
|
||||
let vscode: VSServerResult
|
||||
try {
|
||||
vscode = await createVSServerRouter(args)
|
||||
app.use("/", vscode.router)
|
||||
wsApp.use("/", vscode.wsRouter.router)
|
||||
app.use("/vscode", vscode.router)
|
||||
wsApp.use("/vscode", vscode.wsRouter.router)
|
||||
} catch (error: any) {
|
||||
if (isDevMode) {
|
||||
logger.warn(error)
|
||||
logger.warn("VS Server router may still be compiling.")
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
app.router.use(() => {
|
||||
server.on("close", () => {
|
||||
vscode.vscodeServer.close()
|
||||
})
|
||||
|
||||
app.use(() => {
|
||||
throw new HttpError("Not Found", HttpCode.NotFound)
|
||||
})
|
||||
|
||||
app.router.use(errorHandler)
|
||||
app.wsRouter.use(wsErrorHandler)
|
||||
|
||||
return () => {
|
||||
heart.dispose()
|
||||
pluginApi?.dispose()
|
||||
vsServerRouteHandler.dispose()
|
||||
}
|
||||
app.use(errorHandler)
|
||||
wsApp.use(wsErrorHandler)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { Router, Request } from "express"
|
||||
import { promises as fs } from "fs"
|
||||
import { RateLimiter as Limiter } from "limiter"
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
import { CookieKeys } from "../../common/http"
|
||||
import { rootPath } from "../constants"
|
||||
import { authenticated, getCookieOptions, redirect, replaceTemplates } from "../http"
|
||||
import { authenticated, getCookieDomain, redirect, replaceTemplates } from "../http"
|
||||
import { getPasswordMethod, handlePasswordValidation, humanPath, sanitizeString, escapeHtml } from "../util"
|
||||
|
||||
export enum Cookie {
|
||||
Key = "key",
|
||||
}
|
||||
|
||||
// RateLimiter wraps around the limiter library for logins.
|
||||
// It allows 2 logins every minute plus 12 logins every hour.
|
||||
export class RateLimiter {
|
||||
|
@ -28,7 +30,7 @@ export class RateLimiter {
|
|||
|
||||
const getRoot = async (req: Request, error?: Error): Promise<string> => {
|
||||
const content = await fs.readFile(path.join(rootPath, "src/browser/pages/login.html"), "utf8")
|
||||
let passwordMsg = `Check the config file at ${humanPath(os.homedir(), req.args.config)} for the password.`
|
||||
let passwordMsg = `Check the config file at ${humanPath(req.args.config)} for the password.`
|
||||
if (req.args.usingEnvPassword) {
|
||||
passwordMsg = "Password was set from $PASSWORD."
|
||||
} else if (req.args.usingEnvHashedPassword) {
|
||||
|
@ -59,7 +61,7 @@ router.get("/", async (req, res) => {
|
|||
res.send(await getRoot(req))
|
||||
})
|
||||
|
||||
router.post<{}, string, { password: string; base?: string }, { to?: string }>("/", async (req, res) => {
|
||||
router.post("/", async (req, res) => {
|
||||
const password = sanitizeString(req.body.password)
|
||||
const hashedPasswordFromArgs = req.args["hashed-password"]
|
||||
|
||||
|
@ -84,7 +86,11 @@ router.post<{}, string, { password: string; base?: string }, { to?: string }>("/
|
|||
if (isPasswordValid) {
|
||||
// The hash does not add any actual security but we do it for
|
||||
// obfuscation purposes (and as a side effect it handles escaping).
|
||||
res.cookie(CookieKeys.Session, hashedPassword, getCookieOptions(req))
|
||||
res.cookie(Cookie.Key, hashedPassword, {
|
||||
domain: getCookieDomain(req.headers.host || "", req.args["proxy-domain"]),
|
||||
path: req.body.base || "/",
|
||||
sameSite: "lax",
|
||||
})
|
||||
|
||||
const to = (typeof req.query.to === "string" && req.query.to) || "/"
|
||||
return redirect(req, res, to, { to: undefined })
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import { Router } from "express"
|
||||
import { CookieKeys } from "../../common/http"
|
||||
import { getCookieOptions, redirect } from "../http"
|
||||
import { sanitizeString } from "../util"
|
||||
import { getCookieDomain, redirect } from "../http"
|
||||
import { Cookie } from "./login"
|
||||
|
||||
export const router = Router()
|
||||
|
||||
router.get<{}, undefined, undefined, { base?: string; to?: string }>("/", async (req, res) => {
|
||||
router.get("/", async (req, res) => {
|
||||
// Must use the *identical* properties used to set the cookie.
|
||||
res.clearCookie(CookieKeys.Session, getCookieOptions(req))
|
||||
res.clearCookie(Cookie.Key, {
|
||||
domain: getCookieDomain(req.headers.host || "", req.args["proxy-domain"]),
|
||||
path: req.query.base || "/",
|
||||
sameSite: "lax",
|
||||
})
|
||||
|
||||
const to = sanitizeString(req.query.to) || "/"
|
||||
return redirect(req, res, to, { to: undefined, base: undefined, href: undefined })
|
||||
const to = (typeof req.query.to === "string" && req.query.to) || "/"
|
||||
return redirect(req, res, to, { to: undefined, base: undefined })
|
||||
})
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Request, Response } from "express"
|
||||
import * as path from "path"
|
||||
import * as qs from "qs"
|
||||
import qs from "qs"
|
||||
import * as pluginapi from "../../../typings/pluginapi"
|
||||
import { HttpCode, HttpError } from "../../common/http"
|
||||
import { authenticated, ensureAuthenticated, redirect, self } from "../http"
|
||||
import { normalize } from "../../common/util"
|
||||
import { authenticated, ensureAuthenticated, redirect } from "../http"
|
||||
import { proxy as _proxy } from "../proxy"
|
||||
|
||||
const getProxyTarget = (req: Request, passthroughPath?: boolean): string => {
|
||||
|
@ -24,7 +25,7 @@ export function proxy(
|
|||
if (!authenticated(req)) {
|
||||
// If visiting the root (/:port only) redirect to the login page.
|
||||
if (!req.params[0] || req.params[0] === "/") {
|
||||
const to = self(req)
|
||||
const to = normalize(`${req.baseUrl}${req.path}`)
|
||||
return redirect(req, res, "login", {
|
||||
to: to !== "/" ? to : undefined,
|
||||
})
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
import { Router } from "express"
|
||||
import { version } from "../constants"
|
||||
import { ensureAuthenticated } from "../http"
|
||||
import { UpdateProvider } from "../update"
|
||||
|
||||
export const router = Router()
|
||||
|
||||
const provider = new UpdateProvider()
|
||||
|
||||
router.get("/check", ensureAuthenticated, async (req, res) => {
|
||||
const update = await req.updater.getUpdate(req.query.force === "true")
|
||||
const update = await provider.getUpdate(req.query.force === "true")
|
||||
res.json({
|
||||
checked: update.checked,
|
||||
latest: update.version,
|
||||
current: version,
|
||||
isLatest: req.updater.isLatestVersion(update),
|
||||
isLatest: provider.isLatestVersion(update),
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,138 +1,73 @@
|
|||
import { logger } from "@coder/logger"
|
||||
import * as express from "express"
|
||||
import { WebsocketRequest } from "../../../typings/pluginapi"
|
||||
import { logError } from "../../common/util"
|
||||
import { toVsCodeArgs } from "../cli"
|
||||
import { isDevMode } from "../constants"
|
||||
import { authenticated, ensureAuthenticated, redirect, self } from "../http"
|
||||
import { SocketProxyProvider } from "../socket"
|
||||
import { Server } from "http"
|
||||
import path from "path"
|
||||
import { AuthType, DefaultedArgs } from "../cli"
|
||||
import { version as codeServerVersion, vsRootPath } from "../constants"
|
||||
import { ensureAuthenticated } from "../http"
|
||||
import { loadAMDModule } from "../util"
|
||||
import { Router as WsRouter } from "../wsRouter"
|
||||
import { Router as WsRouter, WebsocketRouter } from "../wsRouter"
|
||||
import { errorHandler } from "./errors"
|
||||
|
||||
export class CodeServerRouteWrapper {
|
||||
/** Assigned in `ensureCodeServerLoaded` */
|
||||
private _codeServerMain!: CodeServerLib.IServerAPI
|
||||
private _wsRouterWrapper = WsRouter()
|
||||
private _socketProxyProvider = new SocketProxyProvider()
|
||||
public router = express.Router()
|
||||
export interface VSServerResult {
|
||||
router: express.Router
|
||||
wsRouter: WebsocketRouter
|
||||
vscodeServer: Server
|
||||
}
|
||||
|
||||
public get wsRouter() {
|
||||
return this._wsRouterWrapper.router
|
||||
}
|
||||
export const createVSServerRouter = async (args: DefaultedArgs): Promise<VSServerResult> => {
|
||||
// Delete `VSCODE_CWD` very early even before
|
||||
// importing bootstrap files. We have seen
|
||||
// reports where `code .` would use the wrong
|
||||
// current working directory due to our variable
|
||||
// somehow escaping to the parent shell
|
||||
// (https://github.com/microsoft/vscode/issues/126399)
|
||||
delete process.env["VSCODE_CWD"]
|
||||
|
||||
//#region Route Handlers
|
||||
const bootstrap = require(path.join(vsRootPath, "out", "bootstrap"))
|
||||
const bootstrapNode = require(path.join(vsRootPath, "out", "bootstrap-node"))
|
||||
const product = require(path.join(vsRootPath, "product.json"))
|
||||
|
||||
private $root: express.Handler = async (req, res, next) => {
|
||||
const isAuthenticated = await authenticated(req)
|
||||
// Avoid Monkey Patches from Application Insights
|
||||
bootstrap.avoidMonkeyPatchFromAppInsights()
|
||||
|
||||
if (!isAuthenticated) {
|
||||
const to = self(req)
|
||||
return redirect(req, res, "login", {
|
||||
to: to !== "/" ? to : undefined,
|
||||
})
|
||||
}
|
||||
// Enable portable support
|
||||
bootstrapNode.configurePortable(product)
|
||||
|
||||
const { query } = await req.settings.read()
|
||||
if (query) {
|
||||
// Ew means the workspace was closed so clear the last folder/workspace.
|
||||
if (req.query.ew) {
|
||||
delete query.folder
|
||||
delete query.workspace
|
||||
}
|
||||
// Enable ASAR support
|
||||
bootstrap.enableASARSupport()
|
||||
|
||||
// Redirect to the last folder/workspace if nothing else is opened.
|
||||
if (
|
||||
!req.query.folder &&
|
||||
!req.query.workspace &&
|
||||
(query.folder || query.workspace) &&
|
||||
!req.args["ignore-last-opened"] // This flag disables this behavior.
|
||||
) {
|
||||
const to = self(req)
|
||||
return redirect(req, res, to, {
|
||||
folder: query.folder,
|
||||
workspace: query.workspace,
|
||||
})
|
||||
}
|
||||
}
|
||||
// Signal processes that we got launched as CLI
|
||||
process.env["VSCODE_CLI"] = "1"
|
||||
|
||||
// Store the query parameters so we can use them on the next load. This
|
||||
// also allows users to create functionality around query parameters.
|
||||
await req.settings.write({ query: req.query })
|
||||
const vscodeServerMain = await loadAMDModule<CodeServerLib.CreateVSServer>("vs/server/entry", "createVSServer")
|
||||
|
||||
next()
|
||||
}
|
||||
const serverUrl = new URL(`${args.cert ? "https" : "http"}://${args.host}:${args.port}`)
|
||||
const vscodeServer = await vscodeServerMain({
|
||||
codeServerVersion,
|
||||
serverUrl,
|
||||
args,
|
||||
authed: args.auth !== AuthType.None,
|
||||
disableUpdateCheck: !!args["disable-update-check"],
|
||||
})
|
||||
|
||||
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)
|
||||
}
|
||||
const router = express.Router()
|
||||
const wsRouter = WsRouter()
|
||||
|
||||
req.once("error", requestErrorHandler)
|
||||
router.all("*", ensureAuthenticated, (req, res, next) => {
|
||||
req.on("error", (error) => errorHandler(error, req, res, next))
|
||||
|
||||
this._codeServerMain.handleRequest(req, res)
|
||||
}
|
||||
vscodeServer.emit("request", req, res)
|
||||
})
|
||||
|
||||
private $proxyWebsocket = async (req: WebsocketRequest) => {
|
||||
const wrappedSocket = await this._socketProxyProvider.createProxy(req.ws)
|
||||
this._codeServerMain.handleUpgrade(req, wrappedSocket)
|
||||
wsRouter.ws("/", ensureAuthenticated, (req) => {
|
||||
vscodeServer.emit("upgrade", req, req.socket, req.head)
|
||||
|
||||
req.ws.resume()
|
||||
}
|
||||
req.socket.resume()
|
||||
})
|
||||
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* Fetches a code server instance asynchronously to avoid an initial memory overhead.
|
||||
*/
|
||||
private ensureCodeServerLoaded: express.Handler = async (req, _res, next) => {
|
||||
if (this._codeServerMain) {
|
||||
// Already loaded...
|
||||
return next()
|
||||
}
|
||||
|
||||
// Create the server...
|
||||
|
||||
const { args } = req
|
||||
|
||||
/**
|
||||
* @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 toVsCodeArgs(args)),
|
||||
// TODO: Make the browser helper script work.
|
||||
"without-browser-env-var": true,
|
||||
})
|
||||
} catch (error) {
|
||||
logError(logger, "CodeServerRouteWrapper", error)
|
||||
if (isDevMode) {
|
||||
return next(new Error((error instanceof Error ? error.message : error) + " (VS Code may still be compiling)"))
|
||||
}
|
||||
return next(error)
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.router.get("/", this.ensureCodeServerLoaded, this.$root)
|
||||
this.router.all("*", ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyRequest)
|
||||
this._wsRouterWrapper.ws("/", ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyWebsocket)
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._codeServerMain?.dispose()
|
||||
this._socketProxyProvider.stop()
|
||||
return {
|
||||
router,
|
||||
wsRouter,
|
||||
vscodeServer,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { logger } from "@coder/logger"
|
||||
import { Query } from "express-serve-static-core"
|
||||
import { promises as fs } from "fs"
|
||||
import * as path from "path"
|
||||
import { paths } from "./util"
|
||||
|
||||
export type Settings = { [key: string]: Settings | string | boolean | number }
|
||||
|
||||
|
@ -52,5 +54,14 @@ export interface UpdateSettings {
|
|||
* Global code-server settings.
|
||||
*/
|
||||
export interface CoderSettings extends UpdateSettings {
|
||||
query?: Query
|
||||
lastVisited: {
|
||||
url: string
|
||||
workspace: boolean
|
||||
}
|
||||
query: Query
|
||||
}
|
||||
|
||||
/**
|
||||
* Global code-server settings file.
|
||||
*/
|
||||
export const settings = new SettingsProvider<CoderSettings>(path.join(paths.data, "coder.json"))
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { field, logger } from "@coder/logger"
|
||||
import * as http from "http"
|
||||
import * as https from "https"
|
||||
import ProxyAgent from "proxy-agent"
|
||||
import * as semver from "semver"
|
||||
import * as url from "url"
|
||||
import { httpProxyUri, version } from "./constants"
|
||||
import { SettingsProvider, UpdateSettings } from "./settings"
|
||||
import { version } from "./constants"
|
||||
import { settings as globalSettings, SettingsProvider, UpdateSettings } from "./settings"
|
||||
|
||||
export interface Update {
|
||||
checked: number
|
||||
|
@ -28,11 +27,12 @@ export class UpdateProvider {
|
|||
* The URL for getting the latest version of code-server. Should return JSON
|
||||
* that fulfills `LatestResponse`.
|
||||
*/
|
||||
private readonly latestUrl: string,
|
||||
private readonly latestUrl = "https://api.github.com/repos/cdr/code-server/releases/latest",
|
||||
/**
|
||||
* Update information will be stored here.
|
||||
* Update information will be stored here. If not provided, the global
|
||||
* settings will be used.
|
||||
*/
|
||||
private readonly settings: SettingsProvider<UpdateSettings>,
|
||||
private readonly settings: SettingsProvider<UpdateSettings> = globalSettings,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
@ -103,10 +103,8 @@ export class UpdateProvider {
|
|||
return new Promise((resolve, reject) => {
|
||||
const request = (uri: string): void => {
|
||||
logger.debug("Making request", field("uri", uri))
|
||||
const isHttps = uri.startsWith("https")
|
||||
const agent = httpProxyUri ? new ProxyAgent(httpProxyUri) : undefined
|
||||
const httpx = isHttps ? https : http
|
||||
const client = httpx.get(uri, { headers: { "User-Agent": "code-server" }, agent }, (response) => {
|
||||
const httpx = uri.startsWith("https") ? https : http
|
||||
const client = httpx.get(uri, { headers: { "User-Agent": "code-server" } }, (response) => {
|
||||
if (!response.statusCode || response.statusCode < 200 || response.statusCode >= 400) {
|
||||
response.destroy()
|
||||
return reject(new Error(`${uri}: ${response.statusCode || "500"}`))
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { logger } from "@coder/logger"
|
||||
import * as argon2 from "argon2"
|
||||
import * as cp from "child_process"
|
||||
import * as crypto from "crypto"
|
||||
|
@ -24,11 +25,10 @@ const pattern = [
|
|||
].join("|")
|
||||
const re = new RegExp(pattern, "g")
|
||||
|
||||
export type OnLineCallback = (strippedLine: string, originalLine: string) => void
|
||||
/**
|
||||
* Split stdout on newlines and strip ANSI codes.
|
||||
*/
|
||||
export const onLine = (proc: cp.ChildProcess, callback: OnLineCallback): void => {
|
||||
export const onLine = (proc: cp.ChildProcess, callback: (strippedLine: string, originalLine: string) => void): void => {
|
||||
let buffer = ""
|
||||
if (!proc.stdout) {
|
||||
throw new Error("no stdout")
|
||||
|
@ -57,10 +57,10 @@ export const paths = getEnvPaths()
|
|||
* On MacOS this function gets the standard XDG directories instead of using the native macOS
|
||||
* ones. Most CLIs do this as in practice only GUI apps use the standard macOS directories.
|
||||
*/
|
||||
export function getEnvPaths(platform = process.platform): Paths {
|
||||
export function getEnvPaths(): Paths {
|
||||
const paths = envPaths("code-server", { suffix: "" })
|
||||
const append = (p: string): string => path.join(p, "code-server")
|
||||
switch (platform) {
|
||||
switch (process.platform) {
|
||||
case "darwin":
|
||||
return {
|
||||
// envPaths uses native directories so force Darwin to use the XDG spec
|
||||
|
@ -88,17 +88,16 @@ export function getEnvPaths(platform = process.platform): Paths {
|
|||
}
|
||||
|
||||
/**
|
||||
* humanPath replaces the home directory in path with ~.
|
||||
* humanPath replaces the home directory in p with ~.
|
||||
* Makes it more readable.
|
||||
*
|
||||
* @param homedir - the home directory(i.e. `os.homedir()`)
|
||||
* @param path - a file path
|
||||
* @param p
|
||||
*/
|
||||
export function humanPath(homedir: string, path?: string): string {
|
||||
if (!path) {
|
||||
export function humanPath(p?: string): string {
|
||||
if (!p) {
|
||||
return ""
|
||||
}
|
||||
return path.replace(homedir, "~")
|
||||
return p.replace(os.homedir(), "~")
|
||||
}
|
||||
|
||||
export const generateCertificate = async (hostname: string): Promise<{ cert: string; certKey: string }> => {
|
||||
|
@ -156,7 +155,12 @@ export const generatePassword = async (length = 24): Promise<string> => {
|
|||
* Used to hash the password.
|
||||
*/
|
||||
export const hash = async (password: string): Promise<string> => {
|
||||
return await argon2.hash(password)
|
||||
try {
|
||||
return await argon2.hash(password)
|
||||
} catch (error: any) {
|
||||
logger.error(error)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -166,7 +170,11 @@ export const isHashMatch = async (password: string, hash: string) => {
|
|||
if (password === "" || hash === "" || !hash.startsWith("$")) {
|
||||
return false
|
||||
}
|
||||
return await argon2.verify(hash, password)
|
||||
try {
|
||||
return await argon2.verify(hash, password)
|
||||
} catch (error: any) {
|
||||
throw new Error(error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -310,10 +318,10 @@ export async function isCookieValid({
|
|||
* - greater than 0 characters
|
||||
* - trims whitespace
|
||||
*/
|
||||
export function sanitizeString(str: unknown): string {
|
||||
export function sanitizeString(str: string): string {
|
||||
// Very basic sanitization of string
|
||||
// Credit: https://stackoverflow.com/a/46719000/3015595
|
||||
return typeof str === "string" ? str.trim() : ""
|
||||
return typeof str === "string" && str.trim().length > 0 ? str.trim() : ""
|
||||
}
|
||||
|
||||
const mimeTypes: { [key: string]: string } = {
|
||||
|
@ -385,17 +393,9 @@ export const isWsl = async (): Promise<boolean> => {
|
|||
}
|
||||
|
||||
/**
|
||||
* Try opening an address using whatever the system has set for opening URLs.
|
||||
* Try opening a URL using whatever the system has set for opening URLs.
|
||||
*/
|
||||
export const open = async (address: URL | string): Promise<void> => {
|
||||
if (typeof address === "string") {
|
||||
throw new Error("Cannot open socket paths")
|
||||
}
|
||||
// Web sockets do not seem to work if browsing with 0.0.0.0.
|
||||
const url = new URL(address)
|
||||
if (url.hostname === "0.0.0.0") {
|
||||
url.hostname = "localhost"
|
||||
}
|
||||
export const open = async (url: string): Promise<void> => {
|
||||
const args = [] as string[]
|
||||
const options = {} as cp.SpawnOptions
|
||||
const platform = (await isWsl()) ? "wsl" : process.platform
|
||||
|
@ -403,9 +403,9 @@ export const open = async (address: URL | string): Promise<void> => {
|
|||
if (platform === "win32" || platform === "wsl") {
|
||||
command = platform === "wsl" ? "cmd.exe" : "cmd"
|
||||
args.push("/c", "start", '""', "/b")
|
||||
url.search = url.search.replace(/&/g, "^&")
|
||||
url = url.replace(/&/g, "^&")
|
||||
}
|
||||
const proc = cp.spawn(command, [...args, url.toString()], options)
|
||||
const proc = cp.spawn(command, [...args, url], options)
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
proc.on("error", reject)
|
||||
proc.on("close", (code) => {
|
||||
|
@ -482,7 +482,7 @@ export function escapeHtml(unsafe: string): string {
|
|||
* it has a .code property.
|
||||
*/
|
||||
export function isNodeJSErrnoException(error: unknown): error is NodeJS.ErrnoException {
|
||||
return error !== undefined && (error as NodeJS.ErrnoException).code !== undefined
|
||||
return error instanceof Error && (error as NodeJS.ErrnoException).code !== undefined
|
||||
}
|
||||
|
||||
// TODO: Replace with proper templating system.
|
||||
|
@ -498,14 +498,6 @@ type AMDModule<T> = { [exportName: string]: T }
|
|||
* @param exportName Given name of export in the file
|
||||
*/
|
||||
export const loadAMDModule = async <T>(amdPath: string, exportName: string): Promise<T> => {
|
||||
// Set default remote native node modules path, if unset
|
||||
process.env["VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH"] =
|
||||
process.env["VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH"] || path.join(vsRootPath, "remote", "node_modules")
|
||||
|
||||
require(path.join(vsRootPath, "out/bootstrap-node")).injectNodeModuleLookupPath(
|
||||
process.env["VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH"],
|
||||
)
|
||||
|
||||
const module = await new Promise<AMDModule<T>>((resolve, reject) => {
|
||||
require(path.join(vsRootPath, "out/bootstrap-amd")).load(amdPath, resolve, reject)
|
||||
})
|
||||
|
|
|
@ -314,7 +314,7 @@ export class ParentProcess extends Process {
|
|||
CODE_SERVER_PARENT_PID: process.pid.toString(),
|
||||
NODE_OPTIONS: `--max-old-space-size=2048 ${process.env.NODE_OPTIONS || ""}`,
|
||||
},
|
||||
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
||||
stdio: ["inherit", "inherit", "inherit", "ipc"],
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -50,5 +50,4 @@ export function Router(): WebsocketRouter {
|
|||
return new WebsocketRouter()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/no-named-as-default-member -- the typings are not updated correctly
|
||||
export const wss = new Websocket.Server({ noServer: true })
|
||||
|
|
|
@ -9,15 +9,10 @@ import { CodeServer, CodeServerPage } from "./models/CodeServer"
|
|||
*
|
||||
* If `includeCredentials` is `true` page requests will be authenticated.
|
||||
*/
|
||||
export const describe = (
|
||||
name: string,
|
||||
includeCredentials: boolean,
|
||||
codeServerArgs: string[],
|
||||
fn: (codeServer: CodeServer) => void,
|
||||
) => {
|
||||
export const describe = (name: string, includeCredentials: boolean, fn: (codeServer: CodeServer) => void) => {
|
||||
test.describe(name, () => {
|
||||
// This will spawn on demand so nothing is necessary on before.
|
||||
const codeServer = new CodeServer(name, codeServerArgs)
|
||||
const codeServer = new CodeServer(name)
|
||||
|
||||
// Kill code-server after the suite has ended. This may happen even without
|
||||
// doing it explicitly but it seems prudent to be sure.
|
||||
|
@ -41,9 +36,6 @@ export const describe = (
|
|||
authenticated: includeCredentials,
|
||||
// This provides a cookie that authenticates with code-server.
|
||||
storageState: includeCredentials ? storageState : {},
|
||||
// NOTE@jsjoeio some tests use --cert which uses a self-signed certificate
|
||||
// without this option, those tests will fail.
|
||||
ignoreHTTPSErrors: true,
|
||||
})
|
||||
|
||||
fn(codeServer)
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
// This is a "gut-check" test to make sure playwright is working as expected
|
||||
describe("browser", true, () => {
|
||||
test("browser should display correct userAgent", async ({ codeServerPage, browserName }) => {
|
||||
const displayNames = {
|
||||
chromium: "Chrome",
|
||||
firefox: "Firefox",
|
||||
webkit: "Safari",
|
||||
}
|
||||
const userAgent = await codeServerPage.page.evaluate(() => navigator.userAgent)
|
||||
|
||||
expect(userAgent).toContain(displayNames[browserName])
|
||||
})
|
||||
})
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
describe("CodeServer", true, [], () => {
|
||||
describe("CodeServer", true, () => {
|
||||
test("should navigate to home page", async ({ codeServerPage }) => {
|
||||
// We navigate codeServer before each test
|
||||
// and we start the test with a storage state
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import { describe, test } from "./baseFixture"
|
||||
|
||||
function runTestExtensionTests() {
|
||||
// This will only work if the test extension is loaded into code-server.
|
||||
test("should have access to VSCODE_PROXY_URI", async ({ codeServerPage }) => {
|
||||
const address = await codeServerPage.address()
|
||||
|
||||
await codeServerPage.executeCommandViaMenus("code-server: Get proxy URI")
|
||||
|
||||
await codeServerPage.page.waitForSelector(`text=${address}/proxy/{{port}}`)
|
||||
})
|
||||
}
|
||||
|
||||
describe("Extensions", true, [], () => {
|
||||
runTestExtensionTests()
|
||||
})
|
||||
|
||||
describe("Extensions with --cert", true, ["--cert"], () => {
|
||||
runTestExtensionTests()
|
||||
})
|
|
@ -1 +0,0 @@
|
|||
/extension.js
|
|
@ -1,13 +0,0 @@
|
|||
import * as vscode from "vscode"
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("codeServerTest.proxyUri", () => {
|
||||
if (process.env.VSCODE_PROXY_URI) {
|
||||
vscode.window.showInformationMessage(process.env.VSCODE_PROXY_URI)
|
||||
} else {
|
||||
vscode.window.showErrorMessage("No proxy URI was set")
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"name": "code-server-extension",
|
||||
"description": "code-server test extension",
|
||||
"version": "0.0.1",
|
||||
"publisher": "coder",
|
||||
"activationEvents": [
|
||||
"onCommand:codeServerTest.proxyUri"
|
||||
],
|
||||
"engines": {
|
||||
"vscode": "^1.56.0"
|
||||
},
|
||||
"main": "./extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "codeServerTest.proxyUri",
|
||||
"title": "Get proxy URI",
|
||||
"category": "code-server"
|
||||
}
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "^1.56.0",
|
||||
"typescript": "^4.0.5"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue