Compare commits

..

2 Commits

Author SHA1 Message Date
Asher
c56304cf4f
Update changelog for 3.10.1 2021-05-17 13:58:23 -05:00
Asher
6bbf7e9e7a
Update versions to 3.10.1 2021-05-17 13:50:56 -05:00
5469 changed files with 1446692 additions and 30125 deletions

46
.eslintrc.yaml Normal file
View File

@ -0,0 +1,46 @@
parser: "@typescript-eslint/parser"
env:
browser: true
es6: true # Map, etc.
jest: true
node: true
parserOptions:
ecmaVersion: 2018
sourceType: module
extends:
- eslint:recommended
- plugin:@typescript-eslint/recommended
- plugin:import/recommended
- plugin:import/typescript
- plugin:prettier/recommended
# Prettier should always be last
# Removes eslint rules that conflict with prettier.
- prettier
rules:
# Sometimes you need to add args to implement a function signature even
# if they are unused.
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }]
# For overloads.
no-dupe-class-members: off
"@typescript-eslint/no-use-before-define": off
"@typescript-eslint/no-non-null-assertion": off
"@typescript-eslint/ban-types": off
"@typescript-eslint/no-var-requires": off
"@typescript-eslint/explicit-module-boundary-types": off
"@typescript-eslint/no-explicit-any": off
"@typescript-eslint/no-extra-semi": off
eqeqeq: error
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:
# Does not work with CommonJS unfortunately.
import/ignore:
- env-paths
- xdg-basedir

View File

@ -1,2 +0,0 @@
# Prettier 3.4.2
9b0340a09276f93c054d705d1b9a5f24cc5dbc97

8
.github/CODEOWNERS vendored
View File

@ -1,7 +1,3 @@
* @coder/code-server
* @cdr/code-server-reviewers
ci/helm-chart/ @Matthew-Beckett @alexgorbatchev
docs/install.md @GNUxeava
src/node/i18n/locales/zh-cn.json @zhaozhiming
ci/helm-chart @Matthew-Beckett @alexgorbatchev

74
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,74 @@
---
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.
-->
## 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

View File

