diff --git a/.changes/next-release/Removal-f27351ac-27fa-41e2-8cb1-443ce9ae9205.json b/.changes/next-release/Removal-f27351ac-27fa-41e2-8cb1-443ce9ae9205.json new file mode 100644 index 00000000..4f91aff7 --- /dev/null +++ b/.changes/next-release/Removal-f27351ac-27fa-41e2-8cb1-443ce9ae9205.json @@ -0,0 +1,4 @@ +{ + "type": "Removal", + "description": "ECR: Remove image retagging option due to breaking change." +} \ No newline at end of file diff --git a/src/tasks/ECRPushImage/TaskOperations.ts b/src/tasks/ECRPushImage/TaskOperations.ts index c7060dee..6e980f98 100644 --- a/src/tasks/ECRPushImage/TaskOperations.ts +++ b/src/tasks/ECRPushImage/TaskOperations.ts @@ -8,7 +8,7 @@ import tl = require('azure-pipelines-task-lib/task') import { DockerHandler } from 'lib/dockerUtils' import { constructTaggedImageName, getEcrAuthorizationData, loginToRegistry } from 'lib/ecrUtils' import { parse } from 'url' -import { imageNameSource, retagSource, TaskParameters } from './TaskParameters' +import { imageNameSource, TaskParameters } from './TaskParameters' export class TaskOperations { private dockerPath = '' @@ -63,76 +63,30 @@ export class TaskOperations { proxyEndpoint = authData.proxyEndpoint } - const targetRepositoryName = this.taskParameters.repositoryName + if (this.taskParameters.autoCreateRepository) { + await this.createRepositoryIfNeeded(this.taskParameters.repositoryName) + } + const targetImageName = constructTaggedImageName( this.taskParameters.repositoryName, - this.taskParameters.targetTag + this.taskParameters.pushTag ) const targetImageRef = `${endpoint}/${targetImageName}` + await this.tagImage(sourceImageRef, targetImageRef) - // Retag an image without pushing the complete image from docker. - if (this.taskParameters.imageSource === retagSource) { - const images = ( - await this.ecrClient - .batchGetImage({ - repositoryName: targetRepositoryName, - imageIds: [{ imageTag: this.taskParameters.targetTag }] - }) - .promise() - ).images - - if (!images || !images[0]) { - throw new Error( - tl.loc( - 'FailureToFindExistingImage', - this.taskParameters.targetTag, - this.taskParameters.repositoryName - ) - ) - } - - const manifest = images[0].imageManifest - if (manifest) { - try { - await this.ecrClient - .putImage({ - imageTag: this.taskParameters.newTag, - repositoryName: targetRepositoryName, - imageManifest: manifest - }) - .promise() - } catch (err) { - if (err.code !== 'ImageAlreadyExistsException') { - // Thrown when manifest and tag already exist in ECR. - // Do not block if the tag already exists on the target image. - throw err - } - console.log(err.message) - } - } else { - throw new Error('batchGetImage did not return an image manifest.') - } - } else { - if (this.taskParameters.autoCreateRepository) { - await this.createRepositoryIfNeeded(this.taskParameters.repositoryName) - } - - await this.tagImage(sourceImageRef, targetImageRef) + await loginToRegistry(this.dockerHandler, this.dockerPath, authToken, proxyEndpoint) - await loginToRegistry(this.dockerHandler, this.dockerPath, authToken, proxyEndpoint) - - await this.pushImageToECR(targetImageRef) - - if (this.taskParameters.removeDockerImage) { - await this.removeDockerImage(sourceImageRef) - } - } + await this.pushImageToECR(targetImageRef) if (this.taskParameters.outputVariable) { console.log(tl.loc('SettingOutputVariable', this.taskParameters.outputVariable, targetImageRef)) tl.setVariable(this.taskParameters.outputVariable, targetImageRef) } + if (this.taskParameters.removeDockerImage) { + await this.removeDockerImage(sourceImageRef) + } + console.log(tl.loc('TaskCompleted')) } diff --git a/src/tasks/ECRPushImage/TaskParameters.ts b/src/tasks/ECRPushImage/TaskParameters.ts index 47a417b9..388d834c 100644 --- a/src/tasks/ECRPushImage/TaskParameters.ts +++ b/src/tasks/ECRPushImage/TaskParameters.ts @@ -9,7 +9,6 @@ import { getInputOrEmpty, getInputRequired } from 'lib/vstsUtils' export const imageNameSource = 'imagename' export const imageIdSource = 'imageid' -export const retagSource = 'retag' export interface TaskParameters { awsConnectionParameters: AWSConnectionParameters @@ -18,8 +17,7 @@ export interface TaskParameters { sourceImageTag: string sourceImageId: string repositoryName: string - targetTag: string - newTag: string + pushTag: string autoCreateRepository: boolean forceDockerNamingConventions: boolean removeDockerImage: boolean @@ -31,37 +29,24 @@ export function buildTaskParameters(): TaskParameters { awsConnectionParameters: buildConnectionParameters(), imageSource: getInputRequired('imageSource'), repositoryName: getInputRequired('repositoryName'), - targetTag: getInputOrEmpty('targetTag'), + pushTag: getInputOrEmpty('pushTag'), autoCreateRepository: tl.getBoolInput('autoCreateRepository', false), forceDockerNamingConventions: tl.getBoolInput('forceDockerNamingConventions', false), removeDockerImage: tl.getBoolInput('removeDockerImage', false), outputVariable: getInputOrEmpty('outputVariable'), sourceImageName: '', sourceImageId: '', - sourceImageTag: '', - newTag: '' + sourceImageTag: '' } - switch (parameters.imageSource) { - case imageNameSource: - parameters.sourceImageName = getInputRequired('sourceImageName') - parameters.sourceImageTag = getInputOrEmpty('sourceImageTag') - if (!parameters.sourceImageTag) { - parameters.sourceImageTag = 'latest' - } - break - case imageIdSource: - parameters.sourceImageId = getInputRequired('sourceImageId') - break - case retagSource: - parameters.newTag = getInputRequired('newTag') - break - default: - throw new Error(`Unknown imageSource specified: ${parameters.imageSource}`) - } - - if (!parameters.targetTag) { - parameters.targetTag = 'latest' + if (parameters.imageSource === imageNameSource) { + parameters.sourceImageName = getInputRequired('sourceImageName') + parameters.sourceImageTag = getInputOrEmpty('sourceImageTag') + if (!parameters.sourceImageTag) { + parameters.sourceImageTag = 'latest' + } + } else { + parameters.sourceImageId = getInputRequired('sourceImageId') } return parameters diff --git a/src/tasks/ECRPushImage/task.json b/src/tasks/ECRPushImage/task.json index 53d7e71b..8fd2c2b2 100644 --- a/src/tasks/ECRPushImage/task.json +++ b/src/tasks/ECRPushImage/task.json @@ -49,11 +49,10 @@ "label": "Image Identity", "required": true, "defaultValue": "imagename", - "helpMarkDown": "How the image to be pushed is identified. You can select from either the image ID or the image name. If image name is selected a tag can also be specified. Alternatively, you can opt to retag an image in ECR by specifying an existing tag in the target repository. [Retagging](https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-retag.html) saves bandwidth by not re-pushing the image to ECR.", + "helpMarkDown": "How the image to be pushed is identified. You can select from either the image ID or the image name. If image name is selected a tag can also be specified", "options": { "imagename": "Image name with optional tag", - "imageid": "Image ID", - "retag": "Retag pushed image" + "imageid": "Image ID" }, "properties": { "EditableOptions": "False" @@ -95,21 +94,12 @@ "helpMarkDown": "The name of the repository to which the image will be pushed." }, { - "name": "targetTag", + "name": "pushTag", "label": "Target Repository Tag", "type": "string", "required": false, "defaultValue": "latest", - "helpMarkDown": "Optional tag for the image in the remote repository. If not specified, ECR will assume 'latest'." - }, - { - "name": "newTag", - "label": "New Tag", - "type": "string", - "required": true, - "defaultValue": "", - "helpMarkDown": "Tag to add to the target image.", - "visibleRule": "imageSource = retag" + "helpMarkDown": "Optional tag for the new image in the repository. If not specified, ECR will assume 'latest'." }, { "name": "autoCreateRepository", @@ -117,8 +107,7 @@ "type": "boolean", "defaultValue": false, "required": false, - "helpMarkDown": "If selected the task will attempt to create the repository if it does not exist.", - "visibleRule": "imageSource != retag" + "helpMarkDown": "If selected the task will attempt to create the repository if it does not exist." }, { "name": "forceDockerNamingConventions", @@ -126,8 +115,7 @@ "type": "boolean", "defaultValue": false, "required": false, - "helpMarkDown": "If enabled, the Docker repository name will be modified to follow Docker naming conventions. Converts upper case characters to lower case. Removes all characters except 0-9, -, . and _ .", - "visibleRule": "imageSource != retag" + "helpMarkDown": "If enabled, the Docker repository name will be modified to follow Docker naming conventions. Converts upper case characters to lower case. Removes all characters except 0-9, -, . and _ ." }, { "name": "removeDockerImage", @@ -135,8 +123,7 @@ "type": "boolean", "defaultValue": false, "required": false, - "helpMarkDown": "If enabled, this command removes the image and untags any references to it", - "visibleRule": "imageSource != retag" + "helpMarkDown": "If enabled, this command removes the image and untags any references to it" }, { "name": "outputVariable", @@ -185,7 +172,6 @@ "SettingOutputVariable": "Setting output variable %s with the pushed image tag %s", "TaskCompleted": "Successfully completed sending the message", "FailureToObtainAuthToken": "Failed to obtain auth token!", - "FailureToFindExistingImage": "Failed to find image with tag '%s' in target repository '%s'", "NoValidEndpoint": "Failed to get endpoint of repository %s. Check your credentials and if the endpoint exists!" } } diff --git a/tests/endToEndTests/ecr-push-image-should-fail-no-docker.json b/tests/endToEndTests/ecr-push-image-should-fail-no-docker.json index 883c12a3..1ae281f7 100644 --- a/tests/endToEndTests/ecr-push-image-should-fail-no-docker.json +++ b/tests/endToEndTests/ecr-push-image-should-fail-no-docker.json @@ -41,7 +41,7 @@ "sourceImageTag": "latest", "sourceImageId": "", "repositoryName": "test-repo", - "targetTag": "latest", + "pushTag": "latest", "autoCreateRepository": "false", "outputVariable": "", "logRequest": "false", diff --git a/tests/taskTests/ecrPushImage/ecrPushImage-test.ts b/tests/taskTests/ecrPushImage/ecrPushImage-test.ts index 5e9c6285..f1db893d 100644 --- a/tests/taskTests/ecrPushImage/ecrPushImage-test.ts +++ b/tests/taskTests/ecrPushImage/ecrPushImage-test.ts @@ -19,8 +19,7 @@ const defaultTaskParameters: TaskParameters = { sourceImageTag: '', sourceImageId: '', repositoryName: '', - targetTag: '', - newTag: '', + pushTag: '', autoCreateRepository: false, forceDockerNamingConventions: false, removeDockerImage: false,