From 9025b6a0fa02c46dd9c859882f1562c6a8ffa45f Mon Sep 17 00:00:00 2001 From: dsx137 <70027572+dsx137@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:37:53 +0800 Subject: [PATCH 1/4] ci: serialize release image workflows --- ...cker-build-and-release-services-images.yml | 27 ++++++-- .github/workflows/publish-docker-image.yml | 25 ++++++- .github/workflows/release.yml | 56 +++++++++++++++ .../update-version-file-on-release.yml | 69 +++++++++++++++++-- 4 files changed, 164 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/docker-build-and-release-services-images.yml b/.github/workflows/docker-build-and-release-services-images.yml index 941f83cfa..2f69434fc 100644 --- a/.github/workflows/docker-build-and-release-services-images.yml +++ b/.github/workflows/docker-build-and-release-services-images.yml @@ -4,14 +4,26 @@ on: push: branches: - release-* - release: - types: [published] workflow_dispatch: inputs: tag: description: "Tag version to be used for Docker image" required: true default: "v3.8.3" + workflow_call: + inputs: + tag: + description: "Tag version to be used for Docker image" + required: true + type: string + checkout_sha: + description: "Commit SHA to checkout" + required: true + type: string + checkout_short_sha: + description: "Short commit SHA for image tags" + required: true + type: string jobs: build-and-push: @@ -23,6 +35,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v7.0.0 + with: + ref: ${{ inputs.checkout_sha || inputs.tag || github.event.inputs.tag }} - name: Set up QEMU uses: docker/setup-qemu-action@v4.1.0 @@ -53,8 +67,9 @@ jobs: - name: Resolve Docker image tags id: tags env: - INPUT_TAG: ${{ github.event.inputs.tag }} + INPUT_TAG: ${{ inputs.tag || github.event.inputs.tag }} RELEASE_TAG: ${{ github.event.release.tag_name }} + CHECKOUT_SHORT_SHA: ${{ inputs.checkout_short_sha }} run: | set -euo pipefail @@ -84,13 +99,17 @@ jobs: add_tag_with_semver_alias "${INPUT_TAG:-}" add_tag_with_semver_alias "${RELEASE_TAG:-}" + if [[ "${GITHUB_EVENT_NAME:-}" == "release" && "${{ github.event.release.prerelease }}" != "true" ]]; then + add_tag "latest" + fi + if [[ "${GITHUB_REF_TYPE:-}" == "tag" ]]; then add_tag_with_semver_alias "${GITHUB_REF_NAME}" elif [[ "${GITHUB_REF_TYPE:-}" == "branch" ]]; then add_tag "${GITHUB_REF_NAME}" fi - add_tag "sha-${GITHUB_SHA::7}" + add_tag "sha-${CHECKOUT_SHORT_SHA:-${GITHUB_SHA::7}}" { echo "tags</dev/null; then + echo "target_branch must be an existing branch: ${TARGET_BRANCH}" + exit 1 + fi + git checkout -B "${TARGET_BRANCH}" "origin/${TARGET_BRANCH}" + - name: Safe submodule initialization run: | echo "Checking for submodules..." @@ -48,7 +92,6 @@ jobs: run: | if git rev-parse ${{ env.TAG_VERSION }} >/dev/null 2>&1; then git tag -d ${{ env.TAG_VERSION }} - git push --delete origin ${{ env.TAG_VERSION }} fi # Step 4: Update version file @@ -62,14 +105,28 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | + set -euo pipefail git add version/version - git commit -m "Update version to ${{ env.TAG_VERSION }}" + if git diff --cached --quiet; then + echo "version/version already matches ${TAG_VERSION}" + else + git commit -m "Update version to ${{ env.TAG_VERSION }}" + git push origin HEAD:${TARGET_BRANCH} + fi # Step 6: Update tag - name: Update tag run: | + set -euo pipefail git tag -fa ${{ env.TAG_VERSION }} -m "Update version to ${{ env.TAG_VERSION }}" - git push origin ${{ env.TAG_VERSION }} --force + git push origin refs/tags/${{ env.TAG_VERSION }}:refs/tags/${{ env.TAG_VERSION }} --force + + - name: Resolve updated tag SHA + id: resolve-tag + run: | + updated_sha="$(git rev-parse "${TAG_VERSION}^{commit}")" + echo "updated_sha=$updated_sha" >> "$GITHUB_OUTPUT" + echo "updated_short_sha=${updated_sha:0:12}" >> "$GITHUB_OUTPUT" # Step 7: Find and Publish Draft Release - name: Find and Publish Draft Release From b3287b579734255f44baac073e463c2c19dc47e5 Mon Sep 17 00:00:00 2001 From: dsx137 <70027572+dsx137@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:19:10 +0800 Subject: [PATCH 2/4] feat(build): add single-service Docker build script --- ...cker-build-and-release-services-images.yml | 25 ++++- build/build_single.sh | 105 ++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100755 build/build_single.sh diff --git a/.github/workflows/docker-build-and-release-services-images.yml b/.github/workflows/docker-build-and-release-services-images.yml index 2f69434fc..27b22be31 100644 --- a/.github/workflows/docker-build-and-release-services-images.yml +++ b/.github/workflows/docker-build-and-release-services-images.yml @@ -26,8 +26,30 @@ on: type: string jobs: + services: + runs-on: ubuntu-latest + outputs: + services: ${{ steps.services.outputs.services }} + steps: + - name: Checkout repository + uses: actions/checkout@v7.0.0 + with: + ref: ${{ inputs.checkout_sha || inputs.tag || github.event.inputs.tag }} + + - name: Resolve service matrix + id: services + run: | + set -euo pipefail + services=$(docker compose -f build/images/openim-server/docker-compose.build.yml config --services | jq -R -s -c 'split("\n") | map(select(length > 0))') + echo "services=$services" >> "$GITHUB_OUTPUT" + build-and-push: + needs: services runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + service: ${{ fromJson(needs.services.outputs.services) }} permissions: contents: read packages: write @@ -121,6 +143,7 @@ jobs: env: RELEASE: "true" PUSH: "true" + SERVICE: ${{ matrix.service }} PLATFORMS: linux/amd64,linux/arm64 IMAGE_TAGS: ${{ steps.tags.outputs.tags }} IMAGE_REGISTRIES: | @@ -128,4 +151,4 @@ jobs: ghcr.io/${{ github.repository_owner }} registry.cn-hangzhou.aliyuncs.com/openimsdk run: | - bash build/build.sh + bash build/build_single.sh diff --git a/build/build_single.sh b/build/build_single.sh new file mode 100755 index 000000000..f5b1e8075 --- /dev/null +++ b/build/build_single.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash + +set -euo pipefail + +CYAN='\033[0;36m' +GREEN='\033[0;32m' +RED='\033[0;31m' +NO_COLOR='\033[0m' + +BASE_DIR="$(cd "$(dirname "$0")" && pwd)" +COMPOSE_FILE="$BASE_DIR/images/openim-server/docker-compose.build.yml" +RELEASE="${RELEASE:-false}" +PUSH="${PUSH:-false}" +DRY_RUN="${DRY_RUN:-false}" +PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}" +IMAGE_TAGS="${IMAGE_TAGS:-}" +IMAGE_REGISTRIES="${IMAGE_REGISTRIES:-}" +SERVICE="${SERVICE:-}" + +if [[ ! -f "$COMPOSE_FILE" ]]; then + echo -e "${RED}docker-compose.build.yml not found: $COMPOSE_FILE${NO_COLOR}" + exit 1 +fi + +if [[ -z "$SERVICE" ]]; then + echo -e "${RED}SERVICE is required${NO_COLOR}" + exit 1 +fi + +cd "$BASE_DIR/.." || exit 1 + +split_values() { + echo "$1" | grep -o '[^, ]\+' +} + +run_or_print() { + if [[ "$DRY_RUN" == "true" ]]; then + printf '%q ' "$@" + printf '\n' + else + "$@" + fi +} + +if ! command -v jq >/dev/null 2>&1; then + echo -e "${RED}jq is required${NO_COLOR}" + exit 1 +fi + +if [[ -z "$IMAGE_TAGS" || -z "$IMAGE_REGISTRIES" ]]; then + echo -e "${RED}IMAGE_TAGS and IMAGE_REGISTRIES are required${NO_COLOR}" + exit 1 +fi + +image_tags=() +while IFS= read -r tag; do + image_tags+=("$tag") +done < <(split_values "$IMAGE_TAGS") + +image_registries=() +while IFS= read -r registry; do + image_registries+=("$registry") +done < <(split_values "$IMAGE_REGISTRIES") + +if [[ ${#image_tags[@]} -eq 0 || ${#image_registries[@]} -eq 0 ]]; then + echo -e "${RED}IMAGE_TAGS and IMAGE_REGISTRIES must contain at least one value${NO_COLOR}" + exit 1 +fi + +compose_config=$(docker compose -f "$COMPOSE_FILE" config --format json) + +context=$(jq -r --arg service "$SERVICE" '.services[$service].build.context // empty' <<< "$compose_config") +dockerfile=$(jq -r --arg service "$SERVICE" '.services[$service].build.dockerfile // empty' <<< "$compose_config") +cmd_path=$(jq -r --arg service "$SERVICE" '.services[$service].build.args.CMD_PATH // empty' <<< "$compose_config") +binary_name=$(jq -r --arg service "$SERVICE" '.services[$service].build.args.BINARY_NAME // empty' <<< "$compose_config") + +if [[ -z "$context" || -z "$dockerfile" || -z "$cmd_path" || -z "$binary_name" ]]; then + echo -e "${RED}Invalid build config for $SERVICE${NO_COLOR}" + exit 1 +fi + +if [[ ! -d "$cmd_path" && ! -f "$cmd_path/main.go" ]]; then + echo -e "${CYAN}Skipping $SERVICE because $cmd_path does not exist${NO_COLOR}" + exit 0 +fi + +tag_args=() +for registry in "${image_registries[@]}"; do + for tag in "${image_tags[@]}"; do + tag_args+=(--tag "$registry/$binary_name:$tag") + done +done + +echo -e "${CYAN}Building $binary_name for $PLATFORMS...${NO_COLOR}" +run_or_print docker buildx build \ + --platform "$PLATFORMS" \ + --file "$dockerfile" \ + --build-arg "CMD_PATH=$cmd_path" \ + --build-arg "BINARY_NAME=$binary_name" \ + --build-arg "RELEASE=$RELEASE" \ + "${tag_args[@]}" \ + --push \ + "$context" + +echo -e "${GREEN}Successfully pushed $binary_name${NO_COLOR}" From ef00cdc66c5ef2a13d4bfc5f011b3b782a6ba887 Mon Sep 17 00:00:00 2001 From: dsx137 <70027572+dsx137@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:37:16 +0800 Subject: [PATCH 3/4] chore(ci): remove draft release publishing step --- .../update-version-file-on-release.yml | 46 ------------------- 1 file changed, 46 deletions(-) diff --git a/.github/workflows/update-version-file-on-release.yml b/.github/workflows/update-version-file-on-release.yml index bc0dbfcd8..38e1106d0 100644 --- a/.github/workflows/update-version-file-on-release.yml +++ b/.github/workflows/update-version-file-on-release.yml @@ -128,49 +128,3 @@ jobs: echo "updated_sha=$updated_sha" >> "$GITHUB_OUTPUT" echo "updated_short_sha=${updated_sha:0:12}" >> "$GITHUB_OUTPUT" - # Step 7: Find and Publish Draft Release - - name: Find and Publish Draft Release - uses: actions/github-script@v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { owner, repo } = context.repo; - const tagName = process.env.TAG_VERSION; - - try { - let release; - try { - const response = await github.rest.repos.getReleaseByTag({ - owner, - repo, - tag: tagName - }); - release = response.data; - } catch (tagError) { - core.info(`Release not found by tag, searching all releases...`); - const releases = await github.rest.repos.listReleases({ - owner, - repo, - per_page: 100 - }); - - release = releases.data.find(r => r.draft && r.tag_name === tagName); - if (!release) { - throw new Error(`No release found with tag ${tagName}`); - } - } - - await github.rest.repos.updateRelease({ - owner, - repo, - release_id: release.id, - draft: false, - prerelease: release.prerelease - }); - - const status = release.draft ? "was draft" : "was already published"; - core.info(`Release ${tagName} ensured to be published (${status}).`); - - } catch (error) { - core.warning(`Could not find or update release for tag ${tagName}: ${error.message}`); - } From 350169e939be245711145300889e469a2a7c9b9f Mon Sep 17 00:00:00 2001 From: dsx137 <70027572+dsx137@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:38:12 +0800 Subject: [PATCH 4/4] fix(gomod): update protocol lib --- go.mod | 4 ++-- go.sum | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4caa277da..c08218c92 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/mitchellh/mapstructure v1.5.0 - github.com/openimsdk/protocol v0.0.73-alpha.12 + github.com/openimsdk/protocol v0.0.73-alpha.19 github.com/openimsdk/tools v0.0.50-alpha.119 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 @@ -134,7 +134,7 @@ require ( github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/lithammer/shortuuid v3.0.0+incompatible // indirect github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect - github.com/magefile/mage v1.16.1 // indirect + github.com/magefile/mage v1.17.2 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect diff --git a/go.sum b/go.sum index 47059e30d..e6bda0f88 100644 --- a/go.sum +++ b/go.sum @@ -319,6 +319,8 @@ github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6 github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/magefile/mage v1.16.1 h1:j5UwkdA48xTlGs0Hcm1Q3sSAcxBorntQjiewDNMsqlo= github.com/magefile/mage v1.16.1/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magefile/mage v1.17.2 h1:fyXVu1eadI8Ap1HCCNgEhJ5McIWiYhLR8uol64ZZc40= +github.com/magefile/mage v1.17.2/go.mod h1:Yj51kqllmsgFpvvSzgrZPK9WtluG3kUhFaBUVLo4feA= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -363,6 +365,8 @@ github.com/openimsdk/gomake v0.0.17 h1:q8haP48VOH45WhJRiLj1YSBJyUFJqD8CTedH65i1Y github.com/openimsdk/gomake v0.0.17/go.mod h1:nnjS8yCtrPJAt1knMbyPiUwCH2gpyBzj/EZAONfUOXg= github.com/openimsdk/protocol v0.0.73-alpha.12 h1:2NYawXeHChYUeSme6QJ9pOLh+Empce2WmwEtbP4JvKk= github.com/openimsdk/protocol v0.0.73-alpha.12/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw= +github.com/openimsdk/protocol v0.0.73-alpha.19 h1:CvXoDF2U73UcMhLnrtMFks2Aw+bXiDgH8AITEt783/s= +github.com/openimsdk/protocol v0.0.73-alpha.19/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw= github.com/openimsdk/tools v0.0.50-alpha.117 h1:ACfijEVCeBcttT7OOkNGOOOvq14pJtb9szNIMHLm6Vc= github.com/openimsdk/tools v0.0.50-alpha.117/go.mod h1:I0WESSa7ghPIo9BL+ETlH/qEIbO6+KZioM1jwNuDwz0= github.com/openimsdk/tools v0.0.50-alpha.119 h1:S/RjRtL0ciwiG6pZKssbU//qVSWi7AuKHOPCHsQgz68=