Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 51 additions & 31 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
6 changes: 6 additions & 0 deletions Framework/angular/repo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "Angular",
"isPublic": true,
"kind": "FRAMEWORK",
"description": "Complete Google Angular Development Toolchain Environment"
}
5 changes: 5 additions & 0 deletions Framework/angular/v18/template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "v18",
"port": 4200,
"isDeleted": false
}
5 changes: 5 additions & 0 deletions Framework/astro/4.10.0/template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "v4.10.0",
"port": 4200,
"isDeleted": false
}
6 changes: 6 additions & 0 deletions Framework/astro/repo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "Astro",
"isPublic": true,
"kind": "FRAMEWORK",
"description": "Complete Google Angular Development Toolchain Environment"
}
1 change: 1 addition & 0 deletions bash
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Usage: script/generate_template_sql.sh <image> <template_json> <template_repo_json>
55 changes: 55 additions & 0 deletions script/generate_template_config.sh
Original file line number Diff line number Diff line change
@@ -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 <app_port> ] \\
# [ --ssh-port <ssh_port> ] \\
# [ --entrypoint <entrypoint> ] \\
# [ --user <user> ] \\
# [ --working-dir <working_dir> ] \\
# [ --output <output_file> ]"
# 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 <<EOF
{"appPorts":[{"name":"devbox-app-port","port":$APP_PORT,"protocol":"TCP"}],"ports":[{"containerPort":$SSH_PORT,"name":"devbox-ssh-port","protocol":"TCP"}],"releaseArgs":["$ENTRYPOINT"],"releaseCommand":["/bin/bash","-c"],"user":"$DEVBOX_USER","workingDir":"$WORKING_DIR"}
EOF
}

# 生成配置
CONFIG=$(generate_template_config)

# 如果指定了输出文件,则写入文件,否则输出到标准输出
if [ -n "$OUTPUT_FILE" ]; then
echo "$CONFIG" > "$OUTPUT_FILE"
echo "Configuration written to $OUTPUT_FILE"
else
echo "$CONFIG"
fi
99 changes: 99 additions & 0 deletions script/generate_template_sql.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/bin/bash


if [ "$#" -ne 3 ]; then
echo "Usage: $0 <image> <template_json> <template_repo_json>"
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 <<EOF
--1. 如果没有找到,创建一个新的 TemplateRepository
WITH org_uid AS (
SELECT "uid" FROM "Organization"
WHERE "name" = 'labring'
LIMIT 1
)
INSERT "TemplateRepository" ("uid", "name", "description", "kind", "organizationUid", "regionUid", "isPublic", "createdAt", "updatedAt")
SELECT
'$(uuidgen)',
'$RUNTIME_NAME',
'A new template repository',
'$KIND',
org_uid.uid,
'<region_uid>', -- 必须替换为实际存在的 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
22 changes: 22 additions & 0 deletions script/get_template_config_json.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash

if [ "$#" -ne 1 ]; then
echo "Usage: $0 <build_target> "
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")
20 changes: 20 additions & 0 deletions script/get_template_repo_config_json.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash

if [ "$#" -ne 1 ]; then
echo "Usage: $0 <build_target>"
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")
23 changes: 23 additions & 0 deletions script/save_sql.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

# 确保脚本在发生错误时立即退出
set -e

if [ "$#" -ne 2 ]; then
echo "Usage: $0 <build_target> <sql>"
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"
4 changes: 4 additions & 0 deletions sql/000_init_org.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- init organization
insert "Organization" (id, "updatedAt", name)
values
('labring', current_timestamp, 'labring');
45 changes: 45 additions & 0 deletions sql/001_init_tag.sql
Original file line number Diff line number Diff line change
@@ -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'
);
Loading