diff --git a/.env.example b/.env.example index 8b11217b5d..08da6601c2 100644 --- a/.env.example +++ b/.env.example @@ -26,9 +26,10 @@ AWS_S3_BUCKET_NAME="uploads" FILE_SIZE_LIMIT=5242880 # GPT settings +SILO_BASE_URL= OPENAI_API_BASE="https://api.openai.com/v1" # deprecated OPENAI_API_KEY="sk-" # deprecated -GPT_ENGINE="gpt-3.5-turbo" # deprecated +GPT_ENGINE="gpt-4o-mini" # deprecated # Settings related to Docker DOCKERIZED=1 # deprecated @@ -38,3 +39,11 @@ USE_MINIO=1 # Nginx Configuration NGINX_PORT=80 + +# Imports Config +SILO_BASE_URL= + +MONGO_DB_URL="mongodb://plane-mongodb:27017/" + +SILO_DB=silo +SILO_DB_URL=postgresql://plane:plane@plane-db/silo diff --git a/.github/actions/build-push-cloud/action.yml b/.github/actions/build-push-cloud/action.yml new file mode 100644 index 0000000000..c4d5aaff25 --- /dev/null +++ b/.github/actions/build-push-cloud/action.yml @@ -0,0 +1,127 @@ +name: "Build and Push Docker Image" +description: "Reusable action for building and pushing Docker images" +inputs: + docker-username: + description: "The Dockerhub username" + required: true + dockerhub-token: + description: "The Dockerhub Token" + required: true + + # Docker Image Options + docker-image-owner: + description: "The owner of the Docker image" + required: true + docker-image-name: + description: "The name of the Docker image" + required: true + build-context: + description: "The build context" + required: true + default: "." + dockerfile-path: + description: "The path to the Dockerfile" + required: true + build-args: + description: "The build arguments" + required: false + default: "" + + # Buildx Options + buildx-driver: + description: "Buildx driver" + required: true + default: "docker-container" + buildx-version: + description: "Buildx version" + required: true + default: "latest" + buildx-platforms: + description: "Buildx platforms" + required: true + default: "linux/amd64" + buildx-endpoint: + description: "Buildx endpoint" + required: true + default: "default" + + # Release Build Options + build-release: + description: "Flag to publish release" + required: false + default: "false" + build-prerelease: + description: "Flag to publish prerelease" + required: false + default: "false" + release-version: + description: "The release version" + required: false + default: "latest" + +runs: + using: "composite" + steps: + - name: Set Docker Tag + shell: bash + env: + IMG_OWNER: ${{ inputs.docker-image-owner }} + IMG_NAME: ${{ inputs.docker-image-name }} + BUILD_RELEASE: ${{ inputs.build-release }} + IS_PRERELEASE: ${{ inputs.build-prerelease }} + REL_VERSION: ${{ inputs.release-version }} + run: | + FLAT_BRANCH_VERSION=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9.-]//g') + + if [ "${{ env.BUILD_RELEASE }}" == "true" ]; then + semver_regex="^v([0-9]+)\.([0-9]+)\.([0-9]+)(-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)?$" + if [[ ! ${{ env.REL_VERSION }} =~ $semver_regex ]]; then + echo "Invalid Release Version Format : ${{ env.REL_VERSION }}" + echo "Please provide a valid SemVer version" + echo "e.g. v1.2.3 or v1.2.3-alpha-1" + echo "Exiting the build process" + exit 1 # Exit with status 1 to fail the step + fi + + TAG=${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:${{ env.REL_VERSION }} + + if [ "${{ env.IS_PRERELEASE }}" != "true" ]; then + TAG=${TAG},${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:stable + fi + elif [ "${{ env.TARGET_BRANCH }}" == "master" ]; then + TAG=${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:latest + else + TAG=${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:${FLAT_BRANCH_VERSION} + fi + + echo "DOCKER_TAGS=${TAG}" >> $GITHUB_ENV + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ inputs.docker-username }} + password: ${{ inputs.dockerhub-token}} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver: ${{ inputs.buildx-driver }} + version: ${{ inputs.buildx-version }} + endpoint: ${{ inputs.buildx-endpoint }} + + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Build and Push Docker Image + uses: docker/build-push-action@v5.1.0 + with: + context: ${{ inputs.build-context }} + file: ${{ inputs.dockerfile-path }} + platforms: ${{ inputs.buildx-platforms }} + tags: ${{ env.DOCKER_TAGS }} + push: true + build-args: ${{ inputs.build-args }} + env: + DOCKER_BUILDKIT: 1 + DOCKER_USERNAME: ${{ inputs.docker-username }} + DOCKER_PASSWORD: ${{ inputs.dockerhub-token }} diff --git a/.github/actions/build-push-ee/action.yml b/.github/actions/build-push-ee/action.yml new file mode 100644 index 0000000000..db98c89ca2 --- /dev/null +++ b/.github/actions/build-push-ee/action.yml @@ -0,0 +1,168 @@ +name: "Build and Push Docker Image" +description: "Reusable action for building and pushing Docker images" +inputs: + docker-username: + description: "The Dockerhub username" + required: true + dockerhub-token: + description: "The Dockerhub Token" + required: true + + # Harbor Options + harbor-push: + description: "Flag to push to Harbor" + required: false + default: "false" + harbor-username: + description: "The Harbor username" + required: false + harbor-token: + description: "The Harbor token" + required: false + harbor-registry: + description: "The Harbor registry" + required: false + default: "registry.plane.tools" + harbor-project: + description: "The Harbor project" + required: false + + # Docker Image Options + docker-image-owner: + description: "The owner of the Docker image" + required: true + docker-image-name: + description: "The name of the Docker image" + required: true + build-context: + description: "The build context" + required: true + default: "." + dockerfile-path: + description: "The path to the Dockerfile" + required: true + build-args: + description: "The build arguments" + required: false + default: "" + + # Buildx Options + buildx-driver: + description: "Buildx driver" + required: true + default: "docker-container" + buildx-version: + description: "Buildx version" + required: true + default: "latest" + buildx-platforms: + description: "Buildx platforms" + required: true + default: "linux/amd64" + buildx-endpoint: + description: "Buildx endpoint" + required: true + default: "default" + + # Release Build Options + build-release: + description: "Flag to publish release" + required: false + default: "false" + build-prerelease: + description: "Flag to publish prerelease" + required: false + default: "false" + release-version: + description: "The release version" + required: false + default: "latest" + +runs: + using: "composite" + steps: + - name: Set Docker Tag + shell: bash + env: + IMG_OWNER: ${{ inputs.docker-image-owner }} + IMG_NAME: ${{ inputs.docker-image-name }} + HARBOR_PUSH: ${{ inputs.harbor-push }} + HARBOR_REGISTRY: ${{ inputs.harbor-registry }} + HARBOR_PROJECT: ${{ inputs.harbor-project }} + BUILD_RELEASE: ${{ inputs.build-release }} + IS_PRERELEASE: ${{ inputs.build-prerelease }} + REL_VERSION: ${{ inputs.release-version }} + run: | + FLAT_BRANCH_VERSION=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9.-]//g') + + if [ "${{ env.BUILD_RELEASE }}" == "true" ]; then + semver_regex="^v([0-9]+)\.([0-9]+)\.([0-9]+)(-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)?$" + if [[ ! ${{ env.REL_VERSION }} =~ $semver_regex ]]; then + echo "Invalid Release Version Format : ${{ env.REL_VERSION }}" + echo "Please provide a valid SemVer version" + echo "e.g. v1.2.3 or v1.2.3-alpha-1" + echo "Exiting the build process" + exit 1 # Exit with status 1 to fail the step + fi + + TAG=${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:${{ env.REL_VERSION }} + + if [ "${{ env.HARBOR_PUSH }}" == "true" ]; then + TAG=${TAG},${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/${{ env.IMG_NAME }}:${{ env.REL_VERSION }} + fi + + if [ "${{ env.IS_PRERELEASE }}" != "true" ]; then + TAG=${TAG},${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:stable + if [ "${{ env.HARBOR_PUSH }}" == "true" ]; then + TAG=${TAG},${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/${{ env.IMG_NAME }}:stable + fi + fi + elif [ "${{ env.TARGET_BRANCH }}" == "master" ]; then + TAG=${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:latest + if [ "${{ env.HARBOR_PUSH }}" == "true" ]; then + TAG=${TAG},${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/${{ env.IMG_NAME }}:latest + fi + else + TAG=${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:${FLAT_BRANCH_VERSION} + if [ "${{ env.HARBOR_PUSH }}" == "true" ]; then + TAG=${TAG},${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/${{ env.IMG_NAME }}:${FLAT_BRANCH_VERSION} + fi + fi + + echo "DOCKER_TAGS=${TAG}" >> $GITHUB_ENV + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ inputs.docker-username }} + password: ${{ inputs.dockerhub-token}} + - name: Login to Harbor + if: ${{ inputs.harbor-push }} == "true" + uses: docker/login-action@v3 + with: + username: ${{ inputs.harbor-username }} + password: ${{ inputs.harbor-token }} + registry: ${{ inputs.harbor-registry }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver: ${{ inputs.buildx-driver }} + version: ${{ inputs.buildx-version }} + endpoint: ${{ inputs.buildx-endpoint }} + + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Build and Push Docker Image + uses: docker/build-push-action@v5.1.0 + with: + context: ${{ inputs.build-context }} + file: ${{ inputs.dockerfile-path }} + platforms: ${{ inputs.buildx-platforms }} + tags: ${{ env.DOCKER_TAGS }} + push: true + build-args: ${{ inputs.build-args }} + env: + DOCKER_BUILDKIT: 1 + DOCKER_USERNAME: ${{ inputs.docker-username }} + DOCKER_PASSWORD: ${{ inputs.dockerhub-token }} diff --git a/.github/workflows/build-aio-branch-ee.yml b/.github/workflows/build-aio-branch-ee.yml new file mode 100644 index 0000000000..293668a570 --- /dev/null +++ b/.github/workflows/build-aio-branch-ee.yml @@ -0,0 +1,204 @@ +name: Branch Build AIO + +on: + workflow_dispatch: + inputs: + full: + description: 'Run full build' + type: boolean + required: false + default: true + slim: + description: 'Run slim build' + type: boolean + required: false + default: true + base_tag_name: + description: 'Base Tag Name' + required: false + default: '' + release: + types: [released, prereleased] + +env: + TARGET_BRANCH: ${{ github.ref_name || github.event.release.target_commitish }} + IS_PRERELEASE: ${{ github.event.release.prerelease }} + FULL_BUILD_INPUT: ${{ github.event.inputs.full }} + SLIM_BUILD_INPUT: ${{ github.event.inputs.slim }} + +jobs: + branch_build_setup: + name: Build Setup + runs-on: ubuntu-latest + outputs: + gh_branch_name: ${{ steps.set_env_variables.outputs.TARGET_BRANCH }} + gh_buildx_driver: ${{ steps.set_env_variables.outputs.BUILDX_DRIVER }} + gh_buildx_version: ${{ steps.set_env_variables.outputs.BUILDX_VERSION }} + gh_buildx_platforms: ${{ steps.set_env_variables.outputs.BUILDX_PLATFORMS }} + gh_buildx_endpoint: ${{ steps.set_env_variables.outputs.BUILDX_ENDPOINT }} + aio_base_tag: ${{ steps.set_env_variables.outputs.AIO_BASE_TAG }} + do_full_build: ${{ steps.set_env_variables.outputs.DO_FULL_BUILD }} + do_slim_build: ${{ steps.set_env_variables.outputs.DO_SLIM_BUILD }} + + steps: + - id: set_env_variables + name: Set Environment Variables + run: | + if [ [ "${{ github.event_name }}" == "release" ] && [ "${{ env.IS_PRERELEASE }}" != "true" ] ; then + echo "BUILDX_DRIVER=cloud" >> $GITHUB_OUTPUT + echo "BUILDX_VERSION=lab:latest" >> $GITHUB_OUTPUT + echo "BUILDX_PLATFORMS=linux/amd64,linux/arm64" >> $GITHUB_OUTPUT + echo "BUILDX_ENDPOINT=makeplane/plane-dev" >> $GITHUB_OUTPUT + + echo "AIO_BASE_TAG=latest" >> $GITHUB_OUTPUT + else + echo "BUILDX_DRIVER=docker-container" >> $GITHUB_OUTPUT + echo "BUILDX_VERSION=latest" >> $GITHUB_OUTPUT + echo "BUILDX_PLATFORMS=linux/amd64" >> $GITHUB_OUTPUT + echo "BUILDX_ENDPOINT=" >> $GITHUB_OUTPUT + + if [ "${{ github.event.inputs.base_tag_name }}" != "" ]; then + echo "AIO_BASE_TAG=${{ github.event.inputs.base_tag_name }}" >> $GITHUB_OUTPUT + elif [ "${{ env.TARGET_BRANCH }}" == "preview" ]; then + echo "AIO_BASE_TAG=preview" >> $GITHUB_OUTPUT + else + echo "AIO_BASE_TAG=develop" >> $GITHUB_OUTPUT + fi + fi + echo "TARGET_BRANCH=${{ env.TARGET_BRANCH }}" >> $GITHUB_OUTPUT + + if [ "${{ env.FULL_BUILD_INPUT }}" == "true" ] || [ "${{github.event_name}}" == "push" ] || [ "${{github.event_name}}" == "release" ]; then + echo "DO_FULL_BUILD=true" >> $GITHUB_OUTPUT + else + echo "DO_FULL_BUILD=false" >> $GITHUB_OUTPUT + fi + + if [ "${{ env.SLIM_BUILD_INPUT }}" == "true" ] || [ "${{github.event_name}}" == "push" ] || [ "${{github.event_name}}" == "release" ]; then + echo "DO_SLIM_BUILD=true" >> $GITHUB_OUTPUT + else + echo "DO_SLIM_BUILD=false" >> $GITHUB_OUTPUT + fi + + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + full_build_push: + if: ${{ needs.branch_build_setup.outputs.do_full_build == 'true' }} + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + env: + BUILD_TYPE: full + AIO_BASE_TAG: ${{ needs.branch_build_setup.outputs.aio_base_tag }} + AIO_IMAGE_TAGS: makeplane/plane-aio-enterprise:full-${{ needs.branch_build_setup.outputs.gh_branch_name }} + TARGET_BRANCH: ${{ needs.branch_build_setup.outputs.gh_branch_name }} + BUILDX_DRIVER: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + BUILDX_VERSION: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + BUILDX_PLATFORMS: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + BUILDX_ENDPOINT: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + steps: + - name: Set Docker Tag + run: | + if [ "${{ github.event_name }}" == "release" ]; then + TAG=makeplane/plane-aio-enterprise:${{env.BUILD_TYPE}}-stable,makeplane/plane-aio-enterprise:${{env.BUILD_TYPE}}-${{ github.event.release.tag_name }} + elif [ "${{ env.TARGET_BRANCH }}" == "master" ]; then + TAG=makeplane/plane-aio-enterprise:${{env.BUILD_TYPE}}-latest + else + TAG=${{ env.AIO_IMAGE_TAGS }} + fi + echo "AIO_IMAGE_TAGS=${TAG}" >> $GITHUB_ENV + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver: ${{ env.BUILDX_DRIVER }} + version: ${{ env.BUILDX_VERSION }} + endpoint: ${{ env.BUILDX_ENDPOINT }} + + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Build and Push to Docker Hub + uses: docker/build-push-action@v5.1.0 + with: + context: . + file: ./aio/Dockerfile-app + platforms: ${{ env.BUILDX_PLATFORMS }} + tags: ${{ env.AIO_IMAGE_TAGS }} + push: true + build-args: | + BUILD_TAG=${{ env.AIO_BASE_TAG }} + BUILD_TYPE=${{env.BUILD_TYPE}} + cache-from: type=gha + cache-to: type=gha,mode=max + + env: + DOCKER_BUILDKIT: 1 + DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }} + + slim_build_push: + if: ${{ needs.branch_build_setup.outputs.do_slim_build == 'true' }} + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + env: + BUILD_TYPE: slim + AIO_BASE_TAG: ${{ needs.branch_build_setup.outputs.aio_base_tag }} + AIO_IMAGE_TAGS: makeplane/plane-aio-enterprise:slim-${{ needs.branch_build_setup.outputs.gh_branch_name }} + TARGET_BRANCH: ${{ needs.branch_build_setup.outputs.gh_branch_name }} + BUILDX_DRIVER: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + BUILDX_VERSION: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + BUILDX_PLATFORMS: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + BUILDX_ENDPOINT: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + steps: + - name: Set Docker Tag + run: | + if [ "${{ github.event_name }}" == "release" ]; then + TAG=makeplane/plane-aio-enterprise:${{env.BUILD_TYPE}}-stable,makeplane/plane-aio-enterprise:${{env.BUILD_TYPE}}-${{ github.event.release.tag_name }} + elif [ "${{ env.TARGET_BRANCH }}" == "master" ]; then + TAG=makeplane/plane-aio-enterprise:${{env.BUILD_TYPE}}-latest + else + TAG=${{ env.AIO_IMAGE_TAGS }} + fi + echo "AIO_IMAGE_TAGS=${TAG}" >> $GITHUB_ENV + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver: ${{ env.BUILDX_DRIVER }} + version: ${{ env.BUILDX_VERSION }} + endpoint: ${{ env.BUILDX_ENDPOINT }} + + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Build and Push to Docker Hub + uses: docker/build-push-action@v5.1.0 + with: + context: . + file: ./aio/Dockerfile-app + platforms: ${{ env.BUILDX_PLATFORMS }} + tags: ${{ env.AIO_IMAGE_TAGS }} + push: true + build-args: | + BUILD_TAG=${{ env.AIO_BASE_TAG }} + BUILD_TYPE=${{env.BUILD_TYPE}} + cache-from: type=gha + cache-to: type=gha,mode=max + + env: + DOCKER_BUILDKIT: 1 + DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/build-branch-cloud.yml b/.github/workflows/build-branch-cloud.yml new file mode 100644 index 0000000000..8e63a2fdd8 --- /dev/null +++ b/.github/workflows/build-branch-cloud.yml @@ -0,0 +1,421 @@ +name: Branch Build Enterprise Cloud + +on: + workflow_dispatch: + inputs: + build_type: + description: "Type of build to run" + required: true + type: choice + default: "Build" + options: + - "Build" + - "Release" + releaseVersion: + description: "Release Version" + type: string + default: v0.0.0-cloud + useVaultSecrets: + description: "Use Vault Secrets" + type: boolean + default: false + required: true + isPrerelease: + description: "Is Pre-release" + type: boolean + default: false + required: true + + push: + branches: + - master + +env: + TARGET_BRANCH: ${{ github.ref_name }} + VAULT_KP_PREFIX: plane-ee-cloud-builds + BUILD_TYPE: ${{ github.event.inputs.build_type }} + RELEASE_VERSION: ${{ github.event.inputs.releaseVersion }} + IS_PRERELEASE: ${{ github.event.inputs.isPrerelease }} + +jobs: + branch_build_setup: + name: Build Setup + runs-on: ubuntu-20.04 + outputs: + gh_branch_name: ${{ steps.set_env_variables.outputs.TARGET_BRANCH }} + gh_buildx_driver: ${{ steps.set_env_variables.outputs.BUILDX_DRIVER }} + gh_buildx_version: ${{ steps.set_env_variables.outputs.BUILDX_VERSION }} + gh_buildx_platforms: ${{ steps.set_env_variables.outputs.BUILDX_PLATFORMS }} + gh_buildx_endpoint: ${{ steps.set_env_variables.outputs.BUILDX_ENDPOINT }} + + build_web: ${{ steps.changed_files.outputs.web_any_changed }} + build_admin: ${{ steps.changed_files.outputs.admin_any_changed }} + build_space: ${{ steps.changed_files.outputs.space_any_changed }} + build_live: ${{ steps.changed_files.outputs.live_any_changed }} + build_silo: ${{ steps.changed_files.outputs.silo_any_changed }} + build_apiserver: ${{ steps.changed_files.outputs.apiserver_any_changed }} + + dh_img_web: ${{ steps.set_env_variables.outputs.DH_IMG_WEB }} + dh_img_space: ${{ steps.set_env_variables.outputs.DH_IMG_SPACE }} + dh_img_admin: ${{ steps.set_env_variables.outputs.DH_IMG_ADMIN }} + dh_img_live: ${{ steps.set_env_variables.outputs.DH_IMG_LIVE }} + dh_img_silo: ${{ steps.set_env_variables.outputs.DH_IMG_SILO }} + dh_img_backend: ${{ steps.set_env_variables.outputs.DH_IMG_BACKEND }} + + build_type: ${{steps.set_env_variables.outputs.BUILD_TYPE}} + build_release: ${{ steps.set_env_variables.outputs.BUILD_RELEASE }} + build_prerelease: ${{ steps.set_env_variables.outputs.BUILD_PRERELEASE }} + release_version: ${{ steps.set_env_variables.outputs.RELEASE_VERSION }} + vault_secrets: ${{ steps.get_vault_secrets.outputs.VAULT_SECRETS }} + build_args: ${{ steps.prepare_build_args.outputs.BUILD_ARGS }} + steps: + - id: set_env_variables + name: Set Environment Variables + run: | + echo "BUILDX_DRIVER=docker-container" >> $GITHUB_OUTPUT + echo "BUILDX_VERSION=latest" >> $GITHUB_OUTPUT + echo "BUILDX_PLATFORMS=linux/amd64" >> $GITHUB_OUTPUT + echo "BUILDX_ENDPOINT=" >> $GITHUB_OUTPUT + + BR_NAME=$( echo "${{ env.TARGET_BRANCH }}" | sed 's/[^a-zA-Z0-9.-]//g') + echo "TARGET_BRANCH=$BR_NAME" >> $GITHUB_OUTPUT + + echo "DH_IMG_WEB=web-cloud" >> $GITHUB_OUTPUT + echo "DH_IMG_SPACE=space-cloud" >> $GITHUB_OUTPUT + echo "DH_IMG_ADMIN=admin-cloud" >> $GITHUB_OUTPUT + echo "DH_IMG_LIVE=live-cloud" >> $GITHUB_OUTPUT + echo "DH_IMG_SILO=silo-cloud" >> $GITHUB_OUTPUT + echo "DH_IMG_BACKEND=backend-cloud" >> $GITHUB_OUTPUT + + echo "BUILD_TYPE=${{env.BUILD_TYPE}}" >> $GITHUB_OUTPUT + BUILD_RELEASE=false + BUILD_PRERELEASE=false + RELVERSION="latest" + + if [ "${{ env.BUILD_TYPE }}" == "Release" ]; then + FLAT_RELEASE_VERSION=$(echo "${{ env.RELEASE_VERSION }}" | sed 's/[^a-zA-Z0-9.-]//g') + echo "FLAT_RELEASE_VERSION=${FLAT_RELEASE_VERSION}" >> $GITHUB_OUTPUT + + semver_regex="^v([0-9]+)\.([0-9]+)\.([0-9]+)(-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)?$" + if [[ ! $FLAT_RELEASE_VERSION =~ $semver_regex ]]; then + echo "Invalid Release Version Format : $FLAT_RELEASE_VERSION" + echo "Please provide a valid SemVer version" + echo "e.g. v1.2.3 or v1.2.3-alpha-1" + echo "Exiting the build process" + exit 1 # Exit with status 1 to fail the step + fi + BUILD_RELEASE=true + RELVERSION=$FLAT_RELEASE_VERSION + + if [ "${{ env.IS_PRERELEASE }}" == "true" ]; then + BUILD_PRERELEASE=true + fi + fi + echo "BUILD_RELEASE=${BUILD_RELEASE}" >> $GITHUB_OUTPUT + echo "BUILD_PRERELEASE=${BUILD_PRERELEASE}" >> $GITHUB_OUTPUT + echo "RELEASE_VERSION=${RELVERSION}" >> $GITHUB_OUTPUT + + - name: Tailscale + uses: tailscale/github-action@v2 + if: ${{github.event.inputs.useVaultSecrets == 'true'}} + with: + oauth-client-id: ${{ secrets.TAILSCALE_OAUTH_CLIENT_ID }} + oauth-secret: ${{ secrets.TAILSCALE_OAUTH_CLIENT_SECRET }} + tags: tag:ci + + - name: Get the ENV values from Vault + id: get_vault_secrets + if: ${{github.event.inputs.useVaultSecrets == 'true'}} + run: | + if [ "${{ env.TARGET_BRANCH }}" == "master" ]; then + ENV_NAME="prod" + else + ENV_NAME="stage" + fi + + curl -fsSL \ + --header "X-Vault-Token: ${{ secrets.VAULT_TOKEN }}" \ + --request GET \ + ${{ vars.VAULT_HOST }}/v1/kv/git-builds/data/${{ env.VAULT_KP_PREFIX }}-${ENV_NAME} | jq .data.data > vault_secrets.json + + if [ $? != 0 ]; then + echo "Failed to get the ENV values from Vault" + exit 1 + fi + + VAULT_SECRETS=$(cat vault_secrets.json | base64 -w 0) + echo "VAULT_SECRETS=${VAULT_SECRETS}" >> $GITHUB_OUTPUT + + - name: Prepare Docker Build Args + id: prepare_build_args + if: ${{github.event.inputs.useVaultSecrets == 'true'}} + run: | + BUILD_ARGS="" + add_build_arg() { + if [ -n "$2" ]; then + BUILD_ARGS="$BUILD_ARGS $1=$2" + fi + } + add_build_arg "NEXT_PUBLIC_API_BASE_URL" "${{ env.NEXT_PUBLIC_API_BASE_URL }}" + add_build_arg "NEXT_PUBLIC_API_BASE_PATH" "${{ env.NEXT_PUBLIC_API_BASE_PATH }}" + + add_build_arg "NEXT_PUBLIC_ADMIN_BASE_URL" "${{ env.NEXT_PUBLIC_ADMIN_BASE_URL }}" + add_build_arg "NEXT_PUBLIC_ADMIN_BASE_PATH" "${{ env.NEXT_PUBLIC_ADMIN_BASE_PATH }}" + + add_build_arg "NEXT_PUBLIC_SPACE_BASE_URL" "${{ env.NEXT_PUBLIC_SPACE_BASE_URL }}" + add_build_arg "NEXT_PUBLIC_SPACE_BASE_PATH" "${{ env.NEXT_PUBLIC_SPACE_BASE_PATH }}" + + add_build_arg "NEXT_PUBLIC_LIVE_BASE_URL" "${{ env.NEXT_PUBLIC_LIVE_BASE_URL }}" + add_build_arg "NEXT_PUBLIC_LIVE_BASE_PATH" "${{ env.NEXT_PUBLIC_LIVE_BASE_PATH }}" + + add_build_arg "NEXT_PUBLIC_SILO_BASE_URL" "${{ env.NEXT_PUBLIC_SILO_BASE_URL }}" + add_build_arg "NEXT_PUBLIC_SILO_BASE_PATH" "${{ env.NEXT_PUBLIC_SILO_BASE_PATH }}" + + add_build_arg "NEXT_PUBLIC_WEB_BASE_URL" "${{ env.NEXT_PUBLIC_WEB_BASE_URL }}" + + echo "BUILD_ARGS=$BUILD_ARGS" >> $GITHUB_OUTPUT + + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + - name: Get changed files + id: changed_files + uses: tj-actions/changed-files@v42 + with: + files_yaml: | + apiserver: + - apiserver/** + admin: + - admin/** + - packages/** + - "package.json" + - "yarn.lock" + - "turbo.json" + space: + - space/** + - packages/** + - "package.json" + - "yarn.lock" + - "turbo.json" + web: + - web/** + - packages/** + - "package.json" + - "yarn.lock" + - "turbo.json" + live: + - live/** + - packages/** + - 'package.json' + - 'yarn.lock' + - 'turbo.json' + silo: + - silo/** + - packages/** + - 'package.json' + - 'yarn.lock' + - 'turbo.json' + + branch_build_push_admin: + if: ${{ needs.branch_build_setup.outputs.build_admin == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Admin Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + - name: Admin Build and Push + uses: ./.github/actions/build-push-cloud + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_admin }} + build-context: . + dockerfile-path: ./admin/Dockerfile.admin + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + build-args: ${{ needs.branch_build_setup.outputs.build_args }} + + branch_build_push_web: + if: ${{ needs.branch_build_setup.outputs.build_web == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Web Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - name: Load Vault Secrets + run: | + echo ${{ needs.branch_build_setup.outputs.vault_secrets }} | base64 -d > vault_secrets.json + jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' vault_secrets.json >> $GITHUB_ENV + + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + - name: Web Build and Push + uses: ./.github/actions/build-push-cloud + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_web }} + build-context: . + dockerfile-path: ./web/Dockerfile.web + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + build-args: ${{ needs.branch_build_setup.outputs.build_args }} + + branch_build_push_space: + if: ${{ needs.branch_build_setup.outputs.build_space == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Space Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - name: Load Vault Secrets + run: | + echo ${{ needs.branch_build_setup.outputs.vault_secrets }} | base64 -d > vault_secrets.json + jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' vault_secrets.json >> $GITHUB_ENV + + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + - name: Space Build and Push + uses: ./.github/actions/build-push-cloud + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_space }} + build-context: . + dockerfile-path: ./space/Dockerfile.space + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + build-args: ${{ needs.branch_build_setup.outputs.build_args }} + + branch_build_push_live: + if: ${{ needs.branch_build_setup.outputs.build_live == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Live Collaboration Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + - name: Live Build and Push + uses: ./.github/actions/build-push-cloud + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_live }} + build-context: . + dockerfile-path: ./live/Dockerfile.live + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + + branch_build_push_silo: + if: ${{ needs.branch_build_setup.outputs.build_silo == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Silo Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + - name: Silo Build and Push + uses: ./.github/actions/build-push-cloud + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_silo }} + build-context: . + dockerfile-path: ./silo/Dockerfile.silo + + branch_build_push_apiserver: + if: ${{ needs.branch_build_setup.outputs.build_apiserver == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push API Server Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + - name: Backend Build and Push + uses: ./.github/actions/build-push-cloud + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_backend }} + build-context: ./apiserver + dockerfile-path: ./apiserver/Dockerfile.api + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + + publish_release: + if: ${{ needs.branch_build_setup.outputs.build_type == 'Release' }} + name: Build Release + runs-on: ubuntu-20.04 + needs: + [ + branch_build_setup, + branch_build_push_admin, + branch_build_push_web, + branch_build_push_space, + branch_build_push_live, + branch_build_push_silo, + branch_build_push_apiserver, + ] + env: + REL_VERSION: ${{ needs.branch_build_setup.outputs.release_version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v2.0.8 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ env.REL_VERSION }} + name: ${{ env.REL_VERSION }} + draft: false + prerelease: ${{ env.IS_PRERELEASE }} + generate_release_notes: true diff --git a/.github/workflows/build-branch-ee.yml b/.github/workflows/build-branch-ee.yml new file mode 100644 index 0000000000..08f7ff24b4 --- /dev/null +++ b/.github/workflows/build-branch-ee.yml @@ -0,0 +1,532 @@ +name: Branch Build Enterprise + +on: + workflow_dispatch: + inputs: + build_type: + description: "Type of build to run" + required: true + type: choice + default: "Build" + options: + - "Build" + - "Release" + releaseVersion: + description: "Release Version" + type: string + default: v0.0.0 + isPrerelease: + description: "Is Pre-release" + type: boolean + default: false + required: true + arm64: + description: "Build for ARM64 architecture" + required: false + default: false + type: boolean + push: + branches: + - master + +env: + TARGET_BRANCH: ${{ github.ref_name }} + ARM64_BUILD: ${{ github.event.inputs.arm64 }} + BUILD_TYPE: ${{ github.event.inputs.build_type }} + RELEASE_VERSION: ${{ github.event.inputs.releaseVersion }} + IS_PRERELEASE: ${{ github.event.inputs.isPrerelease }} + +jobs: + branch_build_setup: + name: Build Setup + runs-on: ubuntu-20.04 + outputs: + gh_branch_name: ${{ steps.set_env_variables.outputs.TARGET_BRANCH }} + gh_buildx_driver: ${{ steps.set_env_variables.outputs.BUILDX_DRIVER }} + gh_buildx_version: ${{ steps.set_env_variables.outputs.BUILDX_VERSION }} + gh_buildx_platforms: ${{ steps.set_env_variables.outputs.BUILDX_PLATFORMS }} + gh_buildx_endpoint: ${{ steps.set_env_variables.outputs.BUILDX_ENDPOINT }} + build_web: ${{ steps.changed_files.outputs.web_any_changed }} + build_admin: ${{ steps.changed_files.outputs.admin_any_changed }} + build_space: ${{ steps.changed_files.outputs.space_any_changed }} + build_live: ${{ steps.changed_files.outputs.live_any_changed }} + build_apiserver: ${{ steps.changed_files.outputs.apiserver_any_changed }} + build_proxy: ${{ steps.changed_files.outputs.proxy_any_changed }} + build_monitor: ${{ steps.changed_files.outputs.monitor_any_changed }} + build_silo: ${{ steps.changed_files.outputs.silo_any_changed }} + artifact_upload_to_s3: ${{ steps.set_env_variables.outputs.artifact_upload_to_s3 }} + artifact_s3_suffix: ${{ steps.set_env_variables.outputs.artifact_s3_suffix }} + + dh_img_web: ${{ steps.set_env_variables.outputs.DH_IMG_WEB }} + dh_img_space: ${{ steps.set_env_variables.outputs.DH_IMG_SPACE }} + dh_img_admin: ${{ steps.set_env_variables.outputs.DH_IMG_ADMIN }} + dh_img_live: ${{ steps.set_env_variables.outputs.DH_IMG_LIVE }} + dh_img_backend: ${{ steps.set_env_variables.outputs.DH_IMG_BACKEND }} + dh_img_proxy: ${{ steps.set_env_variables.outputs.DH_IMG_PROXY }} + dh_img_monitor: ${{ steps.set_env_variables.outputs.DH_IMG_MONITOR }} + dh_img_silo: ${{ steps.set_env_variables.outputs.DH_IMG_SILO }} + harbor_push: ${{ steps.set_env_variables.outputs.HARBOR_PUSH }} + build_type: ${{steps.set_env_variables.outputs.BUILD_TYPE}} + build_release: ${{ steps.set_env_variables.outputs.BUILD_RELEASE }} + build_prerelease: ${{ steps.set_env_variables.outputs.BUILD_PRERELEASE }} + release_version: ${{ steps.set_env_variables.outputs.RELEASE_VERSION }} + + steps: + - id: set_env_variables + name: Set Environment Variables + run: | + if [ "${{ env.ARM64_BUILD }}" == "true" ] || ([ "${{ env.BUILD_TYPE }}" == "Release" ] && [ "${{ env.IS_PRERELEASE }}" != "true" ]); then + echo "BUILDX_DRIVER=cloud" >> $GITHUB_OUTPUT + echo "BUILDX_VERSION=lab:latest" >> $GITHUB_OUTPUT + echo "BUILDX_PLATFORMS=linux/amd64,linux/arm64" >> $GITHUB_OUTPUT + echo "BUILDX_ENDPOINT=makeplane/plane-dev" >> $GITHUB_OUTPUT + else + echo "BUILDX_DRIVER=docker-container" >> $GITHUB_OUTPUT + echo "BUILDX_VERSION=latest" >> $GITHUB_OUTPUT + echo "BUILDX_PLATFORMS=linux/amd64" >> $GITHUB_OUTPUT + echo "BUILDX_ENDPOINT=" >> $GITHUB_OUTPUT + fi + BR_NAME=$( echo "${{ env.TARGET_BRANCH }}" |sed 's/[^a-zA-Z0-9.-]//g') + echo "TARGET_BRANCH=$BR_NAME" >> $GITHUB_OUTPUT + + echo "DH_IMG_WEB=web-enterprise" >> $GITHUB_OUTPUT + echo "DH_IMG_SPACE=space-enterprise" >> $GITHUB_OUTPUT + echo "DH_IMG_ADMIN=admin-enterprise" >> $GITHUB_OUTPUT + echo "DH_IMG_LIVE=live-enterprise" >> $GITHUB_OUTPUT + echo "DH_IMG_BACKEND=backend-enterprise" >> $GITHUB_OUTPUT + echo "DH_IMG_PROXY=proxy-enterprise" >> $GITHUB_OUTPUT + echo "DH_IMG_MONITOR=monitor-enterprise" >> $GITHUB_OUTPUT + echo "DH_IMG_SILO=silo-enterprise" >> $GITHUB_OUTPUT + + echo "BUILD_TYPE=${{env.BUILD_TYPE}}" >> $GITHUB_OUTPUT + BUILD_RELEASE=false + BUILD_PRERELEASE=false + RELVERSION="latest" + HARBOR_PUSH=false + + if [ "${{ env.BUILD_TYPE }}" == "Release" ]; then + FLAT_RELEASE_VERSION=$(echo "${{ env.RELEASE_VERSION }}" | sed 's/[^a-zA-Z0-9.-]//g') + echo "FLAT_RELEASE_VERSION=${FLAT_RELEASE_VERSION}" >> $GITHUB_OUTPUT + HARBOR_PUSH=true + + semver_regex="^v([0-9]+)\.([0-9]+)\.([0-9]+)(-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)?$" + if [[ ! $FLAT_RELEASE_VERSION =~ $semver_regex ]]; then + echo "Invalid Release Version Format : $FLAT_RELEASE_VERSION" + echo "Please provide a valid SemVer version" + echo "e.g. v1.2.3 or v1.2.3-alpha-1" + echo "Exiting the build process" + exit 1 # Exit with status 1 to fail the step + fi + BUILD_RELEASE=true + RELVERSION=$FLAT_RELEASE_VERSION + + if [ "${{ env.IS_PRERELEASE }}" == "true" ]; then + BUILD_PRERELEASE=true + fi + fi + echo "BUILD_RELEASE=${BUILD_RELEASE}" >> $GITHUB_OUTPUT + echo "BUILD_PRERELEASE=${BUILD_PRERELEASE}" >> $GITHUB_OUTPUT + echo "RELEASE_VERSION=${RELVERSION}" >> $GITHUB_OUTPUT + echo "HARBOR_PUSH=${HARBOR_PUSH}" >> $GITHUB_OUTPUT + + if [ "${{ env.BUILD_TYPE }}" == "Release" ]; then + echo "artifact_upload_to_s3=true" >> $GITHUB_OUTPUT + echo "artifact_s3_suffix=${{ env.RELEASE_VERSION }}" >> $GITHUB_OUTPUT + elif [ "${{ env.TARGET_BRANCH }}" == "master" ]; then + echo "artifact_upload_to_s3=true" >> $GITHUB_OUTPUT + echo "artifact_s3_suffix=latest" >> $GITHUB_OUTPUT + elif [ "${{ env.TARGET_BRANCH }}" == "preview" ] || [ "${{ env.TARGET_BRANCH }}" == "develop" ] || [ "${{ env.TARGET_BRANCH }}" == "uat" ]; then + echo "artifact_upload_to_s3=true" >> $GITHUB_OUTPUT + echo "artifact_s3_suffix=${{ env.TARGET_BRANCH }}" >> $GITHUB_OUTPUT + else + echo "artifact_upload_to_s3=false" >> $GITHUB_OUTPUT + echo "artifact_s3_suffix=$BR_NAME" >> $GITHUB_OUTPUT + fi + + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + - name: Get changed files + id: changed_files + uses: tj-actions/changed-files@v42 + with: + files_yaml: | + apiserver: + - apiserver/** + proxy: + - nginx/** + admin: + - admin/** + - packages/** + - "package.json" + - "yarn.lock" + - "tsconfig.json" + - "turbo.json" + space: + - space/** + - packages/** + - "package.json" + - "yarn.lock" + - "tsconfig.json" + - "turbo.json" + web: + - web/** + - packages/** + - "package.json" + - "yarn.lock" + - "tsconfig.json" + - "turbo.json" + silo: + - silo/** + - packages/** + - 'package.json' + - 'yarn.lock' + - 'tsconfig.json' + - 'turbo.json' + live: + - live/** + - packages/** + - 'package.json' + - 'yarn.lock' + - 'tsconfig.json' + - 'turbo.json' + monitor: + - monitor/** + + branch_build_push_admin: + if: ${{ needs.branch_build_setup.outputs.build_admin == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Admin Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + - name: Admin Build and Push + uses: ./.github/actions/build-push-ee + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + harbor-push: ${{ needs.branch_build_setup.outputs.harbor_push }} + harbor-username: ${{ secrets.HARBOR_USERNAME }} + harbor-token: ${{ secrets.HARBOR_TOKEN }} + harbor-registry: ${{ vars.HARBOR_REGISTRY }} + harbor-project: ${{ vars.HARBOR_PROJECT }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_admin }} + build-context: . + dockerfile-path: ./admin/Dockerfile.admin + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + + branch_build_push_web: + if: ${{ needs.branch_build_setup.outputs.build_web == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Web Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + - name: Web Build and Push + uses: ./.github/actions/build-push-ee + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + harbor-push: ${{ needs.branch_build_setup.outputs.harbor_push }} + harbor-username: ${{ secrets.HARBOR_USERNAME }} + harbor-token: ${{ secrets.HARBOR_TOKEN }} + harbor-registry: ${{ vars.HARBOR_REGISTRY }} + harbor-project: ${{ vars.HARBOR_PROJECT }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_web }} + build-context: . + dockerfile-path: ./web/Dockerfile.web + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + + branch_build_push_space: + if: ${{ needs.branch_build_setup.outputs.build_space == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Space Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + - name: Space Build and Push + uses: ./.github/actions/build-push-ee + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + harbor-push: ${{ needs.branch_build_setup.outputs.harbor_push }} + harbor-username: ${{ secrets.HARBOR_USERNAME }} + harbor-token: ${{ secrets.HARBOR_TOKEN }} + harbor-registry: ${{ vars.HARBOR_REGISTRY }} + harbor-project: ${{ vars.HARBOR_PROJECT }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_space }} + build-context: . + dockerfile-path: ./space/Dockerfile.space + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + + branch_build_push_live: + if: ${{ needs.branch_build_setup.outputs.build_live == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Live Collaboration Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + - name: Live Build and Push + uses: ./.github/actions/build-push-ee + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + harbor-push: ${{ needs.branch_build_setup.outputs.harbor_push }} + harbor-username: ${{ secrets.HARBOR_USERNAME }} + harbor-token: ${{ secrets.HARBOR_TOKEN }} + harbor-registry: ${{ vars.HARBOR_REGISTRY }} + harbor-project: ${{ vars.HARBOR_PROJECT }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_live }} + build-context: . + dockerfile-path: ./live/Dockerfile.live + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + + branch_build_push_silo: + if: ${{ needs.branch_build_setup.outputs.build_silo == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Silo Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + - name: Silo Build and Push + uses: ./.github/actions/build-push-ee + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + harbor-push: ${{ needs.branch_build_setup.outputs.harbor_push }} + harbor-username: ${{ secrets.HARBOR_USERNAME }} + harbor-token: ${{ secrets.HARBOR_TOKEN }} + harbor-registry: ${{ vars.HARBOR_REGISTRY }} + harbor-project: ${{ vars.HARBOR_PROJECT }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_silo }} + build-context: . + dockerfile-path: ./silo/Dockerfile.silo + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + + branch_build_push_apiserver: + if: ${{ needs.branch_build_setup.outputs.build_apiserver == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push API Server Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + - name: Backend Build and Push + uses: ./.github/actions/build-push-ee + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + harbor-push: ${{ needs.branch_build_setup.outputs.harbor_push }} + harbor-username: ${{ secrets.HARBOR_USERNAME }} + harbor-token: ${{ secrets.HARBOR_TOKEN }} + harbor-registry: ${{ vars.HARBOR_REGISTRY }} + harbor-project: ${{ vars.HARBOR_PROJECT }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_backend }} + build-context: ./apiserver + dockerfile-path: ./apiserver/Dockerfile.api + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + + branch_build_push_proxy: + if: ${{ needs.branch_build_setup.outputs.build_proxy == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Proxy Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + - name: Proxy Build and Push + uses: ./.github/actions/build-push-ee + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + harbor-push: ${{ needs.branch_build_setup.outputs.harbor_push }} + harbor-username: ${{ secrets.HARBOR_USERNAME }} + harbor-token: ${{ secrets.HARBOR_TOKEN }} + harbor-registry: ${{ vars.HARBOR_REGISTRY }} + harbor-project: ${{ vars.HARBOR_PROJECT }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_proxy }} + build-context: ./nginx + dockerfile-path: ./nginx/Dockerfile + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + + branch_build_push_monitor: + if: ${{ needs.branch_build_setup.outputs.build_monitor == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + name: Build-Push Monitor Docker Image + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + - name: Generate Keypair + run: | + if [ "${{ env.TARGET_BRANCH }}" == "master" ] || [ "${{ env.BUILD_TYPE }}" == "Release" ]; then + openssl genrsa -out private_key.pem 2048 + else + echo "${{ secrets.DEFAULT_PRIME_PRIVATE_KEY }}" > private_key.pem + fi + openssl rsa -in private_key.pem -pubout -out public_key.pem + cat public_key.pem + + # Generating the private key env for the generated keys + PRIVATE_KEY=$(cat private_key.pem | base64 -w 0) + echo "PRIVATE_KEY=${PRIVATE_KEY}" >> $GITHUB_ENV + + - name: Monitor Build and Push + uses: ./.github/actions/build-push-ee + with: + build-release: ${{ needs.branch_build_setup.outputs.build_release }} + build-prerelease: ${{ needs.branch_build_setup.outputs.build_prerelease }} + release-version: ${{ needs.branch_build_setup.outputs.release_version }} + docker-username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} + harbor-push: ${{ needs.branch_build_setup.outputs.harbor_push }} + harbor-username: ${{ secrets.HARBOR_USERNAME }} + harbor-token: ${{ secrets.HARBOR_TOKEN }} + harbor-registry: ${{ vars.HARBOR_REGISTRY }} + harbor-project: ${{ vars.HARBOR_PROJECT }} + docker-image-owner: makeplane + docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_monitor }} + build-context: ./monitor + dockerfile-path: ./monitor/Dockerfile + buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }} + buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }} + buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }} + buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }} + build-args: | + PRIVATE_KEY=${{ env.PRIVATE_KEY }} + + upload_artifacts_s3: + if: ${{ needs.branch_build_setup.outputs.artifact_upload_to_s3 == 'true' }} + name: Upload artifacts to S3 Bucket + runs-on: ubuntu-20.04 + needs: [branch_build_setup] + container: + image: docker:20.10.7 + credentials: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + env: + ARTIFACT_SUFFIX: ${{ needs.branch_build_setup.outputs.artifact_s3_suffix }} + AWS_ACCESS_KEY_ID: ${{ secrets.SELF_HOST_BUCKET_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.SELF_HOST_BUCKET_SECRET_KEY }} + steps: + - id: checkout_files + name: Checkout Files + uses: actions/checkout@v4 + + - name: Upload artifacts + run: | + apk update + apk add --no-cache aws-cli + + mkdir -p ~/${{ env.ARTIFACT_SUFFIX }} + + cp deploy/cli-install/variables.env ~/${{ env.ARTIFACT_SUFFIX }}/variables.env + cp deploy/cli-install/Caddyfile ~/${{ env.ARTIFACT_SUFFIX }}/Caddyfile + sed -e 's@${APP_RELEASE_VERSION}@'${{ env.ARTIFACT_SUFFIX }}'@' deploy/cli-install/docker-compose.yml > ~/${{ env.ARTIFACT_SUFFIX }}/docker-compose.yml + sed -e 's@${APP_RELEASE_VERSION}@'${{ env.ARTIFACT_SUFFIX }}'@' deploy/cli-install/docker-compose-caddy.yml > ~/${{ env.ARTIFACT_SUFFIX }}/docker-compose-caddy.yml + + aws s3 cp ~/${{ env.ARTIFACT_SUFFIX }} s3://${{ vars.SELF_HOST_BUCKET_NAME }}/plane-enterprise/${{ env.ARTIFACT_SUFFIX }} --recursive + + publish_release: + if: ${{ needs.branch_build_setup.outputs.build_type == 'Release' }} + name: Build Release + runs-on: ubuntu-20.04 + needs: + [ + branch_build_setup, + branch_build_push_admin, + branch_build_push_web, + branch_build_push_space, + branch_build_push_live, + branch_build_push_apiserver, + branch_build_push_proxy, + branch_build_push_monitor, + branch_build_push_silo, + upload_artifacts_s3, + ] + env: + REL_VERSION: ${{ needs.branch_build_setup.outputs.release_version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v2.0.8 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ env.REL_VERSION }} + name: ${{ env.REL_VERSION }} + draft: false + prerelease: ${{ env.IS_PRERELEASE }} + generate_release_notes: true + files: | + ${{ github.workspace }}/deploy/cli-install/variables.env + ${{ github.workspace }}/deploy/cli-install/Caddyfile + ${{ github.workspace }}/deploy/cli-install/docker-compose.yml + ${{ github.workspace }}/deploy/cli-install/docker-compose-caddy.yml diff --git a/.github/workflows/build-test-pull-request-ee.yml b/.github/workflows/build-test-pull-request-ee.yml new file mode 100644 index 0000000000..a30db970bd --- /dev/null +++ b/.github/workflows/build-test-pull-request-ee.yml @@ -0,0 +1,162 @@ +name: Build and Lint on Pull Request EE + +on: + workflow_dispatch: + issue_comment: + types: [created] + +jobs: + get-changed-files: + if: github.event.issue.pull_request != '' && github.event.comment.body == 'build-test-pr' + runs-on: ubuntu-latest + outputs: + apiserver_changed: ${{ steps.changed-files.outputs.apiserver_any_changed }} + admin_changed: ${{ steps.changed-files.outputs.admin_any_changed }} + space_changed: ${{ steps.changed-files.outputs.space_any_changed }} + web_changed: ${{ steps.changed-files.outputs.web_any_changed }} + monitor_changed: ${{ steps.changed-files.outputs.monitor_any_changed }} + steps: + - uses: actions/checkout@v4 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v44 + with: + files_yaml: | + apiserver: + - apiserver/** + admin: + - admin/** + - packages/** + - 'package.json' + - 'yarn.lock' + - 'tsconfig.json' + - 'turbo.json' + space: + - space/** + - packages/** + - 'package.json' + - 'yarn.lock' + - 'tsconfig.json' + - 'turbo.json' + web: + - web/** + - packages/** + - 'package.json' + - 'yarn.lock' + - 'tsconfig.json' + - 'turbo.json' + monitor: + - monitor/** + + lint-apiserver: + needs: get-changed-files + runs-on: ubuntu-latest + if: needs.get-changed-files.outputs.apiserver_changed == 'true' + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" # Specify the Python version you need + - name: Install Pylint + run: python -m pip install ruff + - name: Install Apiserver Dependencies + run: cd apiserver && pip install -r requirements.txt + - name: Lint apiserver + run: ruff check --fix apiserver + + lint-admin: + needs: get-changed-files + if: needs.get-changed-files.outputs.admin_changed == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18.x + - run: yarn install + - run: yarn lint --filter=admin + + lint-space: + needs: get-changed-files + if: needs.get-changed-files.outputs.space_changed == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18.x + - run: yarn install + - run: yarn lint --filter=space + + lint-web: + needs: get-changed-files + if: needs.get-changed-files.outputs.web_changed == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18.x + - run: yarn install + - run: yarn lint --filter=web + + test-monitor: + needs: get-changed-files + if: needs.get-changed-files.outputs.monitor_changed == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.22.2" + - run: cd ./monitor && make test + + build-admin: + needs: lint-admin + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18.x + - run: yarn install + - run: yarn build --filter=admin + + build-space: + needs: lint-space + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18.x + - run: yarn install + - run: yarn build --filter=space + + build-web: + needs: lint-web + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18.x + - run: yarn install + - run: yarn build --filter=web + + build-monitor: + needs: test-monitor + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.22.2" + - run: cd ./monitor && make build diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 0000000000..3c6f5a0056 --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,70 @@ +name: Manual Release Workflow + +on: + workflow_dispatch: + inputs: + release_tag: + description: 'Release Tag (e.g., v0.16-cannary-1)' + required: true + prerelease: + description: 'Pre-Release' + required: true + default: true + type: boolean + draft: + description: 'Draft' + required: true + default: true + type: boolean + +permissions: + contents: write + +jobs: + create-release: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 0 # Necessary to fetch all history for tags + + - name: Set up Git + run: | + git config user.name "github-actions" + git config user.email "github-actions@github.com" + + - name: Check for the Prerelease + run: | + echo ${{ github.event.release.prerelease }} + + - name: Generate Release Notes + id: generate_notes + run: | + bash ./generate_release_notes.sh + # Directly use the content of RELEASE_NOTES.md for the release body + RELEASE_NOTES=$(cat RELEASE_NOTES.md) + echo "RELEASE_NOTES<> $GITHUB_ENV + echo "$RELEASE_NOTES" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Create Tag + run: | + git tag ${{ github.event.inputs.release_tag }} + git push origin ${{ github.event.inputs.release_tag }} + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ github.event.inputs.release_tag }} + body_path: RELEASE_NOTES.md + draft: ${{ github.event.inputs.draft }} + prerelease: ${{ github.event.inputs.prerelease }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + + + + + diff --git a/.github/workflows/sync-community.yml b/.github/workflows/sync-community.yml new file mode 100644 index 0000000000..4d97718e45 --- /dev/null +++ b/.github/workflows/sync-community.yml @@ -0,0 +1,55 @@ +name: Sync from Community Repo + +on: + # schedule: + # - cron: "*/30 * * * *" # Runs every 30 minutes + workflow_dispatch: + inputs: + source_branch: + description: "Source branch in Community repo" + required: true + default: "preview" + target_branch: + description: "Target branch in Enterprise repo" + required: true + default: "preview" + +jobs: + sync-from-community-repo: + runs-on: ubuntu-latest + steps: + - name: Checkout enterprise repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set branch names + run: | + echo "SOURCE_BRANCH=${{ github.event.inputs.source_branch || 'preview' }}" >> $GITHUB_ENV + echo "TARGET_BRANCH=${{ github.event.inputs.target_branch || 'preview' }}" >> $GITHUB_ENV + echo "SYNC_BRANCH=sync-${{ github.run_id }}" >> $GITHUB_ENV + + - name: Create sync branch + run: git checkout -b ${{ env.SYNC_BRANCH }} + + - name: Fetch from community repository + run: | + git config user.name github-actions + git config user.email github-actions@github.com + git remote add community https://github.com/makeplane/plane.git + git reset --hard community/${{ env.SOURCE_BRANCH }} + + - name: Create Pull Request + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_TITLE="Sync changes from community repo" + EXISTING_PR=$(gh pr list --base ${{ env.TARGET_BRANCH }} --head ${{ env.SYNC_BRANCH }} --json number --jq '.[0].number') + if [ -z "$EXISTING_PR" ]; then + pr_url=$(gh pr create --base ${{ env.TARGET_BRANCH }} --head ${{ env.SYNC_BRANCH }} --title "$PR_TITLE" --body "This PR syncs changes from the community repository's ${{ env.SOURCE_BRANCH }} branch.") + echo "New Pull Request created: $pr_url" + else + echo "Pull Request already exists with number: $EXISTING_PR" + gh pr edit $EXISTING_PR --title "$PR_TITLE" --body "This PR syncs changes from the community repository's ${{ env.SOURCE_BRANCH }} branch. (Updated)" + echo "Existing Pull Request updated" + fi diff --git a/.github/workflows/sync-repo-pr.yml b/.github/workflows/sync-repo-pr.yml index 548ccbf423..c1b33ab671 100644 --- a/.github/workflows/sync-repo-pr.yml +++ b/.github/workflows/sync-repo-pr.yml @@ -41,12 +41,16 @@ jobs: - name: Create PR to Target Branch run: | + # Determine target branch based on current branch prefix + TARGET_BRANCH="preview" + PR_TITLE="${{vars.SYNC_PR_TITLE}}" + # get all pull requests and check if there is already a PR PR_EXISTS=$(gh pr list --base $TARGET_BRANCH --head $CURRENT_BRANCH --state open --json number | jq '.[] | .number') if [ -n "$PR_EXISTS" ]; then echo "Pull Request already exists: $PR_EXISTS" else echo "Creating new pull request" - PR_URL=$(gh pr create --base $TARGET_BRANCH --head $CURRENT_BRANCH --title "${{ vars.SYNC_PR_TITLE }}" --body "") + PR_URL=$(gh pr create --base $TARGET_BRANCH --head $CURRENT_BRANCH --title "$PR_TITLE" --body "") echo "Pull Request created: $PR_URL" fi diff --git a/.github/workflows/sync-repo.yml b/.github/workflows/sync-repo.yml index 1f13995ded..ac5ddd785f 100644 --- a/.github/workflows/sync-repo.yml +++ b/.github/workflows/sync-repo.yml @@ -36,8 +36,8 @@ jobs: GH_TOKEN: ${{ secrets.ACCESS_TOKEN }} run: | TARGET_REPO="${{ vars.SYNC_TARGET_REPO }}" - TARGET_BRANCH="${{ vars.SYNC_TARGET_BRANCH_NAME }}" SOURCE_BRANCH="${{ env.SOURCE_BRANCH_NAME }}" + TARGET_BRANCH="${{ vars.SYNC_TARGET_BRANCH_NAME }}" git checkout $SOURCE_BRANCH git remote add target-origin-a "https://$GH_TOKEN@github.com/$TARGET_REPO.git" diff --git a/.gitignore b/.gitignore index 80607b92f2..2fbcc1251b 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,12 @@ tmp/ dist .temp/ deploy/selfhost/plane-app/ + ## Storybook *storybook.log output.css + +# Monitor +monitor/prime.key +monitor/prime.key.pub +monitor.db \ No newline at end of file diff --git a/ENV_SETUP.md b/ENV_SETUP.md index cdcf6be370..8034c1c696 100644 --- a/ENV_SETUP.md +++ b/ENV_SETUP.md @@ -27,7 +27,7 @@ FILE_SIZE_LIMIT=5242880 # GPT settings OPENAI_API_BASE="https://api.openai.com/v1" # deprecated OPENAI_API_KEY="sk-" # deprecated -GPT_ENGINE="gpt-3.5-turbo" # deprecated +GPT_ENGINE="gpt-4o-mini" # deprecated # Settings related to Docker DOCKERIZED=1 # deprecated # set to 1 If using the pre-configured minio setup diff --git a/admin/app/ai/form.tsx b/admin/app/ai/form.tsx index 4258a99fbb..2c425e27bb 100644 --- a/admin/app/ai/form.tsx +++ b/admin/app/ai/form.tsx @@ -49,7 +49,7 @@ export const InstanceAIForm: FC = (props) => { ), - placeholder: "gpt-3.5-turbo", + placeholder: "gpt-4o-mini", error: Boolean(errors.GPT_ENGINE), required: false, }, diff --git a/admin/app/authentication/oidc/form.tsx b/admin/app/authentication/oidc/form.tsx new file mode 100644 index 0000000000..3d40967a27 --- /dev/null +++ b/admin/app/authentication/oidc/form.tsx @@ -0,0 +1,244 @@ +import { FC, useState } from "react"; +import Link from "next/link"; +import { useForm } from "react-hook-form"; +// types +import { IFormattedInstanceConfiguration, TInstanceOIDCAuthenticationConfigurationKeys } from "@plane/types"; +// ui +import { Button, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui"; +// components +import { + ConfirmDiscardModal, + ControllerInput, + TControllerInputFormField, + CopyField, + TCopyField, + CodeBlock, +} from "@/components/common"; +// helpers +import { cn } from "@/helpers/common.helper"; +// hooks +import { useInstance } from "@/hooks/store"; + +type Props = { + config: IFormattedInstanceConfiguration; +}; + +type OIDCConfigFormValues = Record; + +export const InstanceOIDCConfigForm: FC = (props) => { + const { config } = props; + // states + const [isDiscardChangesModalOpen, setIsDiscardChangesModalOpen] = useState(false); + // store hooks + const { updateInstanceConfigurations } = useInstance(); + // form data + const { + handleSubmit, + control, + reset, + formState: { errors, isDirty, isSubmitting }, + } = useForm({ + defaultValues: { + OIDC_CLIENT_ID: config["OIDC_CLIENT_ID"], + OIDC_CLIENT_SECRET: config["OIDC_CLIENT_SECRET"], + OIDC_TOKEN_URL: config["OIDC_TOKEN_URL"], + OIDC_USERINFO_URL: config["OIDC_USERINFO_URL"], + OIDC_AUTHORIZE_URL: config["OIDC_AUTHORIZE_URL"], + OIDC_LOGOUT_URL: config["OIDC_LOGOUT_URL"], + OIDC_PROVIDER_NAME: config["OIDC_PROVIDER_NAME"], + }, + }); + + const originURL = typeof window !== "undefined" ? window.location.origin : ""; + + const OIDC_FORM_FIELDS: TControllerInputFormField[] = [ + { + key: "OIDC_CLIENT_ID", + type: "text", + label: "Client ID", + description: "A unique ID for this Plane app that you register on your IdP", + placeholder: "abc123xyz789", + error: Boolean(errors.OIDC_CLIENT_ID), + required: true, + }, + { + key: "OIDC_CLIENT_SECRET", + type: "password", + label: "Client secret", + description: "The secret key that authenticates this Plane app to your IdP", + placeholder: "s3cr3tK3y123!", + error: Boolean(errors.OIDC_CLIENT_SECRET), + required: true, + }, + { + key: "OIDC_AUTHORIZE_URL", + type: "text", + label: "Authorize URL", + description: ( + <> + The URL that brings up your IdP{"'"}s authentication screen when your users click the{" "} + {"Continue with"} + + ), + placeholder: "https://example.com/", + error: Boolean(errors.OIDC_AUTHORIZE_URL), + required: true, + }, + { + key: "OIDC_TOKEN_URL", + type: "text", + label: "Token URL", + description: "The URL that talks to the IdP and persists user authentication on Plane", + placeholder: "https://example.com/oauth/token", + error: Boolean(errors.OIDC_TOKEN_URL), + required: true, + }, + { + key: "OIDC_USERINFO_URL", + type: "text", + label: "Users' info URL", + description: "The URL that fetches your users' info from your IdP", + placeholder: "https://example.com/userinfo", + error: Boolean(errors.OIDC_USERINFO_URL), + required: true, + }, + { + key: "OIDC_LOGOUT_URL", + type: "text", + label: "Logout URL", + description: "Optional field that controls where your users go after they log out of Plane", + placeholder: "https://example.com/logout", + error: Boolean(errors.OIDC_LOGOUT_URL), + required: false, + }, + { + key: "OIDC_PROVIDER_NAME", + type: "text", + label: "IdP's name", + description: ( + <> + Optional field for the name that your users see on the Continue with button + + ), + placeholder: "Okta", + error: Boolean(errors.OIDC_PROVIDER_NAME), + required: false, + }, + ]; + + const OIDC_SERVICE_DETAILS: TCopyField[] = [ + { + key: "Origin_URI", + label: "Origin URI", + url: `${originURL}/auth/oidc/`, + description: + "We will generate this for this Plane app. Add this as a trusted origin on your IdP's corresponding field.", + }, + { + key: "Callback_URI", + label: "Callback URI", + url: `${originURL}/auth/oidc/callback/`, + description: ( + <> + We will generate this for you.Add this in the{" "} + Sign-in redirect URI field of + your IdP. + + ), + }, + { + key: "Logout_URI", + label: "Logout URI", + url: `${originURL}/auth/oidc/logout/`, + description: ( + <> + We will generate this for you. Add this in the{" "} + Logout redirect URI field of + your IdP. + + ), + }, + ]; + + const onSubmit = async (formData: OIDCConfigFormValues) => { + const payload: Partial = { ...formData }; + + await updateInstanceConfigurations(payload) + .then((response = []) => { + setToast({ + type: TOAST_TYPE.SUCCESS, + title: "Done!", + message: "Your OIDC-based authentication is configured. You should test it now.", + }); + reset({ + OIDC_CLIENT_ID: response.find((item) => item.key === "OIDC_CLIENT_ID")?.value, + OIDC_CLIENT_SECRET: response.find((item) => item.key === "OIDC_CLIENT_SECRET")?.value, + OIDC_AUTHORIZE_URL: response.find((item) => item.key === "OIDC_AUTHORIZE_URL")?.value, + OIDC_TOKEN_URL: response.find((item) => item.key === "OIDC_TOKEN_URL")?.value, + OIDC_USERINFO_URL: response.find((item) => item.key === "OIDC_USERINFO_URL")?.value, + OIDC_LOGOUT_URL: response.find((item) => item.key === "OIDC_LOGOUT_URL")?.value, + OIDC_PROVIDER_NAME: response.find((item) => item.key === "OIDC_PROVIDER_NAME")?.value, + }); + }) + .catch((err) => console.error(err)); + }; + + const handleGoBack = (e: React.MouseEvent) => { + if (isDirty) { + e.preventDefault(); + setIsDiscardChangesModalOpen(true); + } + }; + + return ( + <> + setIsDiscardChangesModalOpen(false)} + /> +
+
+
+
IdP-provided details for Plane
+ {OIDC_FORM_FIELDS.map((field) => ( + + ))} +
+
+ + + Go back + +
+
+
+
+
+
Plane-provided details for your IdP
+ {OIDC_SERVICE_DETAILS.map((field) => ( + + ))} +
+
+
+
+ + ); +}; diff --git a/admin/app/authentication/oidc/page.tsx b/admin/app/authentication/oidc/page.tsx new file mode 100644 index 0000000000..ea16d881e1 --- /dev/null +++ b/admin/app/authentication/oidc/page.tsx @@ -0,0 +1,120 @@ +"use client"; + +import { useState } from "react"; +import { observer } from "mobx-react-lite"; +import Image from "next/image"; +import useSWR from "swr"; +// ui +import { Loader, ToggleSwitch, setPromiseToast } from "@plane/ui"; +// components +import { AuthenticationMethodCard } from "@/components/authentication"; +import { PageHeader } from "@/components/common"; +// hooks +import { useInstance } from "@/hooks/store"; +// icons +import OIDCLogo from "/public/logos/oidc-logo.svg"; +// plane admin hooks +import { useInstanceFlag } from "@/plane-admin/hooks/store/use-instance-flag"; +// local components +import { InstanceOIDCConfigForm } from "./form"; + +const InstanceOIDCAuthenticationPage = observer(() => { + // state + const [isSubmitting, setIsSubmitting] = useState(false); + // store + const { fetchInstanceConfigurations, formattedConfig, updateInstanceConfigurations } = useInstance(); + // plane admin store + const isOIDCEnabled = useInstanceFlag("OIDC_SAML_AUTH"); + // config + const enableOIDCConfig = formattedConfig?.IS_OIDC_ENABLED ?? ""; + + useSWR("INSTANCE_CONFIGURATIONS", () => fetchInstanceConfigurations()); + + const updateConfig = async (key: "IS_OIDC_ENABLED", value: string) => { + setIsSubmitting(true); + + const payload = { + [key]: value, + }; + + const updateConfigPromise = updateInstanceConfigurations(payload); + + setPromiseToast(updateConfigPromise, { + loading: "Saving Configuration...", + success: { + title: "Configuration saved", + message: () => `OIDC authentication is now ${value ? "active" : "disabled"}.`, + }, + error: { + title: "Error", + message: () => "Failed to save configuration", + }, + }); + + await updateConfigPromise + .then(() => { + setIsSubmitting(false); + }) + .catch((err) => { + console.error(err); + setIsSubmitting(false); + }); + }; + + if (isOIDCEnabled === false) { + return ( +
+ +
+

