func releaseVersions(releases []pivnet.Release) ([]string, error) {
	releaseVersions := make([]string, len(releases))

	var err error
	for i, r := range releases {
		releaseVersions[i], err = versions.CombineVersionAndFingerprint(r.Version, r.UpdatedAt)
		if err != nil {
			return nil, err
		}
	}

	return releaseVersions, nil
}
// versionsWithFingerprints adds the release Fingerprints to the release versions
func versionsWithFingerprints(
	releases []pivnet.Release,
) ([]string, error) {
	var allVersions []string
	for _, r := range releases {
		version, err := versions.CombineVersionAndFingerprint(r.Version, r.UpdatedAt)
		if err != nil {
			return nil, err
		}

		allVersions = append(allVersions, version)
	}

	return allVersions, nil
}
func (rf ReleaseFinalizer) Finalize(productSlug string, releaseVersion string) (concourse.OutResponse, error) {
	newRelease, err := rf.pivnet.GetRelease(productSlug, releaseVersion)
	if err != nil {
		return concourse.OutResponse{}, err
	}

	outputVersion, err := versions.CombineVersionAndFingerprint(newRelease.Version, newRelease.UpdatedAt)
	if err != nil {
		return concourse.OutResponse{}, err // this will never return an error
	}

	metadata := []concourse.Metadata{
		{Name: "version", Value: newRelease.Version},
		{Name: "release_type", Value: string(newRelease.ReleaseType)},
		{Name: "release_date", Value: newRelease.ReleaseDate},
		{Name: "description", Value: newRelease.Description},
		{Name: "release_notes_url", Value: newRelease.ReleaseNotesURL},
		{Name: "availability", Value: newRelease.Availability},
		{Name: "controlled", Value: fmt.Sprintf("%t", newRelease.Controlled)},
		{Name: "eccn", Value: newRelease.ECCN},
		{Name: "license_exception", Value: newRelease.LicenseException},
		{Name: "end_of_support_date", Value: newRelease.EndOfSupportDate},
		{Name: "end_of_guidance_date", Value: newRelease.EndOfGuidanceDate},
		{Name: "end_of_availability_date", Value: newRelease.EndOfAvailabilityDate},
	}
	if newRelease.EULA != nil {
		metadata = append(
			metadata,
			concourse.Metadata{Name: "eula_slug", Value: newRelease.EULA.Slug})
	}

	return concourse.OutResponse{
		Version: concourse.Version{
			ProductVersion: outputVersion,
		},
		Metadata: metadata,
	}, nil
}
func (c *InCommand) Run(input concourse.InRequest) (concourse.InResponse, error) {
	productSlug := input.Source.ProductSlug

	version, fingerprint, err := versions.SplitIntoVersionAndFingerprint(input.Version.ProductVersion)
	if err != nil {
		c.logger.Info("Parsing of fingerprint failed; continuing without it")
		version = input.Version.ProductVersion
		fingerprint = ""
	}

	c.logger.Info(fmt.Sprintf(
		"Getting release for product slug: '%s' and product version: '%s'",
		productSlug,
		version,
	))

	release, err := c.pivnetClient.GetRelease(productSlug, version)
	if err != nil {
		return concourse.InResponse{}, err
	}

	if fingerprint != "" {
		actualFingerprint := release.UpdatedAt
		if actualFingerprint != fingerprint {
			return concourse.InResponse{}, fmt.Errorf(
				"provided fingerprint: '%s' does not match actual fingerprint (from pivnet): '%s' - %s",
				fingerprint,
				actualFingerprint,
				"pivnet does not support downloading old versions of a release",
			)
		}
	}

	c.logger.Info(fmt.Sprintf("Accepting EULA for release with ID: %d", release.ID))

	err = c.pivnetClient.AcceptEULA(productSlug, release.ID)
	if err != nil {
		return concourse.InResponse{}, err
	}

	c.logger.Info("Getting product files")

	releaseProductFiles, err := c.pivnetClient.ProductFilesForRelease(productSlug, release.ID)
	if err != nil {
		return concourse.InResponse{}, err
	}

	c.logger.Info("Getting file groups")

	fileGroups, err := c.pivnetClient.FileGroupsForRelease(productSlug, release.ID)
	if err != nil {
		return concourse.InResponse{}, err
	}

	allProductFiles := releaseProductFiles
	for _, fg := range fileGroups {
		allProductFiles = append(allProductFiles, fg.ProductFiles...)
	}

	// Get individual product files to obtain metadata that isn't found
	// in the endpoint for all product files.
	for i, p := range allProductFiles {
		allProductFiles[i], err = c.pivnetClient.ProductFileForRelease(
			productSlug,
			release.ID,
			p.ID,
		)
		if err != nil {
			return concourse.InResponse{}, err
		}
	}

	c.logger.Info("Getting release dependencies")

	releaseDependencies, err := c.pivnetClient.ReleaseDependencies(productSlug, release.ID)
	if err != nil {
		return concourse.InResponse{}, err
	}

	c.logger.Info("Getting release upgrade paths")

	releaseUpgradePaths, err := c.pivnetClient.ReleaseUpgradePaths(productSlug, release.ID)
	if err != nil {
		return concourse.InResponse{}, err
	}

	c.logger.Info("Downloading files")

	err = c.downloadFiles(input.Params.Globs, allProductFiles, productSlug, release.ID)
	if err != nil {
		return concourse.InResponse{}, err
	}

	c.logger.Info("Creating metadata")

	versionWithFingerprint, err := versions.CombineVersionAndFingerprint(version, fingerprint)

	mdata := metadata.Metadata{
		Release: &metadata.Release{
			ID:                    release.ID,
			Version:               release.Version,
			ReleaseType:           string(release.ReleaseType),
			ReleaseDate:           release.ReleaseDate,
			Description:           release.Description,
			ReleaseNotesURL:       release.ReleaseNotesURL,
			Availability:          release.Availability,
			Controlled:            release.Controlled,
			ECCN:                  release.ECCN,
			LicenseException:      release.LicenseException,
			EndOfSupportDate:      release.EndOfSupportDate,
			EndOfGuidanceDate:     release.EndOfGuidanceDate,
			EndOfAvailabilityDate: release.EndOfAvailabilityDate,
		},
	}

	if release.EULA != nil {
		mdata.Release.EULASlug = release.EULA.Slug
	}

	for _, pf := range releaseProductFiles {
		mdata.Release.ProductFiles = append(mdata.Release.ProductFiles, metadata.ReleaseProductFile{
			ID: pf.ID,
		})
	}

	for _, pf := range allProductFiles {
		mdata.ProductFiles = append(mdata.ProductFiles, metadata.ProductFile{
			ID:           pf.ID,
			File:         pf.Name,
			Description:  pf.Description,
			AWSObjectKey: pf.AWSObjectKey,
			FileType:     pf.FileType,
			FileVersion:  pf.FileVersion,
			MD5:          pf.MD5,
		})
	}

	for _, d := range releaseDependencies {
		mdata.Dependencies = append(mdata.Dependencies, metadata.Dependency{
			Release: metadata.DependentRelease{
				ID:      d.Release.ID,
				Version: d.Release.Version,
				Product: metadata.Product{
					ID:   d.Release.Product.ID,
					Name: d.Release.Product.Name,
				},
			},
		})
	}

	for _, d := range releaseUpgradePaths {
		mdata.UpgradePaths = append(mdata.UpgradePaths, metadata.UpgradePath{
			ID:      d.Release.ID,
			Version: d.Release.Version,
		})
	}

	for _, fg := range fileGroups {
		mfg := metadata.FileGroup{
			ID:   fg.ID,
			Name: fg.Name,
		}

		for _, pf := range fg.ProductFiles {
			mfg.ProductFiles = append(mfg.ProductFiles, metadata.FileGroupProductFile{
				ID: pf.ID,
			})
		}

		mdata.FileGroups = append(mdata.FileGroups, mfg)
	}

	c.logger.Info("Writing metadata files")

	err = c.fileWriter.WriteVersionFile(versionWithFingerprint)
	if err != nil {
		return concourse.InResponse{}, err
	}

	err = c.fileWriter.WriteMetadataYAMLFile(mdata)
	if err != nil {
		return concourse.InResponse{}, err
	}

	err = c.fileWriter.WriteMetadataJSONFile(mdata)
	if err != nil {
		return concourse.InResponse{}, err
	}

	concourseMetadata := c.addReleaseMetadata([]concourse.Metadata{}, release)

	out := concourse.InResponse{
		Version: concourse.Version{
			ProductVersion: versionWithFingerprint,
		},
		Metadata: concourseMetadata,
	}

	return out, nil
}
				for i := 0; i < totalFiles; i++ {
					localDownloadPath := fmt.Sprintf("%s-downloaded", sourceFilePaths[i])
					err := client.DownloadFile(pivnetBucketName, remotePaths[i], localDownloadPath)
					Expect(err).ShouldNot(HaveOccurred())
				}

				By("Outputting a valid json response")
				response := concourse.OutResponse{}
				err = json.Unmarshal(session.Out.Contents(), &response)
				Expect(err).ShouldNot(HaveOccurred())

				By("Validating the release was created correctly")
				release, err := pivnetClient.GetRelease(productSlug, version)
				Expect(err).NotTo(HaveOccurred())

				expectedVersion, err := versions.CombineVersionAndFingerprint(release.Version, release.UpdatedAt)
				Expect(err).NotTo(HaveOccurred())

				Expect(response.Version.ProductVersion).To(Equal(expectedVersion))

				By("Getting updated list of product files")
				updatedProductFiles, err := pivnetClient.ProductFiles(productSlug)
				Expect(err).NotTo(HaveOccurred())

				By("Verifying number of product files has increased by the expected amount")
				newProductFileCount := len(updatedProductFiles) - len(existingProductFiles)
				Expect(newProductFileCount).To(Equal(totalFiles))

				By("Verifying updated product files contains new files")
				var newProductFiles []pivnet.ProductFile
				for _, p := range updatedProductFiles {
		})
	})

	Describe("CombineVersionAndFingerprint", func() {
		var (
			version     string
			fingerprint string
		)

		BeforeEach(func() {
			version = "some.version"
			fingerprint = "my-fingerprint"
		})

		It("combines without error", func() {
			versionWithFingerprint, err := versions.CombineVersionAndFingerprint(version, fingerprint)

			Expect(err).NotTo(HaveOccurred())
			Expect(versionWithFingerprint).To(Equal("some.version#my-fingerprint"))
		})

		Context("when the fingerprint is empty", func() {
			BeforeEach(func() {
				fingerprint = ""
			})

			It("does not include the #", func() {
				versionWithFingerprint, err := versions.CombineVersionAndFingerprint(version, fingerprint)

				Expect(err).NotTo(HaveOccurred())
				Expect(versionWithFingerprint).To(Equal("some.version"))
		command         *exec.Cmd
		checkRequest    concourse.CheckRequest
		stdinContents   []byte
	)

	BeforeEach(func() {
		By("Getting expected releases")
		allReleases, err := pivnetClient.ReleasesForProductSlug(productSlug)
		Expect(err).NotTo(HaveOccurred())

		releases := allReleases[:4]

		By("Getting release versions")
		releaseVersions = make([]string, len(releases))
		for i, r := range releases {
			releaseVersion, err := versions.CombineVersionAndFingerprint(r.Version, r.UpdatedAt)
			Expect(err).NotTo(HaveOccurred())

			releaseVersions[i] = releaseVersion
		}

		By("Creating command object")
		command = exec.Command(checkPath)

		By("Creating default request")
		checkRequest = concourse.CheckRequest{
			Source: concourse.Source{
				APIToken:    pivnetAPIToken,
				ProductSlug: productSlug,
				Endpoint:    endpoint,
			},