diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 613775b8..0ed32e27 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -10,20 +10,62 @@ on: services: description: 'Services to deploy (space seperated)' required: true + repository_dispatch: + types: + - deploy-trigger jobs: + validate_environments: + runs-on: ubuntu-latest + outputs: + validate_environments: ${{ steps.validate_environments.outputs.validate_environments }} + steps: + - name: Validate environment + id: validate_environments + run: | + CLIENT_PAYLOAD_ENVIRONMENT='${{ toJson(github.event.client_payload.environment) }}' + + # Write the secret to a temporary file + echo '${{ secrets.PERMIT_AUTO_DEPLOY }}' > permit_auto_deploy.json + + PERMIT_AUTO_DEPLOY=$(cat permit_auto_deploy.json) + + echo "PERMIT_AUTO_DEPLOY: $PERMIT_AUTO_DEPLOY" + + # Find common values using jq + VALIDATED_ENVIRONMENTS=$(jq -n --argjson client "$CLIENT_PAYLOAD_ENVIRONMENT" --argjson allow "$PERMIT_AUTO_DEPLOY" \ + '[ $client[] | select($allow[] == .) ]' | jq -c '.') + + # Setting to dev if no common environment found + if [ "$VALIDATED_ENVIRONMENTS" == "" ]; then + VALIDATED_ENVIRONMENTS='["dev"]' + fi + + echo "VALIDATED_ENVIRONMENTS: $VALIDATED_ENVIRONMENTS" + + # Export environment variable and write to file + echo "validated_environments=$VALIDATED_ENVIRONMENTS" >> $GITHUB_OUTPUT + deployment: runs-on: ubuntu-latest - name: Deploy ${{inputs.services}} in ${{inputs.environment}} + needs: validate_environments + strategy: + matrix: + env: ${{ fromJson(needs.validate_environments.outputs.validated_environments) }} + name: Deploy ${{ inputs.services || github.event.client_payload.services }} in ${{inputs.environment || matrix.env }} steps: - name: Uppercase environment run: | - echo "ENV=`echo ${{inputs.environment}} | tr '[:lower:]' '[:upper:]'`" >>${GITHUB_ENV} + echo "ENV=`echo ${{ inputs.environment || matrix.env }} | tr '[:lower:]' '[:upper:]'`" >>${GITHUB_ENV} - name: Set Default Values to Repository Variable run: | - echo "ENABLE_FORCE_RECREATE=${{ vars.ENABLE_FORCE_RECREATE || 1 }}" >> ${GITHUB_ENV} + if [ "${{ github.event_name }}" == "repository_dispatch" ]; then + echo "ENABLE_FORCE_RECREATE=0" >> ${GITHUB_ENV} + else + echo "ENABLE_FORCE_RECREATE=${{ vars.ENABLE_FORCE_RECREATE || 1 }}" >> ${GITHUB_ENV} + fi echo "DISABLE_REMOVE_ORPHANS=${{ vars.DISABLE_REMOVE_ORPHANS || 0 }}" >> ${GITHUB_ENV} echo "DISABLE_ANSI=${{ vars.DISABLE_ANSI || 1 }}" >> ${GITHUB_ENV} echo "ENABLE_GIT_PULL=${{ vars.ENABLE_GIT_PULL || 1 }}" >> ${GITHUB_ENV} @@ -39,15 +81,14 @@ jobs: echo "::error::Secret '${{ format('{0}_WEBHOOK_URL',env.ENV) }}' is not set" exit 1 fi - if [ -z "${{ github.event.inputs.services }}" ]; then - echo "::error::'${{ github.event.inputs.services }}' is empty" + if [ -z "${{ github.event.inputs.services || github.event.client_payload.services }}" ]; then + echo "::error::'${{ github.event.inputs.services || github.event.client_payload.services }}' is empty" exit 1 fi - encoded_services=$(python3 -c "from urllib.parse import quote; print(quote('${{ github.event.inputs.services }}'))") + encoded_services=$(python3 -c "from urllib.parse import quote; print(quote('${{ github.event.inputs.services || github.event.client_payload.services}}'))") curl -X POST \ --fail-with-body -sS --no-buffer\ -H "Content-Type: application/json" \ -d '{"secret_token": "${{ secrets[format('{0}_WEBHOOK_PASSWORD',env.ENV)] }}", "ENABLE_FORCE_RECREATE":${{ env.ENABLE_FORCE_RECREATE }}, "DISABLE_REMOVE_ORPHANS":${{ env.DISABLE_REMOVE_ORPHANS }}, "DISABLE_ANSI":${{ env.DISABLE_ANSI }} ,"ENABLE_GIT_PULL":${{ env.ENABLE_GIT_PULL }}}' \ "${{ secrets[format('{0}_WEBHOOK_URL',env.ENV)] }}/hooks/deploy?services=$encoded_services" - diff --git a/docs/onboarding.md b/docs/onboarding.md index ee6265b9..251350e2 100644 --- a/docs/onboarding.md +++ b/docs/onboarding.md @@ -27,13 +27,27 @@ Example: [/examples/workflows/build-and-push.yaml](../examples/workflows/build-a > In case you see 403 error, checkout [this](https://docs.github.com/en/packages/learn-github-packages/configuring-a-packages-access-control-and-visibility#github-actions-access-for-packages-scoped-to-organizations) - Reference: - For further clarification and detailed instructions, you can refer to the [GitHub documentation](https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages). ### 3. Add a workflow to test your image Example: [/examples/workflows/docker-test.yaml](../examples/workflows/docker-test.yaml) +### 4. To Auto Deploy Service + + #### Assumptions made: + SERVICE_REPO: Repository from which the service is deployed. + DEVOPS_REPO: Repository where deployment is triggered. + #### In SERVICE_REPO + - Allow [access via fine-grained](https://docs.github.com/en/organizations/managing-programmatic-access-to-your-organization/setting-a-personal-access-token-policy-for-your-organization#restricting-access-by-fine-grained-personal-access-tokens) personal access tokens in the organization + - [Configure actions](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#allowing-access-to-components-in-a-private-repository) to be triggered from another repository within the same organization + - Generate a Fine-Grained token (Personal Access Token) permissions required - Actions(Read and Write) and Content(Read and Write) + - Store the PAT as repository secret, set name field as `PAT` + - If devops repository name is not `devops`, set the Repository Secret named `DEVOPS_REPO_NAME` and value as the name of devops repository + - If your repository name in snake_case differs from the service name, set the Repository Secret named `SERVICE_NAME` and value as the name of service name in snake_case + - Create a repository secret named `ENABLE_AUTO_DEPLOY` and set value for targeted auto deployment to run for all environment given here, eg:`["dev", "stage"]` + #### In DEVOPS_REPO + - Create a secret named `PERMIT_AUTO_DEPLOY` and set value as only allowed environments here can be triggered through other repository, eg: `["dev"]` ## Adding your service diff --git a/examples/workflows/build-and-push.yaml b/examples/workflows/build-and-push.yaml index 6543afb9..e49e38ae 100644 --- a/examples/workflows/build-and-push.yaml +++ b/examples/workflows/build-and-push.yaml @@ -18,6 +18,7 @@ jobs: permissions: contents: read packages: write + actions: write steps: - name: Checkout code @@ -54,4 +55,19 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file + labels: ${{ steps.meta.outputs.labels }} + + - name: Convert repository name to snake case + run: | + REPO_NAME=$(echo "${GITHUB_REPOSITORY}" | awk -F/ '{print $2}') + SNAKE_CASE_REPO_NAME=$(echo "${REPO_NAME}" | sed 's/\(.\)\([A-Z]\)/\1_\2/g' | tr '[:upper:]' '[:lower:]' | sed 's/^_//' | tr -s '_' | tr '[:upper:]' '[:lower:]') + echo "SERVICE=${SNAKE_CASE_REPO_NAME}" >> $GITHUB_ENV + + - name: Trigger deployment workflow + if: ${{ success() }} + run: | + curl -X POST \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token ${{ secrets.PAT }}" \ + https://api.github.com/repos/${{ github.repository_owner }}/${{ secrets.DEVOPS_REPO_NAME || 'devops' }}/dispatches \ + -d '{"event_type":"deploy-trigger","client_payload":{"services":"${{ secrets.SERVICE_NAME || env.SERVICE }}", "environment":${{ secrets.ENABLE_AUTO_DEPLOY }}}}'