OpenID Connect (OIDC) authentication is not enabled for this instance.

+

Activate any of your workspace to get this feature.

+
+
+ ); + } + + return ( + <> + +
+
+ } + config={ + { + Boolean(parseInt(enableOIDCConfig)) === true + ? updateConfig("IS_OIDC_ENABLED", "0") + : updateConfig("IS_OIDC_ENABLED", "1"); + }} + size="sm" + disabled={isSubmitting || !formattedConfig} + /> + } + disabled={isSubmitting || !formattedConfig} + withBorder={false} + /> +
+
+ {formattedConfig ? ( + + ) : ( + + + + + + + + + )} +
+
+ + ); +}); + +export default InstanceOIDCAuthenticationPage; diff --git a/admin/app/authentication/saml/form.tsx b/admin/app/authentication/saml/form.tsx new file mode 100644 index 0000000000..87800fa53b --- /dev/null +++ b/admin/app/authentication/saml/form.tsx @@ -0,0 +1,245 @@ +import { FC, useState } from "react"; +import Link from "next/link"; +import { Controller, useForm } from "react-hook-form"; +// types +import { IFormattedInstanceConfiguration, TInstanceSAMLAuthenticationConfigurationKeys } from "@plane/types"; +// ui +import { Button, TOAST_TYPE, TextArea, getButtonStyling, setToast } from "@plane/ui"; +// components +import { + ConfirmDiscardModal, + ControllerInput, + TControllerInputFormField, + CopyField, + TCopyField, + CodeBlock, +} from "@/components/common"; +// helpers +import { cn } from "@/helpers/common.helper"; +// hooks +import { useInstance } from "@/hooks/store"; +import { SAMLAttributeMappingTable } from "@/plane-admin/components/authentication"; + +type Props = { + config: IFormattedInstanceConfiguration; +}; + +type SAMLConfigFormValues = Record; + +export const InstanceSAMLConfigForm: FC = (props) => { + const { config } = props; + // states + const [isDiscardChangesModalOpen, setIsDiscardChangesModalOpen] = useState(false); + // store hooks + const { updateInstanceConfigurations } = useInstance(); + // form data + const { + handleSubmit, + control, + reset, + formState: { errors, isDirty, isSubmitting }, + } = useForm({ + defaultValues: { + SAML_ENTITY_ID: config["SAML_ENTITY_ID"], + SAML_SSO_URL: config["SAML_SSO_URL"], + SAML_LOGOUT_URL: config["SAML_LOGOUT_URL"], + SAML_CERTIFICATE: config["SAML_CERTIFICATE"], + SAML_PROVIDER_NAME: config["SAML_PROVIDER_NAME"], + }, + }); + + const originURL = typeof window !== "undefined" ? window.location.origin : ""; + + const SAML_FORM_FIELDS: TControllerInputFormField[] = [ + { + key: "SAML_ENTITY_ID", + type: "text", + label: "Entity ID", + description: "A unique ID for this Plane app that you register on your IdP", + placeholder: "70a44354520df8bd9bcd", + error: Boolean(errors.SAML_ENTITY_ID), + required: true, + }, + { + key: "SAML_SSO_URL", + type: "text", + label: "SSO URL", + description: ( + <> + The URL that brings up your IdP{"'"}s authentication screen when your users click the{" "} + {"Continue with"} button + + ), + placeholder: "https://example.com/sso", + error: Boolean(errors.SAML_SSO_URL), + required: true, + }, + { + key: "SAML_LOGOUT_URL", + type: "text", + label: "Logout URL", + description: "Optional field that tells your IdP your users have logged out of this Plane app", + placeholder: "https://example.com/logout", + error: Boolean(errors.SAML_LOGOUT_URL), + required: false, + }, + { + key: "SAML_PROVIDER_NAME", + type: "text", + label: "IdP's name", + description: ( + <> + Optional field for the name that your users see on the Continue with button + + ), + placeholder: "Okta", + error: Boolean(errors.SAML_PROVIDER_NAME), + required: false, + }, + ]; + + const SAML_SERVICE_DETAILS: TCopyField[] = [ + { + key: "Metadata_Information", + label: "Entity ID | Audience | Metadata information", + url: `${originURL}/auth/saml/metadata/`, + description: + "We will generate this bit of the metadata that identifies this Plane app as an authorized service on your IdP.", + }, + { + key: "Callback_URI", + label: "Callback URI", + url: `${originURL}/auth/saml/callback/`, + description: ( + <> + We will generate this{" "} + http-post request URL that you + should paste into your ACS URL{" "} + or Sign-in call back URL field + on your IdP. + + ), + }, + { + key: "Logout_URI", + label: "Logout URI", + url: `${originURL}/auth/saml/logout/`, + description: ( + <> + We will generate this{" "} + http-redirect request URL that + you should paste into your{" "} + SLS URL or{" "} + Logout URL + field on your IdP. + + ), + }, + ]; + + const onSubmit = async (formData: SAMLConfigFormValues) => { + const payload: Partial = { ...formData }; + + await updateInstanceConfigurations(payload) + .then((response = []) => { + setToast({ + type: TOAST_TYPE.SUCCESS, + title: "Done!", + message: "Your SAML-based authentication is configured. You should test it now.", + }); + reset({ + SAML_ENTITY_ID: response.find((item) => item.key === "SAML_ENTITY_ID")?.value, + SAML_SSO_URL: response.find((item) => item.key === "SAML_SSO_URL")?.value, + SAML_LOGOUT_URL: response.find((item) => item.key === "SAML_LOGOUT_URL")?.value, + SAML_CERTIFICATE: response.find((item) => item.key === "SAML_CERTIFICATE")?.value, + SAML_PROVIDER_NAME: response.find((item) => item.key === "SAML_PROVIDER_NAME")?.value, + }); + }) + .catch((err) => console.error(err)); + }; + + const handleGoBack = (e: React.MouseEvent) => { + if (isDirty) { + e.preventDefault(); + setIsDiscardChangesModalOpen(true); + } + }; + + return ( + <> + setIsDiscardChangesModalOpen(false)} + /> +
+
+
+
IdP-provided details for Plane
+ {SAML_FORM_FIELDS.map((field) => ( + + ))} +
+

SAML certificate

+ ( +