Compare commits

..

No commits in common. "main" and "v3.6.2" have entirely different histories.
main ... v3.6.2

301 changed files with 17347 additions and 33553 deletions

39
.eslintrc.yaml Normal file
View File

@ -0,0 +1,39 @@
parser: "@typescript-eslint/parser"
env:
browser: true
es6: true # Map, etc.
mocha: 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 # Removes eslint rules that conflict with prettier.
- prettier/@typescript-eslint # Remove conflicts again.
rules:
# 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
eqeqeq: error
import/order:
[error, { alphabetize: { order: "asc" }, groups: [["builtin", "external", "internal"], "parent", "sibling"] }]
no-async-promise-executor: off
settings:
# Does not work with CommonJS unfortunately.
import/ignore:
- env-paths
- xdg-basedir

View File

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

1
.gitattributes vendored
View File

@ -1 +0,0 @@
*.afdesign filter=lfs diff=lfs merge=lfs -text

8
.github/CODEOWNERS vendored
View File

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

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

@ -0,0 +1,28 @@
---
name: Bug report
about: Report a bug and help us improve
title: ""
labels: ""
assignees: ""
---
<!--
Please see https://github.com/cdr/code-server/blob/master/doc/FAQ.md#how-do-i-debug-issues-with-code-server
and include any logging information relevant to the issue.
Please search for existing issues before filing.
If you can reproduce the issue on vanilla VS Code,
please file the issue at the VS Code repository instead.
Provide screenshots if applicable.
Please fill in the issue template and try to be as detailed
and clear as possible!
-->
- Web Browser:
- Local OS:
- Remote OS:
- Remote Architecture:
- `code-server --version`:

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,5 @@
blank_issues_enabled: false
contact_links:
- name: Question?
url: https://github.com/coder/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.
url: https://cdr.co/join-community
- name: Question
url: https://github.com/cdr/code-server/discussions/new?category_id=22503114
about: Ask the community for help

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: cmoog
---
<!--
Details on the code-server extension marketplace are at
https://github.com/cdr/code-server/blob/master/doc/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!
-->

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 +0,0 @@
name: "code-server CodeQL config"

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

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

View File

@ -2,7 +2,5 @@
Please link to the issue this PR solves.
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!
Please make sure the base of your PR is the master branch!
-->
Fixes #

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,293 +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' }}
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:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # 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
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
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
needs: changes
if: needs.changes.outputs.helm == 'true'
steps:
- uses: actions/checkout@v6
- uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # 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
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
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@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
if: success()
with:
token: ${{ secrets.CODECOV_TOKEN }}
build:
name: linux-x64
runs-on: ubuntu-22.04
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
DISABLE_V8_COMPILE_CACHE: 1
VERSION: 0.0.0
VSCODE_TARGET: linux-x64
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- run: sudo apt update && sudo apt install -y libkrb5-dev
- uses: awalsh128/cache-apt-pkgs-action@2c09a5e66da6c8016428a2172bd76e5e4f14bb17 # latest
with:
packages: quilt
version: 1.0
- uses: actions/checkout@v6
with:
submodules: true
- 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
# 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 linux-x64 Code package from cache
id: cache-vscode
uses: actions/cache@v4
with:
path: lib/vscode-reh-web-linux-x64
key: vscode-linux-x64-package-${{ secrets.VSCODE_CACHE_VERSION }}-${{ steps.vscode-rev.outputs.rev }}-${{ hashFiles('patches/*.diff', 'ci/build/build-vscode.sh') }}
- name: Build vscode
if: steps.cache-vscode.outputs.cache-hit != 'true'
run: |
pushd lib/vscode
npm ci
popd
npm run build:vscode
# Push up an artifact containing the linux-x64 release.
- run: KEEP_MODULES=1 npm run release
- run: tar -czf package.tar.gz release
- uses: actions/upload-artifact@v7
with:
name: linux-x64-package
path: ./package.tar.gz
test-e2e:
name: Run e2e tests
runs-on: ubuntu-22.04
needs: [changes, build]
if: needs.changes.outputs.code == 'true' || needs.changes.outputs.deps == 'true' || needs.changes.outputs.ci == '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
- name: Install Playwright OS dependencies
run: |
./test/node_modules/.bin/playwright install-deps
./test/node_modules/.bin/playwright install
- uses: actions/download-artifact@v8
with:
name: linux-x64-package
- run: tar -xzf package.tar.gz
- run: CODE_SERVER_TEST_ENTRY=./release npm run test:e2e
- uses: actions/upload-artifact@v7
if: always()
with:
name: failed-test-videos
path: ./test/test-results
test-e2e-proxy:
name: Run e2e tests behind proxy
runs-on: ubuntu-22.04
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
needs: [changes, build]
if: needs.changes.outputs.code == 'true' || needs.changes.outputs.deps == 'true' || needs.changes.outputs.ci == 'true'
steps:
- name: Cache Caddy
uses: actions/cache@v4
id: caddy-cache
with:
path: |
~/.cache/caddy
key: cache-caddy-2.5.2
- name: Install Caddy
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
- 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
- name: Install Playwright OS dependencies
run: |
./test/node_modules/.bin/playwright install-deps
./test/node_modules/.bin/playwright install
- uses: actions/download-artifact@v8
with:
name: linux-x64-package
- run: tar -xzf package.tar.gz
- 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@v7
if: always()
with:
name: failed-test-videos-proxy
path: ./test/test-results

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