@ -1,126 +0,0 @@
name: Bug report
description: File a bug report
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
Please do not just put "latest" for the version.
value: |
- Web Browser:
- Local OS:
- Remote OS:
- Remote Architecture:
- `code-server --version`:
validations:
required: true
- type: textarea
attributes:
label: Steps to Reproduce
description: |
Please describe exactly how to reproduce the bug. For example:
1. Open code-server in Firefox
2. Install extension `foo.bar` from the extensions sidebar
3. Run command `foo.bar.baz`
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 `npm install -g code-server`).
render: shell
- type: textarea
attributes:
label: Screenshot/Video
description: Please include a screenshot, gif or screen recording of your issue.
validations:
required: false
- type: dropdown
attributes:
label: Does this bug reproduce in native VS Code?
description: If the bug reproduces in native VS Code, submit the issue upstream instead (https://github.com/microsoft/vscode).
options:
- Yes, this is also broken in native VS Code
- No, this works as expected in native VS Code
- This cannot be tested in native VS Code
- I did not test native VS Code
validations:
required: true
- type: dropdown
attributes:
label: Does this bug reproduce in VS Code web?
description: If the bug reproduces in VS Code web, submit the issue upstream instead (https://github.com/microsoft/vscode). You can run VS Code web with `code serve-web` (this is not the same as vscode.dev).
options:
- Yes, this is also broken in VS Code web
- No, this works as expected in VS Code web
- This cannot be tested in VS Code web
- I did not test VS Code web
validations:
required: true
- type: dropdown
attributes:
label: Does this bug reproduce in GitHub Codespaces?
description: If the bug reproduces in GitHub Codespaces, submit the issue upstream instead (https://github.com/microsoft/vscode).
options:
- Yes, this is also broken in GitHub Codespaces
- No, this works as expected in GitHub Codespaces
- This cannot be tested in GitHub Codespaces
- I did not test GitHub Codespaces
validations:
required: true
- type: checkboxes
attributes:
label: Are you accessing code-server over a secure context?
description: code-server relies on service workers (which only work in secure contexts) for many features. Double-check that you are using a secure context like HTTPS or localhost.
options:
- label: I am using a secure context.
required: false
- type: textarea
attributes:
label: Notes
description: Please include any addition notes that will help us resolve this issue.
validations:
required: false

View File

@ -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

View File

@ -1,11 +1,7 @@
---
name: Documentation improvement
about: Suggest a documentation improvement
title: ""
labels: "docs"
assignees: ""
---
## What is your suggestion?
## How will this improve the docs?
## Are you interested in submitting a PR for this?

View File

@ -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:

View File

@ -1,13 +1,13 @@
---
name: Feature request
about: Suggest an idea to improve code-server
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!
-->

16
.github/ISSUE_TEMPLATE/release.md vendored Normal file
View File

@ -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

View File

@ -5,4 +5,6 @@ If there is no existing issue, please first create one unless the fix is minor.
Please make sure the base of your PR is the default branch!
-->
Fixes #
## Checklist
- [ ] updated `CHANGELOG.md`

View File

@ -0,0 +1,16 @@
<!-- Note: this variable $CODE_SERVER_VERSION_TO_UPDATE will be set when you run the release-prep.sh script with `yarn release:prep` -->
This PR is to generate a new release of `code-server` at `$CODE_SERVER_VERSION_TO_UPDATE`
## Screenshot
TODO
## TODOs
Follow "Publishing a release" steps in `ci/README.md`
<!-- Note some of these steps below are redundant since they're listed in the "Publishing a release" docs -->
- [ ] publish release and merge PR
- [ ] update the AUR package

31
.github/codecov.yml vendored
View File

@ -1,31 +0,0 @@
codecov:
require_ci_to_pass: yes
allow_coverage_offsets: True
coverage:
precision: 2
round: down
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:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "reach,diff,flags,files,footer"
behavior: default
require_changes: no

View File

@ -1 +1,4 @@
name: "code-server CodeQL config"
paths-ignore:
- lib/vscode

View File

@ -1,31 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
time: "06:00"
timezone: "America/Chicago"
labels: []
commit-message:
prefix: "chore"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "monthly"
time: "06:00"
timezone: "America/Chicago"
commit-message:
prefix: "chore"
labels: []
ignore:
# Ignore patch updates for all dependencies
- dependency-name: "*"
update-types:
- version-update:semver-patch
# Ignore major updates to Node.js types, because they need to
# correspond to the Node.js engine version
- dependency-name: "@types/node"
update-types:
- version-update:semver-major

28
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,28 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
time: "11:00"
ignore:
# GitHub always delivers the latest versions for each major
# release tag, so handle updates manually
- dependency-name: "actions/*"
- dependency-name: "github/codeql-action/*"
- dependency-name: "microsoft/playwright-github-action"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
time: "11:00"
ignore:
- dependency-name: "@types/node"
versions: ["15.x", "14.x", "13.x"]
- dependency-name: "xdg-basedir"
# 5.0.0 has breaking changes as they switch to named exports
# and convert the module to ESM
# We can't use it until we switch to ESM across the project
# See release notes: https://github.com/sindresorhus/xdg-basedir/releases/tag/v5.0.0
versions: ["5.x"]

37
.github/lock.yml vendored Normal file
View File

@ -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

45
.github/ranger.yml vendored Normal file
View File

@ -0,0 +1,45 @@
# Configuration for the repo ranger bot
# See docs: https://www.notion.so/Documentation-8d7627bb1f3c42b7b1820e8d6f157a57#9879d1374fab4d1f9c607c230fd5123d
default:
close:
# Default time to wait before closing the label. Can either be a number in milliseconds
# or a string specified by the `ms` package (https://www.npmjs.com/package/ms)
delay: "2 days"
# Default comment to post when an issue is first marked with a closing label
comment: "⚠️ This issue has been marked $LABEL and will be closed in $DELAY."
labels:
duplicate: close
wontfix: close
"squash when passing": merge
"rebase when passing": merge
"merge when passing": merge
stale:
action: close
delay: 7 days
comment: "⚠️ This issue has been marked stale and will automatically be closed in $DELAY."
"new contributor":
action: comment
delay: 5s
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
comment: >
This issue has been marked as 'upstream:vscode'.
Please file this upstream: [link to open issue](https://github.com/microsoft/vscode/issues/new/choose)
This issue will automatically close in $DELAY.

66
.github/semantic.yaml vendored
View File

@ -1,66 +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
# A new release.
- release

12
.github/stale.yml vendored
View File

@ -1,12 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 180
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 5
# Label to apply when stale.
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no activity occurs in the next 5 days.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@ -1,311 +0,0 @@
name: Build
on:
push:
branches:
- main
pull_request:
branches:
- main
# Cancel in-progress runs for pull requests when developers push
# additional changes, and serialize builds in branches.
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
# Note: if: success() is used in several jobs -
# this ensures that it only executes if all previous jobs succeeded.
# if: steps.cache-node-modules.outputs.cache-hit != 'true'
# will skip running `npm install` if it successfully fetched from cache
jobs:
changes:
runs-on: ubuntu-latest
outputs:
ci: ${{ steps.filter.outputs.ci }}
code: ${{ steps.filter.outputs.code }}
deps: ${{ steps.filter.outputs.deps }}
docs: ${{ steps.filter.outputs.docs }}
helm: ${{ steps.filter.outputs.helm }}
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Check changed files
uses: dorny/paths-filter@v3
id: filter
with:
filters: |
ci:
- ".github/**"
- "ci/**"
docs:
- "docs/**"
- "README.md"
- "CHANGELOG.md"
helm:
- "ci/helm-chart/**"
code:
- "src/**"
- "test/**"
deps:
- "lib/**"
- "patches/**"
- "package-lock.json"
- "test/package-lock.json"
- id: debug
run: |
echo "${{ toJSON(steps.filter )}}"
prettier:
name: Run prettier check
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- run: npx prettier --check .
doctoc:
name: Doctoc markdown files
runs-on: ubuntu-22.04
timeout-minutes: 5
needs: changes
if: needs.changes.outputs.docs == 'true'
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- run: npm run doctoc
lint-helm:
name: Lint Helm chart
runs-on: ubuntu-22.04
timeout-minutes: 5
needs: changes
if: needs.changes.outputs.helm == 'true'
steps:
- uses: actions/checkout@v6
- uses: azure/setup-helm@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- run: helm plugin install https://github.com/instrumenta/helm-kubeval
- run: helm kubeval ci/helm-chart
lint-ts:
name: Lint TypeScript files
runs-on: ubuntu-22.04
timeout-minutes: 5
needs: changes
if: needs.changes.outputs.code == 'true'
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- run: npm run lint:ts
lint-actions:
name: Lint GitHub Actions
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.ci == 'true'
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Check workflow files
run: |
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.7.9
./actionlint -color -shellcheck= -ignore "softprops/action-gh-release"
shell: bash
test-unit:
name: Run unit tests
runs-on: ubuntu-22.04
timeout-minutes: 5
needs: changes
if: needs.changes.outputs.code == 'true'
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- run: npm run test:unit
- uses: codecov/codecov-action@v5
if: success()
with:
token: ${{ secrets.CODECOV_TOKEN }}
build:
name: Build code-server
runs-on: ubuntu-22.04
timeout-minutes: 70
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
DISABLE_V8_COMPILE_CACHE: 1
steps:
- uses: actions/checkout@v6
with:
submodules: true
- run: sudo apt update && sudo apt install -y libkrb5-dev
- uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: quilt
version: 1.0
- run: quilt push -a
- uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- run: npm run build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Get Code's git hash. When this changes it means the content is
# different and we need to rebuild.
- name: Get latest lib/vscode rev
id: vscode-rev
run: echo "rev=$(git rev-parse HEAD:./lib/vscode)" >> $GITHUB_OUTPUT
# We need to rebuild when we have a new version of Code, when any of
# the patches changed, or when the code-server version changes (since
# it gets embedded into the code). Use VSCODE_CACHE_VERSION to
# force a rebuild.
- name: Fetch prebuilt Code package from cache
id: cache-vscode
uses: actions/cache@v4
with:
path: lib/vscode-reh-web-*
key: vscode-reh-package-${{ secrets.VSCODE_CACHE_VERSION }}-${{ steps.vscode-rev.outputs.rev }}-${{ hashFiles('patches/*.diff', 'ci/build/build-vscode.sh') }}
- name: Build vscode
env:
VERSION: "0.0.0"
if: steps.cache-vscode.outputs.cache-hit != 'true'
run: |
pushd lib/vscode
npm ci
popd
npm run build:vscode
# The release package does not contain any native modules
# and is neutral to architecture/os/libc version.
- run: npm run release
if: success()
# https://github.com/actions/upload-artifact/issues/38
- run: tar -czf package.tar.gz release
- uses: actions/upload-artifact@v4
with:
name: npm-package
path: ./package.tar.gz
test-e2e:
name: Run e2e tests
runs-on: ubuntu-22.04
timeout-minutes: 25
needs: [changes, build]
if: needs.changes.outputs.code == 'true' || needs.changes.outputs.deps == 'true'
steps:
- uses: actions/checkout@v6
- run: sudo apt update && sudo apt install -y libkrb5-dev
- uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- uses: actions/download-artifact@v5
with:
name: npm-package
- run: tar -xzf package.tar.gz
- run: cd release && npm install --unsafe-perm --omit=dev
- name: Install Playwright OS dependencies
run: |
./test/node_modules/.bin/playwright install-deps
./test/node_modules/.bin/playwright install
- run: CODE_SERVER_TEST_ENTRY=./release npm run test:e2e
- uses: actions/upload-artifact@v4
if: always()
with:
name: failed-test-videos
path: ./test/test-results
- run: rm -rf ./release ./test/test-results
test-e2e-proxy:
name: Run e2e tests behind proxy
runs-on: ubuntu-22.04
timeout-minutes: 25
needs: [changes, build]
if: needs.changes.outputs.code == 'true' || needs.changes.outputs.deps == 'true'
steps:
- uses: actions/checkout@v6
- run: sudo apt update && sudo apt install -y libkrb5-dev
- uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- uses: actions/download-artifact@v5
with:
name: npm-package
- run: tar -xzf package.tar.gz
- run: cd release && npm install --unsafe-perm --omit=dev
- name: Install Playwright OS dependencies
run: |
./test/node_modules/.bin/playwright install-deps
./test/node_modules/.bin/playwright install
- name: Cache Caddy
uses: actions/cache@v4
id: caddy-cache
with:
path: |
~/.cache/caddy
key: cache-caddy-2.5.2
- name: Install Caddy
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: steps.caddy-cache.outputs.cache-hit != 'true'
run: |
gh release download v2.5.2 --repo caddyserver/caddy --pattern "caddy_2.5.2_linux_amd64.tar.gz"
mkdir -p ~/.cache/caddy
tar -xzf caddy_2.5.2_linux_amd64.tar.gz --directory ~/.cache/caddy
- run: ~/.cache/caddy/caddy start --config ./ci/Caddyfile
- run: CODE_SERVER_TEST_ENTRY=./release npm run test:e2e:proxy
- run: ~/.cache/caddy/caddy stop --config ./ci/Caddyfile
if: always()
- uses: actions/upload-artifact@v4
if: always()
with:
name: failed-test-videos-proxy
path: ./test/test-results

486
.github/workflows/ci.yaml vendored Normal file
View File

@ -0,0 +1,486 @@
name: ci
on:
push:
branches:
- main
pull_request:
branches:
- main
# Note: if: success() is used in several jobs -
# this ensures that it only executes if all previous jobs succeeded.
# if: steps.cache-yarn.outputs.cache-hit != 'true'
# will skip running `yarn install` if it successfully fetched from cache
jobs:
prebuild:
name: Pre-build checks
runs-on: ubuntu-latest
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
steps:
- name: Checkout repo
uses: actions/checkout@v2
- name: Install Node.js v12
uses: actions/setup-node@v2
with:
node-version: "12"
- name: Install helm
uses: azure/setup-helm@v1.1
- name: Fetch dependencies from cache
id: cache-yarn
uses: actions/cache@v2
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
if: steps.cache-yarn.outputs.cache-hit != 'true'
run: yarn --frozen-lockfile
- name: Run yarn fmt
run: yarn fmt
if: success()
- name: Run yarn lint
run: yarn lint
if: success()
- name: Run code-server unit tests
run: yarn test:unit
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
steps:
- name: Checkout repo
uses: actions/checkout@v2
- name: Install Node.js v12
uses: actions/setup-node@v2
with:
node-version: "12"
- name: Fetch dependencies from cache
id: cache-yarn
uses: actions/cache@v2
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
if: steps.cache-yarn.outputs.cache-hit != 'true'
run: yarn --frozen-lockfile
- name: Audit for vulnerabilities
run: yarn _audit
if: success()
build:
name: Build
needs: prebuild
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Install Node.js v12
uses: actions/setup-node@v2
with:
node-version: "12"
- name: Fetch dependencies from cache
id: cache-yarn
uses: actions/cache@v2
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
if: steps.cache-yarn.outputs.cache-hit != 'true'
run: yarn --frozen-lockfile
- name: Build code-server
run: yarn build
# Parse the hash of the latest commit inside lib/vscode
# use this to avoid rebuilding it if nothing changed
# How it works: the `git log` command fetches the hash of the last commit
# that changed a file inside `lib/vscode`. If a commit changes any file in there,
# the hash returned will change, and we rebuild vscode. If the hash did not change,
# (for example, a change to `src/` or `docs/`), we reuse the same build as last time.
# This saves a lot of time in CI, as compiling VSCode can take anywhere from 5-10 minutes.
- name: Get latest lib/vscode rev
id: vscode-rev
run: echo "::set-output name=rev::$(git log -1 --format='%H' ./lib/vscode)"
- name: Attempt to fetch vscode build from cache
id: cache-vscode
uses: actions/cache@v2
with:
path: |
lib/vscode/.build
lib/vscode/out-build
lib/vscode/out-vscode
lib/vscode/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
# The release package does not contain any native modules
# and is neutral to architecture/os/libc version.
- name: Create release package
run: yarn release
if: success()
# https://github.com/actions/upload-artifact/issues/38
- name: Compress release package
run: tar -czf package.tar.gz release
- name: Upload npm package artifact
uses: actions/upload-artifact@v2
with:
name: npm-package
path: ./package.tar.gz
# TODO: cache building yarn --production
# possibly 2m30s of savings(?)
# this requires refactoring our release scripts
package-linux-amd64:
name: x86-64 Linux build
needs: build
runs-on: ubuntu-latest
container: "centos:7"
steps:
- uses: actions/checkout@v2
- name: Install Node.js v12
uses: actions/setup-node@v2
with:
node-version: "12"
- name: Install development tools
run: |
yum install -y epel-release centos-release-scl
yum install -y devtoolset-9-{make,gcc,gcc-c++} jq rsync
- name: Install nfpm and envsubst
run: |
curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b ~/.local/bin v2.3.1
curl -L https://github.com/a8m/envsubst/releases/download/v1.1.0/envsubst-`uname -s`-`uname -m` -o envsubst
chmod +x envsubst
mv envsubst ~/.local/bin
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Install yarn
run: npm install -g yarn
- name: Download npm package
uses: actions/download-artifact@v2
with:
name: npm-package
- name: Decompress npm package
run: tar -xzf package.tar.gz
# NOTE: && here is deliberate - GitHub puts each line in its own `.sh`
# file when running inside a docker container.
- name: Build standalone release
run: source scl_source enable devtoolset-9 && yarn release:standalone
- name: Sanity test standalone release
run: yarn test:standalone-release
- name: Build packages with nfpm
run: yarn package
- name: Upload release artifacts
uses: actions/upload-artifact@v2
with:
name: release-packages
path: ./release-packages
# NOTE@oxy:
# We use Ubuntu 16.04 here, so that our build is more compatible
# with older libc versions. We used to (Q1'20) use CentOS 7 here,
# but it has a full update EOL of Q4'20 and a 'critical security'
# update EOL of 2024. We're dropping full support a few years before
# the final EOL, but I don't believe CentOS 7 has a large arm64 userbase.
# It is not feasible to cross-compile with CentOS.
# Cross-compile notes: To compile native dependencies for arm64,
# we install the aarch64 cross toolchain and then set it as the default
# compiler/linker/etc. with the AR/CC/CXX/LINK environment variables.
# qemu-user-static on ubuntu-16.04 currently doesn't run Node correctly,
# so we just build with "native"/x86_64 node, then download arm64 node
# and then put it in our release. We can't smoke test the arm64 build this way,
# but this means we don't need to maintain a self-hosted runner!
package-linux-arm64:
name: Linux ARM64 cross-compile build
needs: build
runs-on: ubuntu-16.04
env:
AR: aarch64-linux-gnu-ar
CC: aarch64-linux-gnu-gcc
CXX: aarch64-linux-gnu-g++
LINK: aarch64-linux-gnu-g++
NPM_CONFIG_ARCH: arm64
steps:
- uses: actions/checkout@v2
- name: Install Node.js v12
uses: actions/setup-node@v2
with:
node-version: "12"
- name: Install nfpm
run: |
curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b ~/.local/bin v2.3.1
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Install cross-compiler
run: sudo apt install g++-aarch64-linux-gnu
- name: Download npm package
uses: actions/download-artifact@v2
with:
name: npm-package
- name: Decompress npm package
run: tar -xzf package.tar.gz
- name: Build standalone release
run: yarn release:standalone
- name: Replace node with arm64 equivalent
run: |
wget https://nodejs.org/dist/v12.18.4/node-v12.18.4-linux-arm64.tar.gz
tar -xzf node-v12.18.4-linux-arm64.tar.gz node-v12.18.4-linux-arm64/bin/node --strip-components=2
mv ./node ./release-standalone/lib/node
- name: Build packages with nfpm
run: yarn package arm64
- name: Upload release artifacts
uses: actions/upload-artifact@v2
with:
name: release-packages
path: ./release-packages
package-macos-amd64:
name: x86-64 macOS build
needs: build
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Install Node.js v12
uses: actions/setup-node@v2
with:
node-version: "12"
- name: Install nfpm
run: |
curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b ~/.local/bin v2.3.1
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Download npm package
uses: actions/download-artifact@v2
with:
name: npm-package
- name: Decompress npm package
run: tar -xzf package.tar.gz
- name: Build standalone release
run: yarn release:standalone
- name: Sanity test standalone release
run: yarn test:standalone-release
- name: Build packages with nfpm
run: yarn package
- name: Upload release artifacts
uses: actions/upload-artifact@v2
with:
name: release-packages
path: ./release-packages
test-e2e:
name: End-to-end tests
needs: package-linux-amd64
runs-on: ubuntu-latest
env:
PASSWORD: e45432jklfdsab
CODE_SERVER_ADDRESS: http://localhost:8080
steps:
- uses: actions/checkout@v2
- name: Install Node.js v12
uses: actions/setup-node@v2
with:
node-version: "12"
- name: Install playwright
uses: microsoft/playwright-github-action@v1
- name: Fetch dependencies from cache
id: cache-yarn
uses: actions/cache@v2
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
- name: Download release packages
uses: actions/download-artifact@v2
with:
name: release-packages
path: ./release-packages
- name: Untar code-server file
run: |
cd release-packages && tar -xzf code-server*-linux-amd64.tar.gz
- name: Install dependencies
if: steps.cache-yarn.outputs.cache-hit != 'true'
run: yarn --frozen-lockfile
# 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: |
cd test/
rm -r node_modules/playwright
yarn install --check-files
- name: Run end-to-end tests
run: |
./release-packages/code-server*-linux-amd64/bin/code-server --log trace &
yarn test:e2e
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v2
with:
name: failed-test-videos
path: ./test/test-results
- name: Remove release packages and test artifacts
run: rm -rf ./release-packages ./test/test-results
docker-amd64:
runs-on: ubuntu-latest
needs: package-linux-amd64
steps:
- uses: actions/checkout@v2
- name: Download release package
uses: actions/download-artifact@v2
with:
name: release-packages
path: ./release-packages
- name: Run ./ci/steps/build-docker-image.sh
run: ./ci/steps/build-docker-image.sh
- name: Upload release image
uses: actions/upload-artifact@v2
with:
name: release-images
path: ./release-images
# TODO: this is the last place where we use our self-hosted arm64 runner.
# In the future, consider switching to docker buildx + qemu,
# thus removing the requirement for us to maintain the runner.
docker-arm64:
runs-on: ubuntu-arm64-latest
needs: package-linux-arm64
steps:
- uses: actions/checkout@v2
- name: Download release package
uses: actions/download-artifact@v2
with:
name: release-packages
path: ./release-packages
- name: Run ./ci/steps/build-docker-image.sh
run: ./ci/steps/build-docker-image.sh
- name: Upload release image
uses: actions/upload-artifact@v2
with:
name: release-images
path: ./release-images
trivy-scan-image:
runs-on: ubuntu-20.04
needs: docker-amd64
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Download release images
uses: actions/download-artifact@v2
with:
name: release-images
path: ./release-images
- name: Run Trivy vulnerability scanner in image mode
# Commit SHA for v0.0.17
uses: aquasecurity/trivy-action@dba83feec810c70bacbc4bead308ae1e466c572b
with:
input: "./release-images/code-server-amd64-*.tar"
scan-type: "image"
ignore-unfixed: true
format: "template"
template: "@/contrib/sarif.tpl"
output: "trivy-image-results.sarif"
severity: "HIGH,CRITICAL"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: "trivy-image-results.sarif"
# We have to use two trivy jobs
# because GitHub only allows
# codeql/upload-sarif action per job
trivy-scan-repo:
runs-on: ubuntu-20.04
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Run Trivy vulnerability scanner in repo mode
#Commit SHA for v0.0.17
uses: aquasecurity/trivy-action@dba83feec810c70bacbc4bead308ae1e466c572b
with:
scan-type: "fs"
scan-ref: "."
ignore-unfixed: true
format: "template"
template: "@/contrib/sarif.tpl"
output: "trivy-repo-results.sarif"
severity: "HIGH,CRITICAL"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: "trivy-repo-results.sarif"

33
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: "Code Scanning"
on:
push:
branches: [main]
pull_request:
# The branches below must be a subset of the branches above
branches: [main]
schedule:
# Runs every Monday morning PST
- cron: "17 15 * * 1"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-20.04
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
config-file: ./.github/codeql-config.yml
languages: javascript
- name: Autobuild
uses: github/codeql-action/autobuild@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -1,76 +0,0 @@
name: Installer integration
on:
push:
branches:
- main
paths:
- "install.sh"
- ".github/workflows/installer.yaml"
pull_request:
branches:
- main
paths:
- "install.sh"
- ".github/workflows/installer.yaml"
# Cancel in-progress runs for pull requests when developers push
# additional changes, and serialize builds in branches.
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
ubuntu:
name: Test installer on Ubuntu
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Install code-server
run: ./install.sh
- name: Test code-server was installed globally
run: code-server --help
alpine:
name: Test installer on Alpine
runs-on: ubuntu-latest
container: "alpine:3.17"
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Install curl
run: apk add curl
- name: Add user
run: adduser coder --disabled-password
# Standalone should work without root.
- name: Test standalone to a non-existent prefix
run: su coder -c "./install.sh --method standalone --prefix /tmp/does/not/yet/exist"
# We do not actually have Alpine standalone builds so running code-server
# will not work.
- name: Test code-server was installed to prefix
run: test -f /tmp/does/not/yet/exist/bin/code-server
macos:
name: Test installer on macOS
runs-on: macos-latest
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Install code-server
run: ./install.sh
- name: Test code-server was installed globally
run: code-server --help

View File

@ -1,166 +1,53 @@
name: Publish code-server
name: publish
on:
# Shows the manual trigger in GitHub UI
# helpful as a back-up in case the GitHub Actions Workflow fails
workflow_dispatch:
inputs:
version:
description: The version to publish (include "v", i.e. "v4.9.1").
type: string
required: true
release:
types: [released]
# Cancel in-progress runs for pull requests when developers push
# additional changes, and serialize builds in branches.
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
types: [published]
jobs:
# NOTE: this job requires curl, jq and yarn
# All of them are included in ubuntu-latest.
npm:
runs-on: ubuntu-latest
steps:
- name: Checkout code-server
uses: actions/checkout@v6
- uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version-file: .node-version
- name: Download npm package from release artifacts
uses: robinraju/release-downloader@v1.12
with:
repository: "coder/code-server"
tag: ${{ github.event.inputs.version || github.ref_name }}
fileName: "package.tar.gz"
out-file-path: "release-npm-package"
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ github.event.inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- run: npm run publish:npm
- name: Run ./ci/steps/publish-npm.sh
run: ./ci/steps/publish-npm.sh
env:
VERSION: ${{ env.VERSION }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_ENVIRONMENT: "production"
aur:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
GH_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
steps:
# We need to checkout code-server so we can get the version
- name: Checkout code-server
uses: actions/checkout@v6
with:
fetch-depth: 0
path: "./code-server"
- name: Checkout code-server-aur repo
uses: actions/checkout@v6
with:
repository: "cdrci/code-server-aur"
token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
ref: "master"
- name: Merge in master
run: |
git remote add upstream https://github.com/coder/code-server-aur.git
git fetch upstream
git merge upstream/master
- name: Configure git
run: |
git config --global user.name cdrci
git config --global user.email opensource@coder.com
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ github.event.inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- name: Validate package
uses: heyhusen/archlinux-package-action@v2.4.0
env:
VERSION: ${{ env.VERSION }}
with:
pkgver: ${{ env.VERSION }}
updpkgsums: true
srcinfo: true
- name: Open PR
# We need to git push -u otherwise gh will prompt
# asking where to push the branch.
env:
VERSION: ${{ env.VERSION }}
run: |
git checkout -b update-version-${{ env.VERSION }}
git add .
git commit -m "chore: updating version to ${{ env.VERSION }}"
git push -u origin $(git branch --show)
gh pr create --repo coder/code-server-aur --title "chore: bump version to ${{ env.VERSION }}" --body "PR opened by @$GITHUB_ACTOR" --assignee $GITHUB_ACTOR
# NOTE: this job requires curl, jq and docker
# All of them are included in ubuntu-latest.
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout code-server
uses: actions/checkout@v6
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ github.event.inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- name: Download deb artifacts
uses: robinraju/release-downloader@v1.12
with:
repository: "coder/code-server"
tag: v${{ env.VERSION }}
fileName: "*.deb"
out-file-path: "release-packages"
- name: Download rpm artifacts
uses: robinraju/release-downloader@v1.12
with:
repository: "coder/code-server"
tag: v${{ env.VERSION }}
fileName: "*.rpm"
out-file-path: "release-packages"
- name: Publish to Docker
run: ./ci/steps/docker-buildx-push.sh
- name: Run ./ci/steps/push-docker-manifest.sh
run: ./ci/steps/push-docker-manifest.sh
env:
VERSION: ${{ env.VERSION }}
GITHUB_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
homebrew:
# The newest version of code-server needs to be available on npm when this runs
# otherwise, it will 404 and won't open a PR to bump version on homebrew/homebrew-core
needs: npm
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Configure git
run: |
git config user.name github-actions
git config user.email github-actions@github.com
- name: Bump code-server homebrew version
env:
HOMEBREW_GITHUB_API_TOKEN: ${{secrets.HOMEBREW_GITHUB_API_TOKEN}}
run: ./ci/steps/brew-bump.sh

View File

@ -1,309 +0,0 @@
name: Draft release
on:
workflow_dispatch:
inputs:
version:
description: The version to publish (include "v", i.e. "v4.9.1").
type: string
required: true
permissions:
contents: write # For creating releases.
discussions: write # For creating a discussion.
# Cancel in-progress runs for pull requests when developers push
# additional changes
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
package-linux-cross:
name: ${{ matrix.prefix }}
runs-on: ubuntu-latest
timeout-minutes: 15
needs: npm-version
container: "python:3.8-slim-buster"
strategy:
matrix:
include:
- prefix: x86_64-linux-gnu
npm_arch: x64
apt_arch: amd64
package_arch: amd64
- prefix: aarch64-linux-gnu
npm_arch: arm64
apt_arch: arm64
package_arch: arm64
- prefix: arm-linux-gnueabihf
npm_arch: armv7l
apt_arch: armhf
package_arch: armv7l
env:
AR: ${{ format('{0}-ar', matrix.prefix) }}
AS: ${{ format('{0}-as', matrix.prefix) }}
CC: ${{ format('{0}-gcc', matrix.prefix) }}
CPP: ${{ format('{0}-cpp', matrix.prefix) }}
CXX: ${{ format('{0}-g++', matrix.prefix) }}
FC: ${{ format('{0}-gfortran', matrix.prefix) }}
LD: ${{ format('{0}-ld', matrix.prefix) }}
STRIP: ${{ format('{0}-strip', matrix.prefix) }}
PKG_CONFIG_PATH: ${{ format('/usr/lib/{0}/pkgconfig', matrix.prefix) }}
TARGET_ARCH: ${{ matrix.apt_arch }}
npm_config_arch: ${{ matrix.npm_arch }}
PKG_ARCH: ${{ matrix.package_arch }}
# Not building from source results in an x86_64 argon2, as if
# npm_config_arch is being ignored.
npm_config_build_from_source: true
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- name: Install cross-compiler and system dependencies
run: |
sed -i 's/deb\.debian\.org/archive.debian.org/g' /etc/apt/sources.list
dpkg --add-architecture $TARGET_ARCH
apt update && apt install -y --no-install-recommends \
crossbuild-essential-$TARGET_ARCH \
libx11-dev:$TARGET_ARCH \
libx11-xcb-dev:$TARGET_ARCH \
libxkbfile-dev:$TARGET_ARCH \
libsecret-1-dev:$TARGET_ARCH \
libkrb5-dev:$TARGET_ARCH \
ca-certificates \
curl wget rsync gettext-base
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- name: Install nfpm
run: |
mkdir -p ~/.local/bin
curl -sSfL https://github.com/goreleaser/nfpm/releases/download/v2.3.1/nfpm_2.3.1_`uname -s`_`uname -m`.tar.gz | tar -C ~/.local/bin -zxv nfpm
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Download npm package
uses: actions/download-artifact@v5
with:
name: npm-release-package
- run: tar -xzf package.tar.gz
- run: npm run release:standalone
- name: Replace node with cross-compile equivalent
run: |
node_version=$(node --version)
wget https://nodejs.org/dist/${node_version}/node-${node_version}-linux-${npm_config_arch}.tar.xz
tar -xf node-${node_version}-linux-${npm_config_arch}.tar.xz node-${node_version}-linux-${npm_config_arch}/bin/node --strip-components=2
mv ./node ./release-standalone/lib/node
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- env:
VERSION: ${{ env.VERSION }}
run: npm run package $PKG_ARCH
- uses: softprops/action-gh-release@v1
with:
draft: true
discussion_category_name: "📣 Announcements"
files: ./release-packages/*
package-macos-amd64:
name: x86-64 macOS build
runs-on: macos-15-intel
timeout-minutes: 15
needs: npm-version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- name: Install nfpm
run: |
mkdir -p ~/.local/bin
curl -sSfL https://github.com/goreleaser/nfpm/releases/download/v2.3.1/nfpm_2.3.1_`uname -s`_`uname -m`.tar.gz | tar -C ~/.local/bin -zxv nfpm
echo "$HOME/.local/bin" >> $GITHUB_PATH
# The version of node-gyp we use depends on distutils but it was removed
# in Python 3.12. It seems to be fixed in the latest node-gyp so when we
# next update Node we can probably remove this. For now, install
# setuptools since it contains distutils.
- run: brew install python-setuptools
- name: Download npm package
uses: actions/download-artifact@v5
with:
name: npm-release-package
- run: tar -xzf package.tar.gz
- run: npm run release:standalone
- run: npm run test:native
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- name: Build packages with nfpm
env:
VERSION: ${{ env.VERSION }}
run: npm run package
- uses: softprops/action-gh-release@v1
with:
draft: true
discussion_category_name: "📣 Announcements"
files: ./release-packages/*
package-macos-arm64:
name: arm64 macOS build
runs-on: macos-latest
timeout-minutes: 15
needs: npm-version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: |
package-lock.json
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- name: Install nfpm
run: |
mkdir -p ~/.local/bin
curl -sSfL https://github.com/goreleaser/nfpm/releases/download/v2.3.1/nfpm_2.3.1_`uname -s`_`uname -m`.tar.gz | tar -C ~/.local/bin -zxv nfpm
echo "$HOME/.local/bin" >> $GITHUB_PATH
# The version of node-gyp we use depends on distutils but it was removed
# in Python 3.12. It seems to be fixed in the latest node-gyp so when we
# next update Node we can probably remove this. For now, install
# setuptools since it contains distutils.
- run: brew install python-setuptools
- name: Download npm package
uses: actions/download-artifact@v5
with:
name: npm-release-package
- run: tar -xzf package.tar.gz
- run: npm run release:standalone
- run: npm run test:native
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- name: Build packages with nfpm
env:
VERSION: ${{ env.VERSION }}
run: npm run package
- uses: softprops/action-gh-release@v1
with:
draft: true
discussion_category_name: "📣 Announcements"
files: ./release-packages/*
npm-package:
name: Upload npm package
runs-on: ubuntu-latest
timeout-minutes: 15
needs: npm-version
steps:
- name: Download npm package
uses: actions/download-artifact@v5
with:
name: npm-release-package
- uses: softprops/action-gh-release@v1
with:
draft: true
discussion_category_name: "📣 Announcements"
files: ./package.tar.gz
npm-version:
name: Modify package.json version
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Download artifacts
uses: dawidd6/action-download-artifact@v12
id: download
with:
branch: ${{ github.ref }}
workflow: build.yaml
workflow_conclusion: completed
name: npm-package
check_artifacts: false
if_no_artifact_found: fail
- run: tar -xzf package.tar.gz
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- name: Modify version
env:
VERSION: ${{ env.VERSION }}
run: |
echo "Updating version in root package.json"
npm version --prefix release "$VERSION"
echo "Updating version in lib/vscode/product.json"
tmp=$(mktemp)
jq ".codeServerVersion = \"$VERSION\"" release/lib/vscode/product.json > "$tmp" && mv "$tmp" release/lib/vscode/product.json
# Ensure it has the same permissions as before
chmod 644 release/lib/vscode/product.json
- run: tar -czf package.tar.gz release
- name: Upload npm package artifact
uses: actions/upload-artifact@v4
with:
name: npm-release-package
path: ./package.tar.gz

View File

@ -1,67 +0,0 @@
name: Script unit tests
on:
push:
branches:
- main
paths:
- "**.sh"
- "**.bats"
pull_request:
branches:
- main
paths:
- "**.sh"
- "**.bats"
permissions:
actions: none
checks: none
contents: read
deployments: none
issues: none
packages: none
pull-requests: none
repository-projects: none
security-events: none
statuses: none
# Cancel in-progress runs for pull requests when developers push
# additional changes, and serialize builds in branches.
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
test:
name: Run script unit tests
runs-on: ubuntu-latest
# This runs on Alpine to make sure we're testing with actual sh.
container: "alpine:3.17"
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Install test utilities
run: apk add bats checkbashisms
- name: Check Bashisms
run: checkbashisms ./install.sh
- name: Run script unit tests
run: ./ci/dev/test-scripts.sh
lint:
name: Lint shell files
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Install lint utilities
run: sudo apt install shellcheck
- name: Lint shell files
run: ./ci/dev/lint-scripts.sh

View File

@ -1,92 +0,0 @@
name: Security
on:
push:
branches: [main]
paths:
- "package.json"
pull_request:
paths:
- "package.json"
schedule:
# Runs every Monday morning PST
- cron: "17 15 * * 1"
# Cancel in-progress runs for pull requests when developers push additional
# changes, and serialize builds in branches.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
audit:
name: Audit node modules
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout repo
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version-file: .node-version
- name: Audit npm for vulnerabilities
run: npm audit
if: success()
trivy-scan-repo:
name: Scan repo with Trivy
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
runs-on: ubuntu-22.04
steps:
- name: Checkout repo
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run Trivy vulnerability scanner in repo mode
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
scan-type: "fs"
scan-ref: "."
ignore-unfixed: true
format: "template"
template: "@/contrib/sarif.tpl"
output: "trivy-repo-results.sarif"
severity: "HIGH,CRITICAL"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: "trivy-repo-results.sarif"
codeql-analyze:
permissions:
actions: read # for github/codeql-action/init to get workflow details
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/autobuild to send a status report
name: Analyze with CodeQL
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
config-file: ./.github/codeql-config.yml
languages: javascript
- name: Autobuild
uses: github/codeql-action/autobuild@v4
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4

View File

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

13
.gitignore vendored
View File

@ -1,6 +1,7 @@
.tsbuildinfo
.cache
/out*/
dist*
out*
release/
release-npm-package/
release-standalone/
@ -8,18 +9,12 @@ release-packages/
release-gcp/
release-images/
node_modules
/lib/vscode/node_modules.asar
node-*
/plugins
/lib/coder-cloud-agent
.home
coverage
**/.DS_Store
# Code packages itself here.
/lib/vscode-reh-web-*
# Failed e2e test videos are saved here
test/test-results
# Quilt's internal data.
/.pc
/patches/*.diff~

3
.gitmodules vendored
View File

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

View File

@ -1 +0,0 @@
22.21.1

1
.nvmrc
View File

@ -1 +0,0 @@
.node-version

View File

@ -1,10 +0,0 @@
lib/vscode
lib/vscode-reh-web-linux-x64
release-standalone
release-packages
release
helm-chart
test/scripts
test/e2e/extensions/test-extension
.pc
package-lock.json

View File

@ -2,5 +2,3 @@ printWidth: 120
semi: false
trailingComma: all
arrowParens: always
singleQuote: false
useTabs: false

2
.stylelintrc.yaml Normal file
View File

@ -0,0 +1,2 @@
extends:
- stylelint-config-recommended

View File

@ -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/main/docs/FAQ.md#heartbeat-file](https://github.com/coder/code-server/blob/main/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/main/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/coder/code-server/blob/main/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/main/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/coder/code-server/blob/main/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/main/docs/FAQ.md#healthz-endpoint](https://github.com/coder/code-server/blob/main/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": "lib/vscode",
"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/main/docs/CONTRIBUTING.md#modifications-to-vs-code](https://github.com/coder/code-server/blob/main/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."
}
]
}
}

View File

@ -5,7 +5,7 @@
{
"file": "package.json",
"line": 31,
"description": "## Commands\n\nTo start developing, make sure you have Node 16+ and the [required dependencies](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites) installed. Then, run the following commands:\n\n1. Install dependencies:\n>> npm\n\n3. Start development mode (and watch for changes):\n>> npm run watch"
"description": "## Commands\n\nTo start developing, make sure you have Node 12+ and the [required dependencies](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites) installed. Then, run the following commands:\n\n1. Install dependencies:\n>> yarn\n\n3. Start development mode (and watch for changes):\n>> yarn watch"
},
{
"file": "src/node/app.ts",
@ -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 `npm run 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/main/docs/FAQ.md)\n- [Docs: CONTRIBUTING.md](https://github.com/coder/code-server/blob/main/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)"
}
]
}

File diff suppressed because it is too large Load Diff

77
README.md Normal file
View File

@ -0,0 +1,77 @@
# code-server &middot; [!["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 latest docs](https://img.shields.io/static/v1?label=Docs&message=see%20latest%20&color=blue)](https://github.com/cdr/code-server/tree/v3.10.1/docs)
Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and access it in the browser.
![Screenshot](./docs/assets/screenshot.png)
## Highlights
- Code on any device with a consistent development environment
- Use cloud servers to speed up tests, compilations, downloads, and more
- Preserve battery life when you're on the go; all intensive tasks run on your server
## Requirements
For a good experience, we recommend at least:
- 1 GB of RAM
- 2 cores
You can use whatever linux distribution floats your boat but in our [guide](./docs/guide.md) we assume Debian on Google Cloud.
## Getting Started
There are three ways you can get started:
1. Using the [install script](./install.sh), which automates most of the process. The script uses the system package manager (if possible)
2. Manually installing code-server; see [Installation](./docs/install.md) for instructions applicable to most use cases
3. Use our one-click buttons and guides to [deploy code-server to a popular cloud provider](https://github.com/cdr/deploy-code-server) ⚡
If you choose to use the install script, you can preview what occurs during the install process:
```bash
curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
```
To install, run:
```bash
curl -fsSL https://code-server.dev/install.sh | sh
```
When done, the install script prints out instructions for running and starting code-server.
We also have an in-depth [setup and configuration](./docs/guide.md) guide.
### code-server --link
We're working on a cloud platform that makes deploying and managing code-server easier.
Consider running code-server with the beta flag `--link` if you don't want to worry about
- TLS
- Authentication
- Port Forwarding
```bash
$ code-server --link
Proxying code-server, you can access your IDE at https://valmar-jon.cdr.co
```
## FAQ
See [./docs/FAQ.md](./docs/FAQ.md).
## Want to help?
See [CONTRIBUTING](./docs/CONTRIBUTING.md) for details.
## Hiring
Interested in [working at Coder](https://coder.com)? Check out [our open positions](https://jobs.lever.co/coder)!
## For Organizations
Visit [our website](https://coder.com) for more information about remote development for your organization or enterprise.

View File

@ -1,15 +0,0 @@
{
admin localhost:4444
}
:8000 {
@portLocalhost path_regexp port ^/([0-9]+)\/ide
handle @portLocalhost {
uri strip_prefix {re.port.1}/ide
reverse_proxy localhost:{re.port.1}
}
handle {
respond "Bad hostname" 400
}
}

View File

@ -10,24 +10,48 @@ Any file or directory in this subdirectory should be documented here.
- [./ci/lib.sh](./lib.sh)
- Contains code duplicated across these scripts.
## Publishing a release
1. Run `yarn release:prep` and type in the new version i.e. 3.8.1
2. GitHub actions will generate the `npm-package`, `release-packages` and `release-images` artifacts.
1. You do not have to wait for these.
3. Run `yarn release:github-draft` to create a GitHub draft release from the template with
the updated version.
1. Summarize the major changes in the release notes and link to the relevant issues.
2. Change the @ to target the version branch. Example: `v3.9.0 @ Target: v3.9.0`
4. Wait for the artifacts in step 2 to build.
5. Run `yarn release:github-assets` to download the `release-packages` artifact.
- It will upload them to the draft release.
6. Run some basic sanity tests on one of the released packages.
- Especially make sure the terminal works fine.
7. Publish the release and merge the PR.
1. CI will automatically grab the artifacts and then:
1. Publish the NPM package from `npm-package`.
2. Publish the Docker Hub image from `release-images`.
8. Update the AUR package.
- Instructions on updating the AUR package are at [cdr/code-server-aur](https://github.com/cdr/code-server-aur).
9. Wait for the npm package to be published.
## dev
This directory contains scripts used for the development of code-server.
- [./ci/dev/image](./dev/image)
- See [./docs/CONTRIBUTING.md](../docs/CONTRIBUTING.md) for docs on the development container.
- [./ci/dev/fmt.sh](./dev/fmt.sh) (`npm run fmt`)
- [./ci/dev/fmt.sh](./dev/fmt.sh) (`yarn fmt`)
- Runs formatters.
- [./ci/dev/lint.sh](./dev/lint.sh) (`npm run lint`)
- [./ci/dev/lint.sh](./dev/lint.sh) (`yarn lint`)
- Runs linters.
- [./ci/dev/test-unit.sh](./dev/test-unit.sh) (`npm run test:unit`)
- [./ci/dev/test-unit.sh](./dev/test-unit.sh) (`yarn test:unit`)
- Runs unit tests.
- [./ci/dev/test-e2e.sh](./dev/test-e2e.sh) (`npm run test:e2e`)
- [./ci/dev/test-e2e.sh](./dev/test-e2e.sh) (`yarn test:e2e`)
- Runs end-to-end tests.
- [./ci/dev/watch.ts](./dev/watch.ts) (`npm run watch`)
- [./ci/dev/ci.sh](./dev/ci.sh) (`yarn ci`)
- Runs `yarn fmt`, `yarn lint` and `yarn test`.
- [./ci/dev/watch.ts](./dev/watch.ts) (`yarn watch`)
- Starts a process to build and launch code-server and restart on any code changes.
- Example usage in [./docs/CONTRIBUTING.md](../docs/CONTRIBUTING.md).
- [./ci/dev/gen_icons.sh](./dev/gen_icons.sh) (`npm run icons`)
- [./ci/dev/gen_icons.sh](./ci/dev/gen_icons.sh) (`yarn icons`)
- Generates the various icons from a single `.svg` favicon in
`src/browser/media/favicon.svg`.
- Requires [imagemagick](https://imagemagick.org/index.php)
@ -37,20 +61,23 @@ This directory contains scripts used for the development of code-server.
This directory contains the scripts used to build and release code-server.
You can disable minification by setting `MINIFY=`.
- [./ci/build/build-code-server.sh](./build/build-code-server.sh) (`npm run build`)
- [./ci/build/build-code-server.sh](./build/build-code-server.sh) (`yarn build`)
- Builds code-server into `./out` and bundles the frontend into `./dist`.
- [./ci/build/build-vscode.sh](./build/build-vscode.sh) (`npm run build:vscode`)
- [./ci/build/build-vscode.sh](./build/build-vscode.sh) (`yarn build:vscode`)
- Builds vscode into `./lib/vscode/out-vscode`.
- [./ci/build/build-release.sh](./build/build-release.sh) (`npm run release`)
- [./ci/build/build-release.sh](./build/build-release.sh) (`yarn release`)
- Bundles the output of the above two scripts into a single node module at `./release`.
- [./ci/build/clean.sh](./build/clean.sh) (`npm run clean`)
- [./ci/build/build-standalone-release.sh](./build/build-standalone-release.sh) (`yarn release:standalone`)
- Requires a node module already built into `./release` with the above script.
- Will build a standalone release with node and node_modules bundled into `./release-standalone`.
- [./ci/build/clean.sh](./build/clean.sh) (`yarn clean`)
- Removes all build artifacts.
- Useful to do a clean build.
- [./ci/build/code-server.sh](./build/code-server.sh)
- Copied into standalone releases to run code-server with the bundled node binary.
- [./ci/build/test-standalone-release.sh](./build/test-standalone-release.sh) (`npm run test:standalone-release`)
- [./ci/build/test-standalone-release.sh](./build/test-standalone-release.sh) (`yarn test:standalone-release`)
- Ensures code-server in the `./release-standalone` directory works by installing an extension.
- [./ci/build/build-packages.sh](./build/build-packages.sh) (`npm run package`)
- [./ci/build/build-packages.sh](./build/build-packages.sh) (`yarn package`)
- Packages `./release-standalone` into a `.tar.gz` archive in `./release-packages`.
- If on linux, [nfpm](https://github.com/goreleaser/nfpm) is used to generate `.deb` and `.rpm`.
- [./ci/build/nfpm.yaml](./build/nfpm.yaml)
@ -59,22 +86,22 @@ You can disable minification by setting `MINIFY=`.
- Entrypoint script for code-server for `.deb` and `.rpm`.
- [./ci/build/code-server.service](./build/code-server.service)
- systemd user service packaged into the `.deb` and `.rpm`.
- [./ci/build/release-github-draft.sh](./build/release-github-draft.sh) (`npm run release:github-draft`)
- [./ci/build/release-github-draft.sh](./build/release-github-draft.sh) (`yarn release:github-draft`)
- Uses [gh](https://github.com/cli/cli) to create a draft release with a template description.
- [./ci/build/release-github-assets.sh](./build/release-github-assets.sh) (`npm run release:github-assets`)
- [./ci/build/release-github-assets.sh](./build/release-github-assets.sh) (`yarn release:github-assets`)
- Downloads the release-package artifacts for the current commit from CI.
- Uses [gh](https://github.com/cli/cli) to upload the artifacts to the release
specified in `package.json`.
- [./ci/build/npm-postinstall.sh](./build/npm-postinstall.sh)
- Post install script for the npm package.
- Bundled by`npm run release`.
- Bundled by`yarn release`.
## release-image
This directory contains the release docker container image.
- [./ci/steps/build-docker-buildx-push.sh](./steps/docker-buildx-push.sh)
- Builds the release containers with tags `codercom/code-server-$ARCH:$VERSION` for amd64 and arm64 with `docker buildx` and pushes them.
- [./release-image/build.sh](./release-image/build.sh)
- Builds the release container with the tag `codercom/code-server-$ARCH:$VERSION`.
- Assumes debian releases are ready in `./release-packages`.
## images
@ -87,15 +114,13 @@ This directory contains the scripts used in CI.
Helps avoid clobbering the CI configuration.
- [./steps/fmt.sh](./steps/fmt.sh)
- Runs `npm run fmt`.
- Runs `yarn fmt`.
- [./steps/lint.sh](./steps/lint.sh)
- Runs `npm run lint`.
- Runs `yarn lint`.
- [./steps/test-unit.sh](./steps/test-unit.sh)
- Runs `npm run test:unit`.
- [./steps/test-integration.sh](./steps/test-integration.sh)
- Runs `npm run test:integration`.
- Runs `yarn test:unit`.
- [./steps/test-e2e.sh](./steps/test-e2e.sh)
- Runs `npm run test:e2e`.
- Runs `yarn test:e2e`.
- [./steps/release.sh](./steps/release.sh)
- Runs the release process.
- Generates the npm package at `./release`.
@ -104,8 +129,8 @@ Helps avoid clobbering the CI configuration.
release packages into `./release-packages`.
- [./steps/publish-npm.sh](./steps/publish-npm.sh)
- Grabs the `npm-package` release artifact for the current commit and publishes it on npm.
- [./steps/docker-buildx-push.sh](./steps/docker-buildx-push.sh)
- Builds the docker image and then pushes it.
- [./steps/build-docker-image.sh](./steps/build-docker-image.sh)
- Builds the docker image and then saves it into `./release-images/code-server-$ARCH-$VERSION.tar`.
- [./steps/push-docker-manifest.sh](./steps/push-docker-manifest.sh)
- Loads all images in `./release-images` and then builds and pushes a multi architecture
docker manifest for the amd64 and arm64 images to `codercom/code-server:$VERSION` and

View File

@ -3,6 +3,9 @@ set -euo pipefail
# Builds code-server into out and the frontend into dist.
# MINIFY controls whether parcel minifies dist.
MINIFY=${MINIFY-true}
main() {
cd "$(dirname "${0}")/../.."
@ -14,6 +17,29 @@ main() {
sed -i.bak "1s;^;#!/usr/bin/env node\n;" out/node/entry.js && rm out/node/entry.js.bak
chmod +x out/node/entry.js
fi
if ! [ -f ./lib/coder-cloud-agent ]; then
echo "Downloading the cloud agent..."
# for arch; we do not use OS from lib.sh and get our own.
# lib.sh normalizes macos to darwin - but cloud-agent's binaries do not
source ./ci/lib.sh
OS="$(uname | tr '[:upper:]' '[:lower:]')"
set +e
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
parcel build \
--public-url "." \
--out-dir dist \
$([[ $MINIFY ]] || echo --no-minify) \
src/browser/register.ts \
src/browser/serviceWorker.ts \
src/browser/pages/login.ts \
src/browser/pages/vscode.ts
}
main "$@"

View File

@ -1,28 +0,0 @@
#!/usr/bin/env bash
# This is a library which contains functions used inside ci/build
#
# We separated it into it's own file so that we could easily unit test
# these functions and helpers.
# On some CPU architectures (notably node/uname "armv7l", default on Raspberry Pis),
# different package managers have different labels for the same CPU (deb=armhf, rpm=armhfp).
# This function returns the overriden arch on platforms
# with alternate labels, or the same arch otherwise.
get_nfpm_arch() {
local PKG_FORMAT="${1:-}"
local ARCH="${2:-}"
case "$ARCH" in
armv7l)
if [ "$PKG_FORMAT" = "deb" ]; then
echo armhf
elif [ "$PKG_FORMAT" = "rpm" ]; then
echo armhfp
fi
;;
*)
echo "$ARCH"
;;
esac
}

View File

@ -1,15 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
# Given a platform-specific release found in ./release-standalone, generate an
# compressed archives and bundles (as appropriate for the platform) named after
# the platform's architecture and OS and place them in ./release-packages and
# ./release-gcp.
# Packages code-server for the current OS and architecture into ./release-packages.
# This script assumes that a standalone release is built already into ./release-standalone
main() {
cd "$(dirname "${0}")/../.."
source ./ci/lib.sh
source ./ci/build/build-lib.sh
# Allow us to override architecture
# we use this for our Linux ARM64 cross compile builds
@ -29,7 +26,7 @@ main() {
release_archive() {
local release_name="code-server-$VERSION-$OS-$ARCH"
if [[ $OS == "linux" ]]; then
tar -czf "release-packages/$release_name.tar.gz" --owner=0 --group=0 --transform "s/^\.\/release-standalone/$release_name/" ./release-standalone
tar -czf "release-packages/$release_name.tar.gz" --transform "s/^\.\/release-standalone/$release_name/" ./release-standalone
else
tar -czf "release-packages/$release_name.tar.gz" -s "/^release-standalone/$release_name/" release-standalone
fi
@ -49,22 +46,11 @@ release_gcp() {
# Generates deb and rpm packages.
release_nfpm() {
local nfpm_config
nfpm_config="$(envsubst <./ci/build/nfpm.yaml)"
export NFPM_ARCH
PKG_FORMAT="deb"
NFPM_ARCH="$(get_nfpm_arch $PKG_FORMAT "$ARCH")"
nfpm_config="$(envsubst < ./ci/build/nfpm.yaml)"
echo "Building deb"
echo "$nfpm_config" | head --lines=4
nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server_${VERSION}_${NFPM_ARCH}.deb"
PKG_FORMAT="rpm"
NFPM_ARCH="$(get_nfpm_arch $PKG_FORMAT "$ARCH")"
nfpm_config="$(envsubst < ./ci/build/nfpm.yaml)"
echo "Building rpm"
echo "$nfpm_config" | head --lines=4
nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server-$VERSION-$NFPM_ARCH.rpm"
# The underscores are convention for .deb.
nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server_${VERSION}_$ARCH.deb"
nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server-$VERSION-$ARCH.rpm"
}
main "$@"

View File

@ -1,135 +1,103 @@
#!/usr/bin/env bash
set -euo pipefail
# Once both code-server and VS Code have been built, use this script to copy
# them into a single directory (./release), prepare the package.json and
# product.json, and add shrinkwraps. This results in a generic NPM package that
# we published to NPM and also use to compile platform-specific packages.
# This script requires vscode to be built with matching MINIFY.
# MINIFY controls whether minified VS Code is bundled. It must match the value
# used when VS Code was built.
# MINIFY controls whether minified vscode is bundled.
MINIFY="${MINIFY-true}"
# node_modules are not copied by default. Set KEEP_MODULES=1 to copy them.
# KEEP_MODULES controls whether the script cleans all node_modules requiring a yarn install
# to run first.
KEEP_MODULES="${KEEP_MODULES-0}"
main() {
cd "$(dirname "${0}")/../.."
source ./ci/lib.sh
VSCODE_SRC_PATH="lib/vscode"
VSCODE_OUT_PATH="$RELEASE_PATH/lib/vscode"
create_shrinkwraps
mkdir -p "$RELEASE_PATH"
bundle_code_server
bundle_vscode
rsync ./docs/README.md "$RELEASE_PATH"
rsync LICENSE "$RELEASE_PATH"
rsync README.md "$RELEASE_PATH"
rsync LICENSE.txt "$RELEASE_PATH"
rsync ./lib/vscode/ThirdPartyNotices.txt "$RELEASE_PATH"
}
bundle_code_server() {
rsync out "$RELEASE_PATH"
rsync out dist "$RELEASE_PATH"
# For source maps and images.
mkdir -p "$RELEASE_PATH/src/browser"
rsync src/browser/media/ "$RELEASE_PATH/src/browser/media"
mkdir -p "$RELEASE_PATH/src/browser/pages"
rsync src/browser/pages/*.html "$RELEASE_PATH/src/browser/pages"
rsync src/browser/pages/*.css "$RELEASE_PATH/src/browser/pages"
rsync src/browser/robots.txt "$RELEASE_PATH/src/browser"
# Add typings for plugins
mkdir -p "$RELEASE_PATH/typings"
rsync typings/pluginapi.d.ts "$RELEASE_PATH/typings"
# Adds the commit to package.json
jq --slurp '(.[0] | del(.scripts,.jest,.devDependencies)) * .[1]' package.json <(
cat << EOF
jq --slurp '.[0] * .[1]' package.json <(
cat <<EOF
{
"commit": "$(git rev-parse HEAD)",
"scripts": {
"postinstall": "sh ./postinstall.sh"
"postinstall": "./postinstall.sh"
}
}
EOF
) > "$RELEASE_PATH/package.json"
mv npm-shrinkwrap.json "$RELEASE_PATH"
) >"$RELEASE_PATH/package.json"
rsync yarn.lock "$RELEASE_PATH"
rsync ci/build/npm-postinstall.sh "$RELEASE_PATH/postinstall.sh"
if [ "$KEEP_MODULES" = 1 ]; then
rsync node_modules/ "$RELEASE_PATH/node_modules"
mkdir -p "$RELEASE_PATH/lib"
rsync ./lib/coder-cloud-agent "$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${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
local rsync_opts=()
if [[ ${DEBUG-} = 1 ]]; then
rsync_opts+=(-vh)
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
if [ "$KEEP_MODULES" = 0 ]; then
rm -Rf "$VSCODE_OUT_PATH/extensions/node_modules"
else
rsync "$VSCODE_SRC_PATH/node_modules/" "$VSCODE_OUT_PATH/node_modules"
fi
rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions"
rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions"
rsync "$VSCODE_SRC_PATH/extensions/postinstall.js" "$VSCODE_OUT_PATH/extensions"
# Some extensions have a .gitignore which excludes their built source from the
# npm package so exclude any .gitignore files.
rsync_opts+=(--exclude .gitignore)
mkdir -p "$VSCODE_OUT_PATH/resources/"{linux,web}
rsync "$VSCODE_SRC_PATH/resources/linux/code.png" "$VSCODE_OUT_PATH/resources/linux/code.png"
rsync "$VSCODE_SRC_PATH/resources/web/callback.html" "$VSCODE_OUT_PATH/resources/web/callback.html"
# Exclude Node as we will add it ourselves for the standalone and will not
# need it for the npm package.
rsync_opts+=(--exclude /node)
# Adds the commit and date to product.json
jq --slurp '.[0] * .[1]' "$VSCODE_SRC_PATH/product.json" <(
cat <<EOF
{
"commit": "$(git rev-parse HEAD)",
"date": $(jq -n 'now | todate')
}
EOF
) >"$VSCODE_OUT_PATH/product.json"
# Exclude Node modules.
if [[ $KEEP_MODULES = 0 ]]; then
rsync_opts+=(--exclude node_modules)
fi
# We remove the scripts field so that later on we can run
# yarn to fetch node_modules if necessary without build scripts running.
# We cannot use --no-scripts because we still want dependent package scripts to run.
jq 'del(.scripts)' <"$VSCODE_SRC_PATH/package.json" >"$VSCODE_OUT_PATH/package.json"
rsync "${rsync_opts[@]}" ./lib/vscode-reh-web-*/ "$VSCODE_OUT_PATH"
# Merge the package.json for the web/remote server so we can include
# dependencies, since we want to ship this via NPM.
jq --slurp '.[0] * .[1]' \
"$VSCODE_SRC_PATH/remote/package.json" \
"$VSCODE_OUT_PATH/package.json" > "$VSCODE_OUT_PATH/package.json.merged"
mv "$VSCODE_OUT_PATH/package.json.merged" "$VSCODE_OUT_PATH/package.json"
cp "$VSCODE_SRC_PATH/remote/npm-shrinkwrap.json" "$VSCODE_OUT_PATH/npm-shrinkwrap.json"
# Include global extension dependencies as well.
rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions/package.json"
cp "$VSCODE_SRC_PATH/extensions/npm-shrinkwrap.json" "$VSCODE_OUT_PATH/extensions/npm-shrinkwrap.json"
rsync "$VSCODE_SRC_PATH/extensions/postinstall.mjs" "$VSCODE_OUT_PATH/extensions/postinstall.mjs"
}
create_shrinkwraps() {
# package-lock.json files (used to ensure deterministic versions of
# dependencies) are not packaged when publishing to the NPM registry.
#
# To ensure deterministic dependency versions (even when code-server is
# installed with NPM), we create an npm-shrinkwrap.json file from the
# currently installed node_modules. This ensures the versions used from
# development (that the package-lock.json guarantees) are also the ones
# installed by end-users. These will include devDependencies, but those will
# be ignored when installing globally (for code-server), and because we use
# --omit=dev (for VS Code).
# We first generate the shrinkwrap file for code-server itself - which is the
# current directory.
cp package-lock.json package-lock.json.temp
npm shrinkwrap
mv package-lock.json.temp package-lock.json
# Then the shrinkwrap files for the bundled VS Code.
pushd "$VSCODE_SRC_PATH/remote/"
cp package-lock.json package-lock.json.temp
npm shrinkwrap
mv package-lock.json.temp package-lock.json
popd
pushd "$VSCODE_SRC_PATH/extensions/"
cp package-lock.json package-lock.json.temp
npm shrinkwrap
mv package-lock.json.temp package-lock.json
pushd "$VSCODE_OUT_PATH"
symlink_asar
popd
}

View File

@ -1,37 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
# Once we have an NPM package, use this script to copy it to a separate
# directory (./release-standalone) and install the dependencies. This new
# directory can then be packaged as a platform-specific release.
main() {
cd "$(dirname "${0}")/../.."
source ./ci/lib.sh
rsync "$RELEASE_PATH/" "$RELEASE_PATH-standalone"
RELEASE_PATH+=-standalone
# Package managers may shim their own "node" wrapper into the PATH, so run
# node and ask it for its true path.
# We cannot find the path to node from $PATH because yarn shims a script to ensure
# we use the same version it's using so we instead run a script with yarn that
# will print the path to node.
local node_path
node_path="$(node -p process.execPath)"
node_path="$(yarn -s node <<<'console.info(process.execPath)')"
mkdir -p "$RELEASE_PATH/bin"
mkdir -p "$RELEASE_PATH/lib"
rsync ./ci/build/code-server.sh "$RELEASE_PATH/bin/code-server"
rsync "$node_path" "$RELEASE_PATH/lib/node"
chmod 755 "$RELEASE_PATH/lib/node"
ln -s "./bin/code-server" "$RELEASE_PATH/code-server"
ln -s "./lib/node" "$RELEASE_PATH/node"
pushd "$RELEASE_PATH"
npm install --unsafe-perm --omit=dev
# Code deletes some files from the extension node_modules directory which
# leaves broken symlinks in the corresponding .bin directory. nfpm will fail
# on these broken symlinks so clean them up.
rm -fr "./lib/vscode/extensions/node_modules/.bin"
popd
cd "$RELEASE_PATH"
yarn --production --frozen-lockfile
}
main "$@"

View File

@ -6,144 +6,15 @@ set -euo pipefail
# MINIFY controls whether a minified version of vscode is built.
MINIFY=${MINIFY-true}
delete-bin-script() {
rm -f "lib/vscode-reh-web-linux-x64/bin/$1"
}
copy-bin-script() {
local script="$1"
local dest="lib/vscode-reh-web-linux-x64/bin/$script"
cp "lib/vscode/resources/server/bin/$script" "$dest"
sed -i.bak "s/@@VERSION@@/$(vscode_version)/g" "$dest"
sed -i.bak "s/@@COMMIT@@/$BUILD_SOURCEVERSION/g" "$dest"
sed -i.bak "s/@@APPNAME@@/code-server/g" "$dest"
# Fix Node path on Darwin and Linux.
# We do not want expansion here; this text should make it to the file as-is.
# shellcheck disable=SC2016
sed -i.bak 's/^ROOT=\(.*\)$/VSROOT=\1\nROOT="$(dirname "$(dirname "$VSROOT")")"/g' "$dest"
sed -i.bak 's/ROOT\/out/VSROOT\/out/g' "$dest"
# We do not want expansion here; this text should make it to the file as-is.
# shellcheck disable=SC2016
sed -i.bak 's/$ROOT\/node/${NODE_EXEC_PATH:-$ROOT\/lib\/node}/g' "$dest"
# Fix Node path on Windows.
sed -i.bak 's/^set ROOT_DIR=\(.*\)$/set ROOT_DIR=%~dp0..\\..\\..\\..\r\nset VSROOT_DIR=\1/g' "$dest"
sed -i.bak 's/%ROOT_DIR%\\out/%VSROOT_DIR%\\out/g' "$dest"
chmod +x "$dest"
rm "$dest.bak"
}
main() {
cd "$(dirname "${0}")/../.."
cd lib/vscode
source ./ci/lib.sh
# Set the commit Code will embed into the product.json. We need to do this
# since Code tries to get the commit from the `.git` directory which will fail
# as it is a submodule.
#
# Also, we use code-server's commit rather than VS Code's otherwise it would
# not update when only our patch files change, and that will cause caching
# issues where the browser keeps using outdated code.
export BUILD_SOURCEVERSION
BUILD_SOURCEVERSION=$(git rev-parse HEAD)
pushd lib/vscode
if [[ ! ${VERSION-} ]]; then
echo "VERSION not set. Please set before running this script:"
echo "VERSION='0.0.0' npm run build:vscode"
exit 1
yarn gulp compile-build compile-extensions-build
yarn gulp optimize --gulpfile ./coder.js
if [[ $MINIFY ]]; then
yarn gulp minify --gulpfile ./coder.js
fi
# Add the date, our name, links, enable telemetry (this just makes telemetry
# available; telemetry can still be disabled by flag or setting), and
# configure trusted extensions (since some, like github.copilot-chat, never
# ask to be trusted and this is the only way to get auth working).
#
# This needs to be done before building as Code will read this file and embed
# it into the client-side code.
git checkout product.json # Reset in case the script exited early.
cp product.json product.original.json # Since jq has no inline edit.
jq --slurp '.[0] * .[1]' product.original.json <(
cat << EOF
{
"enableTelemetry": true,
"quality": "stable",
"codeServerVersion": "$VERSION",
"nameShort": "code-server",
"nameLong": "code-server",
"applicationName": "code-server",
"dataFolderName": ".code-server",
"win32MutexName": "codeserver",
"licenseUrl": "https://github.com/coder/code-server/blob/main/LICENSE",
"win32DirName": "code-server",
"win32NameVersion": "code-server",
"win32AppUserModelId": "coder.code-server",
"win32ShellNameShort": "c&ode-server",
"darwinBundleIdentifier": "com.coder.code.server",
"linuxIconName": "com.coder.code.server",
"reportIssueUrl": "https://github.com/coder/code-server/issues/new",
"documentationUrl": "https://go.microsoft.com/fwlink/?LinkID=533484#vscode",
"keyboardShortcutsUrlMac": "https://go.microsoft.com/fwlink/?linkid=832143",
"keyboardShortcutsUrlLinux": "https://go.microsoft.com/fwlink/?linkid=832144",
"keyboardShortcutsUrlWin": "https://go.microsoft.com/fwlink/?linkid=832145",
"introductoryVideosUrl": "https://go.microsoft.com/fwlink/?linkid=832146",
"tipsAndTricksUrl": "https://go.microsoft.com/fwlink/?linkid=852118",
"newsletterSignupUrl": "https://www.research.net/r/vsc-newsletter",
"linkProtectionTrustedDomains": [
"https://open-vsx.org"
],
"trustedExtensionAuthAccess": [
"vscode.git", "vscode.github",
"github.vscode-pull-request-github",
"github.copilot", "github.copilot-chat"
],
"aiConfig": {
"ariaKey": "code-server"
}
}
EOF
) > product.json
# Any platform here works since we will do our own packaging. We have to do
# this because we have an NPM package that could be installed on any platform.
# The correct platform dependencies and scripts will be installed as part of
# the post-install during `npm install` or when building a standalone release.
node --max-old-space-size=16384 --optimize-for-size \
./node_modules/gulp/bin/gulp.js \
"vscode-reh-web-linux-x64${MINIFY:+-min}"
# Reset so if you develop after building you will not be stuck with the wrong
# commit (the dev client will use `oss-dev` but the dev server will still use
# product.json which will have `stable-$commit`).
git checkout product.json
popd
pushd lib/vscode-reh-web-linux-x64
# Make sure Code took the version we set in the environment variable. Not
# having a version will break display languages.
if ! jq -e .commit product.json; then
echo "'commit' is missing from product.json"
exit 1
fi
popd
# These provide a `code-server` command in the integrated terminal to open
# files in the current instance.
delete-bin-script remote-cli/code-server
copy-bin-script remote-cli/code-darwin.sh
copy-bin-script remote-cli/code-linux.sh
copy-bin-script remote-cli/code.cmd
# These provide a way for terminal applications to open browser windows.
delete-bin-script helpers/browser.sh
copy-bin-script helpers/browser-darwin.sh
copy-bin-script helpers/browser-linux.sh
copy-bin-script helpers/browser.cmd
}
main "$@"

View File

@ -6,6 +6,10 @@ main() {
source ./ci/lib.sh
git clean -Xffd
pushd lib/vscode
git clean -xffd
popd
}
main "$@"

View File

@ -5,12 +5,20 @@ 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")"
while [ -L "$(basename "$script")" ]; do
if [ -L "./node" ] && [ -L "./code-server" ] \
&& [ -f "package.json" ] \
&& 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/cdr/code-server/releases/tag/v3.4.0" >&2
fi
script="$(readlink "$(basename "$script")")"
cd "$(dirname "$script")"
done

View File

@ -1,14 +1,14 @@
name: "code-server"
arch: "${NFPM_ARCH}"
arch: "${ARCH}"
platform: "linux"
version: "v${VERSION}"
section: "devel"
priority: "optional"
maintainer: "Joe Previte <joe@coder.com>"
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:
@ -22,4 +22,4 @@ contents:
dst: /usr/lib/systemd/user/code-server.service
- src: ./release-standalone/*
dst: /usr/lib/code-server
dst: /usr/lib/code-server/

View File

@ -1,160 +1,86 @@
#!/usr/bin/env sh
set -eu
# Copied from ../lib.sh except we do not rename Darwin and we do not need to
# detect Alpine.
os() {
osname=$(uname | tr '[:upper:]' '[:lower:]')
case $osname in
cygwin* | mingw*) osname="windows" ;;
esac
echo "$osname"
}
# Create a symlink at $2 pointing to $1 on any platform. Anything that
# currently exists at $2 will be deleted.
symlink() {
source="$1"
dest="$2"
rm -rf "$dest"
case $OS in
windows) mklink /J "$dest" "$source" ;;
*) ln -s "$source" "$dest" ;;
# Copied from arch() in ci/lib.sh.
detect_arch() {
case "$(uname -m)" in
aarch64)
echo arm64
;;
x86_64 | amd64)
echo amd64
;;
*)
# This will cause the download to fail, but is intentional
uname -m
;;
esac
}
# VS Code bundles some modules into an asar which is an archive format that
# works like tar. It then seems to get unpacked into node_modules.asar.
#
# I don't know why they do this but all the dependencies they bundle already
# exist in node_modules so just symlink it. We have to do this since not only
# Code itself but also extensions will look specifically in this directory for
# files (like the ripgrep binary or the oniguruma wasm).
symlink_asar() {
symlink node_modules node_modules.asar
}
# Make a symlink at bin/$1/$3 pointing to the platform-specific version of the
# script in $2. The extension of the link will be .cmd for Windows otherwise it
# will be whatever is in $4 (or no extension if $4 is not set).
symlink_bin_script() {
oldpwd="$(pwd)"
cd "bin/$1"
source="$2"
dest="$3"
ext="${4-}"
case $OS in
windows) symlink "$source.cmd" "$dest.cmd" ;;
darwin | macos) symlink "$source-darwin.sh" "$dest$ext" ;;
*) symlink "$source-linux.sh" "$dest$ext" ;;
esac
cd "$oldpwd"
}
command_exists() {
if [ ! "$1" ]; then return 1; fi
command -v "$@" > /dev/null
}
is_root() {
if command_exists id && [ "$(id -u)" = 0 ]; then
return 0
fi
return 1
}
OS="$(os)"
ARCH="${NPM_CONFIG_ARCH:-$(detect_arch)}"
main() {
# Grabs the major version of node from $npm_config_user_agent which looks like
# yarn/1.21.1 npm/? node/v14.2.0 darwin x64
major_node_version=$(echo "$npm_config_user_agent" | sed -n 's/.*node\/v\([^.]*\).*/\1/p')
if [ -n "${FORCE_NODE_VERSION:-}" ]; then
echo "WARNING: Overriding required Node.js version to v$FORCE_NODE_VERSION"
echo "This could lead to broken functionality, and is unsupported."
echo "USE AT YOUR OWN RISK!"
fi
if [ "$major_node_version" -ne "${FORCE_NODE_VERSION:-22}" ]; then
echo "ERROR: code-server currently requires node v22."
if [ -n "$FORCE_NODE_VERSION" ]; then
echo "However, you have overrided the version check to use v$FORCE_NODE_VERSION."
fi
if [ "$major_node_version" -lt 12 ]; then
echo "code-server currently requires at least node v12"
echo "We have detected that you are on node v$major_node_version"
echo "You can override this version check by setting \$FORCE_NODE_VERSION,"
echo "but configurations that do not use the same node version are unsupported."
echo "See https://github.com/cdr/code-server/issues/1633"
exit 1
fi
# Under npm, if we are running as root, we need --unsafe-perm otherwise
# post-install scripts will not have sufficient permissions to do their thing.
if is_root; then
case "${npm_config_user_agent-}" in npm*)
if [ "${npm_config_unsafe_perm-}" != "true" ]; then
echo "Please pass --unsafe-perm to npm to install code-server"
echo "Otherwise post-install scripts will not have permissions to run"
echo "See https://docs.npmjs.com/misc/config#unsafe-perm"
echo "See https://stackoverflow.com/questions/49084929/npm-sudo-global-installation-unsafe-perm"
exit 1
fi
;;
esac
fi
if ! vscode_install; then
echo "You may not have the required dependencies to build the native modules."
echo "Please see https://github.com/coder/code-server/blob/main/docs/npm.md"
exit 1
fi
if [ -n "${FORCE_NODE_VERSION:-}" ]; then
echo "WARNING: The required Node.js version was overriden to v$FORCE_NODE_VERSION"
echo "This could lead to broken functionality, and is unsupported."
echo "USE AT YOUR OWN RISK!"
fi
}
install_with_yarn_or_npm() {
echo "User agent: ${npm_config_user_agent-none}"
# For development we enforce npm, but for installing the package as an
# end-user we want to keep using whatever package manager is in use.
case "${npm_config_user_agent-}" in
npm*)
if ! npm install --unsafe-perm --omit=dev; then
return 1
fi
;;
yarn*)
if ! yarn --production --frozen-lockfile --no-default-rc; then
return 1
fi
;;
*)
echo "Could not determine which package manager is being used to install code-server"
case "${npm_config_user_agent-}" in npm*)
# We are running under npm.
if [ "${npm_config_unsafe_perm-}" != "true" ]; then
echo "Please pass --unsafe-perm to npm to install code-server"
echo "Otherwise the postinstall script does not have permissions to run"
echo "See https://docs.npmjs.com/misc/config#unsafe-perm"
echo "See https://stackoverflow.com/questions/49084929/npm-sudo-global-installation-unsafe-perm"
exit 1
;;
fi
;;
esac
return 0
OS="$(uname | tr '[:upper:]' '[:lower:]')"
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 ! vscode_yarn; then
echo "You may not have the required dependencies to build the native modules."
echo "Please see https://github.com/cdr/code-server/blob/master/docs/npm.md"
exit 1
fi
}
vscode_install() {
echo 'Installing Code dependencies...'
cd lib/vscode
if ! install_with_yarn_or_npm; then
return 1
# This is a copy of symlink_asar in ../lib.sh. Look there for details.
symlink_asar() {
rm -f node_modules.asar
if [ "${WINDIR-}" ]; then
mklink /J node_modules.asar node_modules
else
ln -s node_modules node_modules.asar
fi
}
vscode_yarn() {
cd lib/vscode
yarn --production --frozen-lockfile
symlink_asar
symlink_bin_script remote-cli code code-server
symlink_bin_script helpers browser browser .sh
cd extensions
if ! install_with_yarn_or_npm; then
return 1
fi
return 0
yarn --production --frozen-lockfile
for ext in */; do
ext="${ext%/}"
echo "extensions/$ext: installing dependencies"
cd "$ext"
yarn --production --frozen-lockfile
cd "$OLDPWD"
done
}
main "$@"

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail
# Downloads the release artifacts from CI for the current
# commit and then uploads them to the release with the version
# in package.json.
# You will need $GITHUB_TOKEN set.
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
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[@]}"
}
main "$@"

