####################################################################################################
#
# FILENAME:     config.yml
#
# PURPOSE:      Configuration file for the CircleCI build automation tool.
#
# DESCRIPTION:  CircleCI requires the presence of a configuration file at the following path:
#                  <repository-root>/.circleci/config.yml
#               When changes are committed to a tracked repository, CircleCI will checkout the
#               appropriate branch and follow the instructions in config.yml to perform a build.
#               Authentication with various Salesforce orgs (eg. your Dev Hub) is performed via
#               force:auth:jwt:grant.  Generation of a self-signed SSL certificate and creation
#               of a Connected App in the orgs you must authenticate to are required before a
#               successful build can be performed.
#
# INSTRUCTIONS: 1. Create a self-signed SSL certificate and private key using the helper script
#                     <repository-root>dev-tools/make-server-key
#
#               2. Create a connected app using the certificate from step one.  See the Trailhead
#                  module, "Create Your Connected App" for more details. (linked provided below)
#
#               3. Create the following CircleCI environment variables in the "org-global" context.
#                     DEVHUB_CONSUMER_KEY
#                     DEVHUB_SERVER_KEY_HEX
#                     DEVHUB_SFDC_USERNAME
#
#               4. Modify this basic CircleCI config file to suit your needs.  See the inline
#                  comments for guidance as to how you might configure this for your purposes.
#
# RELATED DOCS: Create Your Connected App (Trailhead Module)
#               └─ https://trailhead.salesforce.com/trails/sfdx_get_started/modules/sfdx_travis_ci/units/sfdx_travis_ci_connected_app
#
#               CircleCI Contexts, Environment Variables, and Configuration Reference
#               ├─ https://circleci.com/docs/2.0/contexts/
#               ├─ https://circleci.com/docs/2.0/env-vars/
#               └─ https://circleci.com/docs/2.0/configuration-reference/
#
#               Salesforce DX Documentation
#               ├─ Salesforce DX Setup Guide
#               │  └─ https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_intro.htm
#               ├─ Salesforce DX Developer Guide
#               │  └─ https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_intro.htm
#               └─ Salesforce CLI Command Reference
#                  └─ https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference.htm
#
####################################################################################################
version: 2
jobs:
####################################################################################################
## JOB:     setup-build-environment
## PURPOSE: Creates an RSA private key in a build workspace directory based on values from 
##          environment variables that are available to this project.
####################################################################################################
  setup-build-environment:
    docker:
      - image: ncino/ci-sfdx
    steps:
      - run: 
          name: Display version info for the Salesforce CLI and core plugins (will force updates if needed)
          command: |
            sfdx version          # Output the version of the CLI
            sfdx plugins --core   # Output the version of the core plugins
      - run:
          name: Prepare all JWT Key Files that might be required by subsequent jobs
          command: |
            # Create directory where all JWT Org Keys will be stored
            mkdir /tmp/sfdx-keys
            # Convert the Hex Keys stored in the context's environment variables back to binary
            echo $DEVHUB_SERVER_KEY_HEX | xxd -r -ps >> /tmp/sfdx-keys/dev-hub.key
            echo $PKGORG_SERVER_KEY_HEX | xxd -r -ps >> /tmp/sfdx-keys/pkg-org.key
            # Confirm that our converted keys are both valid RSA Private Keys
            openssl rsa -in /tmp/sfdx-keys/dev-hub.key -check -noout
            openssl rsa -in /tmp/sfdx-keys/pkg-org.key -check -noout
      - run:
          name: Validate connection/authentication against the Dev Hub
          command: |
            # Confirm that the key can actually be used to login to the specific
            # Salesforce Org that the username stored in $DEVHUB_SFDC_USERNAME
            # is associated with.
            sfdx force:auth:jwt:grant --clientid $DEVHUB_CONSUMER_KEY \
                                      --jwtkeyfile /tmp/sfdx-keys/dev-hub.key \
                                      --username $DEVHUB_SFDC_USERNAME
      - run:
          name: Validate connection/authentication against the Packaging Org
          command: |
            # Confirm that the key can actually be used to login to the specific
            # Salesforce Org that the username stored in $PKGORG_SFDC_USERNAME
            # is associated with.
            sfdx force:auth:jwt:grant --clientid $PKGORG_CONSUMER_KEY \
                                      --jwtkeyfile /tmp/sfdx-keys/pkg-org.key \
                                      --username $PKGORG_SFDC_USERNAME

      ######
      # NOTE: If you have additional orgs to connect to (eg. UAT Orgs) as part of
      # a complete build workflow, you should create additional private key files and 
      # validate authentication here. This way, if there are any issues with creating the
      # Private Keys or authenticating to the specified orgs, the entire workflow can
      # "fail fast" (here and now), rather than consume resources for a partial build.
      ######

      # Ensure that that the dev-hub.key and pkg-org.key files that were just created will be
      # available to other jobs performed during this build.  This way, subsequent
      # builds can skip the step of constructing the key files from the environment
      # variables.
      - persist_to_workspace:
          root: /tmp/sfdx-keys
          paths:
            - dev-hub.key
            - pkg-org.key

      # Store SFDX logs as artifacts
      - store_artifacts:
          path: ~/.sfdx/sfdx.log
          destination: sfdx-logs