@ -0,0 +1,146 @@
name: ci
on: [push]
jobs:
fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Run ./ci/steps/fmt.sh
uses: ./ci/images/debian10
with:
args: ./ci/steps/fmt.sh
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Run ./ci/steps/lint.sh
uses: ./ci/images/debian10
with:
args: ./ci/steps/lint.sh
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Run ./ci/steps/test.sh
uses: ./ci/images/debian10
with:
args: ./ci/steps/test.sh
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Run ./ci/steps/release.sh
uses: ./ci/images/debian10
with:
args: ./ci/steps/release.sh
- name: Upload npm package artifact
uses: actions/upload-artifact@v2
with:
name: npm-package
path: ./release-npm-package
linux-amd64:
needs: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Download npm package
uses: actions/download-artifact@v2
with:
name: npm-package
path: ./release-npm-package
- name: Run ./ci/steps/release-packages.sh
uses: ./ci/images/centos7
with:
args: ./ci/steps/release-packages.sh
- name: Upload release artifacts
uses: actions/upload-artifact@v2
with:
name: release-packages
path: ./release-packages
linux-arm64:
needs: release
runs-on: ubuntu-arm64-latest
steps:
- uses: actions/checkout@v1
- name: Download npm package
uses: actions/download-artifact@v2
with:
name: npm-package
path: ./release-npm-package
- name: Run ./ci/steps/release-packages.sh
uses: ./ci/images/centos7
with:
args: ./ci/steps/release-packages.sh
- name: Upload release artifacts
uses: actions/upload-artifact@v2
with:
name: release-packages
path: ./release-packages
macos-amd64:
needs: release
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: Download npm package
uses: actions/download-artifact@v2
with:
name: npm-package
path: ./release-npm-package
- run: ./ci/steps/release-packages.sh
env:
# Otherwise we get rate limited when fetching the ripgrep binary.
# For whatever reason only MacOS needs it.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload release artifacts
uses: actions/upload-artifact@v2
with:
name: release-packages
path: ./release-packages
docker-amd64:
runs-on: ubuntu-latest
needs: linux-amd64
steps:
- uses: actions/checkout@v1
- name: Download release package
uses: actions/download-artifact@v2
with:
name: release-packages
path: ./release-packages
- name: Run ./ci/steps/build-docker-image.sh
uses: ./ci/images/debian10
with:
args: ./ci/steps/build-docker-image.sh
- name: Upload release image
uses: actions/upload-artifact@v2
with:
name: release-images
path: ./release-images
docker-arm64:
runs-on: ubuntu-arm64-latest
needs: linux-arm64
steps:
- uses: actions/checkout@v1
- name: Download release package
uses: actions/download-artifact@v2
with:
name: release-packages
path: ./release-packages
- name: Run ./ci/steps/build-docker-image.sh
uses: ./ci/images/centos7
with:
args: ./ci/steps/build-docker-image.sh
- name: Upload release image
uses: actions/upload-artifact@v2
with:
name: release-images
path: ./release-images

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,137 +1,31 @@
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:
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:
npm:
runs-on: ubuntu-latest
env:
TAG: ${{ inputs.version || github.ref_name }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_ENVIRONMENT: "production"
steps:
- name: Set version to tag without leading v
run: |
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
- uses: actions/checkout@v1
- name: Run ./ci/steps/publish-npm.sh
uses: ./ci/images/debian10
with:
node-version-file: .node-version
- uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 # v1.12
with:
repository: "coder/code-server"
tag: ${{ inputs.version || github.ref_name }}
fileName: "package.tar.gz"
out-file-path: "release-npm-package"
- run: tar -xzf release-npm-package/package.tar.gz
- run: |
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
pushd release
npm publish --tag latest --access public
aur:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
GH_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
TAG: ${{ inputs.version || github.ref_name }}
steps:
- name: Set version to tag without leading v
run: |
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- 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
- name: Validate package
uses: heyhusen/archlinux-package-action@c9f94059ccbebe8710d31d582f33ef4e84fe575c # v3.0.0
with:
pkgver: ${{ env.VERSION }}
updpkgsums: true
srcinfo: true
- name: Open PR
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
args: ./ci/steps/publish-npm.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
docker:
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ github.token }}
TAG: ${{ inputs.version || github.ref_name }}
steps:
- name: Set version to tag without leading v
run: |
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- uses: actions/checkout@v6
- uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
- uses: actions/checkout@v1
- name: Run ./ci/steps/push-docker-manifest.sh
uses: ./ci/images/debian10
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 # v1.12
with:
repository: "coder/code-server"
tag: v${{ env.VERSION }}
fileName: "*.deb"
out-file-path: "release-packages"
- uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 # v1.12
with:
repository: "coder/code-server"
tag: v${{ env.VERSION }}
fileName: "*.rpm"
out-file-path: "release-packages"
- run: npm run publish:docker
args: ./ci/steps/push-docker-manifest.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}

View File

