From 6cf25b0561303d5d83e3141c038d03ecab681b7b Mon Sep 17 00:00:00 2001 From: MaksimZhukov Date: Tue, 9 Jun 2020 22:52:06 +0300 Subject: [PATCH] Implement builders to build Go from source code --- .gitmodules | 4 + CODE_OF_CONDUCT.md | 76 ++++++++++++++++ CONTRIBUTING.md | 52 +++++++++++ LICENSE | 21 +++++ README.md | 15 ++++ SECURITY.md | 3 + azure-pipelines/build-go-packages.yml | 65 ++++++++++++++ azure-pipelines/templates/build-job.yml | 21 +++++ azure-pipelines/templates/test-job.yml | 75 ++++++++++++++++ builders/build-go.ps1 | 71 +++++++++++++++ builders/go-builder.psm1 | 110 ++++++++++++++++++++++++ builders/nix-go-builder.psm1 | 57 ++++++++++++ builders/win-go-builder.psm1 | 64 ++++++++++++++ config/go-manifest-config.json | 7 ++ helpers | 1 + installers/nix-setup-template.sh | 25 ++++++ installers/win-setup-template.ps1 | 35 ++++++++ tests/Go.Tests.ps1 | 74 ++++++++++++++++ tests/source/maps/maps.go | 27 ++++++ tests/source/methods/methods.go | 26 ++++++ tests/source/simple/simple.go | 7 ++ 21 files changed, 836 insertions(+) create mode 100644 .gitmodules create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 SECURITY.md create mode 100644 azure-pipelines/build-go-packages.yml create mode 100644 azure-pipelines/templates/build-job.yml create mode 100644 azure-pipelines/templates/test-job.yml create mode 100644 builders/build-go.ps1 create mode 100644 builders/go-builder.psm1 create mode 100644 builders/nix-go-builder.psm1 create mode 100644 builders/win-go-builder.psm1 create mode 100644 config/go-manifest-config.json create mode 160000 helpers create mode 100644 installers/nix-setup-template.sh create mode 100644 installers/win-setup-template.ps1 create mode 100644 tests/Go.Tests.ps1 create mode 100644 tests/source/maps/maps.go create mode 100644 tests/source/methods/methods.go create mode 100644 tests/source/simple/simple.go diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b343909 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "helpers"] + path = helpers + url = https://github.com/actions/versions-package-tools + branch = master diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..517657b --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at opensource@github.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5b71128 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,52 @@ +## Contributing + +[fork]: https://github.com/actions/go-versions/fork +[pr]: https://github.com/actions/go-versions/compare +[code-of-conduct]: CODE_OF_CONDUCT.md + +Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. + +Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [MIT](LICENSE.md). + +Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. + +## Submitting a pull request + +1. [Fork][fork] and clone the repository +1. Create a new branch: `git checkout -b my-branch-name` +1. Make your changes +1. Push to your fork and [submit a pull request][pr] +1. Make sure that checks in your pull request are green + +Here are a few things you can do that will increase the likelihood of your pull request being accepted: + +- Please include a summary of the change and which issue is fixed. Also include relevant motivation and context. +- Follow the style guide for [PowerShell](https://github.com/PoshCode/PowerShellPracticeAndStyle). +- Write [good commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). + +## Code structure + +### Directory structure +``` + +├── azure-pipelines/ +| └──templates/ +├── builders/ +├── helpers/ +├── installers/ +└── tests/ + └──sources/ +``` +- `azure-pipelines*` - contains global YAML definitions for build pipelines. Reusable templates for specific jobs are located in `templates` subfolder. +- `builders` - contains Go builder classes and functions. +- `helpers` - contains global helper functions and functions. +- `installers` - contains installation script templates. +- `tests` - contains test scripts. Required tests sources are located in `sources` subfolder. + +\* _We use Azure Pipelines because there are a few features that Actions is still missing, we'll move to Actions as soon as possible_. + +## Resources + +- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) +- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) +- [GitHub Help](https://help.github.com) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f42f5ab --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index e69de29..837fef1 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,15 @@ +# Go for Actions +This repository contains the code and scripts that we use to prepare Go packages used in [virtual-environments](https://github.com/actions/virtual-environments) and accessible through the [setup-go](https://github.com/actions/setup-go) Action. +The file [versions-manifest.json](./versions-manifest.json) contains the list of available and released versions. + +> Caution: this is prepared for and only permitted for use by actions `virtual-environments` and `setup-go` action. + +**Status**: Currently under development and in use for beta and preview actions. This repo is undergoing rapid changes. + +Latest of LTS versions will be installed on the [virtual-environments](https://github.com/actions/virtual-environments) images. Other versions will be pulled JIT using the [`setup-go`](https://github.com/actions/setup-go) action. + +## Adding new versions +We are trying to prepare packages for new versions of Go as soon as they are released. Please open an issue if any versions are missing. + +## Contribution +Contributions are welcome! See [Contributor's Guide](./CONTRIBUTING.md) for more details about contribution process and code structure diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..f0b196f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +If you discover a security issue in this repo, please submit it through the [GitHub Security Bug Bounty](https://hackerone.com/github) + +Thanks for helping make GitHub Actions safe for everyone. diff --git a/azure-pipelines/build-go-packages.yml b/azure-pipelines/build-go-packages.yml new file mode 100644 index 0000000..0811820 --- /dev/null +++ b/azure-pipelines/build-go-packages.yml @@ -0,0 +1,65 @@ +name: $(date:yyyyMMdd)$(rev:.r)-Go-$(VERSION) +trigger: none +pr: + autoCancel: true + branches: + include: + - master + paths: + exclude: + - versions-manifest.json + +stages: +- stage: Build_Go_Darwin + dependsOn: [] + variables: + Platform: darwin + Architecture: x64 + jobs: + - template: /azure-pipelines/templates/build-job.yml + +- stage: Test_Go_Darwin + condition: succeeded() + dependsOn: Build_Go_Darwin + variables: + VmImage: macOS-latest + Platform: darwin + Architecture: x64 + jobs: + - template: /azure-pipelines/templates/test-job.yml + +- stage: Build_Go_Linux + dependsOn: [] + variables: + Platform: linux + Architecture: x64 + jobs: + - template: /azure-pipelines/templates/build-job.yml + +- stage: Test_Go_Linux + condition: succeeded() + dependsOn: Build_Go_Linux + variables: + VmImage: ubuntu-latest + Platform: linux + Architecture: x64 + jobs: + - template: /azure-pipelines/templates/test-job.yml + +- stage: Build_Go_Windows + dependsOn: [] + variables: + Platform: win32 + Architecture: x64 + jobs: + - template: /azure-pipelines/templates/build-job.yml + +- stage: Test_Go_Windows + condition: succeeded() + dependsOn: Build_Go_Windows + variables: + VmImage: windows-latest + Platform: win32 + Architecture: x64 + jobs: + - template: /azure-pipelines/templates/test-job.yml \ No newline at end of file diff --git a/azure-pipelines/templates/build-job.yml b/azure-pipelines/templates/build-job.yml new file mode 100644 index 0000000..2d8579b --- /dev/null +++ b/azure-pipelines/templates/build-job.yml @@ -0,0 +1,21 @@ +jobs: +- job: Build_Go + timeoutInMinutes: 90 + pool: + name: Azure Pipelines + vmImage: ubuntu-latest + steps: + - checkout: self + + - task: PowerShell@2 + displayName: 'Build Go $(Version)' + inputs: + targetType: filePath + filePath: './builders/build-go.ps1' + arguments: '-Version $(Version) -Platform $(Platform) -Architecture $(Architecture)' + + - task: PublishPipelineArtifact@1 + displayName: 'Publish Artifact: Go $(Version)' + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)' + artifactName: 'go-$(Version)-$(Platform)-$(Architecture)' \ No newline at end of file diff --git a/azure-pipelines/templates/test-job.yml b/azure-pipelines/templates/test-job.yml new file mode 100644 index 0000000..9174712 --- /dev/null +++ b/azure-pipelines/templates/test-job.yml @@ -0,0 +1,75 @@ +jobs: +- job: Test_Go + pool: + name: Azure Pipelines + vmImage: $(VmImage) + steps: + - checkout: self + submodules: true + + - task: PowerShell@2 + displayName: Fully cleanup the toolcache directory before testing + inputs: + targetType: filePath + filePath: helpers/clean-toolcache.ps1 + arguments: -ToolName "go" + + - task: DownloadPipelineArtifact@2 + inputs: + source: 'current' + artifact: 'go-$(Version)-$(Platform)-$(Architecture)' + path: $(Build.ArtifactStagingDirectory) + + - task: ExtractFiles@1 + inputs: + archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/go-$(Version)-$(Platform)-$(Architecture).*' + destinationFolder: $(Build.BinariesDirectory) + cleanDestinationFolder: false + + - task: PowerShell@2 + displayName: 'Apply build artifact to the local machines' + inputs: + targetType: inline + script: | + if ("$(Platform)" -match 'win32') { powershell ./setup.ps1 } else { sh ./setup.sh } + workingDirectory: '$(Build.BinariesDirectory)' + + - task: GoTool@0 + inputs: + version: '$(Version)' + + - task: PowerShell@2 + displayName: 'Wait for the logs' + inputs: + targetType: inline + script: | + Write-Host "Fake step that do nothing" + Write-Host "We need it because log of previous step 'Use Go' is not available here yet." + Write-Host "In testing step (Go.Tests.ps1) we analyze build log of 'GoTool' task" + Write-Host "to determine if Go version was consumed from cache and was downloaded" + + - task: PowerShell@2 + displayName: 'Run tests' + inputs: + TargetType: inline + script: | + Install-Module Pester -Force -Scope CurrentUser -RequiredVersion 4.10.1 + Import-Module Pester + $pesterParams = @{ + Path="./Go.Tests.ps1"; + Parameters=@{ + Version="$(Version)"; + } + } + Invoke-Pester -Script $pesterParams -OutputFile "$(Build.SourcesDirectory)/tests/test_results.xml" -OutputFormat NUnitXml + workingDirectory: '$(Build.SourcesDirectory)/tests' + + - task: PublishTestResults@2 + displayName: 'Publish test results' + inputs: + testResultsFiles: '*.xml' + testResultsFormat: NUnit + searchFolder: 'tests' + failTaskOnFailedTests: true + testRunTitle: "Go $(Version)-$(Platform)" + condition: always() diff --git a/builders/build-go.ps1 b/builders/build-go.ps1 new file mode 100644 index 0000000..e92f082 --- /dev/null +++ b/builders/build-go.ps1 @@ -0,0 +1,71 @@ +using module "./builders/win-go-builder.psm1" +using module "./builders/nix-go-builder.psm1" + +<# +.SYNOPSIS +Generate Go artifact. + +.DESCRIPTION +Main script that creates instance of GoBuilder and builds of Go using specified parameters. + +.PARAMETER Version +Required parameter. The version with which Go will be built. + +.PARAMETER Architecture +Optional parameter. The architecture with which Go will be built. Using x64 by default. + +.PARAMETER Platform +Required parameter. The platform for which Go will be built. + +#> + +param( + [Parameter (Mandatory=$true)][version] $Version, + [Parameter (Mandatory=$true)][string] $Platform, + [string] $Architecture = "x64" +) + +Import-Module (Join-Path $PSScriptRoot "../helpers" | Join-Path -ChildPath "nix-helpers.psm1") -DisableNameChecking +Import-Module (Join-Path $PSScriptRoot "../helpers" | Join-Path -ChildPath "win-helpers.psm1") -DisableNameChecking + +function Get-GoBuilder { + <# + .SYNOPSIS + Wrapper for class constructor to simplify importing GoBuilder. + + .DESCRIPTION + Create instance of GoBuilder with specified parameters. + + .PARAMETER Version + The version with which Go will be built. + + .PARAMETER Platform + The platform for which Go will be built. + + .PARAMETER Architecture + The architecture with which Go will be built. + + #> + + param ( + [version] $Version, + [string] $Architecture, + [string] $Platform + ) + + $Platform = $Platform.ToLower() + if ($Platform -match 'win32') { + $builder = [WinGoBuilder]::New($Version, $Platform, $Architecture) + } elseif (($Platform -match 'linux') -or ($Platform -match 'darwin')) { + $builder = [NixGoBuilder]::New($Version, $Platform, $Architecture) + } else { + Write-Host "##vso[task.logissue type=error;] Invalid platform: $Platform" + exit 1 + } + + return $builder +} + +### Create Go builder instance, and build artifact +$Builder = Get-GoBuilder -Version $Version -Platform $Platform -Architecture $Architecture +$Builder.Build() diff --git a/builders/go-builder.psm1 b/builders/go-builder.psm1 new file mode 100644 index 0000000..e65cef8 --- /dev/null +++ b/builders/go-builder.psm1 @@ -0,0 +1,110 @@ +class GoBuilder { + <# + .SYNOPSIS + Base Go builder class. + + .DESCRIPTION + Base Go builder class that contains general builder methods. + + .PARAMETER Version + The version of Go that should be built. + + .PARAMETER Platform + The platform of Go that should be built. + + .PARAMETER Architecture + The architecture with which Go should be built. + + .PARAMETER TempFolderLocation + The location of temporary files that will be used during Go package generation. Using system BUILD_STAGINGDIRECTORY variable value. + + .PARAMETER ArtifactLocation + The location of generated Go artifact. Using system environment BUILD_BINARIESDIRECTORY variable value. + + .PARAMETER InstallationTemplatesLocation + The location of installation script template. Using "installers" folder from current repository. + + #> + + [version] $Version + [string] $Platform + [string] $Architecture + [string] $TempFolderLocation + [string] $WorkFolderLocation + [string] $ArtifactFolderLocation + [string] $InstallationTemplatesLocation + + GoBuilder ([version] $version, [string] $platform, [string] $architecture) { + $this.Version = $version + $this.Platform = $platform + $this.Architecture = $architecture + + $this.TempFolderLocation = [IO.Path]::GetTempPath() + $this.WorkFolderLocation = $env:BUILD_BINARIESDIRECTORY + $this.ArtifactFolderLocation = $env:BUILD_STAGINGDIRECTORY + + + $this.InstallationTemplatesLocation = Join-Path -Path $PSScriptRoot -ChildPath "../installers" + } + + [uri] GetBinariesUri() { + <# + .SYNOPSIS + Get base Go URI and return complete URI for Go installation executable. + #> + + $arch = ($this.Architecture -eq "x64") ? "amd64" : $this.Architecture + $goPlatform = ($this.Platform -Match "win32") ? "windows" : $this.Platform + $ArchiveType = ($this.Platform -Match "win32") ? "zip" : "tar.gz" + If ($this.Version.Build -eq "0") { + $goVersion = "go$($this.Version.ToString(2))" + } else { + $goVersion = "go$($this.Version.ToString(3))" + } + + $filename = "$goVersion.$goPlatform-$arch.$ArchiveType" + + return "https://storage.googleapis.com/golang/$filename" + } + + [string] Download() { + <# + .SYNOPSIS + Download Go binaries into artifact location. + #> + + $binariesUri = $this.GetBinariesUri() + $targetFilename = [IO.Path]::GetFileName($binariesUri) + $targetFilepath = Join-Path -Path $this.TempFolderLocation -ChildPath $targetFilename + + Write-Debug "Download binaries from $binariesUri to $targetFilepath" + try { + (New-Object System.Net.WebClient).DownloadFile($binariesUri, $targetFilepath) + } catch { + Write-Host "Error during downloading file from '$binariesUri'" + exit 1 + } + + Write-Debug "Done; Binaries location: $targetFilepath" + return $targetFilepath + } + + [void] Build() { + <# + .SYNOPSIS + Generates Go artifact from downloaded binaries. + #> + + Write-Host "Download Go $($this.Version) [$($this.Architecture)] executable..." + $binariesArchivePath = $this.Download() + + Write-Host "Unpack binaries to target directory" + $this.ExtractBinaries($binariesArchivePath) + + Write-Host "Create installation script..." + $this.CreateInstallationScript() + + Write-Host "Archive artifact" + $this.ArchiveArtifact() + } +} diff --git a/builders/nix-go-builder.psm1 b/builders/nix-go-builder.psm1 new file mode 100644 index 0000000..7057d24 --- /dev/null +++ b/builders/nix-go-builder.psm1 @@ -0,0 +1,57 @@ +using module "./builders/go-builder.psm1" + +class NixGoBuilder : GoBuilder { + <# + .SYNOPSIS + Ubuntu Go builder class. + + .DESCRIPTION + Contains methods that required to build Ubuntu Go artifact from sources. Inherited from base NixGoBuilder. + + .PARAMETER platform + The full name of platform for which Go should be built. + + .PARAMETER version + The version of Go that should be built. + + #> + + [string] $InstallationTemplateName + [string] $InstallationScriptName + [string] $OutputArtifactName + + NixGoBuilder( + [version] $version, + [string] $platform, + [string] $architecture + ) : Base($version, $platform, $architecture) { + $this.InstallationTemplateName = "nix-setup-template.sh" + $this.InstallationScriptName = "setup.sh" + $this.OutputArtifactName = "go-$Version-$Platform-$Architecture.tar.gz" + } + + [void] ExtractBinaries($archivePath) { + Extract-TarArchive -ArchivePath $archivePath -OutputDirectory $this.WorkFolderLocation + } + + [void] CreateInstallationScript() { + <# + .SYNOPSIS + Create Go artifact installation script based on template specified in InstallationTemplateName property. + #> + + $installationScriptLocation = New-Item -Path $this.WorkFolderLocation -Name $this.InstallationScriptName -ItemType File + $installationTemplateLocation = Join-Path -Path $this.InstallationTemplatesLocation -ChildPath $this.InstallationTemplateName + + $installationTemplateContent = Get-Content -Path $installationTemplateLocation -Raw + $installationTemplateContent = $installationTemplateContent -f $this.Version.ToString(3) + $installationTemplateContent | Out-File -FilePath $installationScriptLocation + + Write-Debug "Done; Installation script location: $installationScriptLocation)" + } + + [void] ArchiveArtifact() { + $OutputPath = Join-Path $this.ArtifactFolderLocation $this.OutputArtifactName + Create-TarArchive -SourceFolder $this.WorkFolderLocation -ArchivePath $OutputPath + } +} diff --git a/builders/win-go-builder.psm1 b/builders/win-go-builder.psm1 new file mode 100644 index 0000000..a861677 --- /dev/null +++ b/builders/win-go-builder.psm1 @@ -0,0 +1,64 @@ +using module "./builders/go-builder.psm1" + +class WinGoBuilder : GoBuilder { + <# + .SYNOPSIS + Ubuntu Go builder class. + + .DESCRIPTION + Contains methods that required to build Ubuntu Go artifact from sources. Inherited from base NixGoBuilder. + + .PARAMETER platform + The full name of platform for which Go should be built. + + .PARAMETER version + The version of Go that should be built. + + #> + + [string] $InstallationTemplateName + [string] $InstallationScriptName + [string] $OutputArtifactName + + WinGoBuilder( + [version] $version, + [string] $platform, + [string] $architecture + ) : Base($version, $platform, $architecture) { + $this.InstallationTemplateName = "win-setup-template.ps1" + $this.InstallationScriptName = "setup.ps1" + $this.OutputArtifactName = "go-$Version-$Platform-$Architecture.zip" + } + + [void] ExtractBinaries($archivePath) { + $extractTargetDirectory = Join-Path $this.TempFolderLocation "tempExtract" + Extract-SevenZipArchive -ArchivePath $archivePath -OutputDirectory $extractTargetDirectory + $goOutputPath = Get-Item $extractTargetDirectory\* | Select-Object -First 1 -ExpandProperty Fullname + Move-Item -Path $goOutputPath\* -Destination $this.WorkFolderLocation + } + + [void] CreateInstallationScript() { + <# + .SYNOPSIS + Create Go artifact installation script based on specified template. + #> + + $installationScriptLocation = New-Item -Path $this.WorkFolderLocation -Name $this.InstallationScriptName -ItemType File + $installationTemplateLocation = Join-Path -Path $this.InstallationTemplatesLocation -ChildPath $this.InstallationTemplateName + $installationTemplateContent = Get-Content -Path $installationTemplateLocation -Raw + + $variablesToReplace = @{ + "{{__VERSION__}}" = $this.Version; + "{{__ARCHITECTURE__}}" = $this.Architecture; + } + + $variablesToReplace.keys | ForEach-Object { $installationTemplateContent = $installationTemplateContent.Replace($_, $variablesToReplace[$_]) } + $installationTemplateContent | Out-File -FilePath $installationScriptLocation + Write-Debug "Done; Installation script location: $installationScriptLocation)" + } + + [void] ArchiveArtifact() { + $OutputPath = Join-Path $this.ArtifactFolderLocation $this.OutputArtifactName + Create-SevenZipArchive -SourceFolder $this.WorkFolderLocation -ArchivePath $OutputPath -ArchiveType "zip" + } +} diff --git a/config/go-manifest-config.json b/config/go-manifest-config.json new file mode 100644 index 0000000..d766d1b --- /dev/null +++ b/config/go-manifest-config.json @@ -0,0 +1,7 @@ +{ + "regex": "go-\\d+\\.\\d+\\.\\d+-(\\w+)-(x\\d+)", + "groups": { + "arch": 2, + "platform": 1 + } +} \ No newline at end of file diff --git a/helpers b/helpers new file mode 160000 index 0000000..350e288 --- /dev/null +++ b/helpers @@ -0,0 +1 @@ +Subproject commit 350e2888aa8ba786f16e7e37479c41551326d25c diff --git a/installers/nix-setup-template.sh b/installers/nix-setup-template.sh new file mode 100644 index 0000000..8d210df --- /dev/null +++ b/installers/nix-setup-template.sh @@ -0,0 +1,25 @@ +set -e + +GO_VERSION={0} + +GO_TOOLCACHE_PATH=$AGENT_TOOLSDIRECTORY/go +GO_TOOLCACHE_VERSION_PATH=$GO_TOOLCACHE_PATH/$GO_VERSION +GO_TOOLCACHE_VERSION_ARCH_PATH=$GO_TOOLCACHE_VERSION_PATH/x64 + +echo "Check if Go hostedtoolcache folder exist..." +if [ ! -d $GO_TOOLCACHE_PATH ]; then + mkdir -p $GO_TOOLCACHE_PATH +fi + +echo "Delete Go $GO_VERSION if installed" +rm -rf $GO_TOOLCACHE_VERSION_PATH + +echo "Create Go $GO_VERSION folder" +mkdir -p $GO_TOOLCACHE_VERSION_ARCH_PATH + +echo "Copy Go binaries to hostedtoolcache folder" +cp -R ./* $GO_TOOLCACHE_VERSION_ARCH_PATH +rm $GO_TOOLCACHE_VERSION_ARCH_PATH/setup.sh + +echo "Create complete file" +touch $GO_TOOLCACHE_VERSION_PATH/x64.complete diff --git a/installers/win-setup-template.ps1 b/installers/win-setup-template.ps1 new file mode 100644 index 0000000..1214fc2 --- /dev/null +++ b/installers/win-setup-template.ps1 @@ -0,0 +1,35 @@ +$ErrorActionPreference = "Stop" + +[version]$Version = "{{__VERSION__}}" +[string]$Architecture = "{{__ARCHITECTURE__}}" + +$ToolcacheRoot = $env:AGENT_TOOLSDIRECTORY +if ([string]::IsNullOrEmpty($ToolcacheRoot)) { + # GitHub images don't have `AGENT_TOOLSDIRECTORY` variable + $ToolcacheRoot = $env:RUNNER_TOOL_CACHE +} +$GoToolcachePath = Join-Path -Path $ToolcacheRoot -ChildPath "go" +$GoToolcacheVersionPath = Join-Path -Path $GoToolcachePath -ChildPath $Version.ToString() +$GoToolcacheArchitecturePath = Join-Path $GoToolcacheVersionPath $Architecture + +Write-Host "Check if Go hostedtoolcache folder exist..." +if (-not (Test-Path $GoToolcachePath)) { + New-Item -ItemType Directory -Path $GoToolcachePath | Out-Null +} + +Write-Host "Delete Go $Version if installed" +if (Test-Path $GoToolcacheVersionPath) { + Remove-Item $GoToolcachePath -Recurse -Force | Out-Null +} + +Write-Host "Create Go $Version folder" +if (-not (Test-Path $GoToolcacheArchitecturePath)) { + New-Item -ItemType Directory -Path $GoToolcacheArchitecturePath | Out-Null +} + +Write-Host "Copy Go binaries to hostedtoolcache folder" +Copy-Item -Path * -Destination $GoToolcacheArchitecturePath -Recurse +Remove-Item $GoToolcacheArchitecturePath\setup.ps1 -Force | Out-Null + +Write-Host "Create complete file" +New-Item -ItemType File -Path $GoToolcacheVersionPath -Name "$Architecture.complete" | Out-Null \ No newline at end of file diff --git a/tests/Go.Tests.ps1 b/tests/Go.Tests.ps1 new file mode 100644 index 0000000..705e7f1 --- /dev/null +++ b/tests/Go.Tests.ps1 @@ -0,0 +1,74 @@ +param ( + [version] [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] + $Version +) + +Import-Module (Join-Path $PSScriptRoot "../helpers/pester-extensions.psm1") +Import-Module (Join-Path $PSScriptRoot "../helpers/common-helpers.psm1") + +function Get-UseGoLogs { + $logsFolderPath = Join-Path -Path $env:AGENT_HOMEDIRECTORY -ChildPath "_diag" | Join-Path -ChildPath "pages" + + $useGoLogFile = Get-ChildItem -Path $logsFolderPath | Where-Object { + $logContent = Get-Content $_.Fullname -Raw + return $logContent -match "GoTool" + } | Select-Object -First 1 + return $useGoLogFile.Fullname +} + +Describe "Go" { + It "is available" { + "go version" | Should -ReturnZeroExitCode + } + + It "version is correct" { + $versionOutput = Invoke-Expression -Command "go version" + $finalVersion = $Version.ToString(3) + If ($Version.Build -eq "0"){ + $finalVersion = $Version.ToString(2) + } + $versionOutput | Should -Match $finalVersion + } + + It "is used from tool-cache" { + $goPath = (Get-Command "go").Path + $goPath | Should -Not -BeNullOrEmpty + $expectedPath = Join-Path -Path $env:AGENT_TOOLSDIRECTORY -ChildPath "go" + $goPath.startsWith($expectedPath) | Should -BeTrue -Because "'$goPath' is not started with '$expectedPath'" + } + + It "cached version is used without downloading" { + # Analyze output of previous steps to check if Go was consumed from cache or downloaded + $useGoLogFile = Get-UseGoLogs + $useGoLogFile | Should -Exist + $useGoLogContent = Get-Content $useGoLogFile -Raw + $useGoLogContent | Should -Match "Found tool in cache" + } + + Set-Location -Path "source" + $sourceLocation = Get-Location + + It "Run simple code" { + $simpleLocation = Join-Path -Path $sourceLocation -ChildPath "simple" + Set-Location -Path $simpleLocation + "go run simple.go" | Should -ReturnZeroExitCode + "go build simple.go" | Should -ReturnZeroExitCode + "./simple" | Should -ReturnZeroExitCode + } + + It "Run maps code" { + $mapsLocation = Join-Path -Path $sourceLocation -ChildPath "maps" + Set-Location -Path $mapsLocation + "go run maps.go" | Should -ReturnZeroExitCode + "go build maps.go" | Should -ReturnZeroExitCode + "./maps" | Should -ReturnZeroExitCode + } + + It "Run methods code" { + $methodsLocation = Join-Path -Path $sourceLocation -ChildPath "methods" + Set-Location -Path $methodsLocation + "go run methods.go" | Should -ReturnZeroExitCode + "go build methods.go" | Should -ReturnZeroExitCode + "./methods" | Should -ReturnZeroExitCode + } +} \ No newline at end of file diff --git a/tests/source/maps/maps.go b/tests/source/maps/maps.go new file mode 100644 index 0000000..daf39ce --- /dev/null +++ b/tests/source/maps/maps.go @@ -0,0 +1,27 @@ +package main + +import "fmt" + +func main() { + + m := make(map[string]int) + + m["k1"] = 7 + m["k2"] = 13 + + fmt.Println("map:", m) + + v1 := m["k1"] + fmt.Println("v1: ", v1) + + fmt.Println("len:", len(m)) + + delete(m, "k2") + fmt.Println("map:", m) + + _, prs := m["k2"] + fmt.Println("prs:", prs) + + n := map[string]int{"foo": 1, "bar": 2} + fmt.Println("map:", n) +} \ No newline at end of file diff --git a/tests/source/methods/methods.go b/tests/source/methods/methods.go new file mode 100644 index 0000000..8aaff98 --- /dev/null +++ b/tests/source/methods/methods.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +type rect struct { + width, height int +} + +func (r *rect) area() int { + return r.width * r.height +} + +func (r rect) perim() int { + return 2*r.width + 2*r.height +} + +func main() { + r := rect{width: 10, height: 5} + + fmt.Println("area: ", r.area()) + fmt.Println("perim:", r.perim()) + + rp := &r + fmt.Println("area: ", rp.area()) + fmt.Println("perim:", rp.perim()) +} \ No newline at end of file diff --git a/tests/source/simple/simple.go b/tests/source/simple/simple.go new file mode 100644 index 0000000..039314f --- /dev/null +++ b/tests/source/simple/simple.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("Hello, world.") +} \ No newline at end of file