####################################################################################################
## JOB:     test-build-1
## PURPOSE: Builds and tests against a specific org shape.
####################################################################################################
  test-build-1:
    docker:
      - image: ncino/ci-sfdx
    environment:
      - SCRATCH_ORG_CONFIG: test-build-1-scratch-def.json
      - TEST_RESULTS_PATH:  /tmp/test-results
      - TEST_RESULTS_DIR:   test-build-1
    steps:
      - checkout                  # Required step.  Checks out the code from your repository.
      - attach_workspace:
          at: /tmp/sfdx-keys      # Attaches the workspace where our private key files were stored.
      - run: 
          name: Display version info for the Salesforce CLI and core plugins (will force updates if needed)
          command: |
            sfdx version          # Output the version of the CLI
            sfdx plugins --core   # Output the version of the core plugins
      - run: 
          name: Authenticate the Salesforce CLI to the Dev Hub using JWT
          command: |
            #### Use the dev-hub.key that was created by the setup-build-environment job
            ## sfdx force:auth:jwt:grant
            # -i --CLIENTID                 Required. The OAuth client ID (sometimes referred to as the consumer key)
            # -f --JWTKEYFILE               Required. Path to a file containing the private key
            # -u --USERNAME                 Required. The authentication username.
            # -d --SETDEFAULTDEVHUBUSERNAME Optional. Sets the authenticated org as the default Dev Hub org for scratch org creation.
            # -a --SETALIAS                 Optional. Sets an alias for the authenticated org.
            sfdx force:auth:jwt:grant -i $DEVHUB_CONSUMER_KEY \
                                      -f /tmp/sfdx-keys/dev-hub.key \
                                      -u $DEVHUB_SFDC_USERNAME \
                                      -d \
                                      -a DevHub
      - run:
          name: Create a new scratch org
          command: |
            #### Create a new scratch org using $CIRCLE_JOB as a key to correct sratch-def.json
            ## sfdx force:org:create
            # -f --DEFINITIONFILE           Required. Path to the scratch org config file for the org being created
            # -a --SETALIAS                 Optional. Set an alias for the newly created scratch org
            # -s --SETDEFAULTUSERNAME       Optional. Set this org as the default username
            sfdx force:org:create -f config/$SCRATCH_ORG_CONFIG \
                                  -a circle_build_$CIRCLE_BUILD_NUM \
                                  -s
      - run:
          name: Push SFDX source to the scratch org
          command: |
            #### Push source to the scratch org
            ## sfdx force:source:push
            # -u --TARGETUSERNAME           Optional. Specify the username/alias of the org to push to
            # -w --WAIT                     Optional. Number of minutes to wait for the push command to return
            sfdx force:source:push  -u circle_build_$CIRCLE_BUILD_NUM \
                                    -w 20
      - run:
          name: Assign permission sets to the scratch org's Admin user.
          command: |
            #### Assign permission set to Admin user.
            ## sfdx force:user:permset:assign
            # -n --PERMSETNAME              Required. The name of the permission set to assign
            # -u --TARGETUSERNAME           Optional. Username or alias for the target org (Overrides default target org)
            sfdx force:user:permset:assign  -n "FSC_DW" \
                                            -u circle_build_$CIRCLE_BUILD_NUM
      - run:
          name: Create artifact directory to store test results
          command: |
            #### Create artifact directory to store test results.
            mkdir -p "$TEST_RESULTS_PATH/$TEST_RESULTS_DIR"
      - run:
          name: Run all local (unpackaged) Apex tests in the scratch org
          command: |
            #### Run Apex tests and store the results
            ## sfdx force:apex:test:run
            # -d --OUTPUTDIR                Optional. Directory to store test run files.
            # -u --TARGETUSERNAME           Optional. The username of the org that Apex tests will be run against.
            # -l --TESTLEVEL                Optional. Specifies which tests to run, using a TestLevel enum value.
            #                               Permissible values are: RunLocalTests, RunAllTestsInOrg, RunSpecifiedTests
            # -r --RESULTFORMAT             Optional. Format to use when displaying test results.  
            #                               Permissible values are: human, tap, junit, json
            #                               If you also specify the --json flag, --json overrides this parameter.
            # -w --WAIT                     Optional. The number of minutes that the CLI will wait for tests to complete.
            # -c --CODECOVERAGE             Optional. Retrieves code coverage results as part of the test run.
            sfdx force:apex:test:run  -d $TEST_RESULTS_PATH/$TEST_RESULTS_DIR \
                                      -u circle_build_$CIRCLE_BUILD_NUM \
                                      -l RunLocalTests \
                                      -r human \
                                      -w 10 \
                                      -c 
      - run:
          name: Mark all scratch orgs created by this job for deletion
          command: |
            #### Mark the scratch org we used for deletion.
            ## sfdx force:org:delete
            # -u --TARGETUSERNAME           Required. Username or alias for the target org
            # -p --NOPROMPT                 Optional. Do not prompt the user to confirm deletion
            sfdx force:org:delete -u circle_build_$CIRCLE_BUILD_NUM \
                                  -p

      # Store test results and SFDX logs as artifacts
      - store_test_results:
          path: /tmp/test-results
      - store_artifacts:
          path: /tmp/test-results
          destination: test-results
      - store_artifacts:
          path: ~/.sfdx/sfdx.log
          destination: sfdx-logs

