diff --git a/src/commands/deployment/README.md b/src/commands/deployment/README.md index 5e78cb7b2..bacf4618d 100644 --- a/src/commands/deployment/README.md +++ b/src/commands/deployment/README.md @@ -33,21 +33,7 @@ datadog-ci deployment mark --env prod --service payment-service --revision v1.1. The `correlate` command connects a GitOps deployment with the CI pipeline of the application repository. Once they are connected, you can see in Datadog's UI which pipeline triggered a deployment, and which deployments were triggered by a pipeline. -**Important**: This command does not work for every setup. Refer to [when to call the command](#When-to-call-the-command) for more details. - -#### When to call the command - -In order for the command to work properly, it needs to be called between when the configuration changes are committed and when they are pushed to the configuration repository (where the Kubernetes manifests are). The flow should be similar to the following: - -1. Make the changes to the configuration (for example, update a image tag). -2. Run `git commit -m "update kubernetes configuration"`. -3. Run `datadog-ci deployment correlate --provider ` (refer to the command syntax below). -4. Run `git push`. - -If you are using [argo cd image updater][3], this command does not work since it relies on making the changes using `git commit`. - -Again, these steps need to happen in your CI since the end goal of this command is to correlate the pipeline doing the configuration changes -with the associated deployments. +**Important**: This command does not work for every setup. Refer to the [documentation][3] for more details. For example: ```bash @@ -56,6 +42,7 @@ datadog-ci deployment correlate --provider argocd - `--provider` (**required**): the CD provider name. Currently, the only supported CD provider is `argocd`. - `--config-repo`: configuration repository URL where the kubernetes manifests are stored. If empty, the command tries to get it using the git command `git ls-remote --get-url`. +- `--config-shas`: a list of the Git commit SHAs of the configuration repository. If empty, the command tries to get all local commits using a `git log` command. - `--dry-run` (default: `false`): prevents the command from sending any data to Datadog. All the other checks are still performed. ### Environment variables @@ -72,4 +59,4 @@ Additional helpful documentation, links, and articles: [1]: https://docs.datadoghq.com/continuous_delivery/deployments/ciproviders [2]: https://docs.datadoghq.com/continuous_delivery/ -[3]: https://argocd-image-updater.readthedocs.io/en/stable/ +[3]: https://docs.datadoghq.com/continuous_delivery/deployments/argocd#correlate-deployments-with-ci-pipelines diff --git a/src/commands/deployment/__tests__/correlate.test.ts b/src/commands/deployment/__tests__/correlate.test.ts index 059bbf7ec..7c4cc15a3 100644 --- a/src/commands/deployment/__tests__/correlate.test.ts +++ b/src/commands/deployment/__tests__/correlate.test.ts @@ -38,13 +38,25 @@ describe('execute', () => { expect(code).toBe(1) expect(context.stdout.toString()).toContain('Could not extract the commit SHA from the CI environment variables') }) + test('no configuration commit shas', async () => { + const envVars = { + GITLAB_CI: 'placeholder', + CI_REPOSITORY_URL: 'https://github.com/DataDog/example', + CI_COMMIT_SHA: 'abcdef', + } + const {context, code} = await runCLI(['--provider', 'argocd', '--dry-run'], envVars) + expect(code).toBe(1) + expect(context.stdout.toString()).toContain( + 'Could not retrieve commit SHAs, commit changes and then call this command or provide them with --config-shas' + ) + }) test('valid with minimal data', async () => { const envVars = { GITLAB_CI: 'placeholder', CI_REPOSITORY_URL: 'https://github.com/DataDog/example', CI_COMMIT_SHA: 'abcdef', } - const {context: _, code} = await runCLI(['--provider', 'argocd', '--dry-run'], envVars) + const {context: _, code} = await runCLI(['--provider', 'argocd', '--config-shas', 'abcdef', '--dry-run'], envVars) expect(code).toBe(0) }) test('valid', async () => { @@ -56,7 +68,10 @@ describe('execute', () => { CI_PIPELINE_ID: '1', CI_JOB_ID: '1', } - const {context, code} = await runCLI(['--provider', 'argocd', '--dry-run'], envVars) + const {context, code} = await runCLI( + ['--provider', 'argocd', '--config-shas', 'abcdef', '--config-shas', 'fedcba', '--dry-run'], + envVars + ) expect(code).toBe(0) const output = context.stdout.toString() expect(output).toContain(`"type": "ci_app_deployment_correlate"`) @@ -64,7 +79,10 @@ describe('execute', () => { expect(output).toContain(`"ci_provider": "gitlab"`) expect(output).toContain(`"cd_provider": "argocd"`) expect(output).toContain(`"config_repo_url"`) - expect(output).toContain(`"config_commit_shas"`) + expect(output).toContain(`"config_commit_shas": [ + "abcdef", + "fedcba" + ]`) expect(output).toContain(`"ci_env": { "ci.pipeline.id": "1", "ci.provider.name": "gitlab", diff --git a/src/commands/deployment/correlate.ts b/src/commands/deployment/correlate.ts index 1068472d5..c2de1a078 100644 --- a/src/commands/deployment/correlate.ts +++ b/src/commands/deployment/correlate.ts @@ -25,11 +25,22 @@ export class DeploymentCorrelateCommand extends Command { This command will correlate the pipeline with a GitOps CD deployment.\n See README for additional details. `, - examples: [['Correlate an Argo CD deployment', 'datadog-ci deployment correlate --provider argocd']], + examples: [ + ['Correlate an Argo CD deployment', 'datadog-ci deployment correlate --provider argocd'], + [ + 'Correlate ArgoCD deployment manually', + 'datadog-ci deployment correlate --provider argocd --config-repo https://github.com/my-manifests-repo --config-shas 92eb0db6926aaf51b9fb223895b6d8d1c0ff1ff4', + ], + [ + 'Correlate ArgoCD deployment manually to several commits', + 'datadog-ci deployment correlate --provider argocd --config-repo https://github.com/my-manifests-repo --config-shas 92eb0db6926aaf51b9fb223895b6d8d1c0ff1ff4 --config-shas e996e5c30ba1cb4dc7f634ab4a0a59473741c4de', + ], + ], }) private cdProviderParam = Option.String('--provider') private configurationRepo = Option.String('--config-repo') + private configurationShas = Option.Array('--config-shas') private dryRun = Option.Boolean('--dry-run', false) private config = { @@ -76,45 +87,46 @@ export class DeploymentCorrelateCommand extends Command { maxConcurrentProcesses: 2, // max 2 git commands at the same time }) - const currentBranch = await gitCurrentBranch(git) - if (!currentBranch) { - this.logger.error('Could not get current branch') + if (!this.configurationRepo) { + this.configurationRepo = await gitRepositoryURL(git) + } + + if (this.configurationRepo === undefined || this.configurationRepo === '') { + this.logger.error('Could not retrieve repository URL, check out a repository or provide it with --config-repo') return 1 } - let localCommitShas: string[] - if (this.configurationRepo) { - localCommitShas = await gitLocalCommitShas(git, currentBranch) - } else { - ;[this.configurationRepo, localCommitShas] = await Promise.all([ - gitRepositoryURL(git), - gitLocalCommitShas(git, currentBranch), - ]) + if (!this.configurationShas) { + this.logger.info('Retrieving local git commits') + const currentBranch = await gitCurrentBranch(git) + if (!currentBranch) { + this.logger.error('Could not get current branch') + + return 1 + } + this.configurationShas = await gitLocalCommitShas(git, currentBranch) } - if (this.configurationRepo === undefined || this.configurationRepo === '') { - this.logger.error('Could not retrieve repository URL, check out a repository or provide it with --config-repo') + if (this.configurationShas.length === 0) { + this.logger.error( + 'Could not retrieve commit SHAs, commit changes and then call this command or provide them with --config-shas' + ) return 1 } - await this.sendCorrelationData(ciEnv[CI_PROVIDER_NAME], localCommitShas, ciEnv, this.config.apiKey) + await this.sendCorrelationData(ciEnv[CI_PROVIDER_NAME], ciEnv, this.config.apiKey) } - private async sendCorrelationData( - ciProvider: string, - configCommitShas: string[], - ciEnv: Record, - apiKey: string - ) { + private async sendCorrelationData(ciProvider: string, ciEnv: Record, apiKey: string) { const correlateEvent = { type: 'ci_app_deployment_correlate', attributes: { ci_provider: ciProvider, cd_provider: this.cdProviderParam, config_repo_url: this.configurationRepo, - config_commit_shas: configCommitShas, + config_commit_shas: this.configurationShas, ci_env: ciEnv, }, }