PowerShell script to build and pacakge Go application for release












0












$begingroup$


Background



I decided to write this PowerShell build script as a gentle introduction to PS. It builds this Go application, which is an internal tool I decided to open source, and not the focus of this review.



This script is used primarily for packaging artifacts for release.



My approach



The script below gets, vets and builds a small Go application and then invokes a separate command-line tool to add Windows rsrc metadata such as version strings and icons.



Since the version number is mandatory for the packaging process, I validated it using param() rules rather than if statements. It validates against a regex for semver.



I then execute every packing step, check for its return status, and present a graceful message in addition to the error output by the build step.



The packager relies on having rcedit-x64.exe available in the PATH. I originally allowed specifying a path to the executable as a command-line flag, but it seemed to make the code messier for nothing, so I just removed it. The tool is primarily for myself.



Example



Invocation



powershell.exe -ExecutionPolicy Unrestricted .build.ps1 -version 1.1.0


Output



Packing bittray version 1.1.0
Cleaning old build products.
go get...
go vet...
go build...
Validating artifact...
Applying rsrc metadata...
Compressing archive (bittray-1.1.0.zip)...
SHA1 hash of bittray-1.1.0.zip:
cd283afd10f613919bb4dc694bce3c1f9bd23483
CertUtil: -hashfile command completed successfully.
Done!


Concerns




  1. Does the code follow PS idioms?

  2. Is there a more elegant way to check for the success of commands and bail than repeating if (!$?) all the time?

  3. To wit, is the single trap appropriate?

  4. Is the code adequately defensive? Overly defensive?

  5. I cannot sign my script as I don't have a code signing certificate. Is my invocation correct and safe?

  6. Is there a shorter invocation available without altering the system-side Execution Policy?

  7. Because of the validator on -version, you need to provide a valid version to be able to run just -clean. Any way around that (like providing some order of precedence of param()s, or short-cutting)? I really like those top-level validators, and would prefer to keep them in favor of if statements, if possible.


Code



param(
[string]
[Parameter(Mandatory = $True)]
[ValidateNotNullorEmpty()]
[ValidatePattern('^([0-9]|[1-9][0-9]*).([0-9]|[1-9][0-9]*).([0-9]|[1-9][0-9]*)(?:-([0-9A-Za-z-]+(?:.[0-9A-Za-z-]+)*))?(?:+[0-9A-Za-z-]+)?$')]
$version,

[switch]
$clean
)

function Clean-Artifacts
{
Write-Host "Cleaning old build products."
Remove-Item * -Include bittray.exe, bittray-*.zip
if (!$?)
{
Write-Host -BackgroundColor red -ForegroundColor white "Failed to remove existing artifacts; see above."
exit 1
}
}

if ($clean -eq $True)
{
Clean-Artifacts
exit 0
}

if ((Get-Command "rcedit-x64.exe" -ErrorAction SilentlyContinue) -eq $null)
{
Write-Host -ForegroundColor red "Unable to find rcedit-x64.exe in your PATH."
exit 1
}

Write-Host "Packing bittray version $version" -ForegroundColor green

Clean-Artifacts

Write-Host "go get..."
go get

Write-Host "go vet..."
go vet ./...
if (!$?)
{
Write-Host -BackgroundColor red -ForegroundColor white "'go vet' failed; see above."
exit 1
}

Write-Host "go build..."
go build -ldflags -H=windowsgui bittray.go
if (!$?)
{
Write-Host -BackgroundColor red -ForegroundColor white "'go build' failed; see above."
exit 1
}

Write-Host "Validating artifact..."
if ( [System.IO.File]::Exists("bittray.exe"))
{
Write-Host "Applying rsrc metadata..."
trap
{
"Error adding resource metadata: $_"
}

rcedit-x64.exe --set-icon .bitbucket.ico "bittray.exe"
rcedit-x64.exe "bittray.exe" --set-version-string "ProductName" "Bittray"
rcedit-x64.exe "bittray.exe" --set-version-string "ProductVersion" "$version"
}
else
{
Write-Host -BackgroundColor red -ForegroundColor white "'go build' claims to have succeeded, but there is no artifact?"
exit 1
}

