diff --git a/.github/workflows/auto-assign-issue.yml b/.github/workflows/auto-assign-issue.yml index 320174d8c..83c3ede5d 100644 --- a/.github/workflows/auto-assign-issue.yml +++ b/.github/workflows/auto-assign-issue.yml @@ -5,23 +5,23 @@ on: jobs: assign-issue: if: | - contains(github.event.comment.body, '/assign') || contains(github.event.comment.body, '/accept') && - !contains(github.event.comment.user.login, 'openim-robot') + (contains(github.event.comment.body, '/assign') || contains(github.event.comment.body, '/accept')) && + github.event.comment.user.login != 'openim-robot' runs-on: ubuntu-latest permissions: issues: write steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Assign the issue run: | - export LETASE_MILESTONES=$(curl 'https://api.github.com/repos/$OWNER/$PEPO/milestones' | jq -r 'last(.[]).title') + export LATEST_MILESTONE=$(curl "https://api.github.com/repos/$OWNER/$REPO/milestones" | jq -r 'last(.[]).title') gh issue edit ${{ github.event.issue.number }} --add-assignee "${{ github.event.comment.user.login }}" gh issue edit ${{ github.event.issue.number }} --add-label "accepted" - gh issue comment $ISSUE --body "@${{ github.event.comment.user.login }} Glad to see you accepted this issue🤲, this issue has been assigned to you. I set the milestones for this issue to [$LETASE_MILESTONES](https://github.com/$OWNER/$PEPO/milestones), We are looking forward to your PR!" + gh issue comment $ISSUE --body "@${{ github.event.comment.user.login }} Glad to see you accepted this issue🤲, this issue has been assigned to you. I set the milestones for this issue to [$LATEST_MILESTONE](https://github.com/$OWNER/$REPO/milestones), We are looking forward to your PR!" - # gh issue edit ${{ github.event.issue.number }} --milestone "$LETASE_MILESTONES" + # gh issue edit ${{ github.event.issue.number }} --milestone "$LATEST_MILESTONE" env: GH_TOKEN: ${{ secrets.BOT_TOKEN }} ISSUE: ${{ github.event.issue.html_url }} diff --git a/.github/workflows/auto-invite-comment.yml b/.github/workflows/auto-invite-comment.yml index dde36eaf1..3059dbf99 100644 --- a/.github/workflows/auto-invite-comment.yml +++ b/.github/workflows/auto-invite-comment.yml @@ -12,7 +12,7 @@ jobs: issues: write steps: - name: Invite user to join OpenIM Community - uses: peter-evans/create-or-update-comment@v4 + uses: peter-evans/create-or-update-comment@v5 with: token: ${{ secrets.BOT_GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} diff --git a/.github/workflows/auto-invite.yml b/.github/workflows/auto-invite.yml index f8bcfc4c2..04a71e22e 100644 --- a/.github/workflows/auto-invite.yml +++ b/.github/workflows/auto-invite.yml @@ -26,7 +26,7 @@ jobs: issues: write steps: - name: Invite user to join our group - uses: peter-evans/create-or-update-comment@v3 + uses: peter-evans/create-or-update-comment@v5 with: token: ${{ secrets.BOT_GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 56f9f547e..d75789204 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -17,34 +17,31 @@ on: required: true default: "v3.8.0" -env: - GO_VERSION: "1.22" - jobs: build-image: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.8.0 + uses: docker/setup-buildx-action@v4 - name: Log in to Docker Hub - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to GitHub Container Registry - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Log in to Aliyun Container Registry - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4 with: registry: registry.cn-hangzhou.aliyuncs.com username: ${{ secrets.ALIREGISTRY_USERNAME }} @@ -52,7 +49,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@v5.6.0 + uses: docker/metadata-action@v6 with: images: | openim/openim-chat @@ -70,7 +67,7 @@ jobs: type=raw,value=${{ github.event.inputs.tag }} - name: Build and push Docker image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v7 with: context: . platforms: linux/amd64,linux/arm64 diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index b97036d91..cd489e8fa 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Run Go Changelog Generator run: | @@ -66,7 +66,7 @@ jobs: rm -f "${{ github.event.release.tag_name }}-changelog.md" - name: Create Pull Request - uses: peter-evans/create-pull-request@v7.0.5 + uses: peter-evans/create-pull-request@v8 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: "Update CHANGELOG for release ${{ github.event.release.tag_name }}" diff --git a/.github/workflows/chat-build-test.yml b/.github/workflows/chat-build-test.yml index a4762a0e8..ba77fd160 100644 --- a/.github/workflows/chat-build-test.yml +++ b/.github/workflows/chat-build-test.yml @@ -38,19 +38,19 @@ jobs: arch: [amd64] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v6 with: - go-version: "1.22" + go-version: stable - name: init run: sudo bash bootstrap.sh timeout-minutes: 20 - name: Checkout chat repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: repository: "openimsdk/open-im-server" path: "server-repo" diff --git a/.github/workflows/check-coverage.yml b/.github/workflows/check-coverage.yml index 8c8d44185..9b99fa74c 100644 --- a/.github/workflows/check-coverage.yml +++ b/.github/workflows/check-coverage.yml @@ -18,28 +18,28 @@ on: - "**/*.yaml" - "CONTRIBUTORS" - "CHANGELOG/**" -env: - # Common versions - GO_VERSION: "1.20" jobs: coverage: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v7 - name: Setup Golang with cache - uses: magnetikonline/action-golang-cache@v4 + uses: actions/setup-go@v6 with: - go-version: ${{ env.GO_VERSION }} + go-version: stable + cache: true - name: Install Dependencies run: sudo apt update && sudo apt install -y libgpgme-dev libbtrfs-dev libdevmapper-dev - name: Run Cover - run: make cover + run: go test ./... -coverprofile=coverage.txt -covermode=atomic continue-on-error: true - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v7 + with: + files: coverage.txt diff --git a/.github/workflows/cla-assistant.yml b/.github/workflows/cla-assistant.yml index 4aaa4e25a..88c16c8c7 100644 --- a/.github/workflows/cla-assistant.yml +++ b/.github/workflows/cla-assistant.yml @@ -18,7 +18,7 @@ jobs: steps: - name: "CLA Assistant" if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' - uses: contributor-assistant/github-action@v2.4.0 + uses: contributor-assistant/github-action@v2.6.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PERSONAL_ACCESS_TOKEN: ${{ secrets.BOT_TOKEN }} @@ -37,4 +37,4 @@ jobs: custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA' custom-allsigned-prcomment: '🤖 All Contributors have signed the [CLA](https://github.com/OpenIM-Robot/cla/blob/main/README.md).
The signed information is recorded [**here**](https://github.com/OpenIM-Robot/cla/blob/main/signatures/cla.json)' #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) - #use-dco-flag: true - If you are using DCO instead of CLA \ No newline at end of file + #use-dco-flag: true - If you are using DCO instead of CLA diff --git a/.github/workflows/cleanup-after-milestone-prs-merged.yml b/.github/workflows/cleanup-after-milestone-prs-merged.yml index 8a3e381d6..1073ab40d 100644 --- a/.github/workflows/cleanup-after-milestone-prs-merged.yml +++ b/.github/workflows/cleanup-after-milestone-prs-merged.yml @@ -11,14 +11,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.2.0 + uses: actions/checkout@v7 - name: Get the PR title and extract PR numbers id: extract_pr_numbers + env: + PR_TITLE: ${{ github.event.pull_request.title }} run: | - # Get the PR title - PR_TITLE="${{ github.event.pull_request.title }}" - echo "PR Title: $PR_TITLE" # Extract PR numbers from the title @@ -57,9 +56,9 @@ jobs: - name: Delete branch after PR close if: steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge') + env: + BRANCH_NAME: ${{ github.event.pull_request.head.ref }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - BRANCH_NAME="${{ github.event.pull_request.head.ref }}" echo "Branch to delete: $BRANCH_NAME" git push origin --delete "$BRANCH_NAME" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index fd871e2b5..a481303aa 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL @@ -64,4 +64,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 \ No newline at end of file + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/comment-check.yml b/.github/workflows/comment-check.yml index 1609355ed..609b7e6d7 100644 --- a/.github/workflows/comment-check.yml +++ b/.github/workflows/comment-check.yml @@ -17,7 +17,7 @@ jobs: EXCLUDE_FILES: "*.md *.txt *.html *.css *.min.js *.mdx" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Search for Non-English comments run: | @@ -48,4 +48,4 @@ jobs: exit 1 # terminate the workflow else echo "No Non_English comments found." - fi \ No newline at end of file + fi diff --git a/.github/workflows/docker-build-and-release-services-images.yml b/.github/workflows/docker-build-and-release-services-images.yml index bfb018ea4..e6e4f46d2 100644 --- a/.github/workflows/docker-build-and-release-services-images.yml +++ b/.github/workflows/docker-build-and-release-services-images.yml @@ -19,26 +19,26 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.8.0 + uses: docker/setup-buildx-action@v4 - name: Log in to Docker Hub - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to GitHub Container Registry - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Log in to Aliyun Container Registry - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v4 with: registry: registry.cn-hangzhou.aliyuncs.com username: ${{ secrets.ALIREGISTRY_USERNAME }} @@ -46,7 +46,7 @@ jobs: - name: Extract metadata for Docker (tags, labels) id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v6 with: tags: | type=ref,event=tag @@ -58,33 +58,12 @@ jobs: type=raw,value=${{ github.event.inputs.tag }} - name: Build and push Docker images - run: | - IMG_DIR="build/images" - for dir in "$IMG_DIR"/*/; do - # Find Dockerfile or *.dockerfile in a case-insensitive manner - dockerfile=$(find "$dir" -maxdepth 1 -type f \( -iname 'dockerfile' -o -iname '*.dockerfile' \) | head -n 1) - - if [ -n "$dockerfile" ] && [ -f "$dockerfile" ]; then - IMAGE_NAME=$(basename "$dir") - echo "Building Docker image for $IMAGE_NAME with tags:" - - # Initialize tag arguments - tag_args=() - - # Read each tag and append --tag arguments - while IFS= read -r tag; do - tag_args+=(--tag "${{ secrets.DOCKER_USERNAME }}/$IMAGE_NAME:$tag") - tag_args+=(--tag "ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:$tag") - tag_args+=(--tag "registry.cn-hangzhou.aliyuncs.com/openimsdk/$IMAGE_NAME:$tag") - done <<< "${{ steps.meta.outputs.tags }}" - - # Build and push the Docker image with all tags - docker buildx build --platform linux/amd64,linux/arm64 \ - --file "$dockerfile" \ - "${tag_args[@]}" \ - --push \ - "." - else - echo "No valid Dockerfile found in $dir" - fi - done + env: + PUSH: "true" + RELEASE: "true" + IMAGE_TAGS: ${{ steps.meta.outputs.tags }} + IMAGE_REGISTRIES: | + ${{ secrets.DOCKER_USERNAME }} + ghcr.io/${{ github.repository_owner }} + registry.cn-hangzhou.aliyuncs.com/openimsdk + run: build/build.sh diff --git a/.github/workflows/gosec.yml b/.github/workflows/gosec.yml index 43fba5c0c..bcb5ffcad 100644 --- a/.github/workflows/gosec.yml +++ b/.github/workflows/gosec.yml @@ -8,9 +8,11 @@ name: OpenIM Run Gosec # https://github.com/securego/gosec/ on: push: - branches: "*" + branches: + - "*" pull_request: - branches: "*" + branches: + - "*" paths-ignore: - '*.md' - '*.yml' @@ -23,9 +25,9 @@ jobs: GO111MODULE: on steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v7 - name: Run Gosec Security Scanner - uses: securego/gosec@master + uses: securego/gosec@v2.27.1 with: args: ./... - continue-on-error: true \ No newline at end of file + continue-on-error: true diff --git a/.github/workflows/help-comment-issue.yml b/.github/workflows/help-comment-issue.yml index 65b2e99f4..60acad86d 100644 --- a/.github/workflows/help-comment-issue.yml +++ b/.github/workflows/help-comment-issue.yml @@ -12,7 +12,7 @@ jobs: issues: write steps: - name: Add comment - uses: peter-evans/create-or-update-comment@v4 + uses: peter-evans/create-or-update-comment@v5 with: issue-number: ${{ github.event.issue.number }} token: ${{ secrets.BOT_TOKEN }} diff --git a/.github/workflows/merge-from-milestone.yml b/.github/workflows/merge-from-milestone.yml index a5e385239..b3908035e 100644 --- a/.github/workflows/merge-from-milestone.yml +++ b/.github/workflows/merge-from-milestone.yml @@ -40,7 +40,7 @@ jobs: touch ${{ env.TEMP_DIR }}/created_pr_number.txt - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 token: ${{ secrets.BOT_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a46b1c8bd..b2204f392 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: DOCKER_CLI_EXPERIMENTAL: "enabled" steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v7 with: fetch-depth: 0 @@ -30,38 +30,38 @@ jobs: mkdir -p $HOME/.cache/snapcraft/download mkdir -p $HOME/.cache/snapcraft/stage-packages - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v6 with: go-version: stable - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v4 - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Log in to AliYun Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v4 with: registry: registry.cn-hangzhou.aliyuncs.com username: ${{ secrets.ALIREGISTRY_USERNAME }} password: ${{ secrets.ALIREGISTRY_TOKEN }} - name: set action env cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ./_output/dist/*.deb @@ -69,12 +69,12 @@ jobs: ./_output/dist/*.apk key: ${{ github.ref }} - - uses: sigstore/cosign-installer@v3.1.1 - - uses: anchore/sbom-action/download-syft@v0.14.3 - - uses: crazy-max/ghaction-upx@v2 + - uses: sigstore/cosign-installer@v4 + - uses: anchore/sbom-action/download-syft@v0.24.0 + - uses: crazy-max/ghaction-upx@v4 with: install-only: true - - uses: cachix/install-nix-action@v22 + - uses: cachix/install-nix-action@v31 with: github_access_token: ${{ secrets.GITHUB_TOKEN }} # - name: snapcraft-login @@ -83,7 +83,7 @@ jobs: # More assembly might be required: Docker logins, GPG, etc. It all depends # on your needs. - - uses: goreleaser/goreleaser-action@v4 + - uses: goreleaser/goreleaser-action@v7 with: # either 'goreleaser' (default) or 'goreleaser-pro': distribution: goreleaser diff --git a/.github/workflows/remove-unused-labels.yml b/.github/workflows/remove-unused-labels.yml index a2259d718..095daeb01 100644 --- a/.github/workflows/remove-unused-labels.yml +++ b/.github/workflows/remove-unused-labels.yml @@ -11,11 +11,11 @@ jobs: contents: read steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Fetch All Issues and PRs id: fetch_issues_prs - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -38,7 +38,7 @@ jobs: - name: Fetch All Labels id: fetch_labels - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -52,7 +52,7 @@ jobs: result-encoding: string - name: Remove Unused Labels - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -72,4 +72,4 @@ jobs: env: LABELS_IN_USE: ${{ steps.fetch_issues_prs.outputs.result }} - ALL_LABELS: ${{ steps.fetch_labels.outputs.result }} \ No newline at end of file + ALL_LABELS: ${{ steps.fetch_labels.outputs.result }} diff --git a/.github/workflows/reopen-issue.yml b/.github/workflows/reopen-issue.yml index d12e2c30e..75b4a4ac0 100644 --- a/.github/workflows/reopen-issue.yml +++ b/.github/workflows/reopen-issue.yml @@ -12,11 +12,11 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Fetch Closed Issues with lifecycle/stale Label id: fetch_issues - uses: actions/github-script@v7 + uses: actions/github-script@v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -40,7 +40,7 @@ jobs: echo "Issue numbers: ${{ steps.fetch_issues.outputs.result }}" - name: Reopen Issues - uses: actions/github-script@v7 + uses: actions/github-script@v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -59,7 +59,7 @@ jobs: } - name: Remove lifecycle/stale Label - uses: actions/github-script@v7 + uses: actions/github-script@v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/update-version-file-on-release.yml b/.github/workflows/update-version-file-on-release.yml index b7e2a4409..1222dd3b9 100644 --- a/.github/workflows/update-version-file-on-release.yml +++ b/.github/workflows/update-version-file-on-release.yml @@ -12,7 +12,7 @@ jobs: steps: # Step 1: Checkout the original repository's code - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 # submodules: "recursive" @@ -73,7 +73,7 @@ jobs: # Step 7: Find and Publish Draft Release - name: Find and Publish Draft Release - uses: actions/github-script@v7 + uses: actions/github-script@v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 5987088e1..d6807b29b 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -17,7 +17,7 @@ before: hooks: - - make clean + - rm -rf _output/dist # You may remove this if you don't use go modules. - go mod tidy # you may remove this if you don't need go generate diff --git a/Dockerfile b/Dockerfile index dd1038031..ce6abefa4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,52 +1,26 @@ -# Use Go 1.21 Alpine as the base image for building the application -FROM golang:1.22-alpine AS builder +FROM golang:alpine AS builder -# Define the base directory for the application as an environment variable -ENV SERVER_DIR=/openim-chat +ARG RELEASE=false +ARG COMPRESS=false +WORKDIR /openim-chat -# Set the working directory inside the container based on the environment variable -WORKDIR $SERVER_DIR +RUN apk add --no-cache upx +RUN go install github.com/magefile/mage@latest -# Set the Go proxy to improve dependency resolution speed -# ENV GOPROXY=https://goproxy.io,direct - -COPY go.mod go.sum ./ - -RUN go mod download - -# Copy all files from the current directory into the container COPY . . +RUN go mod download +RUN RELEASE=${RELEASE} COMPRESS=${COMPRESS} mage build +RUN mage -compile ./mage -ldflags "-s -w" +FROM alpine:latest -# Install Mage to use for building the application -RUN go install github.com/magefile/mage@v1.15.0 - -# Optionally build your application if needed -RUN mage build - -# Using Alpine Linux with Go environment for the final image -FROM golang:1.22-alpine +WORKDIR /openim-chat -# Install necessary packages, such as bash RUN apk add --no-cache bash -# Set the environment and work directory -ENV SERVER_DIR=/openim-chat -WORKDIR $SERVER_DIR - - -# Copy the compiled binaries and mage from the builder image to the final image -COPY --from=builder $SERVER_DIR/_output $SERVER_DIR/_output -COPY --from=builder $SERVER_DIR/config $SERVER_DIR/config -COPY --from=builder /go/bin/mage /usr/local/bin/mage -COPY --from=builder $SERVER_DIR/magefile_windows.go $SERVER_DIR/ -COPY --from=builder $SERVER_DIR/magefile_unix.go $SERVER_DIR/ -COPY --from=builder $SERVER_DIR/magefile.go $SERVER_DIR/ -COPY --from=builder $SERVER_DIR/start-config.yml $SERVER_DIR/ -COPY --from=builder $SERVER_DIR/go.mod $SERVER_DIR/ -COPY --from=builder $SERVER_DIR/go.sum $SERVER_DIR/ - -RUN go get github.com/openimsdk/gomake@v0.0.14-alpha.5 +COPY --from=builder /openim-chat/_output ./_output +COPY --from=builder /openim-chat/config ./config +COPY --from=builder /openim-chat/start-config.yml ./start-config.yml +COPY --from=builder /openim-chat/mage ./mage -# Set the command to run when the container starts -ENTRYPOINT ["sh", "-c", "mage start && tail -f /dev/null"] +ENTRYPOINT ["sh", "-c", "./mage start && sleep infinity"] diff --git a/build/README.md b/build/README.md index edd419ae5..59dd04dd3 100644 --- a/build/README.md +++ b/build/README.md @@ -1,65 +1,43 @@ -# Building OpenIM +# Building OpenIM Chat Images -Building OpenIM is easy if you take advantage of the containerized build environment. This document will help guide you through understanding this build process. +The chat service images share one Dockerfile. The compose file defines each service and passes a command path and binary name into that Dockerfile. ## Requirements -1. Docker, using one of the following configurations: - * **macOS** Install Docker for Mac. See installation instructions [here](https://docs.docker.com/docker-for-mac/). - **Note**: You will want to set the Docker VM to have at least 4GB of initial memory or building will likely fail. - * **Linux with local Docker** Install Docker according to the [instructions](https://docs.docker.com/installation/#installation) for your OS. - * **Windows with Docker Desktop WSL2 backend** Install Docker according to the [instructions](https://docs.docker.com/docker-for-windows/wsl-tech-preview/). Be sure to store your sources in the local Linux file system, not the Windows remote mount at `/mnt/c`. - - **Note**: You will need to check if Docker CLI plugin buildx is properly installed (`docker-buildx` file should be present in `~/.docker/cli-plugins`). You can install buildx according to the [instructions](https://github.com/docker/buildx/blob/master/README.md#installing). +Docker with the compose and buildx plugins is required. `jq` is required when pushing images with `PUSH=true`. -2. **Optional** [Google Cloud SDK](https://developers.google.com/cloud/sdk/) +## Local Build -You must install and configure Google Cloud SDK if you want to upload your release to Google Cloud Storage and may safely omit this otherwise. - -## Actions - -About [Images packages](https://github.com/orgs/OpenIMSDK/packages?repo_name=Open-IM-Server) - -All files in the `build/images` directory are not templated and are instead rendered by Github Actions, which is an automated process. - -Trigger condition: -1. create a new tag with the format `vX.Y.Z` (e.g. `v1.0.0`) -2. push the tag to the remote repository -3. wait for the build to finish -4. download the artifacts from the release page - -## Make images - -**help info:** +Build all chat service images locally through compose: ```bash -$ make image.help +build/build.sh ``` -**build images:** +Build release-optimized local images: ```bash -$ make image +RELEASE=true build/build.sh ``` -## Overview - -While it is possible to build OpenIM using a local golang installation, we have a build process that runs in a Docker container. This simplifies initial set up and provides for a very consistent build and test environment. +Build one service locally through compose: +```bash +docker compose -f build/images/openim-chat/docker-compose.build.yml build openim-chat-api +``` -## Basic Flow - -The scripts directly under [`build/`](.) are used to build and test. They will ensure that the `openim-build` Docker image is built (based on [`build/build-image/Dockerfile`](../Dockerfile) and after base image's `OPENIM_BUILD_IMAGE_CROSS_TAG` from Dockerfile is replaced with one of those actual tags of the base image, like `v1.13.9-2`) and then execute the appropriate command in that container. These scripts will both ensure that the right data is cached from run to run for incremental builds and will copy the results back out of the container. You can specify a different registry/name and version for `openim-cross` by setting `OPENIM_CROSS_IMAGE` and `OPENIM_CROSS_VERSION`, see [`common.sh`](common.sh) for more details. - -The `openim-build` container image is built by first creating a "context" directory in `_output/images/build-image`. It is done there instead of at the root of the OpenIM repo to minimize the amount of data we need to package up when building the image. +## Push Images -There are 3 different containers instances that are run from this image. The first is a "data" container to store all data that needs to persist across to support incremental builds. Next there is an "rsync" container that is used to transfer data in and out to the data container. Lastly there is a "build" container that is used for actually doing build actions. The data container persists across runs while the rsync and build containers are deleted after each use. +CI uses the same build script with `PUSH=true`. The script reads services from `build/images/openim-chat/docker-compose.build.yml`, then builds and pushes each service defined there. -`rsync` is used transparently behind the scenes to efficiently move data in and out of the container. This will use an ephemeral port picked by Docker. You can modify this by setting the `OPENIM_RSYNC_PORT` env variable. +The required variables are: -All Docker names are suffixed with a hash derived from the file path (to allow concurrent usage on things like CI machines) and a version number. When the version number changes all state is cleared and clean build is started. This allows the build infrastructure to be changed and signal to CI systems that old artifacts need to be deleted. +```bash +PUSH=true \ +RELEASE=true \ +IMAGE_TAGS="v1.0.0,sha-abcdef" \ +IMAGE_REGISTRIES="openim,ghcr.io/openimsdk,registry.cn-hangzhou.aliyuncs.com/openimsdk" \ +build/build.sh +``` -## Build artifacts -The build system output all its products to a top level directory in the source repository named `_output`. -These include the binary compiled packages (e.g. imctl, openim-api etc.) and archived Docker images. -If you intend to run a component with a docker image you will need to import it from this directory with +`IMAGE_TAGS` and `IMAGE_REGISTRIES` can be comma, space, or newline separated. For each compose service, the script reads `build.context`, `build.dockerfile`, `build.args.CMD_PATH`, and `build.args.BINARY_NAME`, then pushes every `registry/BINARY_NAME:tag` combination. diff --git a/build/build.sh b/build/build.sh new file mode 100755 index 000000000..3ae033e0c --- /dev/null +++ b/build/build.sh @@ -0,0 +1,129 @@ +#!/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-chat/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:-}" + +if [[ ! -f "$COMPOSE_FILE" ]]; then + echo -e "${RED}docker-compose.build.yml not found: $COMPOSE_FILE${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 +} + +build_local() { + echo -e "${CYAN}Building all services...${NO_COLOR}" + while IFS= read -r service; do + RELEASE="$RELEASE" docker compose -f "$COMPOSE_FILE" build "$service" + done < <(docker compose -f "$COMPOSE_FILE" config --services) + + echo -e "${CYAN}Tagging compatibility images for Kubernetes...${NO_COLOR}" + while IFS= read -r built_image; do + [[ -n "$built_image" ]] || continue + compatibility_tag="${built_image##*/}" + + if [[ "$built_image" != "$compatibility_tag" ]]; then + docker tag "$built_image" "$compatibility_tag" + fi + done < <(docker compose -f "$COMPOSE_FILE" config --images) + + echo -e "${GREEN}Successfully built all services${NO_COLOR}" +} + +build_push() { + if ! command -v jq >/dev/null 2>&1; then + echo -e "${RED}jq is required for PUSH=true${NO_COLOR}" + exit 1 + fi + + if [[ -z "$IMAGE_TAGS" || -z "$IMAGE_REGISTRIES" ]]; then + echo -e "${RED}IMAGE_TAGS and IMAGE_REGISTRIES are required for PUSH=true${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) + + echo -e "${CYAN}Building and pushing service images...${NO_COLOR}" + while IFS= read -r service; do + 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}" + continue + 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" + done < <(jq -r '.services | keys[]' <<< "$compose_config" | sort) + + echo -e "${GREEN}Successfully pushed service images${NO_COLOR}" +} + +if [[ "$PUSH" == "true" ]]; then + build_push +else + build_local +fi diff --git a/build/images/Dockerfile b/build/images/Dockerfile deleted file mode 100644 index 2b78e8af5..000000000 --- a/build/images/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright © 2023 OpenIM open source community. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -FROM BASE_IMAGE - -WORKDIR ${SERVER_WORKDIR} - -# Set HTTP proxy -ARG BINARY_NAME - -COPY BINARY_NAME ./bin/BINARY_NAME - -ENTRYPOINT ["./bin/BINARY_NAME"] \ No newline at end of file diff --git a/build/images/openim-admin-api/Dockerfile b/build/images/openim-admin-api/Dockerfile deleted file mode 100644 index 5f74d61a7..000000000 --- a/build/images/openim-admin-api/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# Use Go 1.22 Alpine as the base image for building the application -FROM golang:1.22-alpine AS builder - -# Define the base directory for the application as an environment variable -ENV CHAT_DIR=/openim-chat - -# Set the working directory inside the container based on the environment variable -WORKDIR $CHAT_DIR - -# Set the Go proxy to improve dependency resolution speed -#ENV GOPROXY=https://goproxy.io,direct - -# Copy all files from the current directory into the container -COPY . . - -RUN go mod tidy - -RUN go build -o _output/admin-api ./cmd/api/admin-api - -# Using Alpine Linux for the final image -FROM alpine:latest - -# Install necessary packages, such as bash -RUN apk add --no-cache bash - -# Set the environment and work directory -ENV CHAT_DIR=/openim-chat -WORKDIR $CHAT_DIR - - -# Copy the compiled binaries and mage from the builder image to the final image -COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output -COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config - -# Set the command to run when the container starts -ENTRYPOINT ["sh", "-c", "_output/admin-api"] \ No newline at end of file diff --git a/build/images/openim-admin-rpc/Dockerfile b/build/images/openim-admin-rpc/Dockerfile deleted file mode 100644 index 4f1ae7edd..000000000 --- a/build/images/openim-admin-rpc/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# Use Go 1.22 Alpine as the base image for building the application -FROM golang:1.22-alpine AS builder - -# Define the base directory for the application as an environment variable -ENV CHAT_DIR=/openim-chat - -# Set the working directory inside the container based on the environment variable -WORKDIR $CHAT_DIR - -# Set the Go proxy to improve dependency resolution speed -#ENV GOPROXY=https://goproxy.io,direct - -# Copy all files from the current directory into the container -COPY . . - -RUN go mod tidy - -RUN go build -o _output/admin-rpc ./cmd/rpc/admin-rpc - -# Using Alpine Linux for the final image -FROM alpine:latest - -# Install necessary packages, such as bash -RUN apk add --no-cache bash - -# Set the environment and work directory -ENV CHAT_DIR=/openim-chat -WORKDIR $CHAT_DIR - - -# Copy the compiled binaries and mage from the builder image to the final image -COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output -COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config - -# Set the command to run when the container starts -ENTRYPOINT ["sh", "-c", "_output/admin-rpc"] \ No newline at end of file diff --git a/build/images/openim-chat-api/Dockerfile b/build/images/openim-chat-api/Dockerfile deleted file mode 100644 index 4b03ebd6b..000000000 --- a/build/images/openim-chat-api/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# Use Go 1.22 Alpine as the base image for building the application -FROM golang:1.22-alpine AS builder - -# Define the base directory for the application as an environment variable -ENV CHAT_DIR=/openim-chat - -# Set the working directory inside the container based on the environment variable -WORKDIR $CHAT_DIR - -# Set the Go proxy to improve dependency resolution speed -#ENV GOPROXY=https://goproxy.io,direct - -# Copy all files from the current directory into the container -COPY . . - -RUN go mod tidy - -RUN go build -o _output/chat-api ./cmd/api/chat-api - -# Using Alpine Linux for the final image -FROM alpine:latest - -# Install necessary packages, such as bash -RUN apk add --no-cache bash - -# Set the environment and work directory -ENV CHAT_DIR=/openim-chat -WORKDIR $CHAT_DIR - - -# Copy the compiled binaries and mage from the builder image to the final image -COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output -COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config - -# Set the command to run when the container starts -ENTRYPOINT ["sh", "-c", "_output/chat-api"] \ No newline at end of file diff --git a/build/images/openim-chat-rpc/Dockerfile b/build/images/openim-chat-rpc/Dockerfile deleted file mode 100644 index e24e094db..000000000 --- a/build/images/openim-chat-rpc/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# Use Go 1.22 Alpine as the base image for building the application -FROM golang:1.22-alpine AS builder - -# Define the base directory for the application as an environment variable -ENV CHAT_DIR=/openim-chat - -# Set the working directory inside the container based on the environment variable -WORKDIR $CHAT_DIR - -# Set the Go proxy to improve dependency resolution speed -#ENV GOPROXY=https://goproxy.io,direct - -# Copy all files from the current directory into the container -COPY . . - -RUN go mod tidy - -RUN go build -o _output/chat-rpc ./cmd/rpc/chat-rpc - -# Using Alpine Linux for the final image -FROM alpine:latest - -# Install necessary packages, such as bash -RUN apk add --no-cache bash - -# Set the environment and work directory -ENV CHAT_DIR=/openim-chat -WORKDIR $CHAT_DIR - - -# Copy the compiled binaries and mage from the builder image to the final image -COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output -COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config - -# Set the command to run when the container starts -ENTRYPOINT ["sh", "-c", "_output/chat-rpc"] \ No newline at end of file diff --git a/build/images/openim-chat/Dockerfile b/build/images/openim-chat/Dockerfile new file mode 100644 index 000000000..0ea73758e --- /dev/null +++ b/build/images/openim-chat/Dockerfile @@ -0,0 +1,31 @@ +FROM golang:1.25-alpine AS builder + +ENV SERVER_DIR=/openim-chat +WORKDIR $SERVER_DIR + +COPY . . +RUN go mod tidy + +ARG CMD_PATH +ARG BINARY_NAME +ARG RELEASE=false + +RUN if [ "$RELEASE" = "true" ]; then \ + go build -trimpath -ldflags "-s -w" -o _output/${BINARY_NAME} ./${CMD_PATH}; \ + else \ + go build -o _output/${BINARY_NAME} ./${CMD_PATH}; \ + fi + +FROM alpine:latest + +RUN apk add --no-cache bash + +ARG BINARY_NAME +ENV BINARY_NAME=${BINARY_NAME} +ENV SERVER_DIR=/openim-chat +WORKDIR $SERVER_DIR + +COPY --from=builder $SERVER_DIR/_output $SERVER_DIR/_output +COPY --from=builder $SERVER_DIR/config $SERVER_DIR/config + +ENTRYPOINT ["sh", "-c", "_output/${BINARY_NAME}"] diff --git a/build/images/openim-chat/docker-compose.build.yml b/build/images/openim-chat/docker-compose.build.yml new file mode 100644 index 000000000..12292a93b --- /dev/null +++ b/build/images/openim-chat/docker-compose.build.yml @@ -0,0 +1,40 @@ +services: + openim-admin-api: + build: + context: ../../.. + dockerfile: build/images/openim-chat/Dockerfile + args: + CMD_PATH: cmd/api/admin-api + BINARY_NAME: openim-admin-api + RELEASE: ${RELEASE:-false} + image: openim-admin-api:test + + openim-admin-rpc: + build: + context: ../../.. + dockerfile: build/images/openim-chat/Dockerfile + args: + CMD_PATH: cmd/rpc/admin-rpc + BINARY_NAME: openim-admin-rpc + RELEASE: ${RELEASE:-false} + image: openim-admin-rpc:test + + openim-chat-api: + build: + context: ../../.. + dockerfile: build/images/openim-chat/Dockerfile + args: + CMD_PATH: cmd/api/chat-api + BINARY_NAME: openim-chat-api + RELEASE: ${RELEASE:-false} + image: openim-chat-api:test + + openim-chat-rpc: + build: + context: ../../.. + dockerfile: build/images/openim-chat/Dockerfile + args: + CMD_PATH: cmd/rpc/chat-rpc + BINARY_NAME: openim-chat-rpc + RELEASE: ${RELEASE:-false} + image: openim-chat-rpc:test