Exemplo n.º 1
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);
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Posts the new release to GitHub.
        /// </summary>
        /// <param name="repoName">(Required.) Name of the GitHub repository to which the release is to be posted.</param>
        /// <param name="repoOwner">(Required.) GitHub username of a user with push access to the repository to which the release is to be posted.</param>
        /// <param name="userAccessToken">(Required.) GitHub user access token which belongs to the repository owner and that has push access to the repository.</param>
        /// <param name="releaseAssetDir">(Required.) Full path to the directory where the assets for the current release are located.  Must be a path of a folder that currently exists.</param>
        /// <param name="release">(Required.) Reference to an instance of <see cref="T:github_releaser.NewRelease"/></param>
        /// <param name="shouldNotZip">(Optional, default is false). Set to true to upload release assets individually rather than ZIPping the contents of the release asset dir.</param>
        /// that contains the required release information in its properties.
        /// <param name="assetsZipName">Name to give to the zip file of the assets.  Ignored if <see cref="shouldNotZip"/> is set to true.</param>
        /// <returns>True if the post succeeded and all assets got uploaded; false otherwise.</returns>
        /// <remarks>The <see cref="T:github_releaser.NewRelease"/> object is serialized to JSON and then posted to the GitHub Server.  This object is assumed to have valid information.
        /// To validate the information, call the <see cref="M:github_releaser.GitHubReleaeValidator.IsReleaseValid"/> method.</remarks>
        public static bool PostNewRelease(string repoName,
                                          string repoOwner, string userAccessToken, string releaseAssetDir,
                                          NewRelease release, bool shouldNotZip = false, string assetsZipName = "assets.zip")
        {
            Console.WriteLine(Resources.PostingReleaseToWhichRepo, release.name, repoName);

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

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

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

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

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

            if (release == null)
            {
                throw new ArgumentNullException(nameof(release));
            }
            try
            {
                // Form the request body
                var json = release.ToJson();

                if (string.IsNullOrWhiteSpace(json))
                {
                    Console.WriteLine(Resources.FailedToFormatReleaseJson);
                    return(false);
                }

                Console.WriteLine(Resources.SendingPostRequestToCreateRelease, release.name);

                var createReleaseUrl = string.Format(Resources.CreateReleaseApiPostURL, repoOwner, repoName);

                var client  = new RestClient(createReleaseUrl);
                var request = GitHubRequestFactory.PrepareGitHubRequest(Method.POST, userAccessToken);

                request.AddHeader(Resources.AcceptHeaderName, Resources.GitHubApiV3Accept);
                request.AddParameter(Resources.UndefinedParameterName, json, ParameterType.RequestBody);

                var response = client.Execute(request);

                if (response == null || response.StatusCode != HttpStatusCode.Created)
                {
                    Console.WriteLine("ERROR: Failed to post release.");
                    return(false);
                }

                var newRelease = response.Content.FromJson();

                // get the ID of the new release
                Console.WriteLine($"Posted release {newRelease.id} to {newRelease.target_commitish}.");

                Console.WriteLine(Resources.ProcessingReleaseAssets);

                request = GitHubRequestFactory.PrepareGitHubRequest(Method.POST, userAccessToken);

                // process the assets
                // If the user has set shouldNotZip to false, zip up the release assets.
                if (shouldNotZip)
                {
                    AssetUploader.UploadAssetsIndividually(releaseAssetDir, newRelease, userAccessToken);
                }
                else
                {
                    AssetUploader.UploadAssetsZipped(releaseAssetDir, newRelease, userAccessToken, assetsZipName);
                }

                Console.WriteLine(Resources.ReleasePostedToGitHub, newRelease.name);
                return(true);
            }
            catch
            {
                Console.WriteLine(Resources.FailedToPackageReleaseForPosting);
                return(false);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Uploads assets to the release, ZIPping the file tree in the release directory and then uploading the zip.
        /// </summary>
        /// <param name="releaseAssetDir">String containing the fully-qualified path to the directory containing the release's assets.</param>
        /// <param name="newRelease">Reference to an instance of a dynamic object deserialized from the JSON response to the create-new-release action.</param>
        /// <param name="userAccessToken">String containing the user's API access token.</param>
        /// <param name="assetsZipName">Name to call the new zip file of assets.  Default is "assets.zip".</param>
        /// <returns>True if the upload operation succeeded; false otherwise.</returns>
        /// <exception cref="T:System.ArgumentNullException">Thrown if any of the parameters of this method are null references or blank strings.</exception>
        /// <exception cref="T:System.IO.DirectoryNotFoundException">Thrown if the release asset directory cannot be located.</exception>
        public static void UploadAssetsZipped(string releaseAssetDir,
                                              dynamic newRelease, string userAccessToken, string assetsZipName = "assets.zip")
        {
            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));
            }

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

            // Use GUIDs to name the zip and the folder to put it in.
            // make a sub folder under the user's temp folder, and then inside that folder,
            // put the zipped up assets, naming the zip file as the user has specified.
            var outputZipFilePath = $@"{Path.GetTempPath()}\{Guid.NewGuid()}\{assetsZipName}";

            var outputZipFileName = Path.GetFileName(outputZipFilePath);

            if (!ZipperUpper.CompressDirectory(releaseAssetDir, outputZipFilePath))
            {
                Console.WriteLine(Resources.FailedToPackageReleaseForPosting);
                Environment.Exit(Resources.ERROR_FAILED_TO_ZIP_ASSETS);
            }

            /* Determine whether the compression successfully completed.  Stop if it did not. */
            if (!File.Exists(outputZipFilePath))
            {
                Console.WriteLine(Resources.FailedToZipAssets, releaseAssetDir);
                Environment.Exit(Resources.ERROR_FAILED_TO_ZIP_ASSETS);
            }

            /* Determine whether the ZIP file is 2GB or bigger in size.  If it is, then stop.
             *       This is because GitHub API will not accept asset files bigger than 2 GB. */
            if (Convert.ToUInt64(new FileInfo(outputZipFilePath).Length) >= Resources.TwoGigaBytes)
            {
                Console.WriteLine(Resources.ZipFileTooBig, outputZipFilePath);
                Environment.Exit(Resources.ERROR_RELEASE_ASSET_IS_TOO_BIG);
            }

            /* If we are here, then read all the bytes from the file into memory. */
            var fileBytes = File.ReadAllBytes(outputZipFilePath);

            if (!fileBytes.Any())
            {
                Console.WriteLine(Resources.AssetZipProcessResultedInZeroSizePackage);
                Environment.Exit(Resources.ERROR_FAILED_TO_ZIP_ASSETS);
            }

            /* From Tavis.UriTemplates NuGet package -- works like Ruby uri_template gem */
            var uploadUrl = new UriTemplate(newRelease.upload_url.Value)
                            .AddParameters(new
            {
                name  = assetsZipName,
                label = assetsZipName
            })
                            .Resolve();

            if (string.IsNullOrWhiteSpace(uploadUrl))
            {
                Console.WriteLine(Resources.UploadUrlNotObtainable);
                Environment.Exit(Resources.ERROR_NOT_OBTAINED_RELEASE_UPLOAD_URL);
            }

            var client = new RestClient(
                uploadUrl
                );

            var request = GitHubRequestFactory.PrepareGitHubRequest(Method.POST, userAccessToken);

            request.AddHeader(Resources.ContentTypeHeaderName,
                              Resources.ZipFileContentType
                              );

            request.AddParameter(Resources.ZipFileContentType,
                                 fileBytes, ParameterType.RequestBody
                                 );

            var response = client.Execute(request);

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