diff --git a/.github/workflows/cbio-build.yml b/.github/workflows/cbio-build.yml new file mode 100644 index 00000000000..28295e648c1 --- /dev/null +++ b/.github/workflows/cbio-build.yml @@ -0,0 +1,122 @@ +name: Build and Push cBioPortal LibreChat Image + +on: + push: + branches: + - '**' + workflow_dispatch: + inputs: + tag: + description: 'Image tag (e.g. v0.8.3-rc1-custom-v6). Defaults to branch name.' + type: string + required: false + +jobs: + build: + runs-on: ubuntu-24.04-arm + outputs: + image_tag: ${{ steps.tag.outputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + # Image tagging convention: + # - Manual dispatch: uses the user-provided tag (e.g. "v0.8.3-rc1-custom-v8") + # - Automatic (push): uses the branch name with "/" replaced by "-" + # e.g. branch "v0.8.3-rc1-custom-v7" -> tag "v0.8.3-rc1-custom-v7" + # Convention: -custom-v where N is incremented for each cBioPortal-specific release. + # The same tag is deployed to BOTH AWS accounts (203403084713 and 666628074417) + # via the update_k8s_deployment job, which updates both values.yaml files. + - name: Set image tag + id: tag + run: | + if [ -n "${{ github.event.inputs.tag }}" ]; then + echo "tag=${{ github.event.inputs.tag }}" >> "$GITHUB_OUTPUT" + else + # Use branch name, replacing / with - + BRANCH="${GITHUB_REF_NAME//\//-}" + echo "tag=${BRANCH}" >> "$GITHUB_OUTPUT" + fi + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Prepare environment + run: cp .env.example .env + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile + push: true + tags: cbioportal/librechat:${{ steps.tag.outputs.tag }} + platforms: linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + + update_k8s_deployment: + needs: build + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + env: + K8S_REPO: 'knowledgesystems/knowledgesystems-k8s-deployment' + IMAGE_REPO: 'cbioportal/librechat' + DEPLOYMENT_FILES: >- + argocd/aws/203403084713/clusters/cbioportal-prod/apps/cbioagent/values.yaml + argocd/aws/666628074417/clusters/cbioportal-prod/apps/cbioagent/values.yaml + ARGOCD_CLI_VER: '2.13.3' + ARGOCD_SERVER: 'argocd.cbioportal.org' + ARGOCD_APP: 'cbioagent' + steps: + - name: Checkout K8s Repo + uses: actions/checkout@v4 + with: + repository: ${{ env.K8S_REPO }} + token: ${{ secrets.K8S_REPO_TOKEN }} + + - name: Update image tag in values files + run: | + IMAGE_TAG=${{ needs.build.outputs.image_tag }} + for FILE in $DEPLOYMENT_FILES; do + # Only update the image.tag field (indented under 'image:'), not other tag fields + sed -i '/^image:/,/^[^ ]/ s|^\( tag:\).*|\1 "'"${IMAGE_TAG}"'"|' $FILE + done + + - name: Commit and push changes + run: | + git config --global user.email "cBioPortal-Action@github.com" + git config --global user.name "LibreChat Github Action" + if ! git diff --quiet; then + git add -A + git commit -m "Update LibreChat image tag to ${{ needs.build.outputs.image_tag }}" + else + echo "No changes to commit." + fi + + - name: Push changes to K8s repo + uses: ad-m/github-push-action@master + with: + github_token: '${{ secrets.K8S_REPO_TOKEN }}' + repository: ${{ env.K8S_REPO }} + branch: master + + - name: Setup ArgoCD + uses: clowdhaus/argo-cd-action/@main + with: + version: ${{ env.ARGOCD_CLI_VER }} + command: login ${{ env.ARGOCD_SERVER }} + options: --username ${{ secrets.ARGOCD_2034_USERNAME }} --password ${{ secrets.ARGOCD_2034_PASSWORD }} + + - name: Sync ArgoCD deployment + uses: clowdhaus/argo-cd-action/@main + with: + version: ${{ env.ARGOCD_CLI_VER }} + command: app sync ${{ env.ARGOCD_APP }} + options: --resource apps:Deployment:default/librechat diff --git a/.github/workflows/cbio-integration-test.yml b/.github/workflows/cbio-integration-test.yml new file mode 100644 index 00000000000..ead403641af --- /dev/null +++ b/.github/workflows/cbio-integration-test.yml @@ -0,0 +1,116 @@ +name: cBioPortal Integration Test + +on: + pull_request: + branches: + - main + +jobs: + integration-test: + runs-on: ubuntu-latest + + services: + mongodb: + image: mongo:7 + ports: + - 27017:27017 + + steps: + - name: Checkout LibreChat (PR code) + uses: actions/checkout@v4 + + - name: Checkout k8s-deployment repo + uses: actions/checkout@v4 + with: + repository: knowledgesystems/knowledgesystems-k8s-deployment + token: ${{ secrets.K8S_REPO_TOKEN }} + path: k8s-deployment + sparse-checkout: | + argocd/aws/203403084713/clusters/cbioportal-prod/apps/cbioagent/librechat-config.yaml + + - name: Extract librechat.yaml from ConfigMap + run: | + CONFIG_MAP="k8s-deployment/argocd/aws/203403084713/clusters/cbioportal-prod/apps/cbioagent/librechat-config.yaml" + if [ ! -f "$CONFIG_MAP" ]; then + echo "::error::ConfigMap file not found at $CONFIG_MAP" + exit 1 + fi + + # Install yq + sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64 + sudo chmod +x /usr/local/bin/yq + + # Extract the librechat.yaml value from the ConfigMap's .data["librechat.yaml"] field + yq '.data["librechat.yaml"]' "$CONFIG_MAP" > librechat.yaml + + if [ ! -s librechat.yaml ] || grep -q '^null$' librechat.yaml; then + echo "::error::Failed to extract librechat.yaml from ConfigMap" + exit 1 + fi + + echo "Extracted librechat.yaml ($(wc -l < librechat.yaml) lines)" + + - name: Prepare environment file + run: cp .env.example .env + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile.multi + push: false + load: true + tags: librechat-integration-test:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Run container with production config + run: | + docker run -d \ + --name librechat-test \ + --network host \ + -e MONGO_URI="mongodb://127.0.0.1:27017/LibreChat" \ + -e CREDS_KEY="f34be427ebb29de8d88c107a71546019685ed8b241d8f2ed00c3df97ad2566f0" \ + -e CREDS_IV="e2341419ec3dd3d19b13a1a87fafcbfb" \ + -e JWT_SECRET="16f8c0ef4a5d391b26034086c628469d3f9f497f08163ab9b40137092f2909ef" \ + -e JWT_REFRESH_SECRET="dummyrefreshsecret" \ + -e HOST="0.0.0.0" \ + -e PORT="3080" \ + -v "$(pwd)/librechat.yaml:/app/librechat.yaml:ro" \ + librechat-integration-test:latest + + - name: Wait for health check + run: | + echo "Waiting for LibreChat to become healthy..." + TIMEOUT=60 + INTERVAL=3 + ELAPSED=0 + + while [ $ELAPSED -lt $TIMEOUT ]; do + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3080/health 2>/dev/null || true) + if [ "$HTTP_CODE" = "200" ]; then + echo "Health check passed (HTTP 200) after ${ELAPSED}s" + exit 0 + fi + echo " ... not ready yet (HTTP $HTTP_CODE) [${ELAPSED}s/${TIMEOUT}s]" + sleep $INTERVAL + ELAPSED=$((ELAPSED + INTERVAL)) + done + + echo "::error::Health check failed after ${TIMEOUT}s" + echo "" + echo "=== Container logs ===" + docker logs librechat-test 2>&1 | tail -100 + exit 1 + + - name: Dump logs on failure + if: failure() + run: | + echo "=== Container status ===" + docker inspect librechat-test --format='{{.State.Status}}' 2>/dev/null || echo "Container not found" + echo "" + echo "=== Container logs ===" + docker logs librechat-test 2>&1 || echo "No logs available"