@ -1,187 +0,0 @@
name: Draft release
on:
workflow_dispatch:
inputs:
version:
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:
name: ${{ matrix.vscode_target }}
runs-on: ubuntu-latest
container: "python:3.8-slim-buster"
strategy:
matrix:
include:
- prefix: x86_64-linux-gnu
npm_arch: x64
apt_arch: amd64
package_arch: amd64
vscode_target: linux-x64
- prefix: aarch64-linux-gnu
npm_arch: arm64
apt_arch: arm64
package_arch: arm64
vscode_target: linux-arm64
- prefix: arm-linux-gnueabihf
npm_arch: armv7l
apt_arch: armhf
package_arch: armv7l
vscode_target: linux-armhf
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) }}
# Set cross-compiler package arch.
APT_ARCH: ${{ matrix.apt_arch }}
# For downloading the right Node.
npm_config_arch: ${{ matrix.npm_arch }}
# Overrides package architecture.
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
# Overrides VS Code gulp build target.
VSCODE_TARGET: ${{ matrix.vscode_target }}
TAG: ${{ inputs.version || github.ref_name }}
steps:
- 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 $APT_ARCH
apt update && apt install -y --no-install-recommends \
crossbuild-essential-$APT_ARCH \
libx11-dev:$APT_ARCH \
libx11-xcb-dev:$APT_ARCH \
libxkbfile-dev:$APT_ARCH \
libsecret-1-dev:$APT_ARCH \
libkrb5-dev:$APT_ARCH \
ca-certificates \
curl wget rsync gettext-base quilt git
- 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: Set version to tag without leading v
run: |
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- uses: actions/checkout@v6
with:
submodules: true
- 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: npm ci
- run: npm run build
- run: npm run build:vscode
# Platform-agnostic NPM package.
- run: npm run release
if: ${{ matrix.vscode_target == 'linux-x64' }}
- run: tar -czf package.tar.gz release
if: ${{ matrix.vscode_target == 'linux-x64' }}
- uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
if: ${{ matrix.vscode_target == 'linux-x64' }}
with:
draft: true
discussion_category_name: "📣 Announcements"
files: package.tar.gz
# Platform-specific release.
- run: KEEP_MODULES=1 npm run release
- 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/lib/node
- run: npm run package
- uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
draft: true
discussion_category_name: "📣 Announcements"
files: ./release-packages/*
package-macos:
name: ${{ matrix.vscode_target }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: macos-15-intel
vscode_target: darwin-x64
- os: macos-latest
vscode_target: darwin-arm64
env:
VSCODE_TARGET: ${{ matrix.vscode_target }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ inputs.version || github.ref_name }}
steps:
# 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 quilt
- 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: Set version to tag without leading v
run: |
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- uses: actions/checkout@v6
with:
submodules: true
- 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: npm ci
- run: npm run build
- run: npm run build:vscode
- run: KEEP_MODULES=1 npm run release
- run: npm run test:native
- run: npm run package
- uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
draft: true
discussion_category_name: "📣 Announcements"
files: ./release-packages/*

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@97e0b3872f55f89b95b2f65b3dbab56962816478
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@97e0b3872f55f89b95b2f65b3dbab56962816478
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"

18
.gitignore vendored
View File

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

1
.gitmodules vendored
View File

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

1
.ignore Normal file
View File

@ -0,0 +1 @@
lib

View File

@ -1 +0,0 @@
22.22.1

1
.nvmrc
View File

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

View File

@ -1,8 +0,0 @@
lib
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

@ -1,151 +0,0 @@
{
"$schema": "https://aka.ms/codetour-schema",
"title": "Contributing",
"steps": [
{
"directory": "src",
"line": 1,
"description": "Hello world! code-server's source code lives here in `src` (see the explorer). It's broadly arranged into browser code, Node code, and code shared between both."
},
{
"file": "src/node/entry.ts",
"line": 157,
"description": "code-server begins execution here. CLI arguments are parsed, special flags like --help are handled, then the HTTP server is started."
},
{
"file": "src/node/cli.ts",
"line": 28,
"description": "This describes all of the code-server CLI options and how they will be parsed."
},
{
"file": "src/node/cli.ts",
"line": 233,
"description": "Here's the actual CLI parser."
},
{
"file": "src/node/settings.ts",
"line": 1,
"description": "code-server maintains a settings file that is read and written here."
},
{
"file": "src/node/app.ts",
"line": 11,
"description": "The core of code-server are HTTP and web socket servers which are created here. They provide authentication, file access, an API, and serve web-based applications like VS Code."
},
{
"file": "src/node/wsRouter.ts",
"line": 38,
"description": "This is an analog to Express's Router that handles web socket routes."
},
{
"file": "src/node/http.ts",
"line": 1,
"description": "This file provides various HTTP utility functions."
},
{
"file": "src/node/coder_cloud.ts",
"line": 9,
"description": "The cloud agent spawned here provides the --link functionality."
},
{
"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)"
},
{
"file": "src/node/socket.ts",
"line": 13,
"description": "We pass sockets to child processes, however we can't pass TLS sockets so when code-server is handling TLS (via --cert) we use this to create a proxy that can be passed to the child."
},
{
"directory": "src/node/routes",
"line": 1,
"description": "code-server's routes live here in `src/node/routes` (see the explorer)."
},
{
"file": "src/node/routes/index.ts",
"line": 123,
"description": "The architecture of code-server allows it to be extended with applications via plugins. Each application is registered at its own route and handles requests at and below that route. Currently we have only VS Code (although it is not yet actually split out into a plugin)."
},
{
"file": "src/node/plugin.ts",
"line": 103,
"description": "The previously mentioned plugins are loaded here."
},
{
"file": "src/node/routes/apps.ts",
"line": 12,
"description": "This provides a list of the applications registered with code-server."
},
{
"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)"
},
{
"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)"
},
{
"file": "src/node/proxy.ts",
"line": 4,
"description": "Both the domain and path proxy use the single proxy instance created here."
},
{
"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)"
},
{
"file": "src/node/routes/login.ts",
"line": 46,
"description": "code-server supports a password-based login here."
},
{
"file": "src/node/routes/static.ts",
"line": 16,
"description": "This serves static assets. Anything under the code-server directory can be fetched. Anything outside requires authentication."
},
{
"file": "src/node/routes/update.ts",
"line": 10,
"description": "This endpoint lets you query for the latest code-server version. It's used to power the update popup you see in VS Code."
},
{
"file": "src/node/routes/vscode.ts",
"line": 15,
"description": "This is the endpoint that serves VS Code's HTML, handles VS Code's websockets, and handles a few VS Code-specific endpoints for fetching static files."
},
{
"file": "src/node/vscode.ts",
"line": 13,
"description": "The actual VS Code spawn and initialization is handled here. VS Code runs in a separate child process. We communicate via IPC and by passing it web sockets."
},
{
"file": "src/browser/serviceWorker.ts",
"line": 1,
"description": "The service worker only exists to provide PWA functionality."
},
{
"directory": "src/browser/pages",
"line": 1,
"description": "HTML, CSS, and JavaScript for each page lives in here `src/browser/pages` (see the explorer). Currently our HTML uses a simple search and replace template system with variables that {{LOOK_LIKE_THIS}}."
},
{
"file": "src/browser/pages/vscode.html",
"line": 1,
"description": "The VS Code HTML is based off VS Code's own `workbench.html`."
},
{
"directory": "src/browser/media",
"line": 1,
"description": "Static images and the manifest live here in `src/browser/media` (see the explorer)."
},
{
"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."
}
]
}

View File

@ -1,26 +0,0 @@
{
"$schema": "https://aka.ms/codetour-schema",
"title": "Start Development",
"steps": [
{
"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"
},
{
"file": "src/node/app.ts",
"line": 68,
"description": "## Visit the web server\n\nIf all goes well, you should see something like this in your terminal. code-server should be live in development mode.\n\n---\n```bash\n[2020-12-09T21:03:37.156Z] info code-server 3.7.4 development\n[2020-12-09T21:03:37.157Z] info Using user-data-dir ~/.local/share/code-server\n[2020-12-09T21:03:37.165Z] info Using config file ~/.config/code-server/config.yaml\n[2020-12-09T21:03:37.165Z] info HTTP server listening on http://127.0.0.1:8080 \n[2020-12-09T21:03:37.165Z] info - Authentication is enabled\n[2020-12-09T21:03:37.165Z] info - Using password from ~/.config/code-server/config.yaml\n[2020-12-09T21:03:37.165Z] info - Not serving HTTPS\n```\n\n---\n\nIf you have the default configuration, you can access it at [http://localhost:8080](http://localhost:8080)."
},
{
"file": "src/browser/pages/login.html",
"line": 26,
"description": "## Make a change\n\nThis is the login page, let's make a change and see it update on our web server! Perhaps change the text :)\n\n```html\n<div class=\"sub\">Modifying the login page 👨🏼‍💻</div>\n```\n\nReminder, you can likely preview at [http://localhost:8080](http://localhost:8080)"
},
{
"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)"
}
]
}

File diff suppressed because it is too large Load Diff

64
README.md Normal file
View File

@ -0,0 +1,64 @@
# 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)
Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and access it in the browser.
![Screenshot](./doc/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
## Getting Started
There are two ways to 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](./doc/install.md) for instructions applicable to most use cases
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](./doc/guide.md) guide.
### Alpha Program 🐣
We're working on a cloud platform that makes deploying and managing code-server easier. Consider [joining our alpha program](https://codercom.typeform.com/to/U4IKyv0W) if you don't want to worry about
- TLS
- Authentication
- Port Forwarding
## FAQ
See [./doc/FAQ.md](./doc/FAQ.md).
## Want to help?
See [CONTRIBUTING](./doc/CONTRIBUTING.md) for details.
## Hiring
We ([@cdr](https://github.com/cdr)) are looking for engineers to help [maintain
code-server](https://jobs.lever.co/coder/e40becde-2cbd-4885-9029-e5c7b0a734b8), innovate on open source, and streamline dev workflows.
Our main office is in Austin, Texas. Remote is ok as long as
you're in North America or Europe.
Please get in [touch](mailto:jobs@coder.com) with your resume/GitHub if interested.
## 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
}
}

146
ci/README.md Normal file
View File

@ -0,0 +1,146 @@
# ci
This directory contains scripts used for code-server's continuous integration infrastructure.
Some of these scripts contain more detailed documentation and options
in header comments.
Any file or directory in this subdirectory should be documented here.
- [./ci/lib.sh](./lib.sh)
- Contains code duplicated across these scripts.
## Publishing a release
Make sure you have `$GITHUB_TOKEN` set and [hub](https://github.com/github/hub) installed.
1. Update the version of code-server and make a PR.
1. Update in `package.json`
2. Update in [./doc/install.md](../doc/install.md)
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.
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. Make sure the github release tag is the commit with the artifacts. This is a bug in
`hub` where uploading assets in step 5 will break the tag.
8. 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`.
9. Update the AUR package.
- Instructions on updating the AUR package are at [cdr/code-server-aur](https://github.com/cdr/code-server-aur).
10. Wait for the npm package to be published.
11. Update the homebrew package.
- Send a pull request to [homebrew-core](https://github.com/Homebrew/homebrew-core) with the URL in the [formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/code-server.rb) updated.
## dev
This directory contains scripts used for the development of code-server.
- [./ci/dev/image](./dev/image)
- See [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md) for docs on the development container.
- [./ci/dev/fmt.sh](./dev/fmt.sh) (`yarn fmt`)
- Runs formatters.
- [./ci/dev/lint.sh](./dev/lint.sh) (`yarn lint`)
- Runs linters.
- [./ci/dev/test.sh](./dev/test.sh) (`yarn test`)
- Runs tests.
- [./ci/dev/ci.sh](./dev/ci.sh) (`yarn ci`)
- Runs `yarn fmt`, `yarn lint` and `yarn test`.
- [./ci/dev/vscode.sh](./dev/vscode.sh) (`yarn vscode`)
- Ensures [./lib/vscode](../lib/vscode) is cloned, patched and dependencies are installed.
- [./ci/dev/patch-vscode.sh](./dev/patch-vscode.sh) (`yarn vscode:patch`)
- Applies [./ci/dev/vscode.patch](./dev/vscode.patch) to [./lib/vscode](../lib/vscode).
- [./ci/dev/diff-vscode.sh](./dev/diff-vscode.sh) (`yarn vscode:diff`)
- Diffs [./lib/vscode](../lib/vscode) into [./ci/dev/vscode.patch](./dev/vscode.patch).
- [./ci/dev/vscode.patch](./dev/vscode.patch)
- Our patch of VS Code, see [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md#vs-code-patch).
- Generate it with `yarn vscode:diff` and apply with `yarn vscode:patch`.
- [./ci/dev/watch.ts](./dev/watch.ts) (`yarn watch`)
- Starts a process to build and launch code-server and restart on any code changes.
- Example usage in [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md).
## build
This directory contains the scripts used to build and release code-server.
You can disable minification by setting `MINIFY=`.
- [./ci/build/build-code-server.sh](./build/build-code-server.sh) (`yarn build`)
- Builds code-server into `./out` and bundles the frontend into `./dist`.
- [./ci/build/build-vscode.sh](./build/build-vscode.sh) (`yarn build:vscode`)
- Builds vscode into `./lib/vscode/out-vscode`.
- [./ci/build/build-release.sh](./build/build-release.sh) (`yarn release`)
- Bundles the output of the above two scripts into a single node module at `./release`.
- [./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.
- Will also `git reset --hard lib/vscode`.
- 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) (`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) (`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)
- Used to configure [nfpm](https://github.com/goreleaser/nfpm) to generate `.deb` and `.rpm`.
- [./ci/build/code-server-nfpm.sh](./build/code-server-nfpm.sh)
- Entrypoint script for code-server for `.deb` and `.rpm`.
- [./ci/build/code-server.service](./build/code-server.service)
- systemd user service packaged into the `.deb` and `.rpm`.
- [./ci/build/release-github-draft.sh](./build/release-github-draft.sh) (`yarn release:github-draft`)
- Uses [hub](https://github.com/github/hub) to create a draft release with a template description.
- [./ci/build/release-github-assets.sh](./build/release-github-assets.sh) (`yarn release:github-assets`)
- Downloads the release-package artifacts for the current commit from CI.
- Uses [hub](https://github.com/github/hub) to upload the artifacts to the release
specified in `package.json`.
- [./ci/build/npm-postinstall.sh](./build/npm-postinstall.sh)
- Post install script for the npm package.
- Bundled by`yarn release`.
## release-image
This directory contains the release docker container image.
- [./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
This directory contains the images for CI.
## steps
This directory contains the scripts used in CI.
Helps avoid clobbering the CI configuration.
- [./steps/fmt.sh](./steps/fmt.sh)
- Runs `yarn fmt` after ensuring VS Code is patched.
- [./steps/lint.sh](./steps/lint.sh)
- Runs `yarn lint` after ensuring VS Code is patched.
- [./steps/test.sh](./steps/test.sh)
- Runs `yarn test` after ensuring VS Code is patched.
- [./steps/release.sh](./steps/release.sh)
- Runs the release process.
- Generates the npm package at `./release`.
- [./steps/release-packages.sh](./steps/release-packages.sh)
- Takes the output of the previous script and generates a standalone release and
release packages into `./release-packages`.
- [./steps/publish-npm.sh](./steps/publish-npm.sh)
- Grabs the `npm-package` release artifact for the current commit and publishes it on npm.
- [./steps/build-docker-image.sh](./steps/build-docker-image.sh)
- Builds the docker image and then saves it into `./release-images/code-server-$ARCH-$VERSION.tar`.
- [./steps/push-docker-manifest.sh](./steps/push-docker-manifest.sh)
- Loads all images in `./release-images` and then builds and pushes a multi architecture
docker manifest for the amd64 and arm64 images to `codercom/code-server:$VERSION` and
`codercom/code-server:latest`.

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,21 @@ 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
OS="$(uname | tr '[:upper:]' '[:lower:]')"
curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent
chmod +x ./lib/coder-cloud-agent
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,18 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
# Given a release found in $RELEASE_PATH, generate a deb, rpm, and tarball each
# named after $ARCH (derived from uname -m but can be overridden for
# cross-compilation) and $OS (derived from uname and cannot be overridden) 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
VERSION=$(jq -r .version "$RELEASE_PATH/package.json")
export VERSION # for nfpm to use
mkdir -p release-packages
@ -26,9 +20,9 @@ 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_PATH/$release_name/" "$RELEASE_PATH"
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_PATH/$release_name/" "$RELEASE_PATH"
tar -czf "release-packages/$release_name.tar.gz" -s "/^release-standalone/$release_name/" release-standalone
fi
echo "done (release-packages/$release_name)"
@ -46,20 +40,11 @@ release_gcp() {
# Generates deb and rpm packages.
release_nfpm() {
local nfpm_config
export NFPM_ARCH
NFPM_ARCH="$(get_nfpm_arch deb "$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"
NFPM_ARCH="$(get_nfpm_arch rpm "$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,164 +1,101 @@
#!/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 can publish to NPM.
# 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.
# Note these modules will be for the platform that built them, making the result
# no longer generic (it can still be published though as the modules will be
# ignored when pushing).
# 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"
if [ "$KEEP_MODULES" = 1 ]; then
# Copy Node. Package managers may shim their own "node" wrapper into the
# PATH, so run node and ask it for its true path.
local node_path
node_path="$(node -p process.execPath)"
rsync "$node_path" "$RELEASE_PATH/lib/node"
chmod 755 "$RELEASE_PATH/lib/node"
# Copy the code-server launcher.
mkdir -p "$RELEASE_PATH/bin"
rsync ./ci/build/code-server.sh "$RELEASE_PATH/bin/code-server"
chmod 755 "$RELEASE_PATH/bin/code-server"
# Delete the extra bin scripts.
rm "$RELEASE_PATH/lib/vscode/bin/remote-cli/code-darwin.sh"
rm "$RELEASE_PATH/lib/vscode/bin/remote-cli/code-linux.sh"
rm "$RELEASE_PATH/lib/vscode/bin/helpers/browser-darwin.sh"
rm "$RELEASE_PATH/lib/vscode/bin/helpers/browser-linux.sh"
if [ "$OS" != windows ] ; then
rm "$RELEASE_PATH/lib/vscode/bin/remote-cli/code.cmd"
rm "$RELEASE_PATH/lib/vscode/bin/helpers/browser.cmd"
fi
fi
# code-server exports types which can be imported and used by plugins. Those
# types import ipc.d.ts but it isn't included in the final vscode build so
# we'll copy it ourselves here.
mkdir -p "$RELEASE_PATH/lib/vscode/src/vs/server"
rsync ./lib/vscode/src/vs/server/ipc.d.ts "$RELEASE_PATH/lib/vscode/src/vs/server"
}
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"
# Adds the commit to package.json
jq --slurp '(.[0] | del(.scripts,.jest,.devDependencies)) * .[1]' package.json <(
jq --slurp '.[0] * .[1]' package.json <(
cat << EOF
{
"version": "$(jq -r .codeServerVersion "./lib/vscode-reh-web-$VSCODE_TARGET/product.json")",
"commit": "$(git rev-parse HEAD)",
"scripts": {
"postinstall": "sh ./postinstall.sh"
"postinstall": "./postinstall.sh"
}
}
EOF
) > "$RELEASE_PATH/package.json"
mv npm-shrinkwrap.json "$RELEASE_PATH"
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"
rsync "$VSCODE_SRC_PATH/resources/linux/code.png" "$VSCODE_OUT_PATH/resources/linux/code.png"
# 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
rsync "${rsync_opts[@]}" "./lib/vscode-reh-web-$VSCODE_TARGET/" "$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
popd
# 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"
}
main "$@"

View File

@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "${0}")/../.."
source ./ci/lib.sh
rsync "$RELEASE_PATH/" "$RELEASE_PATH-standalone"
RELEASE_PATH+=-standalone
# 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="$(yarn -s node <<< 'console.info(process.execPath)')"
mkdir -p "$RELEASE_PATH/bin"
rsync ./ci/build/code-server.sh "$RELEASE_PATH/bin/code-server"
rsync "$node_path" "$RELEASE_PATH/lib/node"
ln -s "./bin/code-server" "$RELEASE_PATH/code-server"
ln -s "./lib/node" "$RELEASE_PATH/node"
cd "$RELEASE_PATH"
yarn --production --frozen-lockfile
}
main "$@"

View File

@ -6,151 +6,16 @@ set -euo pipefail
# MINIFY controls whether a minified version of vscode is built.
MINIFY=${MINIFY-true}
fix-bin-script() {
local script="lib/vscode-reh-web-$VSCODE_TARGET/bin/$1"
sed -i.bak "s/@@VERSION@@/$(vscode_version)/g" "$script"
sed -i.bak "s/@@COMMIT@@/$BUILD_SOURCEVERSION/g" "$script"
sed -i.bak "s/@@APPNAME@@/code-server/g" "$script"
# 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' "$script"
sed -i.bak 's/ROOT\/out/VSROOT\/out/g' "$script"
# 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' "$script"
# Fix Node path on Windows.
sed -i.bak 's/^set ROOT_DIR=\(.*\)$/set ROOT_DIR=%~dp0..\\..\\..\\..\r\nset VSROOT_DIR=\1/g' "$script"
sed -i.bak 's/%ROOT_DIR%\\out/%VSROOT_DIR%\\out/g' "$script"
chmod +x "$script"
rm "$script.bak"
}
copy-bin-script() {
cp "lib/vscode/resources/server/bin/$1" "lib/vscode-reh-web-$VSCODE_TARGET/bin/$1"
fix-bin-script "$1"
}
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
yarn gulp 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
npm run gulp core-ci
npm run gulp "vscode-reh-web-$VSCODE_TARGET${MINIFY:+-min}-ci"
# 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-$VSCODE_TARGET"
# 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
# Set vars and fix paths.
case $OS in
windows)
fix-bin-script remote-cli/code.cmd
fix-bin-script helpers/browser.cmd
;;
*)
fix-bin-script remote-cli/code-server
fix-bin-script helpers/browser.sh
;;
esac
# Include bin scripts for other platforms so we can use the right one in the
# NPM post-install.
# These provide a `code-server` command in the integrated terminal to open
# files in the current instance.
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.
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,11 @@ main() {
source ./ci/lib.sh
git clean -Xffd
pushd lib/vscode
git clean -xffd
git reset --hard
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,25 +1,19 @@
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:
- src: ./ci/build/code-server-nfpm.sh
dst: /usr/bin/code-server
- src: ./ci/build/code-server@.service
dst: /usr/lib/systemd/system/code-server@.service
- src: ./ci/build/code-server-user.service
dst: /usr/lib/systemd/user/code-server.service
- src: ./release/*
dst: /usr/lib/code-server
files:
./ci/build/code-server-nfpm.sh: /usr/bin/code-server
./ci/build/code-server@.service: /usr/lib/systemd/system/code-server@.service
# Only included for backwards compat with previous releases that shipped
# the user service. See #1997
./ci/build/code-server-user.service: /usr/lib/systemd/user/code-server.service
./release-standalone/**/*: "/usr/lib/code-server/"

