diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index e1db5d68..2462e9b6 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -4,12 +4,12 @@ on: workflow_dispatch: inputs: tag: - description: 'tag for the Docker image' + description: "tag for the Docker image" required: true - default: 'latest' + default: "latest" push: branches: - - 'main' + - "main" jobs: define-matrix: runs-on: ubuntu-latest @@ -50,31 +50,51 @@ jobs: matrix: build_target: ${{ fromJson(needs.define-matrix.outputs.build_targets) }} steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to ghcr.io - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GH_PAT }} - - name: Build and push image - run: | - echo "build_target=${{ matrix.build_target }}" - echo "tag=${{ needs.define-matrix.outputs.tag }}" - echo "tag_cn=${{ needs.define-matrix.outputs.tag_cn }}" - image_name=$(bash script/get_image_name.sh ${{ github.repository_owner }} "${{ matrix.build_target }}" "${{ needs.define-matrix.outputs.tag }}") - image_name_cn=$(bash script/get_image_name.sh ${{ github.repository_owner }} "${{ matrix.build_target }}" "${{ needs.define-matrix.outputs.tag_cn }}") - echo "image_name=$image_name" >> $GITHUB_OUTPUT - echo "image_name_cn=$image_name_cn" >> $GITHUB_OUTPUT - echo "building image $image_name" - is_cn="0" bash script/build_and_push_images.sh "${{ matrix.build_target }}" "$image_name" $is_cn - echo "building image $image_name_cn" - is_cn="1" bash script/build_and_push_images.sh "${{ matrix.build_target }}" "$image_name_cn" $is_cn - # TODO: generate runtime yaml and json + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to ghcr.io + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GH_PAT }} + - name: Install jq + run: | + sudo apt-get install jq + - name: Generate SQL + run: | + echo "build_target=${{ matrix.build_target }}" + echo "tag=${{ needs.define-matrix.outputs.tag }}" + echo "tag_cn=${{ needs.define-matrix.outputs.tag_cn }}" + image_name=$(bash script/get_image_name.sh ${{ github.repository_owner }} "${{ matrix.build_target }}" "${{ needs.define-matrix.outputs.tag }}") + image_name_cn=$(bash script/get_image_name.sh ${{ github.repository_owner }} "${{ matrix.build_target }}" "${{ needs.define-matrix.outputs.tag_cn }}") + echo "image_name=$image_name" >> $GITHUB_OUTPUT + echo "image_name_cn=$image_name_cn" >> $GITHUB_OUTPUT + template_json=$(bash script/get_template_config_json.sh "${{ matrix.build_target }}") + echo "template_json=$template_json" + template_repo_json=$(bash script/get_template_repo_config_json.sh "${{ matrix.build_target }}") + echo "template_repo_json=$template_repo_json" + sql=$(bash script/generate_template_sql.sh "$image_name" "$template_json" "$template_repo_json") + echo "sql=$sql" >> $GITHUB_OUTPUT + # - name: Save SQL to GitHub Packages + # run: | + # bash script/save_sql.sh "${{ matrix.build_target }}" "$sql" + - run: mkdir -p sql/templates + - run: echo $sql > sql/templates/$(echo "$BUILD_TARGET" | sed 's/\//_/g').sql + - uses: actions/upload-artifact@v4 + with: + name: upload sql + path: sql/templates/$(echo "$BUILD_TARGET" | sed 's/\//_/g').sql + - name: Build and push image + run: | + echo "building image $image_name" + is_cn="0" bash script/build_and_push_images.sh "${{ matrix.build_target }}" "$image_name" $is_cn + echo "building image $image_name_cn" + is_cn="1" bash script/build_and_push_images.sh "${{ matrix.build_target }}" "$image_name_cn" $is_cn + # TODO: generate runtime yaml and json diff --git a/Framework/angular/repo.json b/Framework/angular/repo.json new file mode 100644 index 00000000..dcc96e91 --- /dev/null +++ b/Framework/angular/repo.json @@ -0,0 +1,6 @@ +{ + "name": "Angular", + "isPublic": true, + "kind": "FRAMEWORK", + "description": "Complete Google Angular Development Toolchain Environment" +} diff --git a/Framework/angular/v18/template.json b/Framework/angular/v18/template.json new file mode 100644 index 00000000..3d6b8c31 --- /dev/null +++ b/Framework/angular/v18/template.json @@ -0,0 +1,5 @@ +{ + "name": "v18", + "port": 4200, + "isDeleted": false +} diff --git a/Framework/astro/4.10.0/template.json b/Framework/astro/4.10.0/template.json new file mode 100644 index 00000000..8390095c --- /dev/null +++ b/Framework/astro/4.10.0/template.json @@ -0,0 +1,5 @@ +{ + "name": "v4.10.0", + "port": 4200, + "isDeleted": false +} diff --git a/Framework/astro/repo.json b/Framework/astro/repo.json new file mode 100644 index 00000000..927a09d5 --- /dev/null +++ b/Framework/astro/repo.json @@ -0,0 +1,6 @@ +{ + "name": "Astro", + "isPublic": true, + "kind": "FRAMEWORK", + "description": "Complete Google Angular Development Toolchain Environment" +} diff --git a/bash b/bash new file mode 100644 index 00000000..577b2dce --- /dev/null +++ b/bash @@ -0,0 +1 @@ +Usage: script/generate_template_sql.sh diff --git a/script/generate_template_config.sh b/script/generate_template_config.sh new file mode 100755 index 00000000..afca3286 --- /dev/null +++ b/script/generate_template_config.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +# 确保脚本在发生错误时立即退出 +set -e + +# 使用命名参数处理 +while [[ "$#" -gt 0 ]]; do + case $1 in + --app-port) APP_PORT="$2"; shift ;; + --ssh-port) SSH_PORT="$2"; shift ;; + --entrypoint) ENTRYPOINT="$2"; shift ;; + --user) DEVBOX_USER="$2"; shift ;; + --working-dir) WORKING_DIR="$2"; shift ;; + --output) OUTPUT_FILE="$2"; shift ;; + *) echo "Unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +# 检查必需参数 +# if [ -z "$RUNTIME_NAME" ] || [ -z "$SHORT_COMMIT_ID" ] || [ -z "$ORG_UID" ]; then +# echo "Usage: $0 \\ +# [ --app-port ] \\ +# [ --ssh-port ] \\ +# [ --entrypoint ] \\ +# [ --user ] \\ +# [ --working-dir ] \\ +# [ --output ]" +# exit 1 +# fi + +# 设置默认值 +APP_PORT=${APP_PORT:-3001} +SSH_PORT=${SSH_PORT:-22} +ENTRYPOINT=${ENTRYPOINT:-"/home/devbox/project/entrypoint.sh"} +DEVBOX_USER=${DEVBOX_USER:-"devbox"} +WORKING_DIR=${WORKING_DIR:-"/home/devbox/project"} + +# 创建生成配置的函数 +generate_template_config() { + cat < "$OUTPUT_FILE" + echo "Configuration written to $OUTPUT_FILE" +else + echo "$CONFIG" +fi diff --git a/script/generate_template_sql.sh b/script/generate_template_sql.sh new file mode 100755 index 00000000..49f5376f --- /dev/null +++ b/script/generate_template_sql.sh @@ -0,0 +1,99 @@ +#!/bin/bash + + +if [ "$#" -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +# 提取环境变量 +IMAGE=$1 +TEMPLATE_JSON=$2 +TEMPLATE_REPO_JSON=$3 + +echo "IMAGE=$IMAGE" +echo "TEMPLATE_JSON=$TEMPLATE_JSON" +echo "TEMPLATE_REPO_JSON=$TEMPLATE_REPO_JSON" + +SQL_DIR="sql" +SQL_FILE="$SQL_DIR/$RUNTIME_NAME-$SHORT_COMMIT_ID.sql.tmp" +# IMAGE="ghcr.io/labring-actions/devbox/$RUNTIME_NAME:$SHORT_COMMIT_ID" +RUNTIME_NAME=$(echo "$TEMPLATE_REPO_JSON" | jq -r '.name') +IS_PUBLIC=$(echo "$TEMPLATE_REPO_JSON" | jq -r '.isPublic') +KIND=$(echo "$TEMPLATE_REPO_JSON" | jq -r '.kind') +VERSION=$(echo "$TEMPLATE_JSON" | jq -r '.name') +PORT=$(echo "$TEMPLATE_JSON" | jq -r '.port') +TEMPLATE_CONFIG=$(bash script/generate_template_config.sh --app-port $PORT) + + +# 创建目录(如果不存在) +mkdir -p $SQL_DIR + +# 生成 UUID +# TEMPLATE_UID=$(uuidgen) +# TEMPLATE_REPOSITORY_TAG_UID=$(uuidgen) + +# 生成 SQL 文件 +cat <', -- 必须替换为实际存在的 regionUid,空字符串会导致外键错误 + $IS_PUBLIC::boolean, + now(), + now() +WHERE NOT EXISTS ( + SELECT 1 FROM "TemplateRepository" + WHERE "name" = '$RUNTIME_NAME' AND "organizationUid" = '$ORG_UID' AND "regionUid" = '$REGION_UID' +); + +-- 2. 更新已存在的 Template为 isDeleted (如果有) +WITH org_uid AS ( + SELECT "uid" FROM "Organization" + WHERE "name" = 'labring' + LIMIT 1 +), +template_repository_uid AS ( + SELECT "uid" FROM "TemplateRepository" + WHERE "name" = '$RUNTIME_NAME' AND "organizationUid" = org_uid.uid AND "regionUid" = 'region_uid_placeholder' + LIMIT 1 +) + +UPDATE "Template" +SET "image" = '$IMAGE', + "config" = '$TEMPLATE_CONFIG', + "updatedAt" = now(), + "deletedAt" = now(), + "isDeleted" = FALSE +WHERE "name" = '$VERSION' AND "isDeleted" = false; + +-- 3. 插入 新的Template +WITH org_uid AS ( + SELECT "uid" FROM "Organization" + WHERE "name" = 'labring' + LIMIT 1 +), +template_repository_uid AS ( + SELECT "uid" FROM "TemplateRepository" + WHERE "name" = '$RUNTIME_NAME' AND "organizationUid" = org_uid.uid AND "regionUid" = 'region_uid_placeholder' + LIMIT 1 +) +INSERT "Template" ("name", "image", "config", "templateRepositoryUid", "createdAt", "updatedAt") +SELECT + '$VERSION', + '$IMAGE', + '$TEMPLATE_CONFIG', + template_repository_uid.uid, + now(), + now(); +EOF diff --git a/script/get_template_config_json.sh b/script/get_template_config_json.sh new file mode 100644 index 00000000..c3d36065 --- /dev/null +++ b/script/get_template_config_json.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +BUILD_TARGET=$1 + +IFS='/' read -ra ADDR <<< "$BUILD_TARGET" +IMAGE_NAME="${ADDR[1]}-${ADDR[2]}" + +# /Framework/angular/v18/Dockerfile => /Framework/angular +# 生成 config.json 的路径 +TEMPLATE_CONFIG_PATH="${ADDR[0]}/${ADDR[1]}/${ADDR[2]}/template.json" + +if [ ! -f "$TEMPLATE_CONFIG_PATH" ]; then + echo "Error: template.json file not found at $TEMPLATE_CONFIG_PATH" + exit 1 +fi + +echo $(cat "$TEMPLATE_CONFIG_PATH") diff --git a/script/get_template_repo_config_json.sh b/script/get_template_repo_config_json.sh new file mode 100644 index 00000000..68776c4f --- /dev/null +++ b/script/get_template_repo_config_json.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +BUILD_TARGET=$1 + +IFS='/' read -ra ADDR <<< "$BUILD_TARGET" +IMAGE_NAME="${ADDR[1]}-${ADDR[2]}" + +# /Framework/angular/v18/Dockerfile => /Framework/angular +# 生成 config.json 的路径 +TEMPLATE_REPO_CONFIG_PATH="${ADDR[0]}/${ADDR[1]}/repo.json" +if [ ! -f "$TEMPLATE_REPO_CONFIG_PATH" ]; then + echo "Error: repo.json file not found at $TEMPLATE_REPO_CONFIG_PATH" + exit 1 +fi +echo $(cat "$TEMPLATE_REPO_CONFIG_PATH") diff --git a/script/save_sql.sh b/script/save_sql.sh new file mode 100644 index 00000000..ab61b05b --- /dev/null +++ b/script/save_sql.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# 确保脚本在发生错误时立即退出 +set -e + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +BUILD_TARGET=$1 +SQL=$2 + +# 创建目录(如果不存在) +mkdir -p sql/templates/ + +# 将build_target中的斜杠替换为下划线,用于文件名 +BUILD_TARGET_FILENAME=$(echo "$BUILD_TARGET" | sed 's/\//_/g') + +# 保存SQL到文件 +echo "$SQL" > "/sql/templates/${BUILD_TARGET_FILENAME}.sql" + +echo "SQL saved to /sql/templates/${BUILD_TARGET_FILENAME}.sql" diff --git a/sql/000_init_org.sql b/sql/000_init_org.sql new file mode 100644 index 00000000..639fdd2c --- /dev/null +++ b/sql/000_init_org.sql @@ -0,0 +1,4 @@ +-- init organization +insert "Organization" (id, "updatedAt", name) +values + ('labring', current_timestamp, 'labring'); diff --git a/sql/001_init_tag.sql b/sql/001_init_tag.sql new file mode 100644 index 00000000..240e44e5 --- /dev/null +++ b/sql/001_init_tag.sql @@ -0,0 +1,45 @@ +-- init tag +INSERT INTO + "Tag" (name, "enName", "zhName", type) +VALUES + ( + 'javascript', + 'Javascript', + 'Javascript', + 'PROGRAMMING_LANGUAGE' + ), + ('csharp', 'C#', 'C#', 'PROGRAMMING_LANGUAGE'), + ( + 'python', + 'Python', + 'Python', + 'PROGRAMMING_LANGUAGE' + ), + ( + 'golang', + 'Golang', + 'Golang', + 'PROGRAMMING_LANGUAGE' + ), + ('c', 'C', 'C', 'PROGRAMMING_LANGUAGE'), + ('rust', 'Rust', 'Rust', 'PROGRAMMING_LANGUAGE'), + ('cpp', 'C++', 'C++', 'PROGRAMMING_LANGUAGE'), + ('ruby', 'Ruby', 'Ruby', 'PROGRAMMING_LANGUAGE'), + ('java', 'Java', 'Java', 'PROGRAMMING_LANGUAGE'), + ('php', 'Php', 'Php', 'PROGRAMMING_LANGUAGE'), + ('ai', 'AI', 'AI', 'USE_CASE'), + ('os', 'OS', '操作系统', 'USE_CASE'), + ('tool', 'Tool', '工具', 'USE_CASE'), + ('blog', 'Blog', '博客', 'USE_CASE'), + ( + 'OFFICIAL_CONTENT', + 'MCP', + 'MCP', + 'OFFICIAL_CONTENT' + ), + ( + 'official', + 'Official Picks', + '官方精选', + 'OFFICIAL_CONTENT' + ); diff --git a/sql/002_update_description.sql b/sql/002_update_description.sql new file mode 100644 index 00000000..31060caf --- /dev/null +++ b/sql/002_update_description.sql @@ -0,0 +1,123 @@ +-- 更新template 简介 +UPDATE public."TemplateRepository" +SET + description = temp.new_description +FROM + ( + VALUES + ( + 'react', + 'Facebook React Frontend Development Environment with IDE Integration' + ), + ( + 'vue', + 'Vue.js Frontend Environment with Pre-installed Dependencies' + ), + ( + 'angular', + 'Complete Google Angular Development Toolchain Environment' + ), + ( + 'svelte', + 'Comprehensive Svelte Development Toolkit Package' + ), + ( + 'astro', + 'Pre-configured Astro Build and Development Environment' + ), + ( + 'next.js', + 'Next.js Development Runtime Environment' + ), + ( + 'nuxt3', + 'Nuxt3 Server-Side Rendering Environment' + ), + ( + 'umi', + 'Alibaba UMI Framework Complete Development Environment' + ), + ( + 'docusaurus', + 'Facebook Docusaurus Documentation Development Environment' + ), + ( + 'vitepress', + 'Vue-powered Documentation Site Development Environment' + ), + ( + 'hugo', + 'Hugo Static Site Environment with Go Pre-installed' + ), + ('hexo', 'Node.js-powered Hexo Blog Environment'), + ( + 'express.js', + 'Complete Express Backend Development Environment' + ), + ( + 'spring-boot', + 'Java + Spring Boot Development Kit' + ), + ( + 'django', + 'Python Django Full-Stack Development Environment' + ), + ( + 'flask', + 'Lightweight Python Web Development Environment' + ), + ( + 'gin', + 'Go Gin Web Complete Development Environment' + ), + ( + 'chi', + 'Go Chi HTTP Service Development Environment' + ), + ('echo', 'Go Echo Web Framework Environment'), + ( + 'iris', + 'Go Iris Development Toolchain Environment' + ), + ( + 'quarkus', + 'Java Cloud-Native Development Environment' + ), + ('rocket', 'Rust Web Development Toolchain'), + ('vert.x', 'JVM Reactive Development Environment'), + ( + 'python', + 'Python Language Development Runtime Environment' + ), + ('java', 'Java JDK Development Environment'), + ( + 'go', + 'Go Language Complete Development Toolchain' + ), + ( + 'rust', + 'Rust Language Compilation Development Environment' + ), + ( + 'c', + 'C Language Compilation Development Toolchain' + ), + ( + 'cpp', + 'C++ Development and Compilation Environment' + ), + ('php', 'PHP Development Runtime Environment'), + ( + 'node.js', + 'Node.js Runtime Development Environment' + ), + ('nginx', 'Nginx Server Configuration Environment'), + ('ubuntu', 'Ubuntu Basic Development Environment'), + ( + 'debian-ssh', + 'Debian Development Environment with SSH Support' + ), + ('net', '.NET Development Runtime Environment') + ) AS temp (name, new_description) +WHERE + "TemplateRepository".name = temp.name; diff --git a/sql/010_update_templateRepositroyTag.sql b/sql/010_update_templateRepositroyTag.sql new file mode 100644 index 00000000..9fd863c7 --- /dev/null +++ b/sql/010_update_templateRepositroyTag.sql @@ -0,0 +1,127 @@ +--更新绑定 +INSERT INTO + public."TemplateRepositoryTag" ("templateRepositoryUid", "tagUid") +SELECT + t.uid, + c.uid +FROM + public."TemplateRepository" t, + public."Tag" c +WHERE + ( + (c.name = 'official') + OR + -- Programming Languages + ( + t.name = 'python' + AND c.name = 'python' + ) + OR ( + t.name = 'java' + AND c.name = 'java' + ) + OR ( + t.name = 'rust' + AND c.name = 'rust' + ) + OR ( + t.name = 'cpp' + AND c.name = 'cpp' + ) + OR ( + t.name = 'c' + AND c.name = 'c' + ) + OR ( + t.name = 'go' + AND c.name = 'golang' + ) + OR ( + t.name = 'php' + AND c.name = 'php' + ) + OR + -- JavaScript and its frameworks + ( + t.name IN ( + 'node.js', + 'express.js', + 'next.js', + 'nuxt3', + 'angular', + 'vue', + 'react', + 'svelte', + 'astro', + 'sealaf' + ) + AND c.name = 'javascript' + ) + OR + -- go frameworks + ( + t.name IN ('gin', 'iris', 'echo', 'chi') + AND c.name = 'golang' + ) + OR + -- Java frameworks + ( + t.name IN ('quarkus', 'spring-boot', 'vert.x') + AND c.name = 'java' + ) + OR + -- Rust frameworks + ( + t.name IN ('rocket') + AND c.name = 'rust' + ) + OR + -- Python frameworks + ( + t.name IN ('django', 'flask') + AND c.name = 'python' + ) + OR + -- c# + ( + t.name IN ('net') + AND c.name = 'csharp' + ) + OR + -- Operating Systems + ( + t.name IN ('debian-ssh', 'ubuntu') + AND c.name = 'os' + ) + OR + -- Blog/Documentation + ( + t.name IN ('hexo', 'docusaurus', 'hugo', 'vitepress') + AND c.name IN ('blog', 'javascript') + ) + OR + -- Tools + ( + t.name IN ( + 'nginx', + 'gin', + 'chi', + 'iris', + 'echo', + 'sealaf', + 'quarkus', + 'rocket', + 'umi' + ) + AND c.name = 'tool' + ) + ) + AND NOT EXISTS ( + SELECT + 1 + FROM + "TemplateRepositoryTag" tc + WHERE + tc."templateRepositoryUid" = t.uid + AND tc."tagUid" = c.uid + ); diff --git a/sql/templates/ghcr.io_xudaotutou_devbox_angular-v18:latest.sql b/sql/templates/ghcr.io_xudaotutou_devbox_angular-v18:latest.sql new file mode 100644 index 00000000..a08bad20 --- /dev/null +++ b/sql/templates/ghcr.io_xudaotutou_devbox_angular-v18:latest.sql @@ -0,0 +1 @@ +select * from user