From 5a5cdcea71421aa0615054885beb35a8fb97e429 Mon Sep 17 00:00:00 2001 From: Je Xia Date: Sat, 16 Nov 2024 21:58:40 +0800 Subject: [PATCH] Deploy main branch to next.esm.sh (#908) --- .github/workflows/deploy.yml | 28 +++++++++++ .github/workflows/docker-push.yml | 4 +- .github/workflows/{ci.yml => test.yml} | 10 ++-- CONTRIBUTING.md | 2 +- Dockerfile | 2 +- HOSTING.md | 17 ++++--- config.example.jsonc | 6 +-- scripts/build.sh | 15 ------ scripts/deploy-ci.sh | 66 ++++++++++++++++++++++++++ scripts/deploy.sh | 32 ++++++++++--- server/config.go | 2 +- test/bootstrap.ts | 9 ++++ 12 files changed, 150 insertions(+), 43 deletions(-) create mode 100644 .github/workflows/deploy.yml rename .github/workflows/{ci.yml => test.yml} (89%) delete mode 100644 scripts/build.sh create mode 100755 scripts/deploy-ci.sh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..394bbb5c9 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,28 @@ +name: Deploy + +on: + push: + branches: [main] + +jobs: + test: + name: Deploy main branch to next.esm.sh + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: 1.23.x + + - name: Run `deploy-ci.sh` + run: scripts/deploy-ci.sh + env: + GOOS: linux + GOARCH: ${{ secrets.DEPLOY_HOST_ARCH }} + SSH_HOST_NAME: ${{ secrets.DEPLOY_SSH_HOST_NAME }} + SSH_USER: ${{ secrets.DEPLOY_SSH_USER }} + SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }} diff --git a/.github/workflows/docker-push.yml b/.github/workflows/docker-push.yml index e5b0f5217..10801332b 100644 --- a/.github/workflows/docker-push.yml +++ b/.github/workflows/docker-push.yml @@ -1,4 +1,4 @@ -name: Docker +name: Docker Push on: push: @@ -7,7 +7,7 @@ on: jobs: push_image: - name: Push `stable` + name: Push image to ghcr.io runs-on: ubuntu-latest permissions: packages: write diff --git a/.github/workflows/ci.yml b/.github/workflows/test.yml similarity index 89% rename from .github/workflows/ci.yml rename to .github/workflows/test.yml index cbac5e3fa..ab020fa88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: CI +name: Test on: push: @@ -8,7 +8,7 @@ on: jobs: test: - name: Testing + name: Test All runs-on: ubuntu-latest steps: @@ -42,7 +42,7 @@ jobs: - name: Install Go uses: actions/setup-go@v3 with: - go-version: 1.22.x + go-version: 1.23.x - name: Setup Deno uses: denoland/setup-deno@main @@ -52,5 +52,5 @@ jobs: - name: Run `go test` run: go test ./server ./server/storage -v - - name: Run `deno test` - run: deno run -A test/bootstrap.ts + - name: Run `test/bootstrap.ts` + run: test/bootstrap.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a69584b5..255d81cd7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ Create a `config.json` file in the project root directory following the example "port": 8080, "workDir": ".esmd", "npmRegistry": "https://registry.npmjs.org/", // change to your own registry if needed - "npmToken": "xxxxxx" ,// remove this line if you don't have one + "npmToken": "xxxxxx", // remove this line if you don't have one } ``` diff --git a/Dockerfile b/Dockerfile index d7d08c302..b2c31ea92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build Stage -FROM golang:1.22-alpine AS build-stage +FROM golang:1.23-alpine AS build-stage ENV ESM_SH_REPO https://github.com/esm-dev/esm.sh ENV ESM_SH_VERSION v136 diff --git a/HOSTING.md b/HOSTING.md index 2ec35d171..f49b773fb 100644 --- a/HOSTING.md +++ b/HOSTING.md @@ -1,7 +1,7 @@ # Self-Hosting -[esm.sh](https://esm.sh) provides a global fast CDN publicly which is powered by -[Cloudflare](https://cloudflare.com). You can also host esm.sh service by yourself. +[esm.sh](https://esm.sh) provides a global fast CDN publicly which is powered by [Cloudflare](https://cloudflare.com). +You can also host esm.sh service by yourself. Please follow the instructions below. ## Clone the Source Code @@ -19,16 +19,15 @@ To configure the server, create a `config.json` file then pass it to the server { "port": 8080, "npmRegistry": "https://registry.npmjs.org/", - "npmToken": "xxxxxx" + "npmToken": "******" } ``` -You can find all the server options in [config.example.jsonc](./config.example.jsonc). (**Note**: the -`config.example.jsonc` is not a valid JSON file, it's a JSONC file.) +You can find all the server options in [config.example.jsonc](./config.example.jsonc). ## Run the Server Locally -You will need [Go](https://golang.org/dl) 1.18+ to compile the server. +You will need [Go](https://golang.org/dl) 1.22+ to compile and run the server. ```bash go run main.go --config=config.json @@ -38,7 +37,7 @@ Then you can import `React` from . ## Deploy the Server to a Single Machine -Ensure the [supervisor](http://supervisord.org/) has been installed on your host machine. +We provide a bash script to deploy the server to a single machine. ```bash # first time deploy @@ -49,7 +48,7 @@ Ensure the [supervisor](http://supervisord.org/) has been installed on your host Recommended host machine requirements: -- Linux system with `git`, `git-lfs` and `supervisor` installed +- Linux system (Debian/Ubuntu) - 4x CPU cores or more - 8GB RAM or more - 100GB disk space or more @@ -70,7 +69,7 @@ Run the container: ```bash docker run -p 8080:8080 \ -e NPM_REGISTRY=https://registry.npmjs.org/ \ - -e NPM_TOKEN=xxxxxx \ + -e NPM_TOKEN=****** \ ghcr.io/esm-dev/esm.sh:latest ``` diff --git a/config.example.jsonc b/config.example.jsonc index a35ef676d..886c86f88 100644 --- a/config.example.jsonc +++ b/config.example.jsonc @@ -1,10 +1,10 @@ { - // The port to listen server on for HTTP requests, default is 8080. - "port": 8080, + // The port to listen server on for HTTP requests, default is 80. + "port": 80, // The port to listen server on for HTTPs requests, default is 0 (disabled). Change to 443 if you want to enable it. // You don't need to provide a certificate, the server uses ACME protocol to get a free certificate from Let's Encrypt. - // Note: if you are running the server in a docker container, you need to expose the port as well. + // Note: if you are running the server in a docker container, you need to expose the port as `443:443`. "tlsPort": 0, // The secret token to validate the `Authorization: Bearer ` header of incoming requests, default is disabled. diff --git a/scripts/build.sh b/scripts/build.sh deleted file mode 100644 index 18503ebfe..000000000 --- a/scripts/build.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -read -p "? build GOOS (default is 'linux'): " goos -read -p "? build GOARCH (default is 'amd64'): " goarch -if [ "$goos" == "" ]; then - goos="linux" -fi -if [ "$goarch" == "" ]; then - goarch="amd64" -fi - -echo "--- building(${goos}_$goarch)..." -export GOOS=$goos -export GOARCH=$goarch -go build -o $(dirname $0)/esmd $(dirname $0)/../main.go diff --git a/scripts/deploy-ci.sh b/scripts/deploy-ci.sh new file mode 100755 index 000000000..158aefe5e --- /dev/null +++ b/scripts/deploy-ci.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +scriptDir=$(dirname $0) + +echo "--- building..." +go build -o $scriptDir/esmd $scriptDir/../main.go +if [ "$?" != "0" ]; then + exit +fi + +mkdir -p ~/.ssh +echo "${SSH_PRIVATE_KEY}" >> ~/.ssh/id_ed25519 +echo "next.esm.sh" >> ~/.ssh/config +echo " HostName ${SSH_HOST_NAME}" >> ~/.ssh/config +echo " User ${SSH_USER}" >> ~/.ssh/config +echo " IdentityFile ~/.ssh/id_ed25519" >> ~/.ssh/config +echo " IdentitiesOnly yes" >> ~/.ssh/config + +echo "--- uploading..." +tar -czf esmd.tar.gz esmd +scp esmd.tar.gz next.esm.sh:/tmp/esmd.tar.gz +if [ "$?" != "0" ]; then + exit +fi + +echo "--- installing..." +ssh next.esm.sh << EOF + cd /tmp + tar -xzf esmd.tar.gz + if [ "\$?" != "0" ]; then + exit + fi + rm -rf esmd.tar.gz + + supervisorctl version + if [ "\$?" != "0" ]; then + apt update + apt install -y supervisor git git-lfs + fi + + svcf=/etc/supervisor/conf.d/esmd.conf + reload=no + if [ ! -f \$svcf ]; then + echo "[program:esmd]" >> \$svcf + echo "command=/usr/local/bin/esmd" >> \$svcf + echo "directory=/tmp" >> \$svcf + echo "user=${SSH_USER}" >> \$svcf + echo "autostart=true" >> \$svcf + echo "autorestart=true" >> \$svcf + reload=yes + if + + supervisorctl stop esmd + rm -f /usr/local/bin/esmd + mv -f esmd /usr/local/bin/esmd + chmod +x /usr/local/bin/esmd + if [ "\$?" != "0" ]; then + exit + fi + + if [ "\$reload" == "yes" ]; then + supervisorctl reload + else + supervisorctl start esmd + fi +EOF diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 57a5f1baf..f30467f8f 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -13,7 +13,7 @@ workDir="" if [ "$init" == "yes" ]; then echo "Server configuration:" - read -p "? http server port (default is ${port}): " v + read -p "? http server port (default is 80): " v if [ "$v" != "" ]; then port="$v" fi @@ -52,9 +52,19 @@ if [ "$v" != "" ]; then sshPort="$v" fi -cd $(dirname $0) -sh build.sh +read -p "? build GOOS (default is 'linux'): " goos +read -p "? build GOARCH (default is 'amd64'): " goarch +if [ "$goos" == "" ]; then + goos="linux" +fi +if [ "$goarch" == "" ]; then + goarch="amd64" +fi +echo "--- building(${goos}_$goarch)..." +export GOOS=$goos +export GOARCH=$goarch +go build -o $(dirname $0)/esmd $(dirname $0)/../main.go if [ "$?" != "0" ]; then exit fi @@ -69,7 +79,12 @@ if [ "$?" != "0" ]; then fi echo "--- installing..." -ssh -p $sshPort $user@$host << EOF +ssh -p $sshPort ${user}@${host} << EOF + if [ "$init" == "yes" ]; then + apt update + apt install -y supervisor git git-lfs + fi + SVV=\$(supervisorctl version) if [ "\$?" != "0" ]; then echo "error: supervisor not installed!" @@ -84,6 +99,7 @@ ssh -p $sshPort $user@$host << EOF cd /tmp tar -xzf esmd.tar.gz + rm -rf esmd.tar.gz supervisorctl stop esmd rm -f /usr/local/bin/esmd @@ -97,8 +113,12 @@ ssh -p $sshPort $user@$host << EOF if [ -f \$SVCONF ]; then rm -f \$SVCONF fi - mkdir -p /etc/esmd - echo "{\"port\":${port},\"tlsPort\":${tlsPort},\"workDir\":\"${workDir}\"}" >> /etc/esmd/config.json + wd=$workDir + if [ "$wd" == "" ]; then + wd=~/.esmd + fi + mkdir $wd + echo "{\"port\": ${port}, \"tlsPort\": ${tlsPort}, \"workDir\": \"${wd}\"}" >> /etc/esmd/config.json writeSVConfLine "[program:esmd]" writeSVConfLine "command=/usr/local/bin/esmd --config=/etc/esmd/config.json" writeSVConfLine "directory=/tmp" diff --git a/server/config.go b/server/config.go index 593ba39bf..d1d7f8b20 100644 --- a/server/config.go +++ b/server/config.go @@ -103,7 +103,7 @@ func DefaultConfig() *Config { func normalizeConfig(c *Config) { if c.Port == 0 { - c.Port = 8080 + c.Port = 80 } if c.AuthSecret == "" { c.AuthSecret = os.Getenv("AUTH_SECRET") diff --git a/test/bootstrap.ts b/test/bootstrap.ts index 54f7076a1..6fb1807dd 100755 --- a/test/bootstrap.ts +++ b/test/bootstrap.ts @@ -5,6 +5,15 @@ async function startServer(onStart: () => Promise, verbose: boolean) { if (!success) { Deno.exit(code); } + if (!(await existsFile("config.json"))) { + await Deno.writeTextFile( + "config.json", + JSON.stringify({ + "port": 8080, + "workDir": ".esmd", + }), + ); + } const p = new Deno.Command("./esmd", { args: ["--debug"], stdout: verbose ? "inherit" : "null",