View File

@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail
# Creates a draft release with the template for the version in package.json
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
gh release create "v$VERSION" \
--notes-file - \
--target "$(git rev-parse HEAD)" \
--draft <<EOF
v$VERSION
VS Code v$(vscode_version)
Upgrading is as easy as installing the new version over the old one. code-server
maintains all user data in \`~/.local/share/code-server\` so that it is preserved in between
installations.
## New Features
⭐ Summarize new features here with references to issues
- item
## Bug Fixes
⭐ Summarize bug fixes here with references to issues
- item
## Documentation
⭐ Summarize doc changes here with references to issues
- item
## Development
⭐ Summarize development/testing changes here with references to issues
- item
Cheers! 🍻
EOF
}
main "$@"

103
ci/build/release-prep.sh Executable file
View File

@ -0,0 +1,103 @@
#!/usr/bin/env bash
# Description: This is a script to make the release process easier
# Run it with `yarn release:prep` and it will do the following:
# 1. Check that you have gh installed and that you're signed in
# 2. Update the version of code-server (package.json, docs, etc.)
# 3. Update the code coverage badge in the README
# 4. Open a draft PR using the release_template.md and view in browser
# If you want to perform a dry run of this script run DRY_RUN=1 yarn release:prep
set -euo pipefail
main() {
if [ "${DRY_RUN-}" = 1 ]; then
echo "Performing a dry run..."
CMD="echo"
else
CMD=''
fi
cd "$(dirname "$0")/../.."
# Check that gh is installed
if ! command -v gh &>/dev/null; then
echo "gh could not be found."
echo "We use this with the release-github-draft.sh and release-github-assets.sh scripts."
echo -e "See docs here: https://github.com/cli/cli#installation"
exit
fi
# Check that they have jq installed
if ! command -v jq &>/dev/null; then
echo "jq could not be found."
echo "We use this to parse the package.json and grab the current version of code-server."
echo -e "See docs here: https://stedolan.github.io/jq/download/"
exit
fi
# Check that they have rg installed
if ! command -v rg &>/dev/null; then
echo "rg could not be found."
echo "We use this when updating files across the codebase."
echo -e "See docs here: https://github.com/BurntSushi/ripgrep#installation"
exit
fi
# Check that they have node installed
if ! command -v node &>/dev/null; then
echo "node could not be found."
echo "That's surprising..."
echo "We use it in this script for getting the package.json version"
echo -e "See docs here: https://nodejs.org/en/download/"
exit
fi
# Check that gh is authenticated
if ! gh auth status -h github.com &>/dev/null; then
echo "gh isn't authenticated to github.com."
echo "This is needed for our scripts that use gh."
echo -e "See docs regarding authentication: https://cli.github.com/manual/gh_auth_login"
exit
fi
# Note: we need to set upstream as well or the gh pr create step will fail
# See: https://github.com/cli/cli/issues/575
CURRENT_BRANCH=$(git branch | grep '\*' | cut -d' ' -f2-)
if [[ -z $(git config "branch.${CURRENT_BRANCH}.remote") ]]; then
echo "Doesn't look like you've pushed this branch to remote"
# Note: we need to set upstream as well or the gh pr create step will fail
# See: https://github.com/cli/cli/issues/575
echo "Please set the upstream and then run the script"
exit 1
fi
# credit to jakwuh for this solution
# https://gist.github.com/DarrenN/8c6a5b969481725a4413#gistcomment-1971123
CODE_SERVER_CURRENT_VERSION=$(node -pe "require('./package.json').version")
# Ask which version we should update to
# In the future, we'll automate this and determine the latest version automatically
echo "Current version: ${CODE_SERVER_CURRENT_VERSION}"
# The $'\n' adds a line break. See: https://stackoverflow.com/a/39581815/3015595
read -r -p "What version of code-server do you want to update to?"$'\n' CODE_SERVER_VERSION_TO_UPDATE
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"
# Ensure the tests are passing and code coverage is up-to-date
echo -e "Running unit tests and updating code coverage...\n"
$CMD yarn test:unit
$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 @cdr/code-server-reviewers --repo cdr/code-server --draft
# Open PR in browser
$CMD gh pr view --web
}
main "$@"

View File

@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
# Makes sure the release works.
# This is to make sure we don't have Node version errors or any other
# compilation-related errors.
main() {
cd "$(dirname "${0}")/../.."
local EXTENSIONS_DIR
EXTENSIONS_DIR="$(mktemp -d)"
echo "Testing standalone release."
# Note: using a basic theme extension because it doesn't update often and is more reliable for testing
./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension wesbos.theme-cobalt2
local installed_extensions
installed_extensions="$(./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)"
# We use grep as wesbos.theme-cobalt2 may have dependency extensions that change.
if ! echo "$installed_extensions" | grep -q "wesbos.theme-cobalt2"; then
echo "Unexpected output from listing extensions:"
echo "$installed_extensions"
exit 1
fi
echo "Standalone release works correctly."
}
main "$@"

12
ci/dev/audit.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
# Prevents integration with moderate or higher vulnerabilities
# Docs: https://github.com/IBM/audit-ci#options
yarn audit-ci --moderate
}
main "$@"

View File

@ -3,7 +3,11 @@ set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
bats ./test/scripts
yarn fmt
yarn lint
yarn _audit
yarn test:unit
}
main "$@"

View File

@ -1,26 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
doctoc --title '# FAQ' docs/FAQ.md > /dev/null
doctoc --title '# Setup Guide' docs/guide.md > /dev/null
doctoc --title '# Install' docs/install.md > /dev/null
doctoc --title '# npm Install Requirements' docs/npm.md > /dev/null
doctoc --title '# Contributing' docs/CONTRIBUTING.md > /dev/null
doctoc --title '# Maintaining' docs/MAINTAINING.md > /dev/null
doctoc --title '# Contributor Covenant Code of Conduct' docs/CODE_OF_CONDUCT.md > /dev/null
doctoc --title '# iPad' docs/ipad.md > /dev/null
doctoc --title '# Termux' docs/termux.md > /dev/null
if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then
echo "Files need generation or are formatted incorrectly:"
git -c color.ui=always status | grep --color=no '\[31m'
echo "Please run the following locally:"
echo " npm run doctoc"
exit 1
fi
}
main "$@"

45
ci/dev/fmt.sh Executable file
View File

@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
local prettierExts
prettierExts=(
"*.js"
"*.ts"
"*.tsx"
"*.html"
"*.json"
"*.css"
"*.md"
"*.toml"
"*.yaml"
"*.yml"
"*.sh"
)
prettier --write --loglevel=warn $(
git ls-files "${prettierExts[@]}" | grep -v "lib/vscode" | grep -v 'helm-chart'
)
doctoc --title '# FAQ' docs/FAQ.md >/dev/null
doctoc --title '# Setup Guide' docs/guide.md >/dev/null
doctoc --title '# Install' docs/install.md >/dev/null
doctoc --title '# npm Install Requirements' docs/npm.md >/dev/null
doctoc --title '# Contributing' docs/CONTRIBUTING.md >/dev/null
doctoc --title '# Maintaining' docs/MAINTAINING.md >/dev/null
doctoc --title '# Contributor Covenant Code of Conduct' docs/CODE_OF_CONDUCT.md >/dev/null
doctoc --title '# iPad' docs/ipad.md >/dev/null
doctoc --title '# Termux' docs/termux.md >/dev/null
doctoc --title '# Changelog' CHANGELOG.md >/dev/null
if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then
echo "Files need generation or are formatted incorrectly:"
git -c color.ui=always status | grep --color=no '\[31m'
echo "Please run the following locally:"
echo " yarn fmt"
exit 1
fi
}
main "$@"

View File

@ -1,50 +1,44 @@
#!/bin/sh
set -eu
# Generate icons from a single favicon.svg. favicon.svg should have no fill
# colors set.
main() {
cd src/browser/media
# We need .ico for backwards compatibility. The other two are the only icon
# sizes required by Chrome and we use them for stuff like apple-touch-icon as
# well. https://web.dev/add-manifest/
# We need .ico for backwards compatibility.
# The other two are the only icon sizes required by Chrome and
# we use them for stuff like apple-touch-icon as well.
# https://web.dev/add-manifest/
#
# This should be enough and we can always add more if there are problems.
#
# -quiet to avoid https://github.com/ImageMagick/ImageMagick/issues/884
# -background defaults to white but we want it transparent.
# -density somehow makes the image both sharper and smaller in file size.
#
# https://imagemagick.org/script/command-line-options.php#background
convert -quiet -background transparent \
-resize 256x256 -density 256x256 \
favicon.svg favicon.ico
convert -quiet -background transparent -resize 256x256 favicon.svg favicon.ico
# We do not generate the pwa-icon from the favicon as they are slightly different
# designs and sizes.
# See favicon.afdesign and #2401 for details on the differences.
convert -quiet -background transparent -resize 192x192 pwa-icon.png pwa-icon-192.png
convert -quiet -background transparent -resize 512x512 pwa-icon.png pwa-icon-512.png
# Generate PWA icons. There should be enough padding to support masking.
convert -quiet -border 60x60 -bordercolor white -background white \
-resize 192x192 -density 192x192 \
favicon.svg pwa-icon-maskable-192.png
convert -quiet -border 160x160 -bordercolor white -background white \
-resize 512x512 -density 512x512 \
favicon.svg pwa-icon-maskable-512.png
# We use -quiet above to avoid https://github.com/ImageMagick/ImageMagick/issues/884
# Generate non-maskable PWA icons.
magick pwa-icon-maskable-192.png \
\( +clone -threshold 101% -fill white -draw "roundRectangle 0,0 %[fx:int(w)],%[fx:int(h)] 50,50" \) \
-channel-fx "| gray=>alpha" \
pwa-icon-192.png
magick pwa-icon-maskable-512.png \
\( +clone -threshold 101% -fill white -draw "roundRectangle 0,0 %[fx:int(w)],%[fx:int(h)] 100,100" \) \
-channel-fx "| gray=>alpha" \
pwa-icon-512.png
# The following adds dark mode support for the favicon as
# favicon-dark-support.svg There is no similar capability for pwas or .ico so
# we can only add support to the svg.
favicon_dark_style="<style>@media (prefers-color-scheme: dark) {* { fill: white; }}</style>"
cp favicon.svg favicon-dark-support.svg
sed "s%<path%$favicon_dark_style\n <path%" favicon.svg > favicon-dark-support.svg
# The following adds dark mode support for the favicon as favicon-dark-support.svg
# There is no similar capability for pwas or .ico so we can only add support to the svg.
favicon_dark_style="<style>
@media (prefers-color-scheme: dark) {
* {
fill: white;
}
}
</style>"
# See https://stackoverflow.com/a/22901380/4283659
# This escapes all newlines so that sed will accept them.
favicon_dark_style="$(printf "%s\n" "$favicon_dark_style" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g')"
sed "$(
cat -n <<EOF
s%<rect id="favicon"%$favicon_dark_style<rect id="favicon"%
EOF
)" favicon.svg >favicon-dark-support.svg
}
main "$@"

View File

@ -1,9 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files '*.sh' | grep -v 'lib/vscode')
}
main "$@"

21
ci/dev/lint.sh Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js" | grep -v "lib/vscode")
stylelint $(git ls-files "*.css" | grep -v "lib/vscode")
tsc --noEmit --skipLibCheck
shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh" | grep -v "lib/vscode")
if command -v helm && helm kubeval --help >/dev/null; then
helm kubeval ci/helm-chart
fi
cd lib/vscode
# Run this periodically in vanilla VS code to make sure we don't add any more warnings.
yarn -s eslint --max-warnings=3
cd "$OLDPWD"
}
main "$@"

View File

@ -1,38 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail
# Install dependencies in $1.
install-deps() {
local args=()
if [[ ${CI-} ]]; then
args+=(ci)
else
args+=(install)
fi
# If there is no package.json then npm will look upward and end up installing
# from the root resulting in an infinite loop (this can happen if you have not
# checked out the submodule yet for example).
if [[ ! -f "$1/package.json" ]]; then
echo "$1/package.json is missing; did you run git submodule update --init?"
exit 1
fi
pushd "$1"
echo "Installing dependencies for $PWD"
npm "${args[@]}"
popd
}
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
install-deps test
install-deps test/e2e/extensions/test-extension
# We don't need these when running the integration tests
# so you can pass SKIP_SUBMODULE_DEPS
if [[ ! ${SKIP_SUBMODULE_DEPS-} ]]; then
install-deps lib/vscode
fi
# This installs the dependencies needed for testing
cd test
yarn
cd ..
cd lib/vscode
yarn ${CI+--frozen-lockfile}
symlink_asar
}
main "$@"

View File

@ -1,3 +0,0 @@
if (process.env.npm_execpath.includes("yarn")) {
throw new Error("`yarn` is no longer supported; please use `npm install` instead")
}

View File

@ -1,50 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
help() {
echo >&2 " You can build with 'npm run watch' or you can build a release"
echo >&2 " For example: 'npm run build && npm run build:vscode && KEEP_MODULES=1 npm run release'"
echo >&2 " Then 'CODE_SERVER_TEST_ENTRY=./release npm run 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"
npm run build
popd
local dir="$PWD"
if [[ ! ${CODE_SERVER_TEST_ENTRY-} ]]; then
echo "Set CODE_SERVER_TEST_ENTRY to test another build of code-server"
else
pushd "$CODE_SERVER_TEST_ENTRY"
dir="$PWD"
popd
fi
echo "Testing build in '$dir'"
# Simple sanity checks to see that we've built. There could still be things
# wrong (native modules version issues, incomplete build, etc).
if [[ ! -d $dir/out ]]; then
echo >&2 "No code-server build detected"
help
exit 1
fi
if [[ ! -d $dir/lib/vscode/out ]]; then
echo >&2 "No VS Code build detected"
help
exit 1
fi
cd test
./node_modules/.bin/playwright test "$@"
# We set these environment variables because they're used in the e2e tests
# they don't have to be these values, but these are the defaults
PASSWORD=e45432jklfdsab CODE_SERVER_ADDRESS=http://localhost:8080 yarn folio --config=config.ts --reporter=list "$@"
}
main "$@"

View File

@ -1,39 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
help() {
echo >&2 " You can build the standalone release with 'npm run release:standalone'"
echo >&2 " Or you can pass in a custom path."
echo >&2 " CODE_SERVER_PATH='/var/tmp/coder/code-server/bin/code-server' npm run test:integration"
}
# Make sure a code-server release works. You can pass in the path otherwise it
# will look for release-standalone in the current directory.
#
# This is to make sure we don't have Node version errors or any other
# compilation-related errors.
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
local path="$RELEASE_PATH-standalone/bin/code-server"
if [[ ! ${CODE_SERVER_PATH-} ]]; then
echo "Set CODE_SERVER_PATH to test another build of code-server"
else
path="$CODE_SERVER_PATH"
fi
echo "Running tests with code-server binary: '$path'"
if [[ ! -f $path ]]; then
echo >&2 "No code-server build detected"
echo >&2 "Looked in $path"
help
exit 1
fi
CODE_SERVER_PATH="$path" ./test/node_modules/.bin/jest "$@" --coverage=false --testRegex "./test/integration" --testPathIgnorePatterns "./test/integration/fixtures"
}
main "$@"

View File

@ -1,39 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
help() {
echo >&2 " You can build the standalone release with 'npm run release:standalone'"
echo >&2 " Or you can pass in a custom path."
echo >&2 " CODE_SERVER_PATH='/var/tmp/coder/code-server/bin/code-server' npm run test:integration"
}
# Make sure a code-server release works. You can pass in the path otherwise it
# will look for release-standalone in the current directory.
#
# This is to make sure we don't have Node version errors or any other
# compilation-related errors.
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
local path="$RELEASE_PATH-standalone/bin/code-server"
if [[ ! ${CODE_SERVER_PATH-} ]]; then
echo "Set CODE_SERVER_PATH to test another build of code-server"
else
path="$CODE_SERVER_PATH"
fi
echo "Running tests with code-server binary: '$path'"
if [[ ! -f $path ]]; then
echo >&2 "No code-server build detected"
echo >&2 "Looked in $path"
help
exit 1
fi
CODE_SERVER_PATH="$path" ./test/node_modules/.bin/jest "$@" --coverage=false --testRegex "./test/integration/help.test.ts"
}
main "$@"

View File

@ -3,13 +3,13 @@ set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
cd test/unit/test-plugin
make -s out/index.js
# 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.
./test/node_modules/.bin/jest "$@" --testRegex "./test/unit/.*ts"
cd "$OLDPWD"
CS_DISABLE_PLUGINS=true ./test/node_modules/.bin/jest "$@"
}
main "$@"

133
ci/dev/update-vscode.sh Executable file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env bash
# Description: This is a script to make the process of updating vscode versions easier
# Run it with `yarn update:vscode` and it will do the following:
# 1. Check that you have a remote called `vscode`
# 2. Ask you which version you want to upgrade to
# 3. Grab the exact version from the package.json i.e. 1.53.2
# 4. Fetch the vscode remote branches to run the subtree update
# 5. Run the subtree update and pull in the vscode update
# 6. Commit the changes (including merge conflicts)
# 7. Open a draft PR
set -euo pipefail
# This function expects two arguments
# 1. the vscode version we're updating to
# 2. the list of merge conflict files
make_pr_body() {
local BODY="This PR updates vscode to $1
## TODOS
- [ ] test editor locally
- [ ] test terminal locally
- [ ] make notes about any significant changes in docs/CONTRIBUTING.md#notes-about-changes
## Files with conflicts (fix these)
$2"
echo "$BODY"
}
main() {
cd "$(dirname "$0")/../.."
# Check if the remote exists
# if it doesn't, we add it
if ! git config remote.vscode.url >/dev/null; then
echo "Could not find 'vscode' as a remote"
echo "Adding with: git remote add vscode https://github.com/microsoft/vscode.git"
git remote add vscode https://github.com/microsoft/vscode.git
fi
# Ask which version we should update to
# In the future, we'll automate this and grab the latest version automatically
read -r -p "What version of VSCode would you like to update to? (i.e. 1.52) " VSCODE_VERSION_TO_UPDATE
# Check that this version exists
if [[ -z $(git ls-remote --heads vscode release/"$VSCODE_VERSION_TO_UPDATE") ]]; then
echo "Oops, that doesn't look like a valid version."
echo "You entered: $VSCODE_VERSION_TO_UPDATE"
echo "Verify that this branches exists here: https://github.com/microsoft/vscode/branches/all?query=release%2F$VSCODE_VERSION_TO_UPDATE"
exit 1
fi
# Check that they have jq installed
if ! command -v jq &>/dev/null; then
echo "jq could not be found."
echo "We use this when looking up the exact version to update to in the package.json in VS Code."
echo -e "See docs here: https://stedolan.github.io/jq/download/"
exit 1
fi
# Note: `git subtree` returns 129 when installed, and prints help;
# but when uninstalled, returns 1.
set +e
git subtree &>/dev/null
if [ $? -ne 129 ]; then
echo "git-subtree could not be found."
echo "We use this to fetch and update the lib/vscode subtree."
echo -e "Please install git subtree."
exit 1
fi
set -e
# Grab the exact version from package.json
VSCODE_EXACT_VERSION=$(curl -s "https://raw.githubusercontent.com/microsoft/vscode/release/$VSCODE_VERSION_TO_UPDATE/package.json" | jq -r ".version")
echo -e "Great! We'll prep a PR for updating to $VSCODE_EXACT_VERSION\n"
# For some reason the subtree update doesn't work
# unless we fetch all the branches
echo -e "Fetching vscode branches..."
echo -e "Note: this might take a while"
git fetch vscode
# Check if GitHub CLI is installed
if ! command -v gh &>/dev/null; then
echo "GitHub CLI could not be found."
echo "If you install it before you run this script next time, we'll open a draft PR for you!"
echo -e "See docs here: https://github.com/cli/cli#installation\n"
exit
fi
# Push branch to remote if not already pushed
# If we don't do this, the opening a draft PR step won't work
# because it will stop and ask where you want to push the branch
CURRENT_BRANCH=$(git branch | grep '\*' | cut -d' ' -f2-)
if [[ -z $(git config "branch.${CURRENT_BRANCH}.remote") ]]; then
echo "Doesn't look like you've pushed this branch to remote"
echo -e "Pushing now using: git push origin $CURRENT_BRANCH\n"
# Note: we need to set upstream as well or the gh pr create step will fail
# See: https://github.com/cli/cli/issues/575
echo "Please set the upstream and re-run the script"
exit 1
fi
echo "Going to try to update vscode for you..."
echo -e "Running: git subtree pull --prefix lib/vscode vscode release/${VSCODE_VERSION_TO_UPDATE} --squash\n"
# Try to run subtree update command
# Note: we add `|| true` because we want the script to keep running even if the squash fails
# We know the squash fails everytime because there will always be merge conflicts
git subtree pull --prefix lib/vscode vscode release/"${VSCODE_VERSION_TO_UPDATE}" --squash || true
# Get the files with conflicts before we commit them
# so we can list them in the PR body as todo items
CONFLICTS=$(git diff --name-only --diff-filter=U | while read -r line; do echo "- [ ] $line"; done)
PR_BODY=$(make_pr_body "$VSCODE_EXACT_VERSION" "$CONFLICTS")
echo -e "\nForcing a commit with conflicts"
echo "Note: this is intentional"
echo "If we don't do this, code review is impossible."
echo -e "For more info, see docs: docs/CONTRIBUTING.md#updating-vs-code\n"
# We need --no-verify to skip the husky pre-commit hook
# which fails because of the merge conflicts
git add . && git commit -am "chore(vscode): update to $VSCODE_EXACT_VERSION" --no-verify
# Note: we can't open a draft PR unless their are changes.
# Hence why we do this after the subtree update.
echo "Opening a draft PR on GitHub"
# To read about these flags, visit the docs: https://cli.github.com/manual/gh_pr_create
gh pr create --base main --title "feat(vscode): update to version $VSCODE_EXACT_VERSION" --body "$PR_BODY" --reviewer @cdr/code-server-reviewers --repo cdr/code-server --draft
}
main "$@"

View File

@ -1,143 +1,194 @@
import { spawn, ChildProcess } from "child_process"
import * as cp from "child_process"
import Bundler from "parcel-bundler"
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, "lib/vscode"),
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 = spawn("node", [path.join(this.rootPath, "out/node/entry.js"), ...args])
onLine(this.webServer, (line) => console.log("[code-server]", line))
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("npm", ["run", "watch"], { cwd: this.paths.vscodeDir }),
vscodeWebExtensions: spawn("npm", ["run", "watch-web"], { cwd: this.paths.vscodeDir }),
plugins: this.paths.pluginDir
? spawn("npm", ["run", "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("[Code OSS]", originalLine)
if (strippedLine.includes("Finished compilation with")) {
console.log("[Code OSS] ✨ 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
}
async function main(): Promise<void> {
try {
const watcher = new Watcher()
await watcher.initialize()
} catch (error: any) {
await watcher.watch()
} catch (error) {
console.error(error.message)
process.exit(1)
}
}
class Watcher {
private readonly rootPath = path.resolve(__dirname, "../..")
private readonly vscodeSourcePath = path.join(this.rootPath, "lib/vscode")
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 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 bundler = this.createBundler()
const cleanup = (code?: number | null): void => {
Watcher.log("killing vs code watcher")
vscode.removeAllListeners()
vscode.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 bundler")
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)
})
tsc.on("exit", (code) => {
Watcher.log("tsc terminated unexpectedly")
cleanup(code)
})
if (plugin) {
plugin.on("exit", (code) => {
Watcher.log("plugin terminated unexpectedly")
cleanup(code)
})
}
const bundle = bundler.bundle().catch(() => {
Watcher.log("parcel watcher terminated unexpectedly")
cleanup(1)
})
bundler.on("buildEnd", () => {
console.log("[parcel] bundled")
})
bundler.on("buildError", (error) => {
console.error("[parcel]", error)
})
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))
}
// From https://github.com/chalk/ansi-regex
const pattern = [
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
].join("|")
const re = new RegExp(pattern, "g")
/**
* Split stdout on newlines and strip ANSI codes.
*/
const onLine = (proc: cp.ChildProcess, callback: (strippedLine: string, originalLine: string) => void): void => {
let buffer = ""
if (!proc.stdout) {
throw new Error("no stdout")
}
proc.stdout.setEncoding("utf8")
proc.stdout.on("data", (d) => {
const data = buffer + d
const split = data.split("\n")
const last = split.length - 1
for (let i = 0; i < last; ++i) {
callback(split[i].replace(re, ""), split[i])
}
// The last item will either be an empty string (the data ended with a
// newline) or a partial line (did not end with a newline) and we must
// wait to parse it until we get a full line.
buffer = split[last]
})
}
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) {
bundle.then(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")) {
bundle.then(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")) {
bundle.then(restartServer)
}
})
}
}
private createBundler(out = "dist"): Bundler {
return new Bundler(
[
path.join(this.rootPath, "src/browser/register.ts"),
path.join(this.rootPath, "src/browser/serviceWorker.ts"),
path.join(this.rootPath, "src/browser/pages/login.ts"),
path.join(this.rootPath, "src/browser/pages/vscode.ts"),
],
{
outDir: path.join(this.rootPath, out),
cacheDir: path.join(this.rootPath, ".cache"),
minify: !!process.env.MINIFY,
logLevel: 1,
publicUrl: ".",
},
)
}
}
main()

View File

@ -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: 3.32.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.108.0
appVersion: 3.10.1

117
ci/helm-chart/README.md Normal file
View File

@ -0,0 +1,117 @@
# code-server
![Version: 1.0.0](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) ![AppVersion: 3.10.1](https://img.shields.io/badge/AppVersion-3.10.1-informational?style=flat-square)
[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)
## TL;DR;
```console
$ git clone https://github.com/cdr/code-server
$ cd code-server
$ helm upgrade --install code-server ci/helm-chart
```
## Introduction
This chart bootstraps a code-server deployment on a
[Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh)
package manager.
## Prerequisites
- Kubernetes 1.6+
## Installing the Chart
To install the chart with the release name `code-server`:
```console
$ git clone https://github.com/cdr/code-server
$ cd code-server
$ helm upgrade --install code-server ci/helm-chart
```
The command deploys code-server on the Kubernetes cluster in the default
configuration. The [configuration](#configuration) section lists the parameters
that can be configured during installation.
> **Tip**: List all releases using `helm list`
## Uninstalling the Chart
To uninstall/delete the `code-server` deployment:
```console
$ helm delete code-server
```
The command removes all the Kubernetes components associated with the chart and
deletes the release.
## Configuration
The following table lists the configurable parameters of the code-server chart
and their default values.
## Values
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| affinity | object | `{}` | |
| extraArgs | list | `[]` | |
| extraConfigmapMounts | list | `[]` | |
| extraContainers | string | `""` | |
| extraSecretMounts | list | `[]` | |
| extraVars | list | `[]` | |
| extraVolumeMounts | list | `[]` | |
| fullnameOverride | string | `""` | |
| hostnameOverride | string | `""` | |
| image.pullPolicy | string | `"Always"` | |
| image.repository | string | `"codercom/code-server"` | |
| image.tag | string | `"3.10.1"` | |
| imagePullSecrets | list | `[]` | |
| ingress.enabled | bool | `false` | |
| nameOverride | string | `""` | |
| nodeSelector | object | `{}` | |
| persistence.accessMode | string | `"ReadWriteOnce"` | |
| persistence.annotations | object | `{}` | |
| persistence.enabled | bool | `true` | |
| persistence.size | string | `"1Gi"` | |
| podAnnotations | object | `{}` | |
| podSecurityContext | object | `{}` | |
| replicaCount | int | `1` | |
| resources | object | `{}` | |
| securityContext.enabled | bool | `true` | |
| securityContext.fsGroup | int | `1000` | |
| securityContext.runAsUser | int | `1000` | |
| service.port | int | `8443` | |
| service.type | string | `"ClusterIP"` | |
| serviceAccount.create | bool | `true` | |
| serviceAccount.name | string | `nil` | |
| tolerations | list | `[]` | |
| volumePermissions.enabled | bool | `true` | |
| volumePermissions.securityContext.runAsUser | int | `0` | |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm
install`. For example,
```console
$ helm upgrade --install code-server \
ci/helm-chart \
--set persistence.enabled=false
```
The above command sets the the persistence storage to false.
Alternatively, a YAML file that specifies the values for the above parameters
can be provided while installing the chart. For example,
```console
$ helm upgrade --install code-server ci/helm-chart -f values.yaml
```
> **Tip**: You can use the default [values.yaml](values.yaml)

