/// <summary>
        /// Validates the release specified.
        /// </summary>
        /// <param name="release">Reference to an instance of <see cref="github_release_poster.NewRelease"/>
        /// that contains the metadata for the release.</param>
        /// <param name="repoName">String containing the name of the repository to which this release is to be published.</param>
        /// <param name="repoOwner">String containing the GitHub username of the owner of the repository.</param>
        /// <param name="userAcessToken">String containing the user access token of a GitHub user with push access to the repository.</param>
        /// <param name="releaseAssetDir">String containing the path to the directory where release assets are stored.</param>
        /// <returns>True if the release is valid; false otherwise.  Terminates the program with a nonzero exit code if the
        /// release does not pass validation.</returns>
        /// <exception cref="T:System.ArgumentNullException">Thrown if the <see cref="release"/> argument is a null
        /// reference of if any of the string arguments are blank.</exception>
        public static bool IsReleaseValid(NewRelease release,
                                          string repoName, string repoOwner, string userAcessToken,
                                          string releaseAssetDir)
        {
            Console.WriteLine(Resources.ValidatingReleaseMetadata);

            // reject a null reference to the release object itself
            if (release == null)
            {
                throw new ArgumentNullException(nameof(release));
            }

            if (string.IsNullOrWhiteSpace(release.tag_name))
            {
                throw new ArgumentNullException(nameof(release.tag_name));
            }

            if (string.IsNullOrWhiteSpace(release.name))
            {
                throw new ArgumentNullException(nameof(release.name));
            }

            if (string.IsNullOrWhiteSpace(release.target_commitish))
            {
                throw new ArgumentNullException(nameof(release.target_commitish));
            }

            if (string.IsNullOrWhiteSpace(repoName))
            {
                throw new ArgumentNullException(nameof(repoName));
            }

            if (string.IsNullOrWhiteSpace(repoOwner))
            {
                throw new ArgumentNullException(nameof(repoOwner));
            }

            if (string.IsNullOrWhiteSpace(userAcessToken))
            {
                throw new ArgumentNullException(nameof(userAcessToken));
            }

            if (string.IsNullOrWhiteSpace(releaseAssetDir))
            {
                throw new ArgumentNullException(nameof(releaseAssetDir));
            }

            /* If the release asset directory does not yet exist, then the build must have failed! LOL.
             * However, let's tell the user just to be sure. */
            if (!Directory.Exists(releaseAssetDir))
            {
                Console.WriteLine(Resources.ReleaseAssetDirNotFound, releaseAssetDir);
                Environment.Exit(exitCode: Resources.ERROR_RELEASE_ASSET_DIR_NOT_EXISTS);
            }

            /* The GitHub release API allows an unlimited number of assets to be posted to a release.  However,
             * it limits the size of any single file to be no more than 2 GB in size.  Scan the release asset dir.
             * If it, or any of its subdirectories (that the current user can access, anyway) contains a file that is
             * 2 GB or more in size, stop this program after displaying an error.*/
            if (FileSearcher.GetAllFilesInFolder(releaseAssetDir)
                .Where(fsi => (fsi.Attributes & FileAttributes.Directory) != FileAttributes.Directory)
                .Any(fsi => Convert.ToUInt64(new FileInfo(fsi.FullName).Length) >= Resources.TwoGigaBytes))
            {
                Console.WriteLine(Resources.ReleaseAssetDirContainsTooBigFile);
                Environment.Exit(Resources.ERROR_RELEASE_ASSET_IS_TOO_BIG);
            }

            Console.WriteLine(Resources.ReleaseAssetsAndMetadataValid);
            return(true);
        }