####################################################################################################
## JOB:     test-build-2
## PURPOSE: Builds and tests against an alternate org shape
## NOTE:    Tests not implemented for this job during the demo.  If moving this
##          sample code into production, you should add additional tests here.
####################################################################################################
  test-build-2:
    docker:
      - image: ncino/ci-sfdx
    environment:
      - SCRATCH_ORG_CONFIG: test-build-2-scratch-def.json
    steps:
      - run:
          name: Sleep for one minute
          command: |
            sleep 1m

####################################################################################################
## JOB:     create-beta-package
## PURPOSE: Deploys successfully built and tested code to the packaging org so it can be prepped
##          for a new BETA package version upload.
####################################################################################################
  create-beta-package:
    docker:
      - image: ncino/ci-sfdx
    environment:
      - PACKAGE_NAME:         "Falcon-X"                      # Name of your managed package
      - PACKAGE_VERSION_NAME: "Spring 2018-C"                 # Version Name for your managed package
      - METADATA_PACKAGE_ID:  "0331N000000gPC2QAM"            # Metadata Package ID (always begins with 033)
      - PACKAGE_DIRECTORY:    "./sfdx-source/isvte_falcon_x"  # SFDX package directory that has your code
    steps:
      - checkout                  # Required step.  Checks out the code from your repository.
      - attach_workspace:
          at: /tmp/sfdx-keys      # Attaches the workspace where our private key files were stored.
      - run: 
          name: Display version info for the Salesforce CLI and core plugins (will force updates if needed)
          command: |
            sfdx version          # Output the version of the CLI
            sfdx plugins --core   # Output the version of the core plugins
      - run: 
          name: Authenticate the Salesforce CLI to the Packaging Org using JWT
          command: |
            #### Use the pkg-org.key that was created by the setup-build-environment job
            ## sfdx force:auth:jwt:grant
            # -i --CLIENTID                 Required. The OAuth client ID (sometimes referred to as the consumer key)
            # -f --JWTKEYFILE               Required. Path to a file containing the private key
            # -u --USERNAME                 Required. The authentication username.
            # -d --SETDEFAULTDEVHUBUSERNAME Optional. Sets the authenticated org as the default Dev Hub org for scratch org creation.
            # -a --SETALIAS                 Optional. Sets an alias for the authenticated org.
            sfdx force:auth:jwt:grant -i $PKGORG_CONSUMER_KEY \
                                      -f /tmp/sfdx-keys/pkg-org.key \
                                      -u $PKGORG_SFDC_USERNAME \
                                      -d \
                                      -a PkgOrg
      - run: 
          name: Convert SFDX source to MDAPI source
          command: |
            #### Convert SFDX source to MDAPI source so it can be deployed to the Packaging Org
            ## sfdx force:source:convert
            # -r --ROOTDIR                  Optional. The directory that contains the source to convert.
            # -d --OUTPUTDIR                Optional. The output directory to export the Metadata API source to.
            # -n --PACKAGENAME              Optional. The name of the package to associate with the Metadata API source.
            #    --LOGLEVEL                 Optional. The logging level for this command invocation. 
            sfdx force:source:convert -r "$PACKAGE_DIRECTORY" \
                                      -d "./mdapi-source/circle_build_$CIRCLE_BUILD_NUM" \
                                      -n "$PACKAGE_NAME" \
                                      --loglevel error
      - run: 
          name: Deploy MDAPI Source to the Packaging Org
          command: |
            #### Deploy the newly converted MDAPI Source to the Packaging Org
            ## sfdx force:mdapi:deploy
            # -d --DEPLOYDIR                Optional. The root of the directory tree that contains the files to deploy.
            # -l --TESTLEVEL                Optional. Specifies which level of deployment tests to run.
            # -u --TARGETUSERNAME           Optional. A username or alias for the target org. Overrides the default target org.
            # -w --WAIT                     Optional. The number of minutes to wait for the command to complete. Default is –1 (no limit).
            #    --VERBOSE                  Optional. Indicates that you want verbose output from the deploy operation.
            #    --LOGLEVEL                 Optional. The logging level for this command invocation. 
            sfdx force:mdapi:deploy -d "./mdapi-source/circle_build_$CIRCLE_BUILD_NUM" \
                                    -l RunLocalTests \
                                    -u PkgOrg \
                                    -w 15 \
                                    --verbose \
                                    --loglevel error
      - run: 
          name: List current version history for the first-generation package about to be uploaded
          command: |
            #### List version info for all first-gen packages
            ## sfdx force:package1:version:list
            # -u --TARGETUSERNAME           Optional. A username or alias for the target org. Overrides the default target org.
            # -i --PACKAGEID                Optional. ID of the metadata package (starts with 033) we want version info from.
            #    --LOGLEVEL                 Optional. The logging level for this command invocation. 
            sfdx force:package1:version:list  -u PkgOrg \
                                              -i $METADATA_PACKAGE_ID \
                                              --loglevel error                                              
      - run: 
          name: Create (upload) a new MANAGED BETA package version
          command: |
            #### Create a new MANAGED BETA package version
            ## sfdx force:package1:version:create
            # -i --PACKAGEID                Required. ID of the metadata package (starts with 033) of which you’re creating a new version.
            # -n --NAME                     Required. Package version name.
            # -d --DESCRIPTION              Optional. Package version description.
            # -u --TARGETUSERNAME           Optional. A username or alias for the target org. Overrides the default target org.
            # -w --WAIT                     Optional. The number of minutes to wait for the command to complete. Default is –1 (no limit).
            #    --LOGLEVEL                 Optional. The logging level for this command invocation. 
            sfdx force:package1:version:create  -i $METADATA_PACKAGE_ID \
                                                -n "$PACKAGE_VERSION_NAME" \
                                                -d "Package version generated by CI process" \
                                                -u PkgOrg \
                                                -w 15 \
                                                --loglevel error

      # Store SFDX logs as artifacts
      - store_artifacts:
          path: ~/.sfdx/sfdx.log
          destination: sfdx-logs 

####################################################################################################
## WORKFLOW:  build_and_test
## PURPOSE:   Primary workflow used by the CI process.
####################################################################################################
workflows:
  version: 2
  build_and_test:
    jobs:
      - setup-build-environment:
          context: org-global
          filters:
            branches:
              only:
                - non-existant-branch   # Normally, this might be "master". This should be configured after template is customized.
      - test-build-1:
          context: org-global
          requires:
            - setup-build-environment
      - test-build-2:
          context: org-global
          requires:
            - setup-build-environment
      - create-beta-package:
          context: org-global
          requires:
            - test-build-1
            - test-build-2



#END-OF-CONFIG-FILE#