View File

@ -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:

View File

@ -3,39 +3,33 @@ kind: Deployment
metadata:
name: {{ include "code-server.fullname" . }}
labels:
{{- include "code-server.labels" . | nindent 4 }}
{{- if .Values.annotations }}
annotations: {{- toYaml .Values.annotations | nindent 4 }}
{{- end }}
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount | default 1 }}
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
{{- include "code-server.selectorLabels" . | nindent 6 }}
app.kubernetes.io/name: {{ include "code-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
{{- include "code-server.selectorLabels" . | nindent 8 }}
{{- if .Values.podAnnotations }}
annotations: {{- toYaml .Values.podAnnotations | nindent 8 }}
{{- end }}
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 }}
{{- if .Values.priorityClassName }}
priorityClassName: {{ .Values.priorityClassName }}
{{- end }}
{{- if .Values.securityContext.enabled }}
securityContext:
fsGroup: {{ .Values.securityContext.fsGroup }}
{{- end }}
{{- if or (and .Values.volumePermissions.enabled .Values.persistence.enabled) .Values.extraInitContainers }}
initContainers:
{{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }}
initContainers:
- name: init-chmod-data
image: busybox:latest
imagePullPolicy: IfNotPresent
@ -50,13 +44,9 @@ spec:
- name: data
mountPath: /home/coder
{{- end }}
{{- if .Values.extraInitContainers }}
{{ tpl .Values.extraInitContainers . | indent 6}}
{{- end }}
{{- end }}
containers:
{{- if .Values.extraContainers }}
{{ tpl .Values.extraContainers . | indent 8}}
{{ toYaml .Values.extraContainers | indent 8}}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
@ -65,17 +55,6 @@ spec:
securityContext:
runAsUser: {{ .Values.securityContext.runAsUser }}
{{- end }}
{{- if .Values.lifecycle.enabled }}
lifecycle:
{{- if .Values.lifecycle.postStart }}
postStart:
{{ toYaml .Values.lifecycle.postStart | nindent 14 }}
{{- end }}
{{- if .Values.lifecycle.preStop }}
preStop:
{{ toYaml .Values.lifecycle.preStop | nindent 14 }}
{{- end }}
{{- end }}
env:
{{- if .Values.extraVars }}
{{ toYaml .Values.extraVars | indent 10 }}
@ -105,7 +84,6 @@ spec:
{{- range .Values.extraSecretMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- range .Values.extraVolumeMounts }}
@ -118,18 +96,13 @@ spec:
- name: http
containerPort: 8080
protocol: TCP
{{- range .Values.extraPorts }}
- name: {{ .name }}
containerPort: {{ .port }}
protocol: {{ .protocol }}
{{- end }}
livenessProbe:
httpGet:
path: /healthz
path: /
port: http
readinessProbe:
httpGet:
path: /healthz
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
@ -139,7 +112,7 @@ spec:
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- tpl . $ | nindent 8 }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
@ -166,23 +139,14 @@ spec:
secretName: {{ .secretName }}
defaultMode: {{ .defaultMode }}
{{- end }}
{{- range .Values.extraConfigmapMounts }}
- name: {{ .name }}
configMap:
name: {{ .configMap }}
defaultMode: {{ .defaultMode }}
{{- end }}
{{- range .Values.extraVolumeMounts }}
- name: {{ .name }}
{{- if .existingClaim }}
persistentVolumeClaim:
claimName: {{ .existingClaim }}
{{- else if .hostPath }}
{{- else }}
hostPath:
path: {{ .hostPath }}
type: Directory
{{- else }}
emptyDir:
{{- toYaml .emptyDir | nindent 10 }}
{{- end }}
{{- end }}

