Skip to content

Commit

Permalink
Merge pull request #1479 from DataDog/rodrigo.roca/add-config-shas-op…
Browse files Browse the repository at this point in the history
…tion-to-pass-confg-shas-manually

Add option to pass config shas manually on `correlate` command
  • Loading branch information
rodrigo-roca authored Oct 28, 2024
2 parents 3c7feaf + 6d7b076 commit ae2cc7c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 41 deletions.
19 changes: 3 additions & 16 deletions src/commands/deployment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <cd_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
Expand All @@ -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
Expand All @@ -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
24 changes: 21 additions & 3 deletions src/commands/deployment/__tests__/correlate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -56,15 +68,21 @@ 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"`)
expect(output).toContain(`"attributes"`)
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",
Expand Down
56 changes: 34 additions & 22 deletions src/commands/deployment/correlate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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<string, string>,
apiKey: string
) {
private async sendCorrelationData(ciProvider: string, ciEnv: Record<string, string>, 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,
},
}
Expand Down

0 comments on commit ae2cc7c

Please sign in to comment.