View File

@ -1,148 +1,55 @@
#!/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" ;;
esac
}
# 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)"
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://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -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/doc/npm.md"
exit 1
fi
}
vscode_install() {
echo 'Installing Code dependencies...'
vscode_yarn() {
cd lib/vscode
if ! install_with_yarn_or_npm; then
return 1
fi
symlink_bin_script remote-cli code code-server
symlink_bin_script helpers browser browser .sh
yarn --production --frozen-lockfile
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,21 @@
#!/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})
for i in "${!assets[@]}"; do
assets[$i]="--attach=${assets[$i]}"
done
EDITOR=true hub release edit --draft "${assets[@]}" "v$VERSION"
}
main "$@"

View File

@ -0,0 +1,22 @@
#!/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
hub release create \
--file - \
-t "$(git rev-parse HEAD)" \
--draft "${assets[@]}" "v$VERSION" << EOF
v$VERSION
VS Code v$(vscode_version)
- Summarize changes here with references to issues
EOF
}
main "$@"

View File

@ -0,0 +1,27 @@
#!/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."
./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension ms-python.python
local installed_extensions
installed_extensions="$(./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)"
if [[ $installed_extensions != "ms-python.python" ]]; then
echo "Unexpected output from listing extensions:"
echo "$installed_extensions"
exit 1
fi
echo "Standalone release works correctly."
}
main "$@"