$package = "bittray-$version.zip"
Write-Host "Compressing archive ($package)..."
Compress-Archive -Path .bittray.exe -CompressionLevel Optimal -DestinationPath $package
if (!$?)
{
Write-Host -BackgroundColor red -ForegroundColor white "Failed to create zip package."
exit 1
}

certUtil -hashfile "$package" sha1
if (!$?)
{
Write-Host -BackgroundColor red -ForegroundColor white "Failed to generate SHA1 integrity checksum."
exit 1
}
else
{
Write-Host -BackgroundColor green -ForegroundColor white "Done!"
}









share|improve this question









$endgroup$

















    0












    $begingroup$


    Background



    I decided to write this PowerShell build script as a gentle introduction to PS. It builds this Go application, which is an internal tool I decided to open source, and not the focus of this review.



    This script is used primarily for packaging artifacts for release.



    My approach



    The script below gets, vets and builds a small Go application and then invokes a separate command-line tool to add Windows rsrc metadata such as version strings and icons.



    Since the version number is mandatory for the packaging process, I validated it using param() rules rather than if statements. It validates against a regex for semver.



    I then execute every packing step, check for its return status, and present a graceful message in addition to the error output by the build step.



    The packager relies on having rcedit-x64.exe available in the PATH. I originally allowed specifying a path to the executable as a command-line flag, but it seemed to make the code messier for nothing, so I just removed it. The tool is primarily for myself.



    Example



    Invocation



    powershell.exe -ExecutionPolicy Unrestricted .build.ps1 -version 1.1.0


    Output



    Packing bittray version 1.1.0
    Cleaning old build products.
    go get...
    go vet...
    go build...
    Validating artifact...
    Applying rsrc metadata...
    Compressing archive (bittray-1.1.0.zip)...
    SHA1 hash of bittray-1.1.0.zip:
    cd283afd10f613919bb4dc694bce3c1f9bd23483
    CertUtil: -hashfile command completed successfully.
    Done!


    Concerns




    1. Does the code follow PS idioms?

    2. Is there a more elegant way to check for the success of commands and bail than repeating if (!$?) all the time?

    3. To wit, is the single trap appropriate?

    4. Is the code adequately defensive? Overly defensive?

    5. I cannot sign my script as I don't have a code signing certificate. Is my invocation correct and safe?

    6. Is there a shorter invocation available without altering the system-side Execution Policy?

    7. Because of the validator on -version, you need to provide a valid version to be able to run just -clean. Any way around that (like providing some order of precedence of param()s, or short-cutting)? I really like those top-level validators, and would prefer to keep them in favor of if statements, if possible.


    Code



    param(
    [string]
    [Parameter(Mandatory = $True)]
    [ValidateNotNullorEmpty()]
    [ValidatePattern('^([0-9]|[1-9][0-9]*).([0-9]|[1-9][0-9]*).([0-9]|[1-9][0-9]*)(?:-([0-9A-Za-z-]+(?:.[0-9A-Za-z-]+)*))?(?:+[0-9A-Za-z-]+)?$')]
    $version,

    [switch]
    $clean
    )

    function Clean-Artifacts
    {
    Write-Host "Cleaning old build products."
    Remove-Item * -Include bittray.exe, bittray-*.zip
    if (!$?)
    {
    Write-Host -BackgroundColor red -ForegroundColor white "Failed to remove existing artifacts; see above."
    exit 1
    }
    }

    if ($clean -eq $True)
    {
    Clean-Artifacts
    exit 0
    }

    if ((Get-Command "rcedit-x64.exe" -ErrorAction SilentlyContinue) -eq $null)
    {
    Write-Host -ForegroundColor red "Unable to find rcedit-x64.exe in your PATH."
    exit 1
    }

    Write-Host "Packing bittray version $version" -ForegroundColor green

    Clean-Artifacts

    Write-Host "go get..."
    go get

    Write-Host "go vet..."
    go vet ./...
    if (!$?)
    {
    Write-Host -BackgroundColor red -ForegroundColor white "'go vet' failed; see above."
    exit 1
    }

    Write-Host "go build..."
    go build -ldflags -H=windowsgui bittray.go
    if (!$?)
    {
    Write-Host -BackgroundColor red -ForegroundColor white "'go build' failed; see above."
    exit 1
    }

    Write-Host "Validating artifact..."
    if ( [System.IO.File]::Exists("bittray.exe"))
    {
    Write-Host "Applying rsrc metadata..."
    trap
    {
    "Error adding resource metadata: $_"
    }

    rcedit-x64.exe --set-icon .bitbucket.ico "bittray.exe"
    rcedit-x64.exe "bittray.exe" --set-version-string "ProductName" "Bittray"
    rcedit-x64.exe "bittray.exe" --set-version-string "ProductVersion" "$version"
    }
    else
    {
    Write-Host -BackgroundColor red -ForegroundColor white "'go build' claims to have succeeded, but there is no artifact?"
    exit 1
    }

    $package = "bittray-$version.zip"
    Write-Host "Compressing archive ($package)..."
    Compress-Archive -Path .bittray.exe -CompressionLevel Optimal -DestinationPath $package
    if (!$?)
    {
    Write-Host -BackgroundColor red -ForegroundColor white "Failed to create zip package."
    exit 1
    }

    certUtil -hashfile "$package" sha1
    if (!$?)
    {
    Write-Host -BackgroundColor red -ForegroundColor white "Failed to generate SHA1 integrity checksum."
    exit 1
    }
    else
    {
    Write-Host -BackgroundColor green -ForegroundColor white "Done!"
    }









    share|improve this question









    $endgroup$















      0












      0








      0





      $begingroup$


      Background



      I decided to write this PowerShell build script as a gentle introduction to PS. It builds this Go application, which is an internal tool I decided to open source, and not the focus of this review.



      This script is used primarily for packaging artifacts for release.



      My approach



      The script below gets, vets and builds a small Go application and then invokes a separate command-line tool to add Windows rsrc metadata such as version strings and icons.



      Since the version number is mandatory for the packaging process, I validated it using param() rules rather than if statements. It validates against a regex for semver.



      I then execute every packing step, check for its return status, and present a graceful message in addition to the error output by the build step.



      The packager relies on having rcedit-x64.exe available in the PATH. I originally allowed specifying a path to the executable as a command-line flag, but it seemed to make the code messier for nothing, so I just removed it. The tool is primarily for myself.



      Example



      Invocation



      powershell.exe -ExecutionPolicy Unrestricted .build.ps1 -version 1.1.0


      Output



      Packing bittray version 1.1.0
      Cleaning old build products.
      go get...
      go vet...
      go build...
      Validating artifact...
      Applying rsrc metadata...
      Compressing archive (bittray-1.1.0.zip)...
      SHA1 hash of bittray-1.1.0.zip:
      cd283afd10f613919bb4dc694bce3c1f9bd23483
      CertUtil: -hashfile command completed successfully.
      Done!


      Concerns




      1. Does the code follow PS idioms?

      2. Is there a more elegant way to check for the success of commands and bail than repeating if (!$?) all the time?

      3. To wit, is the single trap appropriate?

      4. Is the code adequately defensive? Overly defensive?

      5. I cannot sign my script as I don't have a code signing certificate. Is my invocation correct and safe?

      6. Is there a shorter invocation available without altering the system-side Execution Policy?

      7. Because of the validator on -version, you need to provide a valid version to be able to run just -clean. Any way around that (like providing some order of precedence of param()s, or short-cutting)? I really like those top-level validators, and would prefer to keep them in favor of if statements, if possible.


      Code



      param(
      [string]
      [Parameter(Mandatory = $True)]
      [ValidateNotNullorEmpty()]
      [ValidatePattern('^([0-9]|[1-9][0-9]*).([0-9]|[1-9][0-9]*).([0-9]|[1-9][0-9]*)(?:-([0-9A-Za-z-]+(?:.[0-9A-Za-z-]+)*))?(?:+[0-9A-Za-z-]+)?$')]
      $version,

      [switch]
      $clean
      )

      function Clean-Artifacts
      {
      Write-Host "Cleaning old build products."
      Remove-Item * -Include bittray.exe, bittray-*.zip
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "Failed to remove existing artifacts; see above."
      exit 1
      }
      }

      if ($clean -eq $True)
      {
      Clean-Artifacts
      exit 0
      }

      if ((Get-Command "rcedit-x64.exe" -ErrorAction SilentlyContinue) -eq $null)
      {
      Write-Host -ForegroundColor red "Unable to find rcedit-x64.exe in your PATH."
      exit 1
      }

      Write-Host "Packing bittray version $version" -ForegroundColor green

      Clean-Artifacts

      Write-Host "go get..."
      go get

      Write-Host "go vet..."
      go vet ./...
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "'go vet' failed; see above."
      exit 1
      }

      Write-Host "go build..."
      go build -ldflags -H=windowsgui bittray.go
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "'go build' failed; see above."
      exit 1
      }

      Write-Host "Validating artifact..."
      if ( [System.IO.File]::Exists("bittray.exe"))
      {
      Write-Host "Applying rsrc metadata..."
      trap
      {
      "Error adding resource metadata: $_"
      }

      rcedit-x64.exe --set-icon .bitbucket.ico "bittray.exe"
      rcedit-x64.exe "bittray.exe" --set-version-string "ProductName" "Bittray"
      rcedit-x64.exe "bittray.exe" --set-version-string "ProductVersion" "$version"
      }
      else
      {
      Write-Host -BackgroundColor red -ForegroundColor white "'go build' claims to have succeeded, but there is no artifact?"
      exit 1
      }

      $package = "bittray-$version.zip"
      Write-Host "Compressing archive ($package)..."
      Compress-Archive -Path .bittray.exe -CompressionLevel Optimal -DestinationPath $package
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "Failed to create zip package."
      exit 1
      }

      certUtil -hashfile "$package" sha1
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "Failed to generate SHA1 integrity checksum."
      exit 1
      }
      else
      {
      Write-Host -BackgroundColor green -ForegroundColor white "Done!"
      }









      share|improve this question









      $endgroup$




      Background



      I decided to write this PowerShell build script as a gentle introduction to PS. It builds this Go application, which is an internal tool I decided to open source, and not the focus of this review.



      This script is used primarily for packaging artifacts for release.



      My approach



      The script below gets, vets and builds a small Go application and then invokes a separate command-line tool to add Windows rsrc metadata such as version strings and icons.



      Since the version number is mandatory for the packaging process, I validated it using param() rules rather than if statements. It validates against a regex for semver.



      I then execute every packing step, check for its return status, and present a graceful message in addition to the error output by the build step.



      The packager relies on having rcedit-x64.exe available in the PATH. I originally allowed specifying a path to the executable as a command-line flag, but it seemed to make the code messier for nothing, so I just removed it. The tool is primarily for myself.



      Example



      Invocation



      powershell.exe -ExecutionPolicy Unrestricted .build.ps1 -version 1.1.0


      Output



      Packing bittray version 1.1.0
      Cleaning old build products.
      go get...
      go vet...
      go build...
      Validating artifact...
      Applying rsrc metadata...
      Compressing archive (bittray-1.1.0.zip)...
      SHA1 hash of bittray-1.1.0.zip:
      cd283afd10f613919bb4dc694bce3c1f9bd23483
      CertUtil: -hashfile command completed successfully.
      Done!


      Concerns




      1. Does the code follow PS idioms?

      2. Is there a more elegant way to check for the success of commands and bail than repeating if (!$?) all the time?

      3. To wit, is the single trap appropriate?

      4. Is the code adequately defensive? Overly defensive?

      5. I cannot sign my script as I don't have a code signing certificate. Is my invocation correct and safe?

      6. Is there a shorter invocation available without altering the system-side Execution Policy?

      7. Because of the validator on -version, you need to provide a valid version to be able to run just -clean. Any way around that (like providing some order of precedence of param()s, or short-cutting)? I really like those top-level validators, and would prefer to keep them in favor of if statements, if possible.


      Code



      param(
      [string]
      [Parameter(Mandatory = $True)]
      [ValidateNotNullorEmpty()]
      [ValidatePattern('^([0-9]|[1-9][0-9]*).([0-9]|[1-9][0-9]*).([0-9]|[1-9][0-9]*)(?:-([0-9A-Za-z-]+(?:.[0-9A-Za-z-]+)*))?(?:+[0-9A-Za-z-]+)?$')]
      $version,

      [switch]
      $clean
      )

      function Clean-Artifacts
      {
      Write-Host "Cleaning old build products."
      Remove-Item * -Include bittray.exe, bittray-*.zip
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "Failed to remove existing artifacts; see above."
      exit 1
      }
      }

      if ($clean -eq $True)
      {
      Clean-Artifacts
      exit 0
      }

      if ((Get-Command "rcedit-x64.exe" -ErrorAction SilentlyContinue) -eq $null)
      {
      Write-Host -ForegroundColor red "Unable to find rcedit-x64.exe in your PATH."
      exit 1
      }

      Write-Host "Packing bittray version $version" -ForegroundColor green

      Clean-Artifacts

      Write-Host "go get..."
      go get

      Write-Host "go vet..."
      go vet ./...
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "'go vet' failed; see above."
      exit 1
      }

      Write-Host "go build..."
      go build -ldflags -H=windowsgui bittray.go
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "'go build' failed; see above."
      exit 1
      }

      Write-Host "Validating artifact..."
      if ( [System.IO.File]::Exists("bittray.exe"))
      {
      Write-Host "Applying rsrc metadata..."
      trap
      {
      "Error adding resource metadata: $_"
      }

      rcedit-x64.exe --set-icon .bitbucket.ico "bittray.exe"
      rcedit-x64.exe "bittray.exe" --set-version-string "ProductName" "Bittray"
      rcedit-x64.exe "bittray.exe" --set-version-string "ProductVersion" "$version"
      }
      else
      {
      Write-Host -BackgroundColor red -ForegroundColor white "'go build' claims to have succeeded, but there is no artifact?"
      exit 1
      }

      $package = "bittray-$version.zip"
      Write-Host "Compressing archive ($package)..."
      Compress-Archive -Path .bittray.exe -CompressionLevel Optimal -DestinationPath $package
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "Failed to create zip package."
      exit 1
      }

      certUtil -hashfile "$package" sha1
      if (!$?)
      {
      Write-Host -BackgroundColor red -ForegroundColor white "Failed to generate SHA1 integrity checksum."
      exit 1
      }
      else
      {
      Write-Host -BackgroundColor green -ForegroundColor white "Done!"
      }






      windows powershell






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked 25 mins ago









      msanfordmsanford

      2411316




      2411316






















          0






          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f215590%2fpowershell-script-to-build-and-pacakge-go-application-for-release%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f215590%2fpowershell-script-to-build-and-pacakge-go-application-for-release%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          How to make a Squid Proxy server?

          Is this a new Fibonacci Identity?

          19世紀