View File

@ -1,9 +1,7 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "code-server.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
@ -18,9 +16,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 }}
@ -32,22 +27,6 @@ spec:
{{- end }}
{{- end }}
rules:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion -}}
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ . }}
pathType: Prefix
backend:
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- end }}
{{- end }}
{{- else -}}
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
@ -60,4 +39,3 @@ spec:
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -9,7 +9,10 @@ metadata:
{{ toYaml . | indent 4 }}
{{- end }}
labels:
{{- include "code-server.labels" . | nindent 4 }}
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}

View File

@ -1,4 +1,3 @@
{{- if not .Values.existingSecret }}
apiVersion: v1
kind: Secret
metadata:
@ -6,12 +5,14 @@ metadata:
annotations:
"helm.sh/hook": "pre-install"
labels:
{{- include "code-server.labels" . | nindent 4 }}
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
type: Opaque
data:
{{- if .Values.password }}
{{ if .Values.password }}
password: "{{ .Values.password | b64enc }}"
{{- else }}
{{ else }}
password: "{{ randAlphaNum 24 | b64enc }}"
{{- end }}
{{- end }}
{{ end }}

View File

@ -3,7 +3,10 @@ kind: Service
metadata:
name: {{ include "code-server.fullname" . }}
labels:
{{- include "code-server.labels" . | nindent 4 }}
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
@ -11,12 +14,6 @@ spec:
targetPort: http
protocol: TCP
name: http
{{- range .Values.extraPorts }}
- port: {{ .port }}
targetPort: {{ .port }}
protocol: {{ .protocol }}
name: {{ .name }}
{{- end }}
selector:
app.kubernetes.io/name: {{ include "code-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}

View File

@ -3,6 +3,9 @@ apiVersion: v1
kind: ServiceAccount
metadata:
labels:
{{- include "code-server.labels" . | nindent 4 }}
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
name: {{ template "code-server.serviceAccountName" . }}
{{- end -}}

View File

@ -3,13 +3,16 @@ kind: Pod
metadata:
name: "{{ include "code-server.fullname" . }}-test-connection"
labels:
{{- include "code-server.labels" . | nindent 4 }}
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
annotations:
"helm.sh/hook": test
"helm.sh/hook": test-success
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "code-server.fullname" . }}:{{ .Values.service.port }}/healthz']
args: ['{{ include "code-server.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

View File

@ -6,22 +6,14 @@ replicaCount: 1
image:
repository: codercom/code-server
tag: '4.108.0'
tag: '3.10.1'
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: ""
# The existing secret to use for code-server authentication in the frontend. the password is stored in the secret under the key `password`
# existingSecret: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
@ -31,15 +23,18 @@ serviceAccount:
# If not set and create is true, a name is generated using the fullname template
name: ""
# Specifies annotations for deployment
annotations: {}
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
priorityClassName: ""
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
@ -48,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:
@ -61,26 +57,13 @@ ingress:
# Optional additional arguments
extraArgs: []
# These are the arguments normally passed to code-server; run
# code-server --help for a list of available options.
#
# Each argument and parameter must have its own entry; if you use
# --param value on the command line, then enter it here as:
#
# - --param
# - value
#
# If you receive an error like "Unknown option --param value", it may be
# because both the parameter and value are specified as a single argument,
# rather than two separate arguments (e.g. "- --param value" on a line).
# - --allow-http
# - --no-auth
# Optional additional environment variables
extraVars: []
# - name: DISABLE_TELEMETRY
# value: "true"
# if dind is desired:
# - name: DOCKER_HOST
# value: "tcp://localhost:2376"
# value: true
##
## Init containers parameters:
@ -134,73 +117,33 @@ persistence:
# existingClaim: ""
# hostPath: /data
lifecycle:
enabled: false
# postStart:
# exec:
# command:
# - /bin/bash
# - -c
# - curl -s -L SOME_SCRIPT | bash
# for dind, the following may be helpful
# postStart:
# exec:
# command:
# - /bin/sh
# - -c
# - |
# sudo apt-get update \
# && sudo apt-get install -y docker.io
serviceAccount:
create: true
name:
## Enable an Specify container in extraContainers.
## This is meant to allow adding code-server dependencies, like docker-dind.
extraContainers: |
# If docker-dind is used, DOCKER_HOST env is mandatory to set in "extraVars"
# - name: docker-dind
# image: docker:28.3.2-dind
# imagePullPolicy: IfNotPresent
# resources:
# requests:
# cpu: 1
# ephemeral-storage: "50Gi"
# memory: 10Gi
# securityContext:
# privileged: true
# procMount: Default
# env:
# - name: DOCKER_TLS_CERTDIR
# value: "" # disable TLS setup
# command:
# - dockerd
# - --host=unix:///var/run/docker.sock
# - --host=tcp://0.0.0.0:2376
extraInitContainers: |
# - name: customization
# image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
# imagePullPolicy: IfNotPresent
# env:
# - name: SERVICE_URL
# value: https://open-vsx.org/vscode/gallery
# - name: ITEM_URL
# value: https://open-vsx.org/vscode/item
# command:
# - sh
# - -c
# - |
# code-server --install-extension ms-python.python
# code-server --install-extension golang.Go
# volumeMounts:
# - name: data
# mountPath: /home/coder
#- name: docker-dind
# image: docker:19.03-dind
# imagePullPolicy: IfNotPresent
# resources:
# requests:
# cpu: 250m
# memory: 256M
# securityContext:
# privileged: true
# procMount: Default
# env:
# - name: DOCKER_TLS_CERTDIR
# value: ""
# - name: DOCKER_DRIVER
# value: "overlay2"
## Additional code-server secret mounts
extraSecretMounts: []
# - name: secret-files
# mountPath: /etc/secrets
# subPath: private.key # (optional)
# secretName: code-server-secret-files
# readOnly: true
@ -211,7 +154,6 @@ extraVolumeMounts: []
# readOnly: true
# existingClaim: volume-claim
# hostPath: ""
# emptyDir: {}
extraConfigmapMounts: []
# - name: certs-configmap
@ -219,8 +161,3 @@ extraConfigmapMounts: []
# subPath: certificates.crt # (optional)
# configMap: certs-configmap
# readOnly: true
extraPorts: []
# - name: minecraft
# port: 25565
# protocol: tcp

114
ci/lib.sh
View File

@ -2,11 +2,15 @@
set -euo pipefail
pushd() {
builtin pushd "$@" > /dev/null
builtin pushd "$@" >/dev/null
}
popd() {
builtin popd > /dev/null
builtin popd >/dev/null
}
pkg_json_version() {
jq -r .version package.json
}
vscode_version() {
@ -14,36 +18,84 @@ vscode_version() {
}
os() {
osname=$(uname | tr '[:upper:]' '[:lower:]')
case $osname in
linux)
# Alpine's ldd doesn't have a version flag but if you use an invalid flag
# (like --version) it outputs the version to stderr and exits with 1.
# TODO: Better to check /etc/os-release; see ../install.sh.
ldd_output=$(ldd --version 2>&1 || true)
if echo "$ldd_output" | grep -iq musl; then
osname="alpine"
fi
;;
darwin) osname="macos" ;;
cygwin* | mingw*) osname="windows" ;;
esac
echo "$osname"
local os
os=$(uname | tr '[:upper:]' '[:lower:]')
if [[ $os == "linux" ]]; then
# Alpine's ldd doesn't have a version flag but if you use an invalid flag
# (like --version) it outputs the version to stderr and exits with 1.
local ldd_output
ldd_output=$(ldd --version 2>&1 || true)
if echo "$ldd_output" | grep -iq musl; then
os="alpine"
fi
elif [[ $os == "darwin" ]]; then
os="macos"
fi
echo "$os"
}
arch() {
cpu="$(uname -m)"
case "$cpu" in
aarch64) cpu=arm64 ;;
x86_64) cpu=amd64 ;;
case "$(uname -m)" in
aarch64)
echo arm64
;;
x86_64 | amd64)
echo amd64
;;
*)
echo "unknown architecture $(uname -a)"
exit 1
;;
esac
echo "$cpu"
}
# Grabs the most recent ci.yaml github workflow run that was triggered from the
# pull request of the release branch for this version (regardless of whether
# that run succeeded or failed). The release branch name must be in semver
# format with a v prepended.
# This will contain the artifacts we want.
# https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs
get_artifacts_url() {
local artifacts_url
local workflow_runs_url="repos/:owner/:repo/actions/workflows/ci.yaml/runs?event=pull_request"
local version_branch="v$VERSION"
artifacts_url=$(gh api "$workflow_runs_url" | jq -r ".workflow_runs[] | select(.head_branch == \"$version_branch\") | .artifacts_url" | head -n 1)
if [[ -z "$artifacts_url" ]]; then
echo >&2 "ERROR: artifacts_url came back empty"
echo >&2 "We looked for a successful run triggered by a pull_request with for code-server version: $code_server_version and a branch named $version_branch"
echo >&2 "URL used for gh API call: $workflow_runs_url"
exit 1
fi
echo "$artifacts_url"
}
# Grabs the artifact's download url.
# https://developer.github.com/v3/actions/artifacts/#list-workflow-run-artifacts
get_artifact_url() {
local artifact_name="$1"
gh api "$(get_artifacts_url)" | jq -r ".artifacts[] | select(.name == \"$artifact_name\") | .archive_download_url" | head -n 1
}
# Uses the above two functions to download a artifact into a directory.
download_artifact() {
local artifact_name="$1"
local dst="$2"
local tmp_file
tmp_file="$(mktemp)"
gh api "$(get_artifact_url "$artifact_name")" >"$tmp_file"
unzip -q -o "$tmp_file" -d "$dst"
rm "$tmp_file"
}
rsync() {
command rsync -a --del "$@"
}
VERSION="$(pkg_json_version)"
export VERSION
ARCH="$(arch)"
export ARCH
OS=$(os)
@ -52,3 +104,21 @@ export OS
# RELEASE_PATH is the destination directory for the release from the root.
# Defaults to release
RELEASE_PATH="${RELEASE_PATH-release}"
# VS Code bundles some modules into an asar which is an archive format that
# works like tar. It then seems to get unpacked into node_modules.asar.
#
# I don't know why they do this but all the dependencies they bundle already
# exist in node_modules so just symlink it. We have to do this since not only VS
# Code itself but also extensions will look specifically in this directory for
# files (like the ripgrep binary or the oniguruma wasm).
symlink_asar() {
rm -f node_modules.asar
if [ "${WINDIR-}" ]; then
# mklink takes the link name first.
mklink /J node_modules.asar node_modules
else
# ln takes the link name second.
ln -s node_modules node_modules.asar
fi
}