View File

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

12
ci/dev/diff-vscode.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
cd ./lib/vscode
git add -A
git diff HEAD --full-index > ../../ci/dev/vscode.patch
}
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 "$@"

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

@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
shfmt -i 2 -w -sr $(git ls-files "*.sh")
local prettierExts
prettierExts=(
"*.js"
"*.ts"
"*.tsx"
"*.html"
"*.json"
"*.css"
"*.md"
"*.toml"
"*.yaml"
"*.yml"
)
prettier --write --loglevel=warn $(git ls-files "${prettierExts[@]}")
doctoc --title '# FAQ' doc/FAQ.md > /dev/null
doctoc --title '# Setup Guide' doc/guide.md > /dev/null
doctoc --title '# Install' doc/install.md > /dev/null
doctoc --title '# npm Install Requirements' doc/npm.md > /dev/null
doctoc --title '# Contributing' doc/CONTRIBUTING.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 +0,0 @@
#!/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/
#
# 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
# 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
# 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
}
main "$@"

31
ci/dev/image/run.sh Executable file
View File

@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../../.."
source ./ci/lib.sh
mkdir -p .home
docker run \
-it \
--rm \
-v "$PWD:/src" \
-e HOME="/src/.home" \
-e USER="coder" \
-e GITHUB_TOKEN \
-e KEEP_MODULES \
-e MINIFY \
-w /src \
-p 127.0.0.1:8080:8080 \
-u "$(id -u):$(id -g)" \
-e CI \
"$(docker_build ./ci/images/"${IMAGE-debian10}")" \
"$@"
}
docker_build() {
docker build "$@" >&2
docker build -q "$@"
}
main "$@"