Пример #2
0
        /// <summary>
        /// Uploads the assets in the release asset directory individually to the newly-created release.   Flattens any directory structure that might exist in the
        /// folder referred to by <see cref="releaseAssetDir"/>.
        /// </summary>
        /// <param name="releaseAssetDir">String containing the fully-qualified path to the directory containing release assets to be uploaded.</param>
        /// <param name="newRelease">Reference to an instance of a dynamic object which has been deserialized from the response JSON
        /// of the call to create the new release.</param>
        /// <param name="userAccessToken">String containing the user's API access token.</param>
        public static void UploadAssetsIndividually(string releaseAssetDir,
                                                    dynamic newRelease, string userAccessToken)
        {
            if (string.IsNullOrWhiteSpace(releaseAssetDir))
            {
                throw new ArgumentNullException(nameof(releaseAssetDir));
            }

            if (!Directory.Exists(releaseAssetDir))
            {
                throw new DirectoryNotFoundException(string.Format(Resources.DirectoryNotFound, releaseAssetDir));
            }

            if (newRelease == null)
            {
                throw new ArgumentNullException(nameof(newRelease));
            }

            if (string.IsNullOrWhiteSpace(userAccessToken))
            {
                throw new ArgumentNullException(nameof(userAccessToken));
            }

            // Iterate over all the files in the release asset directory and its subdirectories,
            // one by one.  Flatten the directory tree into just a big ol' list of files.  To preserve
            // the directory tree, distribute the release assets in ZIP format and then have your
            // Setup program un zip the assets into their directory structure.
            foreach (var assetFile in FileSearcher.GetAllFilesInFolder(
                         releaseAssetDir).Where(fsi => (fsi.Attributes & FileAttributes.Directory)
                                                != FileAttributes.Directory))
            {
                /* Make a new request each iteration of the loop over asset files */
                var request = GitHubRequestFactory.PrepareGitHubRequest(Method.POST, userAccessToken);

                // Get just the name and extension of the asset for use in the
                // upload url later.  If blank is returned, then something went wrong.
                // In that case, just skip the current file.
                var assetFileName = Path.GetFileName(assetFile.FullName);
                if (string.IsNullOrWhiteSpace(assetFileName))
                {
                    continue;
                }

                // If the file has zero bytes of length, do not upload it
                if (FileAndFolderHelper.FileHasZeroLength((FileInfo)assetFile))
                {
                    Console.WriteLine(
                        $"ERROR: File '{assetFileName}' has zero bytes of length.  Not uploading it.");
                    // Just skip files that have zero length
                    continue;
                }

                /* From Tavis.UriTemplates NuGet package -- works like Ruby uri_template gem */
                var uploadUrl = new UriTemplate(newRelease.upload_url.Value)
                                .AddParameters(new
                {
                    name  = assetFileName,
                    label = assetFileName
                })
                                .Resolve();
                if (string.IsNullOrWhiteSpace(uploadUrl))
                {
                    Console.WriteLine(Resources.UploadUrlNotObtainable);
                    Environment.Exit(Resources.ERROR_NOT_OBTAINED_RELEASE_UPLOAD_URL);
                }

                // Prepare a REST request with the upload url from the create release API response
                // above
                var client = new RestClient(
                    uploadUrl
                    );

                var assetMimeMapping = MimeMapping.GetMimeMapping(assetFile.FullName);
                request.AddHeader(Resources.ContentTypeHeaderName,
                                  assetMimeMapping
                                  );

                var bytes = File.ReadAllBytes(assetFile.FullName);
                if (!bytes.Any())
                {
                    continue;   // zero-length file
                }
                request.AddHeader("Content-Length", bytes.Length.ToString());
                Console.WriteLine($"{bytes.Length} bytes read from file '{assetFile.FullName}'. Uploading...");

                request.AddParameter(
                    assetMimeMapping, bytes, ParameterType.RequestBody
                    );

                var response = client.Execute(request);

                if (response == null || response.StatusCode != HttpStatusCode.Created)
                {
                    Console.WriteLine(Resources.FailedToUploadAsset, assetFileName);
                    Environment.Exit(Resources.ERROR_ASSET_NOT_ACCEPTED);
                }
                else
                {
                    Console.WriteLine(Resources.AssetAccepted, assetFileName);
                }
            }
        }