View File

@ -1,29 +1,20 @@
# syntax=docker/dockerfile:experimental
ARG BASE=debian:12
FROM scratch AS packages
COPY release-packages/code-server*.deb /tmp/
FROM $BASE
FROM debian:10
RUN apt-get update \
&& apt-get install -y \
&& apt-get install -y \
curl \
dumb-init \
git \
git-lfs \
zsh \
htop \
locales \
lsb-release \
man-db \
man \
nano \
openssh-client \
git \
procps \
openssh-client \
sudo \
vim-tiny \
wget \
zsh \
&& git lfs install \
vim.tiny \
lsb-release \
&& rm -rf /var/lib/apt/lists/*
# https://wiki.debian.org/Locale#Manually
@ -31,25 +22,19 @@ RUN sed -i "s/# en_US.UTF-8/en_US.UTF-8/" /etc/locale.gen \
&& locale-gen
ENV LANG=en_US.UTF-8
RUN if grep -q 1000 /etc/passwd; then \
userdel -r "$(id -un 1000)"; \
fi \
&& adduser --gecos '' --disabled-password coder \
&& echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
RUN adduser --gecos '' --disabled-password coder && \
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
RUN ARCH="$(dpkg --print-architecture)" \
&& curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
&& chown root:root /usr/local/bin/fixuid \
&& chmod 4755 /usr/local/bin/fixuid \
&& mkdir -p /etc/fixuid \
&& printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
RUN ARCH="$(dpkg --print-architecture)" && \
curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.5/fixuid-0.5-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - && \
chown root:root /usr/local/bin/fixuid && \
chmod 4755 /usr/local/bin/fixuid && \
mkdir -p /etc/fixuid && \
printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
COPY release-packages/code-server*.deb /tmp/
COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh
RUN --mount=from=packages,src=/tmp,dst=/tmp/packages dpkg -i /tmp/packages/code-server*$(dpkg --print-architecture).deb
# Allow users to have scripts run on container startup to prepare workspace.
# https://github.com/coder/code-server/issues/5177
ENV ENTRYPOINTD=${HOME}/entrypoint.d
RUN dpkg -i /tmp/code-server*$(dpkg --print-architecture).deb && rm /tmp/code-server*.deb
EXPOSE 8080
# This way, if someone sets $DOCKER_USER, docker-exec will still work as

View File

@ -1,51 +0,0 @@
# syntax=docker/dockerfile:experimental
ARG BASE=fedora:39
FROM scratch AS packages
COPY release-packages/code-server*.rpm /tmp/
FROM $BASE
RUN dnf update -y \
&& dnf install -y \
curl \
git \
git-lfs \
htop \
nano \
openssh-clients \
procps \
wget \
zsh \
dumb-init \
glibc-langpack-en \
&& rm -rf /var/cache/dnf
RUN git lfs install
ENV LANG=en_US.UTF-8
RUN echo 'LANG="en_US.UTF-8"' > /etc/locale.conf
RUN useradd -u 1000 coder && echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g')" \
&& curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
&& chown root:root /usr/local/bin/fixuid \
&& chmod 4755 /usr/local/bin/fixuid \
&& mkdir -p /etc/fixuid \
&& printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh
RUN --mount=from=packages,src=/tmp,dst=/tmp/packages rpm -i /tmp/packages/code-server*$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g').rpm
# Allow users to have scripts run on container startup to prepare workspace.
# https://github.com/coder/code-server/issues/5177
ENV ENTRYPOINTD=${HOME}/entrypoint.d
EXPOSE 8080
# This way, if someone sets $DOCKER_USER, docker-exec will still work as
# the uid will remain the same. note: only relevant if -u isn't passed to
# docker-run.
USER 1000
ENV USER=coder
WORKDIR /home/coder
ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "."]

View File

@ -1,51 +0,0 @@
# syntax=docker/dockerfile:experimental
ARG BASE=opensuse/tumbleweed
FROM scratch AS packages
COPY release-packages/code-server*.rpm /tmp/
FROM $BASE
RUN zypper dup -y \
&& zypper in -y \
curl \
git \
git-lfs \
htop \
nano \
openssh-clients \
procps \
wget \
zsh \
sudo \
catatonit \
&& rm -rf /var/cache/zypp /var/cache/zypper
RUN git lfs install
ENV LANG=en_US.UTF-8
RUN echo 'LANG="en_US.UTF-8"' > /etc/locale.conf
RUN useradd -u 1000 coder && echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g')" \
&& curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
&& chown root:root /usr/local/bin/fixuid \
&& chmod 4755 /usr/local/bin/fixuid \
&& mkdir -p /etc/fixuid \
&& printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
COPY ci/release-image/entrypoint-catatonit.sh /usr/bin/entrypoint-catatonit.sh
RUN --mount=from=packages,src=/tmp,dst=/tmp/packages rpm -i /tmp/packages/code-server*$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g').rpm
# Allow users to have scripts run on container startup to prepare workspace.
# https://github.com/coder/code-server/issues/5177
ENV ENTRYPOINTD=${HOME}/entrypoint.d
EXPOSE 8080
# This way, if someone sets $DOCKER_USER, docker-exec will still work as
# the uid will remain the same. note: only relevant if -u isn't passed to
# docker-run.
USER 1000
ENV USER=coder
WORKDIR /home/coder
ENTRYPOINT ["/usr/bin/entrypoint-catatonit.sh", "--bind-addr", "0.0.0.0:8080", "."]

11
ci/release-image/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
docker build -t "codercom/code-server-$ARCH:$VERSION" -f ./ci/release-image/Dockerfile .
}
main "$@"

View File

@ -1,106 +0,0 @@
# Use this file from the top of the repo, with `-f ci/release-image/docker-bake.hcl`
# Uses env var VERSION if set;
# normally, this is set by ci/lib.sh
variable "VERSION" {
default = "latest"
}
variable "DOCKER_REGISTRY" {
default = "docker.io/codercom/code-server"
}
variable "GITHUB_REGISTRY" {
default = "ghcr.io/coder/code-server"
}
group "default" {
targets = [
"code-server-debian-12",
"code-server-ubuntu-focal",
"code-server-ubuntu-noble",
"code-server-fedora-39",
"code-server-opensuse-tumbleweed",
]
}
function "prepend_hyphen_if_not_null" {
params = [tag]
result = notequal("","${tag}") ? "-${tag}" : "${tag}"
}
# use empty tag (tag="") to generate default tags
function "gen_tags" {
params = [registry, tag]
result = notequal("","${registry}") ? [
notequal("", "${tag}") ? "${registry}:${tag}" : "${registry}:latest",
notequal("latest",VERSION) ? "${registry}:${VERSION}${prepend_hyphen_if_not_null(tag)}" : "",
] : []
}
# helper function to generate tags for docker registry and github registry.
# set (DOCKER|GITHUB)_REGISTRY="" to disable corresponding registry
function "gen_tags_for_docker_and_ghcr" {
params = [tag]
result = concat(
gen_tags("${DOCKER_REGISTRY}", "${tag}"),
gen_tags("${GITHUB_REGISTRY}", "${tag}"),
)
}
target "code-server-debian-12" {
dockerfile = "ci/release-image/Dockerfile"
tags = concat(
gen_tags_for_docker_and_ghcr(""),
gen_tags_for_docker_and_ghcr("debian"),
gen_tags_for_docker_and_ghcr("bookworm"),
)
platforms = ["linux/amd64", "linux/arm64"]
}
target "code-server-ubuntu-focal" {
dockerfile = "ci/release-image/Dockerfile"
tags = concat(
gen_tags_for_docker_and_ghcr("ubuntu"),
gen_tags_for_docker_and_ghcr("focal"),
)
args = {
BASE = "ubuntu:focal"
}
platforms = ["linux/amd64", "linux/arm64"]
}
target "code-server-ubuntu-noble" {
dockerfile = "ci/release-image/Dockerfile"
tags = concat(
gen_tags_for_docker_and_ghcr("noble"),
)
args = {
BASE = "ubuntu:noble"
}
platforms = ["linux/amd64", "linux/arm64"]
}
target "code-server-fedora-39" {
dockerfile = "ci/release-image/Dockerfile.fedora"
tags = concat(
gen_tags_for_docker_and_ghcr("fedora"),
gen_tags_for_docker_and_ghcr("39"),
)
args = {
BASE = "fedora:39"
}
platforms = ["linux/amd64", "linux/arm64"]
}
target "code-server-opensuse-tumbleweed" {
dockerfile = "ci/release-image/Dockerfile.opensuse"
tags = concat(
gen_tags_for_docker_and_ghcr("opensuse"),
gen_tags_for_docker_and_ghcr("tumbleweed"),
)
args = {
BASE = "opensuse/tumbleweed"
}
platforms = ["linux/amd64", "linux/arm64"]
}

View File

@ -1,27 +0,0 @@
#!/bin/sh
set -eu
# We do this first to ensure sudo works below when renaming the user.
# Otherwise the current container UID may not exist in the passwd database.
eval "$(fixuid -q)"
if [ "${DOCKER_USER-}" ]; then
USER="$DOCKER_USER"
if [ "$DOCKER_USER" != "$(whoami)" ]; then
echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
# Unfortunately we cannot change $HOME as we cannot move any bind mounts
# nor can we bind mount $HOME into a new home as that requires a privileged container.
sudo usermod --login "$DOCKER_USER" coder
sudo groupmod -n "$DOCKER_USER" coder
sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
fi
fi
# Allow users to have scripts run on container startup to prepare workspace.
# https://github.com/coder/code-server/issues/5177
if [ -d "${ENTRYPOINTD}" ]; then
find "${ENTRYPOINTD}" -type f -executable -print -exec {} \;
fi
exec catatonit -- /usr/bin/code-server "$@"

View File

@ -7,8 +7,8 @@ eval "$(fixuid -q)"
if [ "${DOCKER_USER-}" ]; then
USER="$DOCKER_USER"
if [ -z "$(id -u "$DOCKER_USER" 2>/dev/null)" ]; then
echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
if [ "$DOCKER_USER" != "$(whoami)" ]; then
echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd >/dev/null
# Unfortunately we cannot change $HOME as we cannot move any bind mounts
# nor can we bind mount $HOME into a new home as that requires a privileged container.
sudo usermod --login "$DOCKER_USER" coder
@ -18,10 +18,4 @@ if [ "${DOCKER_USER-}" ]; then
fi
fi
# Allow users to have scripts run on container startup to prepare workspace.
# https://github.com/coder/code-server/issues/5177
if [ -d "${ENTRYPOINTD}" ]; then
find "${ENTRYPOINTD}" -type f -executable -print -exec {} \;
fi
exec dumb-init /usr/bin/code-server "$@"
dumb-init /usr/bin/code-server "$@"

View File

@ -2,36 +2,12 @@
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
# Only sourcing this so we get access to $VERSION
source ./ci/lib.sh
source ./ci/steps/steps-lib.sh
echo "Checking environment variables"
# We need VERSION to bump the brew formula
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
echo "HOMEBREW_GITHUB_API_TOKEN is not set"
exit 1
fi
# Find the docs for bump-formula-pr here
# https://github.com/Homebrew/brew/blob/master/Library/Homebrew/dev-cmd/bump-formula-pr.rb#L18
local output
if ! output=$(brew bump-formula-pr --version="${VERSION}" code-server --no-browse --no-audit --message="PR opened by @${GITHUB_ACTOR}" 2>&1); then
if [[ $output == *"Duplicate PRs should not be opened"* ]]; then
echo "$VERSION is already submitted"
exit 0
else
echo "$output"
exit 1
fi
fi
brew bump-formula-pr --force --version="${VERSION}" code-server --no-browse --no-audit
}
main "$@"

14
ci/steps/build-docker-image.sh Executable file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
./ci/release-image/build.sh
mkdir -p release-images
docker save "codercom/code-server-$ARCH:$VERSION" >"release-images/code-server-$ARCH-$VERSION.tar"
}
main "$@"

View File

@ -1,15 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
# NOTE@jsjoeio - this script assumes VERSION exists as an
# environment variable.
# NOTE@jsjoeio - this script assumes that you've downloaded
# the release-packages artifact to ./release-packages before
# running this docker buildx step
docker buildx bake -f ci/release-image/docker-bake.hcl --push
}
main "$@"

View File

@ -4,146 +4,15 @@ 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
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 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
# Check that we're using at least v7 of npm CLI
if ! command -v jq &> /dev/null; then
echo "Couldn't find jq"
echo "We need this in order to modify the package.json for dev builds."
exit 1
fi
# This allows us to publish to npm in CI workflows
if [[ ${CI-} ]]; then
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
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 `npm install code-server@<pr-number>`
# "staging" - this means we tag with `beta`, allowing
# a developer to install this version with `npm install code-server@beta`
# "production" - this means we tag with `latest` (default), allowing
# a developer to install this version with `npm install code-server@latest`
if ! is_env_var_set "NPM_ENVIRONMENT"; then
echo "NPM_ENVIRONMENT is not set."
echo "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
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
# We use this to set the name of the package in the
# package.json
PACKAGE_NAME="code-server"
# NOTES:@jsjoeio
# We only need to run npm version for "development" and "staging".
# This is because our release:prep script automatically bumps the version
# 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 `npm install code-server`
NPM_TAG="latest"
else
COMMIT_SHA="$GITHUB_SHA"
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 `npm install code-server@beta`
NPM_TAG="beta"
PACKAGE_NAME="@coder/code-server-pr"
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"
PACKAGE_NAME="@coder/code-server-pr"
# This means the npm version will be tagged with "<pr number>"
# and installed when a user runs `npm install code-server@<pr number>`
NPM_TAG="$PR_NUMBER"
fi
echo "- tag: $NPM_TAG"
echo "- version: $NPM_VERSION"
echo "- package name: $PACKAGE_NAME"
echo "- npm environment: $NPM_ENVIRONMENT"
# 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
npm version "$NPM_VERSION"
# Use the development package name
# This is so we don't clutter the code-server versions on npm
# with development versions.
# jq can't edit in place so we must store in memory and echo
local contents
contents="$(jq ".name |= \"$PACKAGE_NAME\"" package.json)"
echo "${contents}" > package.json
popd
fi
# We need to make sure we haven't already published the version.
# If we get error, continue with script because we want to publish
# If version is valid, we check if we're publishing the same one
local hasVersion
if hasVersion=$(npm view "$PACKAGE_NAME@$NPM_VERSION" version 2> /dev/null) && [[ $hasVersion == "$NPM_VERSION" ]]; then
echo "$NPM_VERSION is already published under $PACKAGE_NAME"
return
fi
# Since the dev builds are scoped to @coder
# We pass --access public to ensure npm knows it's not private.
cd release
npm publish --tag "$NPM_TAG" --access public
yarn publish --non-interactive release
}
main "$@"

View File

@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
download_artifact release-images ./release-images
if [[ ${CI-} ]]; then
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
fi
for img in ./release-images/*; do
docker load -i "$img"
done
# We have to ensure the amd64 and arm64 images exist on the remote registry
# in order to build the manifest.
# We don't put the arch in the tag to avoid polluting the main repository.
# These other repositories are private so they don't pollute our organization namespace.
docker push "codercom/code-server-amd64:$VERSION"
docker push "codercom/code-server-arm64:$VERSION"
export DOCKER_CLI_EXPERIMENTAL=enabled
docker manifest create "codercom/code-server:$VERSION" \
"codercom/code-server-amd64:$VERSION" \
"codercom/code-server-arm64:$VERSION"
docker manifest push --purge "codercom/code-server:$VERSION"
docker manifest create "codercom/code-server:latest" \
"codercom/code-server-amd64:$VERSION" \
"codercom/code-server-arm64:$VERSION"
docker manifest push --purge "codercom/code-server:latest"
}
main "$@"

View File

@ -1,47 +0,0 @@
#!/usr/bin/env bash
# This is a library which contains functions used inside ci/steps
#
# We separated it into it's own file so that we could easily unit test
# these functions and helpers
# Checks whether and environment variable is set.
# Source: https://stackoverflow.com/a/62210688/3015595
is_env_var_set() {
local name="${1:-}"
if test -n "${!name:-}"; then
return 0
else
return 1
fi
}
# Checks whether a directory exists.
directory_exists() {
local dir="${1:-}"
if [[ -d "${dir:-}" ]]; then
return 0
else
return 1
fi
}
# Checks whether a file exists.
file_exists() {
local file="${1:-}"
if test -f "${file:-}"; then
return 0
else
return 1
fi
}
# Checks whether a file is executable.
is_executable() {
local file="${1:-}"
if [ -f "${file}" ] && [ -r "${file}" ] && [ -x "${file}" ]; then
return 0
else
return 1
fi
}

View File

@ -1,18 +1,5 @@
<!-- prettier-ignore-start -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
# Contributor Covenant Code of Conduct
- [Contributor Covenant Code of Conduct](#contributor-covenant-code-of-conduct)
- [Our Pledge](#our-pledge)
- [Our Standards](#our-standards)
- [Our Responsibilities](#our-responsibilities)
- [Scope](#scope)
- [Enforcement](#enforcement)
- [Attribution](#attribution)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- prettier-ignore-end -->
# Contributor Covenant Code of Conduct

View File

@ -1,296 +1,161 @@
<!-- prettier-ignore-start -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
# Contributing
- [Pull Requests](#pull-requests)
- [Commits](#commits)
- [Requirements](#requirements)
- [Linux-specific requirements](#linux-specific-requirements)
- [Development workflow](#development-workflow)
- [Version updates to Code](#version-updates-to-code)
- [Patching Code](#patching-code)
- [Build](#build)
- [Creating a Standalone Release](#creating-a-standalone-release)
- [Troubleshooting](#troubleshooting)
- [I see "Forbidden access" when I load code-server in the browser](#i-see-forbidden-access-when-i-load-code-server-in-the-browser)
- ["Can only have one anonymous define call per script"](#can-only-have-one-anonymous-define-call-per-script)
- [Help](#help)
- [Test](#test)
- [Unit tests](#unit-tests)
- [Script tests](#script-tests)
- [Integration tests](#integration-tests)
- [End-to-end tests](#end-to-end-tests)
- [Development Workflow](#development-workflow)
- [Updating VS Code](#updating-vs-code)
- [Notes about Changes](#notes-about-changes)
- [Build](#build)
- [Structure](#structure)
- [Modifications to Code](#modifications-to-code)
- [Modifications to VS Code](#modifications-to-vs-code)
- [Currently Known Issues](#currently-known-issues)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- prettier-ignore-end -->
- [Detailed CI and build process docs](../ci)
## Pull Requests
Please create a [GitHub Issue](https://github.com/cdr/code-server/issues) for each issue
you'd like to address unless the proposed fix is minor.
In your Pull Requests (PR), link to the issue that the PR solves.
Please ensure that the base of your PR is the **main** branch.
### Commits
We prefer a clean commit history. This means you should squash all fixups and fixup-type commits before asking for review (cleanup, squash, force-push). If you need help with this, feel free to leave a comment in your PR and we'll guide you.
## Requirements
The prerequisites for contributing to code-server are almost the same as those
for [VS Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
Here is what is needed:
The prerequisites for contributing to code-server are almost the same as those for
[VS Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
There are several differences, however. Here is what is needed:
- `node` v22.x
- `node` v12.x or greater
- `git` v2.x or greater
- [`git-lfs`](https://git-lfs.github.com)
- [`npm`](https://www.npmjs.com/)
- Used to install JS packages and run scripts
- [`nfpm`](https://nfpm.goreleaser.com/)
- Used to build `.deb` and `.rpm` packages
- [`yarn`](https://classic.yarnpkg.com/en/)
- used to install JS packages and run scripts
- [`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
- used to build code-server releases
- [`gnupg`](https://gnupg.org/index.html)
- All commits must be signed and verified; see GitHub's [Managing commit
signature
verification](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification)
or follow [this tutorial](https://joeprevite.com/verify-commits-on-github)
- `quilt`
- Used to manage patches to Code
- all commits must be signed and verified
- see GitHub's ["Managing commit 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)
- `apt-get install -y build-essential` - used by VS Code
- `rsync` and `unzip`
- Used for code-server releases
- `bats`
- Used to run script unit tests
- used for code-server releases
### Linux-specific requirements
If you're developing code-server on Linux, make sure you have installed or
install the following dependencies:
## Development Workflow
```shell
sudo apt-get install build-essential g++ libx11-dev libxkbfile-dev libsecret-1-dev libkrb5-dev python-is-python3
yarn
yarn watch
# Visit http://localhost:8080 once the build is completed.
```
These are required by Code. See [their Wiki](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites)
for more information.
`yarn watch` will live reload changes to the source.
## Development workflow
### Updating VS Code
1. `git clone https://github.com/coder/code-server.git` - Clone `code-server`
2. `git submodule update --init` - Clone `vscode` submodule
3. `quilt push -a` - Apply patches to the `vscode` submodule.
4. `npm install` - Install dependencies
5. `npm run watch` - Launch code-server localhost:8080. code-server will be live
reloaded when changes are made; the browser needs to be refreshed manually.
Updating VS Code requires `git subtree`. On some rpm-based Linux distros, `git subtree` is not included by default, and needs to be installed separately.
To install, run `dnf install git-subtree` or `yum install git-subtree` as necessary.
When pulling down changes that include modifications to the patches you will
need to apply them with `quilt`. If you pull down changes that update the
`vscode` submodule you will need to run `git submodule update --init` and
re-apply the patches.
To update VS Code, follow these steps:
When you make a change that affects people deploying the marketplace please
update the changelog as part of your PR.
1. Run `yarn update:vscode`.
2. Enter a version. Ex. 1.53
3. This will open a draft PR for you.
4. There will be merge conflicts. First commit them.
1. We do this because if we don't, it will be impossible to review your PR.
5. Once they're all fixed, test code-server locally and make sure it all works.
Note that building code-server takes a very, very long time, and loading it in
the browser in development mode also takes a very, very long time.
#### Notes about Changes
Display language (Spanish, etc) support only works in a full build; it will not
work in development mode.
- watch out for updates to `lib/vscode/src/vs/code/browser/workbench/workbench.html`. You may need to make changes to `src/browser/pages/vscode.html`
Generally we prefer that PRs be squashed into `main` but you can rebase or merge
if it is important to keep the individual commits (make sure to clean up the
commits first if you are doing this).
## Build
### Version updates to Code
1. Remove any patches with `quilt pop -a`.
2. Update the `lib/vscode` submodule to the desired upstream version branch.
1. `cd lib/vscode && git checkout release/1.66 && cd ../..`
2. `git add lib && git commit -m "chore: update to Code <version>"`
3. Apply the patches one at a time (`quilt push`). If the application succeeds
but the lines changed, update the patch with `quilt refresh`. If there are
conflicts, then force apply with `quilt push -f`, manually add back the
rejected code, then run `quilt refresh`.
4. From the code-server **project root**, run `npm install`.
5. Check the Node.js version that's used by Electron (which is shipped with VS
Code. If necessary, update our version of Node.js to match.
### Patching Code
1. You can go through the patch stack with `quilt push` and `quilt pop`.
2. Create a new patch (`quilt new {name}.diff`) or use an existing patch.
3. Add the file(s) you are patching (`quilt add [-P patch] {file}`). A file
**must** be added before you make changes to it.
4. Make your changes. Patches do not need to be independent of each other but
each patch must result in a working code-server without any broken in-between
states otherwise they are difficult to test and modify.
5. Add your changes to the patch (`quilt refresh`)
6. Add a comment in the patch about the reason for the patch and how to
reproduce the behavior it fixes or adds. Every patch should have an e2e test
as well.
### Build
You can build a full production as follows:
You can build using:
```shell
git submodule update --init
quilt push -a
npm install
npm run build
VERSION=0.0.0 npm run build:vscode
npm run release
yarn build
yarn build:vscode
yarn release
```
This does not keep `node_modules`. If you want them to be kept, use
`KEEP_MODULES=1 npm run release`
Run your build:
Run your build with:
```shell
cd release
npm install --omit=dev # Skip if you used KEEP_MODULES=1
yarn --production
# Runs the built JavaScript with Node.
node .
```
Then, to build the release package:
Build the release packages (make sure that you run `yarn release` first):
```shell
npm run release:standalone
npm run test:integration
npm run package
yarn release:standalone
yarn test:standalone-release
yarn package
```
> On Linux, the currently running distro will become the minimum supported
> version. In our GitHub Actions CI, we use CentOS 8 for maximum compatibility.
> If you need your builds to support older distros, run the build commands
> inside a Docker container with all the build requirements installed.
#### Creating a Standalone Release
Part of the build process involves creating standalone releases. At the time of
writing, we do this for the following platforms/architectures:
- Linux amd64 (.tar.gz, .deb, and .rpm)
- Linux arm64 (.tar.gz, .deb, and .rpm)
- Linux arm7l (.tar.gz)
- Linux armhf.deb
- Linux armhf.rpm
- macOS arm64.tar.gz
Currently, these are compiled in CI using the `npm run release:standalone`
command in the `release.yaml` workflow. We then upload them to the draft release
and distribute via GitHub Releases.
### Troubleshooting
#### I see "Forbidden access" when I load code-server in the browser
This means your patches didn't apply correctly. We have a patch to remove the
auth from vanilla Code because we use our own.
Try popping off the patches with `quilt pop -a` and reapplying with `quilt push
-a`.
#### "Can only have one anonymous define call per script"
Code might be trying to use a dev or prod HTML in the wrong context. You can try
re-running code-server and setting `VSCODE_DEV=1`.
### Help
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:
1. Unit tests
2. Script tests
3. Integration tests
4. End-to-end tests
### Unit tests
Our unit tests are written in TypeScript and run using
[Jest](https://jestjs.io/), the testing framework].
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 tests with `npm run
test:integration`, which ensures that code-server builds work on their
respective platforms.
Our integration tests look at components that rely on one another. For example,
testing the CLI requires us to build and package code-server.
### End-to-end tests
The end-to-end (e2e) tests are written in TypeScript and run using
[Playwright](https://playwright.dev/).
These live under [test/e2e](../test/e2e).
Before the e2e tests run, we run `globalSetup`, which eliminates the need to log
in before each test by preserving the authentication state.
Take a look at `codeServer.test.ts` to see how you would use it (see
`test.use`).
We also have a model where you can create helpers to use within tests. See
[models/CodeServer.ts](../test/e2e/models/CodeServer.ts) for an example.
NOTE: On Linux, the currently running distro will become the minimum supported version.
In our GitHub Actions CI, we use CentOS 7 for maximum compatibility.
If you need your builds to support older distros, run the build commands
inside a Docker container with all the build requirements installed.
## Structure
code-server essentially serves as an HTTP API for logging in and starting a
remote Code process.
The `code-server` script serves an HTTP API for login and starting a remote VS Code process.
The CLI code is in [src/node](../src/node) and the HTTP routes are implemented
in [src/node/routes](../src/node/routes).
The CLI code is in [src/node](../src/node) and the HTTP routes are implemented in
[src/node/routes](../src/node/routes).
Most of the meaty parts are in the Code portion of the codebase under
[lib/vscode](../lib/vscode), which we describe next.
Most of the meaty parts are in the VS Code portion of the codebase under [lib/vscode](../lib/vscode), which we described next.
### Modifications to Code
### Modifications to VS Code
Our modifications to Code can be found in the [patches](../patches) directory.
We pull in Code as a submodule pointing to an upstream release branch.
In v1 of code-server, we had a patch of VS Code that split the codebase into a front-end
and a server. The front-end consisted of all UI code, while the server ran the extensions
and exposed an API to the front-end for file access and all UI needs.
In v1 of code-server, we had Code as a submodule and used a single massive patch
that split the codebase into a front-end and a server. The front-end consisted
of the UI code, while the server ran the extensions and exposed an API to the
front-end for file access and all UI needs.
Over time, Microsoft added support to VS Code to run it on the web. They have made
the front-end open source, but not the server. As such, code-server v2 (and later) uses
the VS Code front-end and implements the server. We do this by using a git subtree to fork and modify VS Code. This code lives under [lib/vscode](../lib/vscode).
Over time, Microsoft added support to Code to run it on the web. They had made
the front-end open source, but not the server. As such, code-server v2 (and
later) uses the Code front-end and implements the server. We did this by using a
Git subtree to fork and modify Code.
Some noteworthy changes in our version of VS Code:
Microsoft eventually made the server open source and we were able to reduce our
changes significantly. Some time later we moved back to a submodule and patches
(managed by `quilt` this time instead of the mega-patch).
- Adding our build file, which includes our code and VS Code's web code
- Allowing multiple extension directories (both user and built-in)
- Modifying the loader, websocket, webview, service worker, and asset requests to
use the URL of the page as a base (and TLS, if necessary for the websocket)
- Sending client-side telemetry through the server
- Allowing modification of the display language
- Making it possible for us to load code on the client
- Making it possible to install extensions of any kind
- Fixing issue with getting disconnected when your machine sleeps or hibernates
- Adding connection type to web socket query parameters
As the web portion of Code continues to mature, we'll be able to shrink and
possibly eliminate our patches. In the meantime, upgrading the Code version
requires us to ensure that our changes are still applied correctly and work as
intended. In the future, we'd like to run Code unit tests against our builds to
ensure that features work as expected.
As the web portion of VS Code matures, we'll be able to shrink and possibly
eliminate our modifications. In the meantime, upgrading the VS Code version requires
us to ensure that our changes are still applied and work as intended. In the future,
we'd like to run VS Code unit tests against our builds to ensure that features
work as expected.
> We have [extension docs](../ci/README.md) on the CI and build system.
**Note**: We have [extension docs](../ci/README.md) on the CI and build system.
If the functionality you're working on does NOT depend on code from Code, please
If the functionality you're working on does NOT depend on code from VS Code, please
move it out and into code-server.
### Currently Known Issues
- Creating custom Code extensions and debugging them doesn't work
- Creating custom VS Code extensions and debugging them doesn't work
- Extension profiling and tips are currently disabled

View File

@ -1,153 +1,161 @@
<!-- prettier-ignore-start -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
# FAQ
- [Questions?](#questions)
- [How should I expose code-server to the internet?](#how-should-i-expose-code-server-to-the-internet)
- [Can I use code-server on the iPad?](#can-i-use-code-server-on-the-ipad)
- [How does the config file work?](#how-does-the-config-file-work)
- [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work)
- [Why can't code-server use Microsoft's extension marketplace?](#why-cant-code-server-use-microsofts-extension-marketplace)
- [How can I request an extension that's missing from the marketplace?](#how-can-i-request-an-extension-thats-missing-from-the-marketplace)
- [How do I install an extension?](#how-do-i-install-an-extension)
- [How do I install an extension manually?](#how-do-i-install-an-extension-manually)
- [How do I use my own extensions marketplace?](#how-do-i-use-my-own-extensions-marketplace)
- [Where are extensions stored?](#where-are-extensions-stored)
- [Where is VS Code configuration stored?](#where-is-vs-code-configuration-stored)
- [iPad Status?](#ipad-status)
- [Community Projects (awesome-code-server)](#community-projects-awesome-code-server)
- [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration)
- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open)
- [How do I access my Documents/Downloads/Desktop folders in code-server on macOS?](#how-do-i-access-my-documentsdownloadsdesktop-folders-in-code-server-on-macos)
- [How do I direct server-side requests through a proxy?](#how-do-i-direct-server-side-requests-through-a-proxy)
- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server)
- [What is the healthz endpoint?](#what-is-the-healthz-endpoint)
- [What is the heartbeat file?](#what-is-the-heartbeat-file)
- [How do I change the password?](#how-do-i-change-the-password)
- [Differences compared to VS Code?](#differences-compared-to-vs-code)
- [Installing an extension](#installing-an-extension)
- [How can I request a missing extension?](#how-can-i-request-a-missing-extension)
- [Installing an extension manually](#installing-an-extension-manually)
- [How do I configure the marketplace URL?](#how-do-i-configure-the-marketplace-url)
- [Where are extensions stored?](#where-are-extensions-stored)
- [How is this different from VS Code Codespaces?](#how-is-this-different-from-vs-code-codespaces)
- [How should I expose code-server to the internet?](#how-should-i-expose-code-server-to-the-internet)
- [Can I store my password hashed?](#can-i-store-my-password-hashed)
- [Is multi-tenancy possible?](#is-multi-tenancy-possible)
- [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 Coder?](#whats-the-difference-between-code-server-and-coder)
- [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 web?](#whats-the-difference-between-code-server-and-vs-code-web)
- [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)
- [How do I hide the coder/coder promotion in Help: Getting Started?](#how-do-i-hide-the-codercoder-promotion-in-help-getting-started)
- [How do I disable the proxy?](#how-do-i-disable-the-proxy)
- [How do I disable file download?](#how-do-i-disable-file-download)
- [Why do web views not work?](#why-do-web-views-not-work)
- [How do I securely access web services?](#how-do-i-securely-access-web-services)
- [Sub-paths](#sub-paths)
- [Sub-domains](#sub-domains)
- [Why does the code-server proxy strip `/proxy/<port>` from the request path?](#why-does-the-code-server-proxy-strip-proxyport-from-the-request-path)
- [Proxying to Create React App](#proxying-to-create-react-app)
- [Multi-tenancy](#multi-tenancy)
- [Docker in code-server container?](#docker-in-code-server-container)
- [How can I disable telemetry?](#how-can-i-disable-telemetry)
- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open)
- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server)
- [Heartbeat File](#heartbeat-file)
- [Healthz endpoint](#healthz-endpoint)
- [How does the config file work?](#how-does-the-config-file-work)
- [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure)
- [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work)
- [How do I access my Documents/Downloads/Desktop folders in code-server on OSX?](#how-do-i-access-my-documentsdownloadsdesktop-folders-in-code-server-on-osx)
- [Differences compared to Theia?](#differences-compared-to-theia)
- [`$HTTP_PROXY`, `$HTTPS_PROXY`, `$NO_PROXY`](#http_proxy-https_proxy-no_proxy)
- [Enterprise](#enterprise)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- prettier-ignore-end -->
## Questions?
Please file all questions and support requests at
<https://github.com/coder/code-server/discussions>.
Please file all questions and support requests at <https://github.com/cdr/code-server/discussions>.
## How should I expose code-server to the internet?
## iPad Status?
Please see [our instructions on exposing code-server safely to the
internet](./guide.md).
Please see [./ipad.md](./ipad.md).
## Can I use code-server on the iPad?
## Community Projects (awesome-code-server)
See [iPad](./ipad.md) for information on using code-server on the iPad.
Visit the [awesome-code-server](https://github.com/cdr/awesome-code-server) repository to view community projects and guides with code-server! Feel free to add your own!
## How does the config file work?
## How can I reuse my VS Code configuration?
When `code-server` starts up, it creates a default config file in `~/.config/code-server/config.yaml`:
The very popular [Settings Sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync) extension works.
```yaml
bind-addr: 127.0.0.1:8080
auth: password
password: mew...22 # Randomly generated for each config.yaml
cert: false
```
You can also pass `--user-data-dir ~/.vscode` to reuse your existing VS Code extensions and configuration.
The default config defines the following behavior:
Or copy `~/.vscode` into `~/.local/share/code-server`.
- Listen on the loopback IP port 8080
- Enable password authorization
- Do not use TLS
## Differences compared to VS Code?
Each key in the file maps directly to a `code-server` flag (run `code-server --help` to see a listing of all the flags). Any flags passed to `code-server`
will take priority over the config file.
`code-server` takes the open source core of VS Code and allows you to run it in the browser.
However, it is not entirely equivalent to Microsoft's VS Code.
You can change the config file's location using the `--config` flag or
`$CODE_SERVER_CONFIG` environment variable.
While the core of VS Code is open source, the marketplace and many published Microsoft extensions are not.
The default location respects `$XDG_CONFIG_HOME`.
Furthermore, Microsoft prohibits the use of any non-Microsoft VS Code from accessing their marketplace.
## How do I make my keyboard shortcuts work?
See the [TOS](https://cdn.vsassets.io/v/M146_20190123.39/_content/Microsoft-Visual-Studio-Marketplace-Terms-of-Use.pdf).
Many shortcuts will not work by default, since they'll be "caught" by the browser.
> Marketplace Offerings are intended for use only with Visual Studio Products and Services
> and you may only install and use Marketplace Offerings with Visual Studio Products and Services.
If you use Chrome, you can work around this by installing the progressive web
app (PWA):
As a result, we cannot offer any extensions on the Microsoft marketplace. Instead,
we have created our own marketplace for open source extensions.
It works by scraping GitHub for VS Code extensions and building them. It's not perfect but getting
better by the day with more and more extensions.
1. Start the editor
2. Click the **plus** icon in the URL toolbar to install the PWA
These are the closed source extensions presently unavailable:
If you use Firefox, you can use the appropriate extension to install PWA.
1. [Live Share](https://visualstudio.microsoft.com/services/live-share)
- We may implement something similar, see [#33](https://github.com/cdr/code-server/issues/33)
1. [Remote Extensions (SSH, Containers, WSL)](https://github.com/microsoft/vscode-remote-release)
- We may reimplement these at some point, see [#1315](https://github.com/cdr/code-server/issues/1315)
1. Go to the installation [website](https://addons.mozilla.org/en-US/firefox/addon/pwas-for-firefox/) of the add-on
2. Add the add-on to Firefox
3. Follow the os-specific instructions on how to install the runtime counterpart
For more about the closed source parts of VS Code, see [vscodium/vscodium](https://github.com/VSCodium/vscodium#why-does-this-exist).
For other browsers, you'll have to remap keybindings for shortcuts to work.
### Installing an extension
## Why can't code-server use Microsoft's extension marketplace?
Though code-server takes the open-source core of VS Code and allows you to run
it in the browser, it is not entirely equivalent to Microsoft's VS Code.
One major difference is in regards to extensions and the marketplace. The core
of VS code is open source, while the marketplace and many published Microsoft
extensions are not. Furthermore, Microsoft prohibits the use of any
non-Microsoft VS Code from accessing their marketplace. Per the [Terms of
Service](https://cdn.vsassets.io/v/M146_20190123.39/_content/Microsoft-Visual-Studio-Marketplace-Terms-of-Use.pdf):
> Marketplace Offerings are intended for use only with Visual Studio Products
> and Services, and you may only install and use Marketplace Offerings with
> 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.
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))
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)).
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.
## How do I install an extension?
You can install extensions from the marketplace using the extensions sidebar in
Extensions can be installed from the marketplace using the extensions sidebar in
code-server or from the command line:
```console
```shell
code-server --install-extension <extension id>
# example: code-server --install-extension wesbos.theme-cobalt2
```
## How can I request a missing extension?
We are currently in the process of transitioning 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.
Instead, we suggest one of the following:
- [Switch to Open VSX](#how-do-i-configure-the-marketplace-url) now
- Download and [install the extension manually](#installing-an-extension-manually)
## Installing an extension manually
If an extension is not available from the marketplace or does not work, you can
grab its VSIX from its GitHub releases or build it yourself.
Once you have downloaded the VSIX to the remote machine you can either:
- Run the `Extensions: Install from VSIX` command in the Command Palette.
- Use `code-server --install-extension <path to vsix>`
You can also download extensions from the command line. For instance, downloading off OpenVSX can be done like this:
```shell
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 configure the marketplace URL?
If you have your own marketplace that implements the VS Code Extension Gallery API, it is possible to
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`.
e.g. to use [open-vsx.org](https://open-vsx.org):
```bash
export SERVICE_URL=https://open-vsx.org/vscode/gallery
export ITEM_URL=https://open-vsx.org/vscode/item
```
While you can technically use Microsoft's marketplace with these, please do not do so as it
is against their terms of use. See [above](#differences-compared-to-vs-code) and this
discussion regarding the use of the Microsoft URLs in forks:
<https://github.com/microsoft/vscode/issues/31168#issue-244533026>
See also [VSCodium's docs](https://github.com/VSCodium/vscodium/blob/master/DOCS.md#extensions--marketplace).
These variables are most valuable to our enterprise customers for whom we have a self hosted marketplace product.
## Where are extensions stored?
Defaults to `~/.local/share/code-server/extensions`.
If the `XDG_DATA_HOME` environment variable is set the data directory will be
`$XDG_DATA_HOME/code-server/extensions`. In general we try to follow the XDG directory spec.
You can install an extension on the CLI with:
```bash
# From the Coder extension marketplace
code-server --install-extension ms-python.python
@ -155,110 +163,280 @@ code-server --install-extension ms-python.python
code-server --install-extension downloaded-ms-python.python.vsix
```
## How do I install an extension manually?
## How is this different from VS Code Codespaces?
If there's an extension unavailable in the marketplace or an extension that
doesn't work, you can download the VSIX from its GitHub releases or build it
yourself.
VS Code Codespaces is a closed source and paid service by Microsoft. It also allows you to access
VS Code via the browser.
Once you have downloaded the VSIX to the remote machine, you can either:
However, code-server is free, open source and can be run on any machine without any limitations.
- Run the **Extensions: Install from VSIX** command in the Command Palette.
- Run `code-server --install-extension <path to vsix>` in the terminal
While you can self host environments with VS Code Codespaces, you still need an Azure billing
account and you have to access VS Code via the Codespaces web dashboard instead of directly
connecting to your instance.
You can also download extensions using the command line. For instance,
downloading from OpenVSX can be done like this:
## How should I expose code-server to the internet?
```shell
code-server --install-extension <extension id>
Please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server.
code-server only supports password authentication natively.
**note**: code-server will rate limit password authentication attempts at 2 a minute and 12 an hour.
If you want to use external authentication (i.e sign in with Google) you should handle this
with a reverse proxy using something like [oauth2_proxy](https://github.com/pusher/oauth2_proxy)
or [Cloudflare Access](https://teams.cloudflare.com/access).
For HTTPS, you can use a self signed certificate by passing in just `--cert` or
pass in an existing certificate by providing the path to `--cert` and the path to
the key with `--cert-key`.
The self signed certificate will be generated into
`~/.local/share/code-server/self-signed.crt`.
If `code-server` has been passed a certificate it will also respond to HTTPS
requests and will redirect all HTTP requests to HTTPS.
You can use [Let's Encrypt](https://letsencrypt.org/) to get a TLS certificate
for free.
Again, please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server.
## Can I store my password hashed?
Yes you can! Set the value of `hashed-password` instead of `password`. Generate the hash with:
```
printf "thisismypassword" | sha256sum | cut -d' ' -f1
```
## How do I use my own extensions marketplace?
Of course replace `thisismypassword` with your actual password.
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`.
Example:
For example:
```bash
export EXTENSIONS_GALLERY='{"serviceUrl": "https://my-extensions/api"}'
```yaml
auth: password
hashed-password: 1da9133ab9dbd11d2937ec8d312e1e2569857059e73cc72df92e670928983ab5 # You got this from the command above
```
Though you can technically use Microsoft's marketplace in this manner, we
strongly discourage you from doing so since this is [against their Terms of Use](#why-cant-code-server-use-microsofts-extension-marketplace).
## How do I securely access web services?
For further information, see [this
discussion](https://github.com/microsoft/vscode/issues/31168#issue-244533026)
regarding the use of the Microsoft URLs in forks, as well as [VSCodium's
docs](https://github.com/VSCodium/vscodium/blob/master/DOCS.md#extensions--marketplace).
code-server is capable of proxying to any port using either a subdomain or a
subpath which means you can securely access these services using code-server's
built-in authentication.
## Where are extensions stored?
### Sub-paths
Extensions are stored in `~/.local/share/code-server/extensions` by default.
Just browse to `/proxy/<port>/`.
On Linux and macOS if you set the `XDG_DATA_HOME` environment variable, the
extensions directory will be `$XDG_DATA_HOME/code-server/extensions`. In
general, we try to follow the XDG directory spec.
### Sub-domains
## Where is VS Code configuration stored?
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).
VS Code configuration such as settings and keybindings are stored in
`~/.local/share/code-server` by default.
You should also set up TLS certificates for these subdomains, either using a
wildcard certificate for `*.<domain>` or individual certificates for each port.
On Linux and macOS if you set the `XDG_DATA_HOME` environment variable, the data
directory will be `$XDG_DATA_HOME/code-server`. In general, we try to follow the
XDG directory spec.
Start code-server with the `--proxy-domain` flag set to your domain.
## How can I reuse my VS Code configuration?
```
code-server --proxy-domain <domain>
```
You can use the [Settings
Sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync)
extension for this purpose.
Now you can browse to `<port>.<domain>`. Note that this uses the host header so
ensure your reverse proxy forwards that information if you are using one.
Alternatively, you can also pass `--user-data-dir ~/.vscode` or copy `~/.vscode`
into `~/.local/share/code-server` to reuse your existing VS Code extensions and
configuration.
## Why does the code-server proxy strip `/proxy/<port>` from the request path?
HTTP servers should strive to use relative URLs to avoid needed to be coupled to the
absolute path at which they are served. This means you must use trailing slashes on all
paths with subpaths. See <https://blog.cdivilly.com/2019/02/28/uri-trailing-slashes>
This is really the "correct" way things work and why the striping of the base path is the
default. 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 many people prefer the cleaner aesthetic of no trailing slashes. This couples you
to the base path as you cannot use relative redirects correctly anymore. See the above
link.
For users who are ok with this tradeoff, use `/absproxy` instead and the path will be
passed as is. e.g. `/absproxy/3000/my-app-path`
### Proxying to Create 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). 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`.
e.g.
```sh
PUBLIC_URL=/absproxy/3000 \
WDS_SOCKET_PATH=$PUBLIC_URL/sockjs-node \
BROWSER=none yarn start
```
Then visit `https://my-code-server-address.io/absproxy/3000` to see your app exposed through
code-server!
Highly recommend using the subdomain approach instead to avoid this class of issue.
## Multi-tenancy
If you want to run multiple code-servers on shared infrastructure, we recommend using virtual
machines with a VM per user. This will easily allow users to run a docker daemon. If you want
to use kubernetes, you'll definitely want to use [kubevirt](https://kubevirt.io) or [sysbox](https://github.com/nestybox/sysbox) to give each
user a VM-like experience instead of just a container.
## Docker in code-server container?
If you'd like to access docker inside of code-server, mount the docker socket in from `/var/run/docker.sock`.
Install the docker CLI in the code-server container and you should be able to access the daemon!
You can even make volume mounts work. Lets say you want to run a container and mount in
`/home/coder/myproject` into it from inside the `code-server` container. You need to make sure
the docker daemon's `/home/coder/myproject` is the same as the one mounted inside the `code-server`
container and the mount will just work.
## How can I disable telemetry?
Use the `--disable-telemetry` flag to completely disable telemetry. We use the
data collected only to improve code-server.
## How does code-server decide what workspace or folder to open?
code-server tries the following in this order:
code-server tries the following in order:
1. The `workspace` query parameter
2. The `folder` query parameter
3. The workspace or directory passed via the command line
4. The last opened workspace or directory
1. The `workspace` query parameter.
2. The `folder` query parameter.
3. The workspace or directory passed on the command line.
4. The last opened workspace or directory.
## How do I access my Documents/Downloads/Desktop folders in code-server on macOS?
## How do I debug issues with code-server?
Newer versions of macOS require permission through a non-UNIX mechanism for
code-server to access the Desktop, Documents, Pictures, Downloads, and other folders.
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`.
You may have to give Node.js full disk access, since it doesn't implement any of the macOS permission request features natively:
```
code-server --log debug
```
1. Find where Node.js is installed on your machine
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.
## Heartbeat File
`code-server` touches `~/.local/share/code-server/heartbeat` once a minute as long
as there is an active browser connection.
If you want to shutdown `code-server` if there hasn't been an active connection in X minutes
you can do so by continuously checking the last modified time on the heartbeat file and if it is
older than X minutes, kill `code-server`.
[#1636](https://github.com/cdr/code-server/issues/1636) will make the experience here better.
## Healthz endpoint
`code-server` exposes an endpoint at `/healthz` which can be used to check
whether `code-server` is up without triggering a heartbeat. The response will
include a status (`alive` or `expired`) and a timestamp for the last heartbeat
(defaults to `0`). This endpoint does not require authentication.
```json
{
"status": "alive",
"lastHeartbeat": 1599166210566
}
```
## How does the config file work?
When `code-server` starts up, it creates a default config file in `~/.config/code-server/config.yaml` that looks
like this:
```yaml
bind-addr: 127.0.0.1:8080
auth: password
password: mewkmdasosafuio3422 # This is randomly generated for each config.yaml
cert: false
```
Each key in the file maps directly to a `code-server` flag. Run `code-server --help` to see
a listing of all the flags.
The default config here says to listen on the loopback IP port 8080, enable password authorization
and no TLS. Any flags passed to `code-server` will take priority over the config file.
The `--config` flag or `$CODE_SERVER_CONFIG` can be used to change the config file's location.
The default location also respects `$XDG_CONFIG_HOME`.
## Isn't an install script piped into sh insecure?
Please give
[this wonderful blogpost](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install) by
[sandstorm.io](https://sandstorm.io) a read.
## How do I make my keyboard shortcuts work?
Many shortcuts will not work by default as they'll be caught by the browser.
If you use Chrome you can get around this by installing the PWA.
Once you've entered the editor, click the "plus" icon present in the URL toolbar area.
This will install a Chrome PWA and now all keybindings will work!
For other browsers you'll have to remap keybindings unfortunately.
## How do I access my Documents/Downloads/Desktop folders in code-server on OSX?
Newer versions of macOS require permission through a non-UNIX mechanism for access to the Desktop, Documents, Pictures, Downloads, and other folders.
You may have to give Node "full disk access" since it doesn't implement any of the macOS permission request stuff natively.
1. Find where Node is installed on your machine
```console
$ which node
➜ ~ which node
/usr/local/bin/node
```
2. Grant Node.js full disk access. Open **System Preferences** > **Security &
Privacy** > **Privacy** > **Full Disk Access**. Then, click the 🔒 to unlock,
click **+**, and select the Node.js binary you located in the previous step.
1. Grant Node Full Disk Access:
See [#2794](https://github.com/coder/code-server/issues/2794) for additional context.
Open System Preferences > Security & Privacy > Privacy (horizontal) tab > Full Disk Access (vertical) tab > Click the 🔒 to unlock > Click + and select the Node binary you located.
## How do I direct server-side requests through a proxy?
See [#2794](https://github.com/cdr/code-server/issues/2794) for context on this.
> code-server proxies only server-side requests.
## Differences compared to Theia?
To direct server-side requests through a proxy, code-server supports the
following environment variables:
[Theia](https://github.com/eclipse-theia/theia) is a browser IDE loosely based on VS Code. It uses the same
text editor library named [Monaco](https://github.com/Microsoft/monaco-editor) and the same
extension API but everything else is very different. It also uses [open-vsx.org](https://open-vsx.org)
for extensions which has an order of magnitude less extensions than our marketplace.
See [#1473](https://github.com/cdr/code-server/issues/1473).
- `$HTTP_PROXY`
- `$HTTPS_PROXY`
- `$NO_PROXY`
You can't just use your VS Code config in Theia like you can with code-server.
To summarize, code-server is a patched fork of VS Code to run in the browser whereas
Theia takes some parts of VS Code but is an entirely different editor.
## `$HTTP_PROXY`, `$HTTPS_PROXY`, `$NO_PROXY`
code-server supports the standard environment variables to allow directing
server side requests through a proxy.
```sh
export HTTP_PROXY=https://134.8.5.4
@ -268,250 +446,18 @@ export HTTPS_PROXY=https://134.8.5.4
code-server
```
- See
[proxy-from-env](https://www.npmjs.com/package/proxy-from-env#environment-variables)
for a detailed reference on these environment variables and their syntax (note
that code-server only uses the `http` and `https` protocols).
- See [proxy-agent](https://www.npmjs.com/package/proxy-agent) for information
on on the supported proxy protocols.
- See [proxy-from-env](https://www.npmjs.com/package/proxy-from-env#environment-variables)
for a detailed reference on the various environment variables and their syntax.
- code-server only uses the `http` and `https` protocols.
- See [proxy-agent](https://www.npmjs.com/package/proxy-agent) for the various supported
proxy protocols.
## How do I debug issues with code-server?
**note**: Only server side requests will be proxied! This includes fetching extensions,
requests made from extensions etc. To proxy requests from your browser you need to
configure your browser separately. Browser requests would cover exploring the extension
marketplace.
First, run code-server with the `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`.
## Enterprise
First, run code-server with `debug` logging (or `trace` logging for more
thorough messages) by setting the `--log` flag or the `LOG_LEVEL` environment
variable.
```text
code-server --log debug
```
> Note that the `-vvv` and `--verbose` flags are aliases for `--log trace`.
Next, replicate the issue you're having so that you can 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.
## What is the healthz endpoint?
You can use the `/healthz` endpoint exposed by code-server to check whether
code-server is running without triggering a heartbeat. The response includes a
status (e.g., `alive` or `expired`) and a timestamp for the last heartbeat
(the default is `0`).
```json
{
"status": "alive",
"lastHeartbeat": 1599166210566
}
```
This endpoint doesn't require authentication.
## What is the heartbeat file?
As long as there is an active browser connection, code-server touches
`~/.local/share/code-server/heartbeat` once a minute.
If you want to shutdown code-server if there hasn't been an active connection
after a predetermined amount of time, you can use the --idle-timeout-seconds flag
or set an `CODE_SERVER_IDLE_TIMEOUT_SECONDS` environment variable.
## How do I change the password?
Edit the `password` field in the code-server config file at
`~/.config/code-server/config.yaml`, then restart code-server:
```bash
sudo systemctl restart code-server@$USER
```
## Can I store my password hashed?
Yes, you can do so by setting the value of `hashed-password` instead of `password`. Generate the hash with:
```shell
echo -n "thisismypassword" | npx argon2-cli -e
$argon2i$v=19$m=4096,t=3,p=1$wst5qhbgk2lu1ih4dmuxvg$ls1alrvdiwtvzhwnzcm1dugg+5dto3dt1d5v9xtlws4
```
Replace `thisismypassword` with your actual password and **remember to put it
inside quotes**! For example:
```yaml
auth: password
hashed-password: "$argon2i$v=19$m=4096,t=3,p=1$wST5QhBgk2lu1ih4DMuxvg$LS1alrVdIWtvZHwnzCM1DUGg+5DTO3Dt1d5v9XtLws4"
```
The `hashed-password` field takes precedence over `password`.
If you're using Docker Compose file, in order to make this work, you need to change all the single $ to $$. For example:
```yaml
- HASHED_PASSWORD=$$argon2i$$v=19$$m=4096,t=3,p=1$$wST5QhBgk2lu1ih4DMuxvg$$LS1alrVdIWtvZHwnzCM1DUGg+5DTO3Dt1d5v9XtLws4
```
## Is multi-tenancy possible?
If you want to run multiple code-servers on shared infrastructure, we recommend
using virtual machines (provide one VM per user). This will easily allow users
to run a Docker daemon. If you want to use Kubernetes, you'll want to
use [kubevirt](https://kubevirt.io) or
[sysbox](https://github.com/nestybox/sysbox) to give each user a VM-like
experience instead of just a container.
## Can I use Docker in a code-server container?
If you'd like to access Docker inside of code-server, mount the Docker socket in
from `/var/run/docker.sock`. Then, install the Docker CLI in the code-server
container, and you should be able to access the daemon.
You can even make volume mounts work. Let's say you want to run a container and
mount into `/home/coder/myproject` from inside the `code-server` container. You
need to make sure the Docker daemon's `/home/coder/myproject` is the same as the
one mounted inside the `code-server` container, and the mount will work.
If you want Docker enabled when deploying on Kubernetes, look at the `values.yaml`
file for the 3 fields: `extraVars`, `lifecycle.postStart`, and `extraContainers`.
## How do I disable telemetry?
Use the `--disable-telemetry` flag to disable telemetry.
> We use the data collected only to improve code-server.
## What's the difference between code-server and Coder?
code-server and Coder are both applications that can be installed on any
machine. The main difference is who they serve. Out of the box, code-server is
simply VS Code in the browser while Coder is a tool for provisioning remote
development environments via Terraform.
code-server was built for individuals while Coder was built for teams. In Coder, you create Workspaces which can have applications like code-server. If you're looking for a team solution, you should reach for [Coder](https://github.com/coder/coder).
## What's the difference between code-server and Theia?
At a high level, code-server is a patched fork of VS Code that runs in the
browser whereas Theia takes some parts of VS Code but is an entirely different
editor.
[Theia](https://github.com/eclipse-theia/theia) is a browser IDE loosely based
on VS Code. It uses the same text editor library
([Monaco](https://github.com/Microsoft/monaco-editor)) and extension API, but
everything else is different. Theia also uses [Open VSX](https://open-vsx.org)
for extensions.
Theia doesn't allow you to reuse your existing VS Code config.
## What's the difference between code-server and OpenVSCode-Server?
code-server and OpenVSCode-Server both allow you to access VS Code via a
browser. OpenVSCode-Server is a direct fork of VS Code with changes comitted
directly while code-server pulls VS Code in via a submodule and makes changes
via patch files.
However, OpenVSCode-Server is scoped at only making VS Code available as-is in
the web browser. code-server contains additional changes to make the self-hosted
experience better (see the next section for details).
## 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.
Specific changes include:
- Password authentication
- The ability to host at sub-paths
- Self-contained web views that do not call out to Microsoft's servers
- The ability to use your own marketplace and collect your own telemetry
- Built-in proxy for accessing ports on the remote machine integrated into
VS Code's ports panel
- Settings are stored on disk like desktop VS Code, instead of in browser
storage (note that state is still stored in browser storage).
- Wrapper process that spawns VS Code on-demand and has a separate CLI
- Notification when updates are available
- [Some other things](https://github.com/coder/code-server/tree/main/patches)
Some of these changes appear very unlikely to ever be adopted by Microsoft.
Some may make their way upstream, further closing the gap, but at the moment it
looks like there will always be some subtle differences.
## What's the difference between code-server and VS Code web?
VS Code web (which can be ran using `code serve-web`) has the same differences
as the Codespaces section above. VS Code web can be a better choice if you need
access to the official Microsoft marketplace.
## Does code-server have any security login validation?
code-server supports setting a single password and limits logins to two per
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)
repository to view community projects and guides with code-server! Feel free to
add your own!
## How do I change the port?
There are two ways to change the port on which code-server runs:
1. with an environment variable e.g. `PORT=3000 code-server`
2. using the flag `--bind-addr` e.g. `code-server --bind-addr localhost:3000`
## How do I hide the coder/coder promotion in Help: Getting Started?
You can pass the flag `--disable-getting-started-override` to `code-server` or
you can set the environment variable `CS_DISABLE_GETTING_STARTED_OVERRIDE=1` or
`CS_DISABLE_GETTING_STARTED_OVERRIDE=true`.
## How do I disable the proxy?
You can pass the flag `--disable-proxy` to `code-server` or
you can set the environment variable `CS_DISABLE_PROXY=1` or
`CS_DISABLE_PROXY=true`.
Note, this option currently only disables the proxy routes to forwarded ports, including
the domain and path proxy routes over HTTP and WebSocket; however, it does not
disable the automatic port forwarding in the VS Code workbench itself. In other words,
user will still see the Ports tab and notifications, but will not be able to actually
use access the ports. It is recommended to set `remote.autoForwardPorts` to `false`
when using the option.
## How do I disable file download?
You can pass the flag `--disable-file-downloads` to `code-server`
## Why do web views not work?
Web views rely on service workers, and service workers are only available in a
secure context, so most likely the answer is that you are using an insecure
context (for example an IP address).
If this happens, in the browser log you will see something like:
> Error loading webview: Error: Could not register service workers: SecurityError: Failed to register a ServiceWorker for scope with script: An SSL certificate error occurred when fetching the script..
To fix this, you must either:
- Access over localhost/127.0.0.1 which is always considered secure.
- Use a domain with a real certificate (for example with Let's Encrypt).
- Use a trusted self-signed certificate with [mkcert](https://mkcert.dev) (or
create and trust a certificate manually).
- Disable security if your browser allows it. For example, in Chromium see
`chrome://flags/#unsafely-treat-insecure-origin-as-secure`
Visit [our enterprise page](https://coder.com) for more information about our
enterprise offerings.

Some files were not shown because too many files have changed in this diff Show More