View File

@ -3,7 +3,11 @@ set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files '*.sh' | grep -v 'lib/vscode')
eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js")
stylelint $(git ls-files "*.css")
tsc --noEmit
shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh")
}
main "$@"

11
ci/dev/patch-vscode.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
cd ./lib/vscode
git apply ../../ci/dev/vscode.patch
}
main "$@"

View File

@ -1,38 +0,0 @@
#!/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
}
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 +0,0 @@
#!/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 "$@"
}
main "$@"

View File

@ -1,39 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
help() {
echo >&2 " You can build the release with 'KEEP_MODULES=1 npm run release'"
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_PATH 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/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 release with 'KEEP_MODULES=1 npm run release'"
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_PATH 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/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

@ -1,15 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
# 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"
}
main "$@"

10
ci/dev/test.sh Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
mocha -r ts-node/register ./test/*.test.ts
}
main "$@"

3546
ci/dev/vscode.patch Normal file

File diff suppressed because it is too large Load Diff

22
ci/dev/vscode.sh Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
# 1. Ensures VS Code is cloned.
# 2. Patches it.
# 3. Installs it.
main() {
cd "$(dirname "$0")/../.."
git submodule update --init
# If the patch fails to apply, then it's likely already applied
yarn vscode:patch &> /dev/null || true
(
cd lib/vscode
# Install VS Code dependencies.
yarn ${CI+--frozen-lockfile}
)
}
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,23 +0,0 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

View File

@ -1,23 +0,0 @@
apiVersion: v2
name: code-server
description: A Helm chart for coder/code-server
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
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.33.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: 4.109.5

View File

@ -1,24 +0,0 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "code-server.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "code-server.fullname" . }}'
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 }}
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
{{- end }}
Administrator credentials:
Password: echo $(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "code-server.fullname" . }} -o jsonpath="{.data.password}" | base64 --decode)

View File

@ -1,63 +0,0 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "code-server.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "code-server.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "code-server.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Common labels
*/}}
{{- define "code-server.labels" -}}
helm.sh/chart: {{ include "code-server.chart" . }}
{{ include "code-server.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "code-server.selectorLabels" -}}
app.kubernetes.io/name: {{ include "code-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "code-server.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "code-server.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}

View File

@ -1,192 +0,0 @@
apiVersion: apps/v1
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 }}
spec:
replicas: {{ .Values.replicaCount | default 1 }}
strategy:
type: Recreate
selector:
matchLabels:
{{- include "code-server.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "code-server.selectorLabels" . | nindent 8 }}
{{- if .Values.podAnnotations }}
annotations: {{- toYaml .Values.podAnnotations | nindent 8 }}
{{- end }}
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 }}
- name: init-chmod-data
image: busybox:latest
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- |
chown -R {{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /home/coder
securityContext:
runAsUser: {{ .Values.volumePermissions.securityContext.runAsUser }}
volumeMounts:
- 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}}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.securityContext.enabled }}
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 }}
{{- end }}
- name: PASSWORD
valueFrom:
secretKeyRef:
{{- if .Values.existingSecret }}
name: {{ .Values.existingSecret }}
{{- else }}
name: {{ template "code-server.fullname" . }}
{{- end }}
key: password
{{- if .Values.extraArgs }}
args:
{{ toYaml .Values.extraArgs | indent 10 }}
{{- end }}
volumeMounts:
- name: data
mountPath: /home/coder
{{- range .Values.extraConfigmapMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- range .Values.extraSecretMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- range .Values.extraVolumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
ports:
- name: http
containerPort: 8080
protocol: TCP
{{- range .Values.extraPorts }}
- name: {{ .name }}
containerPort: {{ .port }}
protocol: {{ .protocol }}
{{- end }}
{{- if ne .Values.livenessProbe.enabled false }}
livenessProbe:
httpGet:
path: /healthz
port: http
{{- end }}
{{- if ne .Values.readinessProbe.enabled false }}
readinessProbe:
httpGet:
path: /healthz
port: http
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- tpl . $ | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ template "code-server.serviceAccountName" . }}
volumes:
- name: data
{{- if .Values.persistence.enabled }}
{{- if not .Values.persistence.hostPath }}
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim | default (include "code-server.fullname" .) }}
{{- else }}
hostPath:
path: {{ .Values.persistence.hostPath }}
type: Directory
{{- end -}}
{{- else }}
emptyDir: {}
{{- end -}}
{{- range .Values.extraSecretMounts }}
- name: {{ .name }}
secret:
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 }}
hostPath:
path: {{ .hostPath }}
type: Directory
{{- else }}
emptyDir:
{{- toYaml .emptyDir | nindent 10 }}
{{- end }}
{{- end }}

View File

@ -1,63 +0,0 @@
{{- 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 -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "code-server.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.ingressClassName }}
ingressClassName: {{ .Values.ingress.ingressClassName }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- 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:
paths:
{{- range .paths }}
- path: {{ . }}
backend:
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -1,26 +0,0 @@
{{- if and (and .Values.persistence.enabled (not .Values.persistence.existingClaim)) (not .Values.persistence.hostPath) }}
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ include "code-server.fullname" . }}
namespace: {{ .Release.Namespace }}
{{- with .Values.persistence.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
labels:
{{- include "code-server.labels" . | nindent 4 }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- if .Values.persistence.storageClass }}
{{- if (eq "-" .Values.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistence.storageClass }}"
{{- end }}
{{- end }}
{{- end }}

View File

@ -1,17 +0,0 @@
{{- if not .Values.existingSecret }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "code-server.fullname" . }}
annotations:
"helm.sh/hook": "pre-install"
labels:
{{- include "code-server.labels" . | nindent 4 }}
type: Opaque
data:
{{- if .Values.password }}
password: "{{ .Values.password | b64enc }}"
{{- else }}
password: "{{ randAlphaNum 24 | b64enc }}"
{{- end }}
{{- end }}

View File

@ -1,22 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "code-server.fullname" . }}
labels:
{{- include "code-server.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
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

@ -1,8 +0,0 @@
{{- if or .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
{{- include "code-server.labels" . | nindent 4 }}
name: {{ template "code-server.serviceAccountName" . }}
{{- end -}}

View File

@ -1,15 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "code-server.fullname" . }}-test-connection"
labels:
{{- include "code-server.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "code-server.fullname" . }}:{{ .Values.service.port }}/healthz']
restartPolicy: Never

View File

@ -1,232 +0,0 @@
# Default values for code-server.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: codercom/code-server
tag: '4.109.5'
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
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# 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: ""
service:
type: ClusterIP
port: 8080
ingress:
enabled: false
#annotations:
# kubernetes.io/tls-acme: "true"
#hosts:
# - host: code-server.example.loc
# paths:
# - /
ingressClassName: ""
#tls:
# - secretName: code-server
# hosts:
# - code-server.example.loc
# 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).
# Optional additional environment variables
extraVars: []
# - name: DISABLE_TELEMETRY
# value: "true"
# if dind is desired:
# - name: DOCKER_HOST
# value: "tcp://localhost:2376"
##
## Init containers parameters:
## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup
##
volumePermissions:
enabled: true
securityContext:
runAsUser: 0
## Pod Security Context
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
##
securityContext:
enabled: true
fsGroup: 1000
runAsUser: 1000
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 1000Mi
livenessProbe:
enabled: true
readinessProbe:
enabled: true
nodeSelector: {}
tolerations: []
affinity: {}
## Persist data to a persistent volume
persistence:
enabled: true
## code-server data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
accessMode: ReadWriteOnce
size: 10Gi
annotations: {}
# 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
## 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
## Additional code-server secret mounts
extraSecretMounts: []
# - name: secret-files
# mountPath: /etc/secrets
# subPath: private.key # (optional)
# secretName: code-server-secret-files
# readOnly: true
## Additional code-server volume mounts
extraVolumeMounts: []
# - name: extra-volume
# mountPath: /mnt/volume
# readOnly: true
# existingClaim: volume-claim
# hostPath: ""
# emptyDir: {}
extraConfigmapMounts: []
# - name: certs-configmap
# mountPath: /etc/code-server/ssl/
# subPath: certificates.crt # (optional)
# configMap: certs-configmap
# readOnly: true
extraPorts: []
# - name: minecraft
# port: 25565
# protocol: tcp

View File

@ -0,0 +1,32 @@
FROM centos:7
ARG NODE_VERSION=v12.18.4
RUN ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')" && \
curl -fsSL "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-linux-$ARCH.tar.xz" | tar -C /usr/local -xJ && \
mv "/usr/local/node-$NODE_VERSION-linux-$ARCH" "/usr/local/node-$NODE_VERSION"
ENV PATH=/usr/local/node-$NODE_VERSION/bin:$PATH
RUN npm install -g yarn
RUN yum groupinstall -y 'Development Tools'
RUN yum install -y python2 libsecret-devel libX11-devel libxkbfile-devel
RUN npm config set python python2
RUN yum install -y epel-release && yum install -y jq
RUN yum install -y rsync
# Copied from ../debian10/Dockerfile
# Install Go.
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \
curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz
ENV GOPATH=/gopath
# Ensures running this image as another user works.
RUN mkdir -p $GOPATH && chmod -R 777 $GOPATH
ENV PATH=/usr/local/go/bin:$GOPATH/bin:$PATH
# Install Go dependencies
ENV GO111MODULE=on
RUN go get mvdan.cc/sh/v3/cmd/shfmt
RUN go get github.com/goreleaser/nfpm/cmd/nfpm
RUN curl -fsSL https://get.docker.com | sh

View File

@ -0,0 +1,48 @@
FROM debian:10
RUN apt-get update
# Needed for debian repositories added below.
RUN apt-get install -y curl gnupg
# Installs node.
RUN curl -fsSL https://deb.nodesource.com/setup_12.x | bash - && \
apt-get install -y nodejs
# Installs yarn.
RUN curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
apt-get update && apt-get install -y yarn
# Installs VS Code build deps.
RUN apt-get install -y build-essential \
libsecret-1-dev \
libx11-dev \
libxkbfile-dev
# Installs envsubst.
RUN apt-get install -y gettext-base
# Misc build dependencies.
RUN apt-get install -y git rsync unzip jq
# Installs shellcheck.
RUN curl -fsSL https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.$(uname -m).tar.xz | \
tar -xJ && \
mv shellcheck*/shellcheck /usr/local/bin && \
rm -R shellcheck*
# Install Go.
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \
curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz
ENV GOPATH=/gopath
# Ensures running this image as another user works.
RUN mkdir -p $GOPATH && chmod -R 777 $GOPATH
ENV PATH=/usr/local/go/bin:$GOPATH/bin:$PATH
# Install Go dependencies
ENV GO111MODULE=on
RUN go get mvdan.cc/sh/v3/cmd/shfmt
RUN go get github.com/goreleaser/nfpm/cmd/nfpm
RUN curl -fsSL https://get.docker.com | sh

124
ci/lib.sh
View File

@ -1,5 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail
pushd() {
builtin pushd "$@" > /dev/null
@ -9,77 +8,88 @@ popd() {
builtin popd > /dev/null
}
pkg_json_version() {
jq -r .version package.json
}
vscode_version() {
jq -r .version lib/vscode/package.json
}
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)
echo amd64
;;
*)
echo "unknown architecture $(uname -a)"
exit 1
;;
esac
echo "$cpu"
}
curl() {
command curl -H "Authorization: token $GITHUB_TOKEN" "$@"
}
# Grabs the most recent ci.yaml github workflow run that was successful and triggered from the same commit being pushd.
# This will contain the artifacts we want.
# https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs
get_artifacts_url() {
curl -fsSL 'https://api.github.com/repos/cdr/code-server/actions/workflows/ci.yaml/runs?status=success&event=push' | jq -r ".workflow_runs[] | select(.head_sha == \"$(git rev-parse HEAD)\") | .artifacts_url" | head -n 1
}
# Grabs the artifact's download url.
# https://developer.github.com/v3/actions/artifacts/#list-workflow-run-artifacts
get_artifact_url() {
local artifact_name="$1"
curl -fsSL "$(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)"
curl -fsSL "$(get_artifact_url "$artifact_name")" > "$tmp_file"
unzip -q -o "$tmp_file" -d "$dst"
rm "$tmp_file"
}
rsync() {
command rsync -a --del "$@"
}
if [[ ! ${ARCH-} ]]; then
ARCH=$(arch)
export ARCH
fi
if [[ ! ${OS-} ]]; then
OS=$(os)
export OS
fi
VERSION="$(pkg_json_version)"
export VERSION
ARCH="$(arch)"
export ARCH
OS=$(os)
export OS
# RELEASE_PATH is the destination directory for the release from the root.
# Defaults to release
if [[ ! ${RELEASE_PATH-} ]]; then
RELEASE_PATH="release"
export RELEASE_PATH
fi
nodeOS() {
osname=$OS
case $osname in
macos) osname=darwin ;;
windows) osname=win32 ;;
esac
echo "$osname"
}
nodeArch() {
cpu=$ARCH
case $cpu in
amd64) cpu=x64 ;;
esac
echo "$cpu"
}
# See gulpfile.reh.ts for available targets.
if [[ ! ${VSCODE_TARGET-} ]]; then
VSCODE_TARGET="$(nodeOS)-$(nodeArch)"
export VSCODE_TARGET
fi
RELEASE_PATH="${RELEASE_PATH-release}"

View File

@ -1,29 +1,19 @@
# syntax=docker/dockerfile:experimental
ARG BASE=debian:13
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 \
htop \
locales \
lsb-release \
man-db \
man \
nano \
openssh-client \
git \
procps \
ssh \
sudo \
vim-tiny \
wget \
zsh \
&& git lfs install \
vim \
lsb-release \
&& rm -rf /var/lib/apt/lists/*
# https://wiki.debian.org/Locale#Manually
@ -31,25 +21,22 @@ 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 chsh -s /bin/bash
ENV SHELL=/bin/bash
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 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.4.1/fixuid-0.4.1-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,118 +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-13",
"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-13" {
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("trixie"),
)
platforms = ["linux/amd64", "linux/arm64"]
}
target "code-server-debian-12" {
dockerfile = "ci/release-image/Dockerfile"
tags = concat(
gen_tags_for_docker_and_ghcr("bookworm"),
)
args = {
BASE = "debian:12"
}
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

@ -6,22 +6,15 @@ set -eu
eval "$(fixuid -q)"
if [ "${DOCKER_USER-}" ]; 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
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
# 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
sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
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 "$@"

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

17
ci/steps/fmt.sh Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
yarn --frozen-lockfile
git submodule update --init
# We do not `yarn vscode` to make test.sh faster.
# If the patch fails to apply, then it's likely already applied
yarn vscode:patch &> /dev/null || true
yarn fmt
}
main "$@"

17
ci/steps/lint.sh Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
yarn --frozen-lockfile
git submodule update --init
# We do not `yarn vscode` to make test.sh faster.
# If the patch fails to apply, then it's likely already applied
yarn vscode:patch &> /dev/null || true
yarn lint
}
main "$@"

18
ci/steps/publish-npm.sh Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
source ./ci/lib.sh
if [[ ${CI-} ]]; then
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
fi
download_artifact npm-package ./release-npm-package
# https://github.com/actions/upload-artifact/issues/38
tar -xzf release-npm-package/package.tar.gz
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 "$@"

21
ci/steps/release-packages.sh Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
NODE_VERSION=v12.18.4
NODE_OS="$(uname | tr '[:upper:]' '[:lower:]')"
NODE_ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')"
curl -L "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-$NODE_OS-$NODE_ARCH.tar.gz" | tar -xz
PATH="$PWD/node-$NODE_VERSION-$NODE_OS-$NODE_ARCH/bin:$PATH"
# https://github.com/actions/upload-artifact/issues/38
tar -xzf release-npm-package/package.tar.gz
yarn release:standalone
yarn test:standalone-release
yarn package
}
main "$@"

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