mirror of
https://github.com/actions/runner.git
synced 2025-12-11 12:57:05 +00:00
Compare commits
8 Commits
h10s-assoc
...
users/tihu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eed84f6cf3 | ||
|
|
f994ae0542 | ||
|
|
3c5aef791c | ||
|
|
c4626d0c3a | ||
|
|
416a7ac4b8 | ||
|
|
11435857e4 | ||
|
|
6f260012a3 | ||
|
|
4fc87ddfc6 |
@@ -1,20 +1,14 @@
|
|||||||
## Features
|
## Features
|
||||||
- Sample scripts to automate scalable runners (#427)
|
- N/A
|
||||||
- Raise warning when action input does not match action.yml. (#429)
|
|
||||||
- Add secret masker for trimming double quotes. (#440)
|
|
||||||
- Use the API_URL and munge action URLs for GHES (#437 #469)
|
|
||||||
- Help trace worker crash in Kusto. (#450)
|
|
||||||
- update checkout@v1 for GHES (#470)
|
|
||||||
## Bugs
|
## Bugs
|
||||||
- Print node version in debug instead of output. (#433)
|
- Handle `jq` returns "null" if the field does not exist in create-latest-svc.sh (#478)
|
||||||
- Better error when runner removed from service. (#441)
|
- Switch GITHUB_URL to GITHUB_SERVER_URL (#482)
|
||||||
- Add help info for '--labels' config option (#472)
|
- Fix problem matcher for GHES (#488)
|
||||||
- Sps/token migration fix, job.status/steps.outcome/steps.conclusion case match with GitHub check suites conclusion. (#462)
|
- Fix container action inputs validation warning (#490)
|
||||||
- Docker build using -f instead of implied default (#471)
|
- Fix post step display name (#490)
|
||||||
|
- Fix worker crash due to exception from evaluating step.env (#490)
|
||||||
## Misc
|
## Misc
|
||||||
- Make release notes code blocks copy-paste-able (#430)
|
- N/A
|
||||||
- Fix spelling of RHEL and CentOS. (#436)
|
|
||||||
- Add CodeQL Analysis workflow (#459)
|
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
|
|||||||
193
src/Misc/dotnet-install.ps1
vendored
193
src/Misc/dotnet-install.ps1
vendored
@@ -684,3 +684,196 @@ Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath
|
|||||||
|
|
||||||
Say "Installation finished"
|
Say "Installation finished"
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
|
# SIG # Begin signature block
|
||||||
|
# MIIjkQYJKoZIhvcNAQcCoIIjgjCCI34CAQExDzANBglghkgBZQMEAgEFADB5Bgor
|
||||||
|
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
|
||||||
|
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAwp4UsNdAkvwY3
|
||||||
|
# VhbuN9D6NGOz+qNqW2+62YubWa4qJaCCDYEwggX/MIID56ADAgECAhMzAAABh3IX
|
||||||
|
# chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
|
||||||
|
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
||||||
|
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
|
||||||
|
# bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ3WhcNMjEwMzAzMTgzOTQ3WjB0MQsw
|
||||||
|
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
|
||||||
|
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
|
||||||
|
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
||||||
|
# AQDOt8kLc7P3T7MKIhouYHewMFmnq8Ayu7FOhZCQabVwBp2VS4WyB2Qe4TQBT8aB
|
||||||
|
# znANDEPjHKNdPT8Xz5cNali6XHefS8i/WXtF0vSsP8NEv6mBHuA2p1fw2wB/F0dH
|
||||||
|
# sJ3GfZ5c0sPJjklsiYqPw59xJ54kM91IOgiO2OUzjNAljPibjCWfH7UzQ1TPHc4d
|
||||||
|
# weils8GEIrbBRb7IWwiObL12jWT4Yh71NQgvJ9Fn6+UhD9x2uk3dLj84vwt1NuFQ
|
||||||
|
# itKJxIV0fVsRNR3abQVOLqpDugbr0SzNL6o8xzOHL5OXiGGwg6ekiXA1/2XXY7yV
|
||||||
|
# Fc39tledDtZjSjNbex1zzwSXAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE
|
||||||
|
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhov4ZyO96axkJdMjpzu2zVXOJcsw
|
||||||
|
# UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1
|
||||||
|
# ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDU4Mzg1MB8GA1UdIwQYMBaAFEhu
|
||||||
|
# ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu
|
||||||
|
# bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w
|
||||||
|
# Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3
|
||||||
|
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx
|
||||||
|
# MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAixmy
|
||||||
|
# S6E6vprWD9KFNIB9G5zyMuIjZAOuUJ1EK/Vlg6Fb3ZHXjjUwATKIcXbFuFC6Wr4K
|
||||||
|
# NrU4DY/sBVqmab5AC/je3bpUpjtxpEyqUqtPc30wEg/rO9vmKmqKoLPT37svc2NV
|
||||||
|
# BmGNl+85qO4fV/w7Cx7J0Bbqk19KcRNdjt6eKoTnTPHBHlVHQIHZpMxacbFOAkJr
|
||||||
|
# qAVkYZdz7ikNXTxV+GRb36tC4ByMNxE2DF7vFdvaiZP0CVZ5ByJ2gAhXMdK9+usx
|
||||||
|
# zVk913qKde1OAuWdv+rndqkAIm8fUlRnr4saSCg7cIbUwCCf116wUJ7EuJDg0vHe
|
||||||
|
# yhnCeHnBbyH3RZkHEi2ofmfgnFISJZDdMAeVZGVOh20Jp50XBzqokpPzeZ6zc1/g
|
||||||
|
# yILNyiVgE+RPkjnUQshd1f1PMgn3tns2Cz7bJiVUaqEO3n9qRFgy5JuLae6UweGf
|
||||||
|
# AeOo3dgLZxikKzYs3hDMaEtJq8IP71cX7QXe6lnMmXU/Hdfz2p897Zd+kU+vZvKI
|
||||||
|
# 3cwLfuVQgK2RZ2z+Kc3K3dRPz2rXycK5XCuRZmvGab/WbrZiC7wJQapgBodltMI5
|
||||||
|
# GMdFrBg9IeF7/rP4EqVQXeKtevTlZXjpuNhhjuR+2DMt/dWufjXpiW91bo3aH6Ea
|
||||||
|
# jOALXmoxgltCp1K7hrS6gmsvj94cLRf50QQ4U8Qwggd6MIIFYqADAgECAgphDpDS
|
||||||
|
# AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
|
||||||
|
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
|
||||||
|
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0
|
||||||
|
# ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla
|
||||||
|
# MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
|
||||||
|
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT
|
||||||
|
# H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB
|
||||||
|
# AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG
|
||||||
|
# OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S
|
||||||
|
# 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz
|
||||||
|
# y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7
|
||||||
|
# 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u
|
||||||
|
# M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33
|
||||||
|
# X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl
|
||||||
|
# XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP
|
||||||
|
# 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB
|
||||||
|
# l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF
|
||||||
|
# RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM
|
||||||
|
# CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ
|
||||||
|
# BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud
|
||||||
|
# DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO
|
||||||
|
# 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0
|
||||||
|
# LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
|
||||||
|
# Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p
|
||||||
|
# Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
|
||||||
|
# Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB
|
||||||
|
# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw
|
||||||
|
# cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA
|
||||||
|
# XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY
|
||||||
|
# 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj
|
||||||
|
# 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd
|
||||||
|
# d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ
|
||||||
|
# Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf
|
||||||
|
# wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ
|
||||||
|
# aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j
|
||||||
|
# NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B
|
||||||
|
# xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96
|
||||||
|
# eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7
|
||||||
|
# r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I
|
||||||
|
# RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVZjCCFWICAQEwgZUwfjELMAkG
|
||||||
|
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
|
||||||
|
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z
|
||||||
|
# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN
|
||||||
|
# BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
|
||||||
|
# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQga11B1DE+
|
||||||
|
# y9z0lmEO+MC+bhXPKfWALB7Snkn7G/wCUncwQgYKKwYBBAGCNwIBDDE0MDKgFIAS
|
||||||
|
# AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN
|
||||||
|
# BgkqhkiG9w0BAQEFAASCAQBIgx+sFXkLXf7Xbx7opCD3uhpQGEQ4x/LsqTax0bu1
|
||||||
|
# GC/cxiI+dodUz+T4hKj1ZQyUH0Zlce32GutY048O9tkr7fQyuohoFUgChdIATEOY
|
||||||
|
# qAIESFbDT07i7khJfO2pewlhgM+A5ClvBa8HAvV0wOd+2IVgv3pgow1LEJm0/5NB
|
||||||
|
# E3IFA+hFrqiWALOY0uUep4H20EHMrbqw3YoV3EodIkTj3fC76q4K/bF84EZLUgjY
|
||||||
|
# e4rmXac8n7A9qR18QzGl8usEJej4OHU4nlUT1J734m+AWIFmfb/Zr2MyXED0V4q4
|
||||||
|
# Vbmw3O7xD9STeNYrn5RjPmGPEN04akHxhNUSqLIc9vxQoYIS8DCCEuwGCisGAQQB
|
||||||
|
# gjcDAwExghLcMIIS2AYJKoZIhvcNAQcCoIISyTCCEsUCAQMxDzANBglghkgBZQME
|
||||||
|
# AgEFADCCAVQGCyqGSIb3DQEJEAEEoIIBQwSCAT8wggE7AgEBBgorBgEEAYRZCgMB
|
||||||
|
# MDEwDQYJYIZIAWUDBAIBBQAEIPPK1A0D1n7ZEdgTjKPY4sWiOMtohMqGpFvG55NY
|
||||||
|
# SFHeAgZepuJh/dEYEjIwMjAwNTI5MTYyNzE1LjMxWjAEgAIB9KCB1KSB0TCBzjEL
|
||||||
|
# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
|
||||||
|
# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWlj
|
||||||
|
# cm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBU
|
||||||
|
# U1MgRVNOOjYwQkMtRTM4My0yNjM1MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1T
|
||||||
|
# dGFtcCBTZXJ2aWNloIIORDCCBPUwggPdoAMCAQICEzMAAAEm37pLIrmCggcAAAAA
|
||||||
|
# ASYwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
|
||||||
|
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
|
||||||
|
# b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAw
|
||||||
|
# HhcNMTkxMjE5MDExNDU5WhcNMjEwMzE3MDExNDU5WjCBzjELMAkGA1UEBhMCVVMx
|
||||||
|
# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT
|
||||||
|
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9zb2Z0IE9wZXJh
|
||||||
|
# dGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjYwQkMt
|
||||||
|
# RTM4My0yNjM1MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
|
||||||
|
# MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnjC+hpxO8w2VdBO18X8L
|
||||||
|
# Hk6XdfR9yNQ0y+MuBOY7n5YdgkVunvbk/f6q8UoNFAdYQjVLPSAHbi6tUMiNeMGH
|
||||||
|
# k1U0lUxAkja2W2/szj/ghuFklvfHNBbsuiUShlhRlqcFNS7KXL2iwKDijmOhWJPY
|
||||||
|
# a2bLEr4W/mQLbSXail5p6m138Ttx4MAVEzzuGI0Kwr8ofIL7z6zCeWDiBM57LrNC
|
||||||
|
# qHOA2wboeuMsG4O0Oz2LMAzBLbJZPRPnZAD2HdD4HUL2mzZ8wox74Mekb7RzrUP3
|
||||||
|
# hiHpxXZceJvhIEKfAgVkB5kTZQnio8A1JijMjw8f4TmsJPdJWpi8ei73sexe8/Yj
|
||||||
|
# cwIDAQABo4IBGzCCARcwHQYDVR0OBBYEFEmrrB8XsH6YQo3RWKZfxqM0DmFBMB8G
|
||||||
|
# A1UdIwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeG
|
||||||
|
# RWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Rp
|
||||||
|
# bVN0YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUH
|
||||||
|
# MAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3Rh
|
||||||
|
# UENBXzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYB
|
||||||
|
# BQUHAwgwDQYJKoZIhvcNAQELBQADggEBAECW+51o6W/0J/O/npudfjVzMXq0u0cs
|
||||||
|
# HjqXpdRyH6o03jlmY5MXAui3cmPBKufijJxD2pMRPVMUNh3VA0PQuJeYrP06oFdq
|
||||||
|
# LpLxd3IJARm98vzaMgCz2nCwBDpe9X2M3Js9K1GAX+w4Az8N7J+Z6P1OD0VxHBdq
|
||||||
|
# eTaqDN1lk1vwagTN7t/WitxMXRDz0hRdYiWbATBAVgXXCOfzs3hnEv1n/EDab9HX
|
||||||
|
# OLMXKVY/+alqYKdV9lkuRp8Us1Q1WZy9z72Azu9x4mzft3fJ1puTjBHo5tHfixZo
|
||||||
|
# ummbI+WwjVCrku7pskJahfNi5amSgrqgR6nWAwvpJELccpVLdSxxmG0wggZxMIIE
|
||||||
|
# WaADAgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV
|
||||||
|
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
|
||||||
|
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9v
|
||||||
|
# dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0y
|
||||||
|
# NTA3MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
|
||||||
|
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
|
||||||
|
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjAN
|
||||||
|
# BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RU
|
||||||
|
# ENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBE
|
||||||
|
# D/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50
|
||||||
|
# YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd
|
||||||
|
# /XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaR
|
||||||
|
# togINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQAB
|
||||||
|
# o4IB5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8
|
||||||
|
# RhvFM2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIB
|
||||||
|
# hjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fO
|
||||||
|
# mhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9w
|
||||||
|
# a2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggr
|
||||||
|
# BgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNv
|
||||||
|
# bS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSAB
|
||||||
|
# Af8EgZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3
|
||||||
|
# dy5taWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEF
|
||||||
|
# BQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBt
|
||||||
|
# AGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Eh
|
||||||
|
# b7Prpsz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7
|
||||||
|
# uVOMzPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqR
|
||||||
|
# UgCvOA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9
|
||||||
|
# Va8v/rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8
|
||||||
|
# +n99lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+
|
||||||
|
# Y1klD3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh
|
||||||
|
# 2rBQHm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRy
|
||||||
|
# zR30uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoo
|
||||||
|
# uLGp25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx
|
||||||
|
# 16HSxVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341
|
||||||
|
# Hgi62jbb01+P3nSISRKhggLSMIICOwIBATCB/KGB1KSB0TCBzjELMAkGA1UEBhMC
|
||||||
|
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
|
||||||
|
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9zb2Z0IE9w
|
||||||
|
# ZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjYw
|
||||||
|
# QkMtRTM4My0yNjM1MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2
|
||||||
|
# aWNloiMKAQEwBwYFKw4DAhoDFQAKZzI5aZnESumrToHx3Lqgxnr//KCBgzCBgKR+
|
||||||
|
# MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
|
||||||
|
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT
|
||||||
|
# HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUAAgUA
|
||||||
|
# 4nuQTDAiGA8yMDIwMDUyOTE3NDQ0NFoYDzIwMjAwNTMwMTc0NDQ0WjB3MD0GCisG
|
||||||
|
# AQQBhFkKBAExLzAtMAoCBQDie5BMAgEAMAoCAQACAiZJAgH/MAcCAQACAhEjMAoC
|
||||||
|
# BQDifOHMAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEA
|
||||||
|
# AgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEFBQADgYEAprmyJTXdH9FmQZ0I
|
||||||
|
# mRSJdjc/RrSqDm8DUEq/h3FL73G/xvg9MbQj1J/h3hdlSIPcQXjrhL8hud/vyF0j
|
||||||
|
# IFaTK5YOcixkX++9t7Vz3Mn0KkQo8F4DNSyZEPpz682AyKKwLMJDy52pFFFKNP5l
|
||||||
|
# NpOz6YY1Od1xvk4nyN1WwfLnGswxggMNMIIDCQIBATCBkzB8MQswCQYDVQQGEwJV
|
||||||
|
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
|
||||||
|
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGlt
|
||||||
|
# ZS1TdGFtcCBQQ0EgMjAxMAITMwAAASbfuksiuYKCBwAAAAABJjANBglghkgBZQME
|
||||||
|
# AgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJ
|
||||||
|
# BDEiBCB0IE0Q6P23RQlh8TFyp57UQQUF/sbui7mOMStRgTFZxTCB+gYLKoZIhvcN
|
||||||
|
# AQkQAi8xgeowgecwgeQwgb0EIDb9z++evV5wDO9qk5ZnbEZ8CTOuR+kZyu8xbTsJ
|
||||||
|
# CXUPMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
|
||||||
|
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
|
||||||
|
# bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAEm
|
||||||
|
# 37pLIrmCggcAAAAAASYwIgQgtwi02bvsGAOdpAxEF607G6g9PlyS8vc2bAUSHovH
|
||||||
|
# /IIwDQYJKoZIhvcNAQELBQAEggEAEMCfsXNudrjztjI6JNyNDVpdF1axRVcGiNy6
|
||||||
|
# 67pgb1EePsjA2EaBB+5ZjgO/73JxuiVgsoXgH7em8tKG5RQJtcm5obVDb+jKksK4
|
||||||
|
# qcFLA1f7seQRGfE06UAPnSFh2GqMtTNJGCXWwqWLH2LduTjOqPt8Nupo16ABFIT2
|
||||||
|
# akTzBSJ81EHBkEU0Et6CgeaZiBYrCCXUtD+ASvLDkPSrjweQGu3Zk1SSROEzxMY9
|
||||||
|
# jdlGfMkK2krMd9ub9UZ13RcQDijJqo+h6mz76pAuiFFvuQl6wMoSGFaaUQwfd+WQ
|
||||||
|
# gXlVVX/A9JFBihrxnDVglEPlsIOxCHkTeIxLfnAkCbax+9pevA==
|
||||||
|
# SIG # End signature block
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ namespace GitHub.Runner.Common
|
|||||||
CredentialData GetMigratedCredentials();
|
CredentialData GetMigratedCredentials();
|
||||||
RunnerSettings GetSettings();
|
RunnerSettings GetSettings();
|
||||||
void SaveCredential(CredentialData credential);
|
void SaveCredential(CredentialData credential);
|
||||||
void SaveMigratedCredential(CredentialData credential);
|
|
||||||
void SaveSettings(RunnerSettings settings);
|
void SaveSettings(RunnerSettings settings);
|
||||||
void DeleteCredential();
|
void DeleteCredential();
|
||||||
|
void DeleteMigratedCredential();
|
||||||
void DeleteSettings();
|
void DeleteSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,21 +232,6 @@ namespace GitHub.Runner.Common
|
|||||||
File.SetAttributes(_credFilePath, File.GetAttributes(_credFilePath) | FileAttributes.Hidden);
|
File.SetAttributes(_credFilePath, File.GetAttributes(_credFilePath) | FileAttributes.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveMigratedCredential(CredentialData credential)
|
|
||||||
{
|
|
||||||
Trace.Info("Saving {0} migrated credential @ {1}", credential.Scheme, _migratedCredFilePath);
|
|
||||||
if (File.Exists(_migratedCredFilePath))
|
|
||||||
{
|
|
||||||
// Delete existing credential file first, since the file is hidden and not able to overwrite.
|
|
||||||
Trace.Info("Delete exist runner migrated credential file.");
|
|
||||||
IOUtil.DeleteFile(_migratedCredFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
IOUtil.SaveObject(credential, _migratedCredFilePath);
|
|
||||||
Trace.Info("Migrated Credentials Saved.");
|
|
||||||
File.SetAttributes(_migratedCredFilePath, File.GetAttributes(_migratedCredFilePath) | FileAttributes.Hidden);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveSettings(RunnerSettings settings)
|
public void SaveSettings(RunnerSettings settings)
|
||||||
{
|
{
|
||||||
Trace.Info("Saving runner settings.");
|
Trace.Info("Saving runner settings.");
|
||||||
@@ -268,6 +253,11 @@ namespace GitHub.Runner.Common
|
|||||||
IOUtil.Delete(_migratedCredFilePath, default(CancellationToken));
|
IOUtil.Delete(_migratedCredFilePath, default(CancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteMigratedCredential()
|
||||||
|
{
|
||||||
|
IOUtil.Delete(_migratedCredFilePath, default(CancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteSettings()
|
public void DeleteSettings()
|
||||||
{
|
{
|
||||||
IOUtil.Delete(_configFilePath, default(CancellationToken));
|
IOUtil.Delete(_configFilePath, default(CancellationToken));
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
// agent update
|
// agent update
|
||||||
Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState);
|
Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState);
|
||||||
|
|
||||||
// runner authorization url
|
|
||||||
Task<string> GetRunnerAuthUrlAsync(int runnerPoolId, int runnerId);
|
|
||||||
Task ReportRunnerAuthUrlErrorAsync(int runnerPoolId, int runnerId, string error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class RunnerServer : RunnerService, IRunnerServer
|
public sealed class RunnerServer : RunnerService, IRunnerServer
|
||||||
|
|||||||
@@ -96,13 +96,14 @@ namespace GitHub.Runner.Common
|
|||||||
Trace.Info($"WRITE: {message}");
|
Trace.Info($"WRITE: {message}");
|
||||||
if (!Silent)
|
if (!Silent)
|
||||||
{
|
{
|
||||||
if(colorCode != null)
|
if (colorCode != null)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = colorCode.Value;
|
Console.ForegroundColor = colorCode.Value;
|
||||||
Console.Write(message);
|
Console.Write(message);
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
Console.Write(message);
|
Console.Write(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,13 +121,14 @@ namespace GitHub.Runner.Common
|
|||||||
Trace.Info($"WRITE LINE: {line}");
|
Trace.Info($"WRITE LINE: {line}");
|
||||||
if (!Silent)
|
if (!Silent)
|
||||||
{
|
{
|
||||||
if(colorCode != null)
|
if (colorCode != null)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = colorCode.Value;
|
Console.ForegroundColor = colorCode.Value;
|
||||||
Console.WriteLine(line);
|
Console.WriteLine(line);
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
Console.WriteLine(line);
|
Console.WriteLine(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,19 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
||||||
runnerSettings.IsHostedServer = runnerSettings.GitHubUrl == null || IsHostedServer(new UriBuilder(runnerSettings.GitHubUrl));
|
runnerSettings.IsHostedServer = runnerSettings.GitHubUrl == null || IsHostedServer(new UriBuilder(runnerSettings.GitHubUrl));
|
||||||
|
|
||||||
|
// Warn if the Actions server url and GHES server url has different Host
|
||||||
|
if (!runnerSettings.IsHostedServer)
|
||||||
|
{
|
||||||
|
// Example actionsServerUrl is https://my-ghes/_services/pipelines/[...]
|
||||||
|
// Example githubServerUrl is https://my-ghes
|
||||||
|
var actionsServerUrl = new Uri(runnerSettings.ServerUrl);
|
||||||
|
var githubServerUrl = new Uri(runnerSettings.GitHubUrl);
|
||||||
|
if (!string.Equals(actionsServerUrl.Authority, githubServerUrl.Authority, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"GitHub Actions is not properly configured in GHES. GHES url: {runnerSettings.GitHubUrl}, Actions url: {runnerSettings.ServerUrl}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate can connect.
|
// Validate can connect.
|
||||||
await _runnerServer.ConnectAsync(new Uri(runnerSettings.ServerUrl), creds);
|
await _runnerServer.ConnectAsync(new Uri(runnerSettings.ServerUrl), creds);
|
||||||
|
|
||||||
@@ -221,36 +234,11 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// Add Agent Id to settings
|
// Add Agent Id to settings
|
||||||
runnerSettings.AgentId = agent.Id;
|
runnerSettings.AgentId = agent.Id;
|
||||||
|
|
||||||
// respect the serverUrl resolve by server.
|
|
||||||
// in case of agent configured using collection url instead of account url.
|
|
||||||
string agentServerUrl;
|
|
||||||
if (agent.Properties.TryGetValidatedValue<string>("ServerUrl", out agentServerUrl) &&
|
|
||||||
!string.IsNullOrEmpty(agentServerUrl))
|
|
||||||
{
|
|
||||||
Trace.Info($"Agent server url resolve by server: '{agentServerUrl}'.");
|
|
||||||
|
|
||||||
// we need make sure the Schema/Host/Port component of the url remain the same.
|
|
||||||
UriBuilder inputServerUrl = new UriBuilder(runnerSettings.ServerUrl);
|
|
||||||
UriBuilder serverReturnedServerUrl = new UriBuilder(agentServerUrl);
|
|
||||||
if (Uri.Compare(inputServerUrl.Uri, serverReturnedServerUrl.Uri, UriComponents.SchemeAndServer, UriFormat.Unescaped, StringComparison.OrdinalIgnoreCase) != 0)
|
|
||||||
{
|
|
||||||
inputServerUrl.Path = serverReturnedServerUrl.Path;
|
|
||||||
Trace.Info($"Replace server returned url's scheme://host:port component with user input server url's scheme://host:port: '{inputServerUrl.Uri.AbsoluteUri}'.");
|
|
||||||
runnerSettings.ServerUrl = inputServerUrl.Uri.AbsoluteUri;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
runnerSettings.ServerUrl = agentServerUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if the server supports our OAuth key exchange for credentials
|
// See if the server supports our OAuth key exchange for credentials
|
||||||
if (agent.Authorization != null &&
|
if (agent.Authorization != null &&
|
||||||
agent.Authorization.ClientId != Guid.Empty &&
|
agent.Authorization.ClientId != Guid.Empty &&
|
||||||
agent.Authorization.AuthorizationUrl != null)
|
agent.Authorization.AuthorizationUrl != null)
|
||||||
{
|
{
|
||||||
UriBuilder configServerUrl = new UriBuilder(runnerSettings.ServerUrl);
|
|
||||||
UriBuilder oauthEndpointUrlBuilder = new UriBuilder(agent.Authorization.AuthorizationUrl);
|
|
||||||
var credentialData = new CredentialData
|
var credentialData = new CredentialData
|
||||||
{
|
{
|
||||||
Scheme = Constants.Configuration.OAuth,
|
Scheme = Constants.Configuration.OAuth,
|
||||||
@@ -258,7 +246,6 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
{ "clientId", agent.Authorization.ClientId.ToString("D") },
|
{ "clientId", agent.Authorization.ClientId.ToString("D") },
|
||||||
{ "authorizationUrl", agent.Authorization.AuthorizationUrl.AbsoluteUri },
|
{ "authorizationUrl", agent.Authorization.AuthorizationUrl.AbsoluteUri },
|
||||||
{ "oauthEndpointUrl", oauthEndpointUrlBuilder.Uri.AbsoluteUri },
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -464,7 +451,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// update should replace the existing labels
|
// update should replace the existing labels
|
||||||
agent.Version = BuildConstants.RunnerPackage.Version;
|
agent.Version = BuildConstants.RunnerPackage.Version;
|
||||||
agent.OSDescription = RuntimeInformation.OSDescription;
|
agent.OSDescription = RuntimeInformation.OSDescription;
|
||||||
|
|
||||||
agent.Labels.Clear();
|
agent.Labels.Clear();
|
||||||
|
|
||||||
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
|
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
|
||||||
@@ -475,7 +462,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
agent.Labels.Add(new AgentLabel(userLabel, LabelType.User));
|
agent.Labels.Add(new AgentLabel(userLabel, LabelType.User));
|
||||||
}
|
}
|
||||||
|
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
public interface ICredentialManager : IRunnerService
|
public interface ICredentialManager : IRunnerService
|
||||||
{
|
{
|
||||||
ICredentialProvider GetCredentialProvider(string credType);
|
ICredentialProvider GetCredentialProvider(string credType);
|
||||||
VssCredentials LoadCredentials(bool preferMigrated = true);
|
VssCredentials LoadCredentials();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CredentialManager : RunnerService, ICredentialManager
|
public class CredentialManager : RunnerService, ICredentialManager
|
||||||
@@ -40,7 +40,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
return creds;
|
return creds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VssCredentials LoadCredentials(bool preferMigrated = true)
|
public VssCredentials LoadCredentials()
|
||||||
{
|
{
|
||||||
IConfigurationStore store = HostContext.GetService<IConfigurationStore>();
|
IConfigurationStore store = HostContext.GetService<IConfigurationStore>();
|
||||||
|
|
||||||
@@ -50,14 +50,16 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
CredentialData credData = store.GetCredentials();
|
CredentialData credData = store.GetCredentials();
|
||||||
|
var migratedCred = store.GetMigratedCredentials();
|
||||||
if (preferMigrated)
|
if (migratedCred != null)
|
||||||
{
|
{
|
||||||
var migratedCred = store.GetMigratedCredentials();
|
credData = migratedCred;
|
||||||
if (migratedCred != null)
|
|
||||||
{
|
// Re-write .credentials with Token URL
|
||||||
credData = migratedCred;
|
store.SaveCredential(credData);
|
||||||
}
|
|
||||||
|
// Delete .credentials_migrated
|
||||||
|
store.DeleteMigratedCredential();
|
||||||
}
|
}
|
||||||
|
|
||||||
ICredentialProvider credProv = GetCredentialProvider(credData.Scheme);
|
ICredentialProvider credProv = GetCredentialProvider(credData.Scheme);
|
||||||
|
|||||||
@@ -13,10 +13,7 @@ using System.Diagnostics;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Test")]
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
[ServiceLocator(Default = typeof(MessageListener))]
|
[ServiceLocator(Default = typeof(MessageListener))]
|
||||||
@@ -35,30 +32,18 @@ namespace GitHub.Runner.Listener
|
|||||||
private ITerminal _term;
|
private ITerminal _term;
|
||||||
private IRunnerServer _runnerServer;
|
private IRunnerServer _runnerServer;
|
||||||
private TaskAgentSession _session;
|
private TaskAgentSession _session;
|
||||||
private ICredentialManager _credMgr;
|
|
||||||
private IConfigurationStore _configStore;
|
|
||||||
private TimeSpan _getNextMessageRetryInterval;
|
private TimeSpan _getNextMessageRetryInterval;
|
||||||
private readonly TimeSpan _sessionCreationRetryInterval = TimeSpan.FromSeconds(30);
|
private readonly TimeSpan _sessionCreationRetryInterval = TimeSpan.FromSeconds(30);
|
||||||
private readonly TimeSpan _sessionConflictRetryLimit = TimeSpan.FromMinutes(4);
|
private readonly TimeSpan _sessionConflictRetryLimit = TimeSpan.FromMinutes(4);
|
||||||
private readonly TimeSpan _clockSkewRetryLimit = TimeSpan.FromMinutes(30);
|
private readonly TimeSpan _clockSkewRetryLimit = TimeSpan.FromMinutes(30);
|
||||||
private readonly Dictionary<string, int> _sessionCreationExceptionTracker = new Dictionary<string, int>();
|
private readonly Dictionary<string, int> _sessionCreationExceptionTracker = new Dictionary<string, int>();
|
||||||
|
|
||||||
// Whether load credentials from .credentials_migrated file
|
|
||||||
internal bool _useMigratedCredentials;
|
|
||||||
|
|
||||||
// need to check auth url if there is only .credentials and auth schema is OAuth
|
|
||||||
internal bool _needToCheckAuthorizationUrlUpdate;
|
|
||||||
internal Task<VssCredentials> _authorizationUrlMigrationBackgroundTask;
|
|
||||||
internal Task _authorizationUrlRollbackReattemptDelayBackgroundTask;
|
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
|
|
||||||
_term = HostContext.GetService<ITerminal>();
|
_term = HostContext.GetService<ITerminal>();
|
||||||
_runnerServer = HostContext.GetService<IRunnerServer>();
|
_runnerServer = HostContext.GetService<IRunnerServer>();
|
||||||
_credMgr = HostContext.GetService<ICredentialManager>();
|
|
||||||
_configStore = HostContext.GetService<IConfigurationStore>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Boolean> CreateSessionAsync(CancellationToken token)
|
public async Task<Boolean> CreateSessionAsync(CancellationToken token)
|
||||||
@@ -73,8 +58,8 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
// Create connection.
|
// Create connection.
|
||||||
Trace.Info("Loading Credentials");
|
Trace.Info("Loading Credentials");
|
||||||
_useMigratedCredentials = !StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_SPSAUTHURL"));
|
var credMgr = HostContext.GetService<ICredentialManager>();
|
||||||
VssCredentials creds = _credMgr.LoadCredentials(_useMigratedCredentials);
|
VssCredentials creds = credMgr.LoadCredentials();
|
||||||
|
|
||||||
var agent = new TaskAgentReference
|
var agent = new TaskAgentReference
|
||||||
{
|
{
|
||||||
@@ -89,17 +74,6 @@ namespace GitHub.Runner.Listener
|
|||||||
string errorMessage = string.Empty;
|
string errorMessage = string.Empty;
|
||||||
bool encounteringError = false;
|
bool encounteringError = false;
|
||||||
|
|
||||||
var originalCreds = _configStore.GetCredentials();
|
|
||||||
var migratedCreds = _configStore.GetMigratedCredentials();
|
|
||||||
if (migratedCreds == null)
|
|
||||||
{
|
|
||||||
_useMigratedCredentials = false;
|
|
||||||
if (originalCreds.Scheme == Constants.Configuration.OAuth)
|
|
||||||
{
|
|
||||||
_needToCheckAuthorizationUrlUpdate = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
@@ -127,12 +101,6 @@ namespace GitHub.Runner.Listener
|
|||||||
encounteringError = false;
|
encounteringError = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_needToCheckAuthorizationUrlUpdate)
|
|
||||||
{
|
|
||||||
// start background task try to get new authorization url
|
|
||||||
_authorizationUrlMigrationBackgroundTask = GetNewOAuthAuthorizationSetting(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
@@ -164,44 +132,10 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ex is TaskAgentSessionConflictException)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var newCred = await GetNewOAuthAuthorizationSetting(token, true);
|
|
||||||
if (newCred != null)
|
|
||||||
{
|
|
||||||
await _runnerServer.ConnectAsync(new Uri(_settings.ServerUrl), newCred);
|
|
||||||
Trace.Info("Updated connection to use migrated credential for next CreateSession call.");
|
|
||||||
_useMigratedCredentials = true;
|
|
||||||
_authorizationUrlMigrationBackgroundTask = null;
|
|
||||||
_needToCheckAuthorizationUrlUpdate = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Trace.Error("Fail to refresh connection with new authorization url.");
|
|
||||||
Trace.Error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsSessionCreationExceptionRetriable(ex))
|
if (!IsSessionCreationExceptionRetriable(ex))
|
||||||
{
|
{
|
||||||
if (_useMigratedCredentials && !(ex is TaskAgentSessionConflictException))
|
_term.WriteError($"Failed to create session. {ex.Message}");
|
||||||
{
|
return false;
|
||||||
// migrated credentials might cause lose permission during permission check,
|
|
||||||
// we will force to use original credential and try again
|
|
||||||
_useMigratedCredentials = false;
|
|
||||||
var reattemptBackoff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromHours(24), TimeSpan.FromHours(36));
|
|
||||||
_authorizationUrlRollbackReattemptDelayBackgroundTask = HostContext.Delay(reattemptBackoff, token); // retry migrated creds in 24-36 hours.
|
|
||||||
creds = _credMgr.LoadCredentials(false);
|
|
||||||
Trace.Error("Fallback to original credentials and try again.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_term.WriteError($"Failed to create session. {ex.Message}");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!encounteringError) //print the message only on the first error
|
if (!encounteringError) //print the message only on the first error
|
||||||
@@ -262,51 +196,6 @@ namespace GitHub.Runner.Listener
|
|||||||
encounteringError = false;
|
encounteringError = false;
|
||||||
continuousError = 0;
|
continuousError = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_needToCheckAuthorizationUrlUpdate &&
|
|
||||||
_authorizationUrlMigrationBackgroundTask?.IsCompleted == true)
|
|
||||||
{
|
|
||||||
if (HostContext.GetService<IJobDispatcher>().Busy ||
|
|
||||||
HostContext.GetService<ISelfUpdater>().Busy)
|
|
||||||
{
|
|
||||||
Trace.Info("Job or runner updates in progress, update credentials next time.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var newCred = await _authorizationUrlMigrationBackgroundTask;
|
|
||||||
await _runnerServer.ConnectAsync(new Uri(_settings.ServerUrl), newCred);
|
|
||||||
Trace.Info("Updated connection to use migrated credential for next GetMessage call.");
|
|
||||||
_useMigratedCredentials = true;
|
|
||||||
_authorizationUrlMigrationBackgroundTask = null;
|
|
||||||
_needToCheckAuthorizationUrlUpdate = false;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.Error("Fail to refresh connection with new authorization url.");
|
|
||||||
Trace.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_authorizationUrlRollbackReattemptDelayBackgroundTask?.IsCompleted == true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// we rolled back to use original creds about 2 days before, now it's a good time to try migrated creds again.
|
|
||||||
Trace.Info("Re-attempt to use migrated credential");
|
|
||||||
var migratedCreds = _credMgr.LoadCredentials();
|
|
||||||
await _runnerServer.ConnectAsync(new Uri(_settings.ServerUrl), migratedCreds);
|
|
||||||
_useMigratedCredentials = true;
|
|
||||||
_authorizationUrlRollbackReattemptDelayBackgroundTask = null;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.Error("Fail to refresh connection with new authorization url on rollback reattempt.");
|
|
||||||
Trace.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -330,21 +219,7 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
else if (!IsGetNextMessageExceptionRetriable(ex))
|
else if (!IsGetNextMessageExceptionRetriable(ex))
|
||||||
{
|
{
|
||||||
if (_useMigratedCredentials)
|
throw;
|
||||||
{
|
|
||||||
// migrated credentials might cause lose permission during permission check,
|
|
||||||
// we will force to use original credential and try again
|
|
||||||
_useMigratedCredentials = false;
|
|
||||||
var reattemptBackoff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromHours(24), TimeSpan.FromHours(36));
|
|
||||||
_authorizationUrlRollbackReattemptDelayBackgroundTask = HostContext.Delay(reattemptBackoff, token); // retry migrated creds in 24-36 hours.
|
|
||||||
var originalCreds = _credMgr.LoadCredentials(false);
|
|
||||||
await _runnerServer.ConnectAsync(new Uri(_settings.ServerUrl), originalCreds);
|
|
||||||
Trace.Error("Fallback to original credentials and try again.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -536,94 +411,5 @@ namespace GitHub.Runner.Listener
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<VssCredentials> GetNewOAuthAuthorizationSetting(CancellationToken token, bool adhoc = false)
|
|
||||||
{
|
|
||||||
Trace.Info("Start checking oauth authorization url update.");
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var migratedAuthorizationUrl = await _runnerServer.GetRunnerAuthUrlAsync(_settings.PoolId, _settings.AgentId);
|
|
||||||
if (!string.IsNullOrEmpty(migratedAuthorizationUrl))
|
|
||||||
{
|
|
||||||
var credData = _configStore.GetCredentials();
|
|
||||||
var clientId = credData.Data.GetValueOrDefault("clientId", null);
|
|
||||||
var currentAuthorizationUrl = credData.Data.GetValueOrDefault("authorizationUrl", null);
|
|
||||||
Trace.Info($"Current authorization url: {currentAuthorizationUrl}, new authorization url: {migratedAuthorizationUrl}");
|
|
||||||
|
|
||||||
if (string.Equals(currentAuthorizationUrl, migratedAuthorizationUrl, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
// We don't need to update credentials.
|
|
||||||
Trace.Info("No needs to update authorization url");
|
|
||||||
if (adhoc)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Task.Delay(TimeSpan.FromMilliseconds(-1), token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var keyManager = HostContext.GetService<IRSAKeyManager>();
|
|
||||||
var signingCredentials = VssSigningCredentials.Create(() => keyManager.GetKey());
|
|
||||||
|
|
||||||
var migratedClientCredential = new VssOAuthJwtBearerClientCredential(clientId, migratedAuthorizationUrl, signingCredentials);
|
|
||||||
var migratedRunnerCredential = new VssOAuthCredential(new Uri(migratedAuthorizationUrl, UriKind.Absolute), VssOAuthGrant.ClientCredentials, migratedClientCredential);
|
|
||||||
|
|
||||||
Trace.Info("Try connect service with Token Service OAuth endpoint.");
|
|
||||||
var runnerServer = HostContext.CreateService<IRunnerServer>();
|
|
||||||
await runnerServer.ConnectAsync(new Uri(_settings.ServerUrl), migratedRunnerCredential);
|
|
||||||
await runnerServer.GetAgentPoolsAsync();
|
|
||||||
Trace.Info($"Successfully connected service with new authorization url.");
|
|
||||||
|
|
||||||
var migratedCredData = new CredentialData
|
|
||||||
{
|
|
||||||
Scheme = Constants.Configuration.OAuth,
|
|
||||||
Data =
|
|
||||||
{
|
|
||||||
{ "clientId", clientId },
|
|
||||||
{ "authorizationUrl", migratedAuthorizationUrl },
|
|
||||||
{ "oauthEndpointUrl", migratedAuthorizationUrl },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
_configStore.SaveMigratedCredential(migratedCredData);
|
|
||||||
return migratedRunnerCredential;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Trace.Verbose("No authorization url updates");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) when (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
Trace.Error("Fail to get/test new authorization url.");
|
|
||||||
Trace.Error(ex);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _runnerServer.ReportRunnerAuthUrlErrorAsync(_settings.PoolId, _settings.AgentId, ex.ToString());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
// best effort
|
|
||||||
Trace.Error("Fail to report the migration error");
|
|
||||||
Trace.Error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adhoc)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var backoff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(45));
|
|
||||||
await HostContext.Delay(backoff, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,9 @@ namespace GitHub.Runner.Listener
|
|||||||
IRunner runner = context.GetService<IRunner>();
|
IRunner runner = context.GetService<IRunner>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await runner.ExecuteCommand(command);
|
var returnCode = await runner.ExecuteCommand(command);
|
||||||
|
trace.Info($"Runner execution has finished with return code {returnCode}");
|
||||||
|
return returnCode;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException) when (context.RunnerShutdownToken.IsCancellationRequested)
|
catch (OperationCanceledException) when (context.RunnerShutdownToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -318,7 +318,12 @@ namespace GitHub.Runner.Sdk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var registration = cancellationToken.Register(async () => await CancelAndKillProcessTree(killProcessOnCancel)))
|
var cancellationFinished = new TaskCompletionSource<bool>();
|
||||||
|
using (var registration = cancellationToken.Register(async () =>
|
||||||
|
{
|
||||||
|
await CancelAndKillProcessTree(killProcessOnCancel);
|
||||||
|
cancellationFinished.TrySetResult(true);
|
||||||
|
}))
|
||||||
{
|
{
|
||||||
Trace.Info($"Process started with process id {_proc.Id}, waiting for process exit.");
|
Trace.Info($"Process started with process id {_proc.Id}, waiting for process exit.");
|
||||||
while (true)
|
while (true)
|
||||||
@@ -344,6 +349,13 @@ namespace GitHub.Runner.Sdk
|
|||||||
Trace.Info($"Finished process {_proc.Id} with exit code {_proc.ExitCode}, and elapsed time {_stopWatch.Elapsed}.");
|
Trace.Info($"Finished process {_proc.Id} with exit code {_proc.ExitCode}, and elapsed time {_stopWatch.Elapsed}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
// Ensure cancellation also finish on the cancellationToken.Register thread.
|
||||||
|
await cancellationFinished.Task;
|
||||||
|
Trace.Info($"Process Cancellation finished.");
|
||||||
|
}
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
// Wait for process to finish.
|
// Wait for process to finish.
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ namespace GitHub.Runner.Worker
|
|||||||
// Clear the cache (for self-hosted runners)
|
// Clear the cache (for self-hosted runners)
|
||||||
IOUtil.DeleteDirectory(HostContext.GetDirectory(WellKnownDirectory.Actions), executionContext.CancellationToken);
|
IOUtil.DeleteDirectory(HostContext.GetDirectory(WellKnownDirectory.Actions), executionContext.CancellationToken);
|
||||||
|
|
||||||
|
// todo: Remove when feature flag DistributedTask.NewActionMetadata is removed
|
||||||
|
var newActionMetadata = executionContext.Variables.GetBoolean("DistributedTask.NewActionMetadata") ?? false;
|
||||||
|
|
||||||
|
var repositoryActions = new List<Pipelines.ActionStep>();
|
||||||
|
|
||||||
foreach (var action in actions)
|
foreach (var action in actions)
|
||||||
{
|
{
|
||||||
if (action.Reference.Type == Pipelines.ActionSourceType.ContainerRegistry)
|
if (action.Reference.Type == Pipelines.ActionSourceType.ContainerRegistry)
|
||||||
@@ -90,7 +95,8 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Info($"Action {action.Name} ({action.Id}) needs to pull image '{containerReference.Image}'");
|
Trace.Info($"Action {action.Name} ({action.Id}) needs to pull image '{containerReference.Image}'");
|
||||||
imagesToPull[containerReference.Image].Add(action.Id);
|
imagesToPull[containerReference.Image].Add(action.Id);
|
||||||
}
|
}
|
||||||
else if (action.Reference.Type == Pipelines.ActionSourceType.Repository)
|
// todo: Remove when feature flag DistributedTask.NewActionMetadata is removed
|
||||||
|
else if (action.Reference.Type == Pipelines.ActionSourceType.Repository && !newActionMetadata)
|
||||||
{
|
{
|
||||||
// only download the repository archive
|
// only download the repository archive
|
||||||
await DownloadRepositoryActionAsync(executionContext, action);
|
await DownloadRepositoryActionAsync(executionContext, action);
|
||||||
@@ -124,6 +130,81 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var repoAction = action.Reference as Pipelines.RepositoryPathReference;
|
||||||
|
if (repoAction.RepositoryType != Pipelines.PipelineConstants.SelfAlias)
|
||||||
|
{
|
||||||
|
var definition = LoadAction(executionContext, action);
|
||||||
|
if (definition.Data.Execution.HasPre)
|
||||||
|
{
|
||||||
|
var actionRunner = HostContext.CreateService<IActionRunner>();
|
||||||
|
actionRunner.Action = action;
|
||||||
|
actionRunner.Stage = ActionRunStage.Pre;
|
||||||
|
actionRunner.Condition = definition.Data.Execution.InitCondition;
|
||||||
|
|
||||||
|
Trace.Info($"Add 'pre' execution for {action.Id}");
|
||||||
|
preStepTracker[action.Id] = actionRunner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (action.Reference.Type == Pipelines.ActionSourceType.Repository && newActionMetadata)
|
||||||
|
{
|
||||||
|
repositoryActions.Add(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repositoryActions.Count > 0)
|
||||||
|
{
|
||||||
|
// Get the download info
|
||||||
|
var downloadInfos = await GetDownloadInfoAsync(executionContext, repositoryActions);
|
||||||
|
|
||||||
|
// Download each action
|
||||||
|
foreach (var action in repositoryActions)
|
||||||
|
{
|
||||||
|
var lookupKey = GetDownloadInfoLookupKey(action);
|
||||||
|
if (string.IsNullOrEmpty(lookupKey))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!downloadInfos.TryGetValue(lookupKey, out var downloadInfo))
|
||||||
|
{
|
||||||
|
throw new Exception($"Missing download info for {lookupKey}");
|
||||||
|
}
|
||||||
|
|
||||||
|
await DownloadRepositoryActionAsync(executionContext, downloadInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// More preparation based on content in the repository (action.yml)
|
||||||
|
foreach (var action in repositoryActions)
|
||||||
|
{
|
||||||
|
var setupInfo = PrepareRepositoryActionAsync(executionContext, action);
|
||||||
|
if (setupInfo != null)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(setupInfo.Image))
|
||||||
|
{
|
||||||
|
if (!imagesToPull.ContainsKey(setupInfo.Image))
|
||||||
|
{
|
||||||
|
imagesToPull[setupInfo.Image] = new List<Guid>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace.Info($"Action {action.Name} ({action.Id}) from repository '{setupInfo.ActionRepository}' needs to pull image '{setupInfo.Image}'");
|
||||||
|
imagesToPull[setupInfo.Image].Add(action.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ArgUtil.NotNullOrEmpty(setupInfo.ActionRepository, nameof(setupInfo.ActionRepository));
|
||||||
|
|
||||||
|
if (!imagesToBuild.ContainsKey(setupInfo.ActionRepository))
|
||||||
|
{
|
||||||
|
imagesToBuild[setupInfo.ActionRepository] = new List<Guid>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace.Info($"Action {action.Name} ({action.Id}) from repository '{setupInfo.ActionRepository}' needs to build image '{setupInfo.Dockerfile}'");
|
||||||
|
imagesToBuild[setupInfo.ActionRepository].Add(action.Id);
|
||||||
|
imagesToBuildInfo[setupInfo.ActionRepository] = setupInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var repoAction = action.Reference as Pipelines.RepositoryPathReference;
|
var repoAction = action.Reference as Pipelines.RepositoryPathReference;
|
||||||
if (repoAction.RepositoryType != Pipelines.PipelineConstants.SelfAlias)
|
if (repoAction.RepositoryType != Pipelines.PipelineConstants.SelfAlias)
|
||||||
{
|
{
|
||||||
@@ -150,8 +231,7 @@ namespace GitHub.Runner.Worker
|
|||||||
containerSetupSteps.Add(new JobExtensionRunner(runAsync: this.PullActionContainerAsync,
|
containerSetupSteps.Add(new JobExtensionRunner(runAsync: this.PullActionContainerAsync,
|
||||||
condition: $"{PipelineTemplateConstants.Success}()",
|
condition: $"{PipelineTemplateConstants.Success}()",
|
||||||
displayName: $"Pull {imageToPull.Key}",
|
displayName: $"Pull {imageToPull.Key}",
|
||||||
data: new ContainerSetupInfo(imageToPull.Value, imageToPull.Key),
|
data: new ContainerSetupInfo(imageToPull.Value, imageToPull.Key)));
|
||||||
repositoryRef: null));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,8 +244,7 @@ namespace GitHub.Runner.Worker
|
|||||||
containerSetupSteps.Add(new JobExtensionRunner(runAsync: this.BuildActionContainerAsync,
|
containerSetupSteps.Add(new JobExtensionRunner(runAsync: this.BuildActionContainerAsync,
|
||||||
condition: $"{PipelineTemplateConstants.Success}()",
|
condition: $"{PipelineTemplateConstants.Success}()",
|
||||||
displayName: $"Build {setupInfo.ActionRepository}",
|
displayName: $"Build {setupInfo.ActionRepository}",
|
||||||
data: new ContainerSetupInfo(imageToBuild.Value, setupInfo.Dockerfile, setupInfo.WorkingDirectory),
|
data: new ContainerSetupInfo(imageToBuild.Value, setupInfo.Dockerfile, setupInfo.WorkingDirectory)));
|
||||||
repositoryRef: setupInfo.RepositoryRef));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,6 +545,127 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This implementation is temporary and will be removed when we switch to a REST API call to the service to resolve the download info
|
||||||
|
private async Task<bool> RepoExistsAsync(IExecutionContext executionContext, Pipelines.RepositoryPathReference repositoryReference, string authorization)
|
||||||
|
{
|
||||||
|
var apiUrl = GetApiUrl(executionContext);
|
||||||
|
var repoUrl = $"{apiUrl}/repos/{repositoryReference.Name}";
|
||||||
|
for (var attempt = 1; attempt <= 3; attempt++)
|
||||||
|
{
|
||||||
|
executionContext.Debug($"Checking whether repo exists: {repoUrl}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
|
{
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = CreateAuthHeader(authorization);
|
||||||
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
|
using (var response = await httpClient.GetAsync(repoUrl))
|
||||||
|
{
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (response.StatusCode == HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Throw
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (attempt < 3)
|
||||||
|
{
|
||||||
|
executionContext.Debug($"Failed checking whether repo '{repositoryReference.Name}' exists: {ex.Message}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
executionContext.Error($"Failed checking whether repo '{repositoryReference.Name}' exists: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Never reaches here
|
||||||
|
}
|
||||||
|
|
||||||
|
// This implementation is temporary and will be replaced with a REST API call to the service to resolve
|
||||||
|
private async Task<Dictionary<string, ActionDownloadInfo>> GetDownloadInfoAsync(IExecutionContext executionContext, List<Pipelines.ActionStep> actions)
|
||||||
|
{
|
||||||
|
var result = new Dictionary<string, ActionDownloadInfo>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
var configurationStore = HostContext.GetService<IConfigurationStore>();
|
||||||
|
var runnerSettings = configurationStore.GetSettings();
|
||||||
|
var apiUrl = GetApiUrl(executionContext);
|
||||||
|
var accessToken = executionContext.GetGitHubContext("token");
|
||||||
|
var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"x-access-token:{accessToken}"));
|
||||||
|
var authorization = $"Basic {base64EncodingToken}";
|
||||||
|
|
||||||
|
foreach (var action in actions)
|
||||||
|
{
|
||||||
|
var lookupKey = GetDownloadInfoLookupKey(action);
|
||||||
|
if (string.IsNullOrEmpty(lookupKey) || result.ContainsKey(lookupKey))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var repositoryReference = action.Reference as Pipelines.RepositoryPathReference;
|
||||||
|
ArgUtil.NotNull(repositoryReference, nameof(repositoryReference));
|
||||||
|
|
||||||
|
var downloadInfo = default(ActionDownloadInfo);
|
||||||
|
|
||||||
|
if (runnerSettings.IsHostedServer)
|
||||||
|
{
|
||||||
|
downloadInfo = new ActionDownloadInfo
|
||||||
|
{
|
||||||
|
NameWithOwner = repositoryReference.Name,
|
||||||
|
Ref = repositoryReference.Ref,
|
||||||
|
ArchiveLink = BuildLinkToActionArchive(apiUrl, repositoryReference.Name, repositoryReference.Ref),
|
||||||
|
Authorization = authorization,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Test whether the repo exists in the instance
|
||||||
|
else if (await RepoExistsAsync(executionContext, repositoryReference, authorization))
|
||||||
|
{
|
||||||
|
downloadInfo = new ActionDownloadInfo
|
||||||
|
{
|
||||||
|
NameWithOwner = repositoryReference.Name,
|
||||||
|
Ref = repositoryReference.Ref,
|
||||||
|
ArchiveLink = BuildLinkToActionArchive(apiUrl, repositoryReference.Name, repositoryReference.Ref),
|
||||||
|
Authorization = authorization,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Fallback to dotcom
|
||||||
|
else
|
||||||
|
{
|
||||||
|
downloadInfo = new ActionDownloadInfo
|
||||||
|
{
|
||||||
|
NameWithOwner = repositoryReference.Name,
|
||||||
|
Ref = repositoryReference.Ref,
|
||||||
|
ArchiveLink = BuildLinkToActionArchive(_dotcomApiUrl, repositoryReference.Name, repositoryReference.Ref),
|
||||||
|
Authorization = null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Add(lookupKey, downloadInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register secrets
|
||||||
|
foreach (var downloadInfo in result.Values)
|
||||||
|
{
|
||||||
|
HostContext.SecretMasker.AddValue(downloadInfo.Authorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: Remove when feature flag DistributedTask.NewActionMetadata is removed
|
||||||
private async Task DownloadRepositoryActionAsync(IExecutionContext executionContext, Pipelines.ActionStep repositoryAction)
|
private async Task DownloadRepositoryActionAsync(IExecutionContext executionContext, Pipelines.ActionStep repositoryAction)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
@@ -511,7 +711,7 @@ namespace GitHub.Runner.Worker
|
|||||||
string archiveLink = BuildLinkToActionArchive(apiUrl, repositoryReference.Name, repositoryReference.Ref);
|
string archiveLink = BuildLinkToActionArchive(apiUrl, repositoryReference.Name, repositoryReference.Ref);
|
||||||
Trace.Info($"Download archive '{archiveLink}' to '{destDirectory}'.");
|
Trace.Info($"Download archive '{archiveLink}' to '{destDirectory}'.");
|
||||||
var downloadDetails = new ActionDownloadDetails(archiveLink, ConfigureAuthorizationFromContext);
|
var downloadDetails = new ActionDownloadDetails(archiveLink, ConfigureAuthorizationFromContext);
|
||||||
await DownloadRepositoryActionAsync(executionContext, downloadDetails, destDirectory);
|
await DownloadRepositoryActionAsync(executionContext, downloadDetails, null, destDirectory);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -538,7 +738,7 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Info($"Download archive '{downloadAttempt.ArchiveLink}' to '{destDirectory}'.");
|
Trace.Info($"Download archive '{downloadAttempt.ArchiveLink}' to '{destDirectory}'.");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await DownloadRepositoryActionAsync(executionContext, downloadAttempt, destDirectory);
|
await DownloadRepositoryActionAsync(executionContext, downloadAttempt, null, destDirectory);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (ActionNotFoundException)
|
catch (ActionNotFoundException)
|
||||||
@@ -551,6 +751,33 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task DownloadRepositoryActionAsync(IExecutionContext executionContext, ActionDownloadInfo downloadInfo)
|
||||||
|
{
|
||||||
|
Trace.Entering();
|
||||||
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
|
ArgUtil.NotNull(downloadInfo, nameof(downloadInfo));
|
||||||
|
ArgUtil.NotNullOrEmpty(downloadInfo.NameWithOwner, nameof(downloadInfo.NameWithOwner));
|
||||||
|
ArgUtil.NotNullOrEmpty(downloadInfo.Ref, nameof(downloadInfo.Ref));
|
||||||
|
|
||||||
|
string destDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Actions), downloadInfo.NameWithOwner.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar), downloadInfo.Ref);
|
||||||
|
string watermarkFile = GetWatermarkFilePath(destDirectory);
|
||||||
|
if (File.Exists(watermarkFile))
|
||||||
|
{
|
||||||
|
executionContext.Debug($"Action '{downloadInfo.NameWithOwner}@{downloadInfo.Ref}' already downloaded at '{destDirectory}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// make sure we get a clean folder ready to use.
|
||||||
|
IOUtil.DeleteDirectory(destDirectory, executionContext.CancellationToken);
|
||||||
|
Directory.CreateDirectory(destDirectory);
|
||||||
|
executionContext.Output($"Download action repository '{downloadInfo.NameWithOwner}@{downloadInfo.Ref}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace.Info($"Download archive '{downloadInfo.ArchiveLink}' to '{destDirectory}'.");
|
||||||
|
await DownloadRepositoryActionAsync(executionContext, null, downloadInfo, destDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
private string GetApiUrl(IExecutionContext executionContext)
|
private string GetApiUrl(IExecutionContext executionContext)
|
||||||
{
|
{
|
||||||
string apiUrl = executionContext.GetGitHubContext("api_url");
|
string apiUrl = executionContext.GetGitHubContext("api_url");
|
||||||
@@ -571,7 +798,8 @@ namespace GitHub.Runner.Worker
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadRepositoryActionAsync(IExecutionContext executionContext, ActionDownloadDetails actionDownloadDetails, string destDirectory)
|
// todo: Remove the parameter "actionDownloadDetails" when feature flag DistributedTask.NewActionMetadata is removed
|
||||||
|
private async Task DownloadRepositoryActionAsync(IExecutionContext executionContext, ActionDownloadDetails actionDownloadDetails, ActionDownloadInfo downloadInfo, string destDirectory)
|
||||||
{
|
{
|
||||||
//download and extract action in a temp folder and rename it on success
|
//download and extract action in a temp folder and rename it on success
|
||||||
string tempDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Actions), "_temp_" + Guid.NewGuid());
|
string tempDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Actions), "_temp_" + Guid.NewGuid());
|
||||||
@@ -583,7 +811,7 @@ namespace GitHub.Runner.Worker
|
|||||||
string archiveFile = Path.Combine(tempDirectory, $"{Guid.NewGuid()}.tar.gz");
|
string archiveFile = Path.Combine(tempDirectory, $"{Guid.NewGuid()}.tar.gz");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
string link = actionDownloadDetails.ArchiveLink;
|
string link = downloadInfo != null ? downloadInfo.ArchiveLink : actionDownloadDetails.ArchiveLink;
|
||||||
Trace.Info($"Save archive '{link}' into {archiveFile}.");
|
Trace.Info($"Save archive '{link}' into {archiveFile}.");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -603,7 +831,16 @@ namespace GitHub.Runner.Worker
|
|||||||
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
{
|
{
|
||||||
actionDownloadDetails.ConfigureAuthorization(executionContext, httpClient);
|
// Legacy
|
||||||
|
if (downloadInfo == null)
|
||||||
|
{
|
||||||
|
actionDownloadDetails.ConfigureAuthorization(executionContext, httpClient);
|
||||||
|
}
|
||||||
|
// FF DistributedTask.NewActionMetadata
|
||||||
|
else
|
||||||
|
{
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = CreateAuthHeader(downloadInfo.Authorization);
|
||||||
|
}
|
||||||
|
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
using (var response = await httpClient.GetAsync(link))
|
using (var response = await httpClient.GetAsync(link))
|
||||||
@@ -743,6 +980,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: Remove when feature flag DistributedTask.NewActionMetadata is removed
|
||||||
private void ConfigureAuthorizationFromContext(IExecutionContext executionContext, HttpClient httpClient)
|
private void ConfigureAuthorizationFromContext(IExecutionContext executionContext, HttpClient httpClient)
|
||||||
{
|
{
|
||||||
var authToken = Environment.GetEnvironmentVariable("_GITHUB_ACTION_TOKEN");
|
var authToken = Environment.GetEnvironmentVariable("_GITHUB_ACTION_TOKEN");
|
||||||
@@ -778,7 +1016,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
var setupInfo = new ActionContainer();
|
var setupInfo = new ActionContainer();
|
||||||
setupInfo.RepositoryRef = repositoryReference;
|
|
||||||
string destDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Actions), repositoryReference.Name.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar), repositoryReference.Ref);
|
string destDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Actions), repositoryReference.Name.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar), repositoryReference.Ref);
|
||||||
string actionEntryDirectory = destDirectory;
|
string actionEntryDirectory = destDirectory;
|
||||||
string dockerFileRelativePath = repositoryReference.Name;
|
string dockerFileRelativePath = repositoryReference.Name;
|
||||||
@@ -875,6 +1112,48 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetDownloadInfoLookupKey(Pipelines.ActionStep action)
|
||||||
|
{
|
||||||
|
if (action.Reference.Type != Pipelines.ActionSourceType.Repository)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var repositoryReference = action.Reference as Pipelines.RepositoryPathReference;
|
||||||
|
ArgUtil.NotNull(repositoryReference, nameof(repositoryReference));
|
||||||
|
|
||||||
|
if (string.Equals(repositoryReference.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.Equals(repositoryReference.RepositoryType, Pipelines.RepositoryTypes.GitHub, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
throw new NotSupportedException(repositoryReference.RepositoryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgUtil.NotNullOrEmpty(repositoryReference.Name, nameof(repositoryReference.Name));
|
||||||
|
ArgUtil.NotNullOrEmpty(repositoryReference.Ref, nameof(repositoryReference.Ref));
|
||||||
|
return $"{repositoryReference.Name}@{repositoryReference.Ref}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AuthenticationHeaderValue CreateAuthHeader(string authorization)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(authorization))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var split = authorization.Split(new char[] { ' ' }, 2);
|
||||||
|
if (split.Length != 2 || string.IsNullOrWhiteSpace(split[0]) || string.IsNullOrWhiteSpace(split[1]))
|
||||||
|
{
|
||||||
|
throw new Exception("Unexpected authorization header format");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AuthenticationHeaderValue(split[0].Trim(), split[1].Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: Remove when feature flag DistributedTask.NewActionMetadata is removed
|
||||||
private class ActionDownloadDetails
|
private class ActionDownloadDetails
|
||||||
{
|
{
|
||||||
public string ArchiveLink { get; }
|
public string ArchiveLink { get; }
|
||||||
@@ -887,6 +1166,17 @@ namespace GitHub.Runner.Worker
|
|||||||
ConfigureAuthorization = configureAuthorization;
|
ConfigureAuthorization = configureAuthorization;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ActionDownloadInfo
|
||||||
|
{
|
||||||
|
public string NameWithOwner { get; set; }
|
||||||
|
|
||||||
|
public string Ref { get; set; }
|
||||||
|
|
||||||
|
public string ArchiveLink { get; set; }
|
||||||
|
|
||||||
|
public string Authorization { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class Definition
|
public sealed class Definition
|
||||||
@@ -1025,6 +1315,5 @@ namespace GitHub.Runner.Worker
|
|||||||
public string Dockerfile { get; set; }
|
public string Dockerfile { get; set; }
|
||||||
public string WorkingDirectory { get; set; }
|
public string WorkingDirectory { get; set; }
|
||||||
public string ActionRepository { get; set; }
|
public string ActionRepository { get; set; }
|
||||||
public Pipelines.RepositoryPathReference RepositoryRef { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,6 +94,13 @@ namespace GitHub.Runner.Worker
|
|||||||
if (handlerData.HasPost && (Stage == ActionRunStage.Pre || Stage == ActionRunStage.Main))
|
if (handlerData.HasPost && (Stage == ActionRunStage.Pre || Stage == ActionRunStage.Main))
|
||||||
{
|
{
|
||||||
string postDisplayName = $"Post {this.DisplayName}";
|
string postDisplayName = $"Post {this.DisplayName}";
|
||||||
|
if (Stage == ActionRunStage.Pre &&
|
||||||
|
this.DisplayName.StartsWith("Pre ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// Trim the leading `Pre ` from the display name.
|
||||||
|
// Otherwise, we will get `Post Pre xxx` as DisplayName for the Post step.
|
||||||
|
postDisplayName = $"Post {this.DisplayName.Substring("Pre ".Length)}";
|
||||||
|
}
|
||||||
var repositoryReference = Action.Reference as RepositoryPathReference;
|
var repositoryReference = Action.Reference as RepositoryPathReference;
|
||||||
var pathString = string.IsNullOrEmpty(repositoryReference.Path) ? string.Empty : $"/{repositoryReference.Path}";
|
var pathString = string.IsNullOrEmpty(repositoryReference.Path) ? string.Empty : $"/{repositoryReference.Path}";
|
||||||
var repoString = string.IsNullOrEmpty(repositoryReference.Ref) ? $"{repositoryReference.Name}{pathString}" :
|
var repoString = string.IsNullOrEmpty(repositoryReference.Ref) ? $"{repositoryReference.Name}{pathString}" :
|
||||||
@@ -155,6 +162,13 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
var validInputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
var validInputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
if (handlerData.ExecutionType == ActionExecutionType.Container)
|
||||||
|
{
|
||||||
|
// container action always accept 'entryPoint' and 'args' as inputs
|
||||||
|
// https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepswithargs
|
||||||
|
validInputs.Add("entryPoint");
|
||||||
|
validInputs.Add("args");
|
||||||
|
}
|
||||||
// Merge the default inputs from the definition
|
// Merge the default inputs from the definition
|
||||||
if (definition.Data?.Inputs != null)
|
if (definition.Data?.Inputs != null)
|
||||||
{
|
{
|
||||||
@@ -173,13 +187,19 @@ namespace GitHub.Runner.Worker
|
|||||||
// Validate inputs only for actions with action.yml
|
// Validate inputs only for actions with action.yml
|
||||||
if (Action.Reference.Type == Pipelines.ActionSourceType.Repository)
|
if (Action.Reference.Type == Pipelines.ActionSourceType.Repository)
|
||||||
{
|
{
|
||||||
|
var unexpectedInputs = new List<string>();
|
||||||
foreach (var input in userInputs)
|
foreach (var input in userInputs)
|
||||||
{
|
{
|
||||||
if (!validInputs.Contains(input))
|
if (!validInputs.Contains(input))
|
||||||
{
|
{
|
||||||
ExecutionContext.Warning($"Unexpected input '{input}', valid inputs are ['{string.Join("', '", validInputs)}']");
|
unexpectedInputs.Add(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unexpectedInputs.Count > 0)
|
||||||
|
{
|
||||||
|
ExecutionContext.Warning($"Unexpected input(s) '{string.Join("', '", unexpectedInputs)}', valid inputs are ['{string.Join("', '", validInputs)}']");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the action environment.
|
// Load the action environment.
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ namespace GitHub.Runner.Worker
|
|||||||
var postJobStep = new JobExtensionRunner(runAsync: this.StopContainersAsync,
|
var postJobStep = new JobExtensionRunner(runAsync: this.StopContainersAsync,
|
||||||
condition: $"{PipelineTemplateConstants.Always}()",
|
condition: $"{PipelineTemplateConstants.Always}()",
|
||||||
displayName: "Stop containers",
|
displayName: "Stop containers",
|
||||||
data: data,
|
data: data);
|
||||||
repositoryRef: null);
|
|
||||||
|
|
||||||
executionContext.Debug($"Register post job cleanup for stopping/deleting containers.");
|
executionContext.Debug($"Register post job cleanup for stopping/deleting containers.");
|
||||||
executionContext.RegisterPostJobStep(postJobStep);
|
executionContext.RegisterPostJobStep(postJobStep);
|
||||||
|
|||||||
@@ -260,9 +260,7 @@ namespace GitHub.Runner.Worker
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string refName = step.GetRefName();
|
step.ExecutionContext = Root.CreatePostChild(step.DisplayName, IntraActionState);
|
||||||
|
|
||||||
step.ExecutionContext = Root.CreatePostChild(step.DisplayName, refName, IntraActionState);
|
|
||||||
Root.PostJobSteps.Push(step);
|
Root.PostJobSteps.Push(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,12 +268,6 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
|
|
||||||
// TODO: Null out old, non-json refNames only if a FF is set.
|
|
||||||
if (refName != null && !refName.StartsWith("{"))
|
|
||||||
{
|
|
||||||
refName = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var child = new ExecutionContext();
|
var child = new ExecutionContext();
|
||||||
child.Initialize(HostContext);
|
child.Initialize(HostContext);
|
||||||
child.ScopeName = scopeName;
|
child.ScopeName = scopeName;
|
||||||
@@ -372,7 +364,11 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_cancellationTokenSource?.Dispose();
|
if (Root != this)
|
||||||
|
{
|
||||||
|
// only dispose TokenSource for step level ExecutionContext
|
||||||
|
_cancellationTokenSource?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
_logger.End();
|
_logger.End();
|
||||||
|
|
||||||
@@ -869,7 +865,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IExecutionContext CreatePostChild(string displayName, string refName, Dictionary<string, string> intraActionState)
|
private IExecutionContext CreatePostChild(string displayName, Dictionary<string, string> intraActionState)
|
||||||
{
|
{
|
||||||
if (!_expandedForPostJob)
|
if (!_expandedForPostJob)
|
||||||
{
|
{
|
||||||
@@ -879,9 +875,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
var newGuid = Guid.NewGuid();
|
var newGuid = Guid.NewGuid();
|
||||||
|
return CreateChild(newGuid, displayName, newGuid.ToString("N"), null, null, intraActionState, _childTimelineRecordOrder - Root.PostJobSteps.Count);
|
||||||
// TODO: Check feature flag here, conditionally set refName to newGuid.ToString("N").
|
|
||||||
return CreateChild(newGuid, displayName, refName, null, null, intraActionState, _childTimelineRecordOrder - Root.PostJobSteps.Count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ namespace GitHub.Runner.Worker.Expressions
|
|||||||
{
|
{
|
||||||
public sealed class HashFilesFunction : Function
|
public sealed class HashFilesFunction : Function
|
||||||
{
|
{
|
||||||
|
private const int _hashFileTimeoutSeconds = 120;
|
||||||
|
|
||||||
protected sealed override Object EvaluateCore(
|
protected sealed override Object EvaluateCore(
|
||||||
EvaluationContext context,
|
EvaluationContext context,
|
||||||
out ResultMemory resultMemory)
|
out ResultMemory resultMemory)
|
||||||
@@ -89,19 +91,29 @@ namespace GitHub.Runner.Worker.Expressions
|
|||||||
}
|
}
|
||||||
env["patterns"] = string.Join(Environment.NewLine, patterns);
|
env["patterns"] = string.Join(Environment.NewLine, patterns);
|
||||||
|
|
||||||
int exitCode = p.ExecuteAsync(workingDirectory: githubWorkspace,
|
using (var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(_hashFileTimeoutSeconds)))
|
||||||
fileName: node,
|
|
||||||
arguments: $"\"{hashFilesScript.Replace("\"", "\\\"")}\"",
|
|
||||||
environment: env,
|
|
||||||
requireExitCodeZero: false,
|
|
||||||
cancellationToken: new CancellationTokenSource(TimeSpan.FromSeconds(120)).Token).GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
if (exitCode != 0)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"hashFiles('{ExpressionUtility.StringEscape(string.Join(", ", patterns))}') failed. Fail to hash files under directory '{githubWorkspace}'");
|
try
|
||||||
}
|
{
|
||||||
|
int exitCode = p.ExecuteAsync(workingDirectory: githubWorkspace,
|
||||||
|
fileName: node,
|
||||||
|
arguments: $"\"{hashFilesScript.Replace("\"", "\\\"")}\"",
|
||||||
|
environment: env,
|
||||||
|
requireExitCodeZero: false,
|
||||||
|
cancellationToken: tokenSource.Token).GetAwaiter().GetResult();
|
||||||
|
|
||||||
return hashResult;
|
if (exitCode != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"hashFiles('{ExpressionUtility.StringEscape(string.Join(", ", patterns))}') failed. Fail to hash files under directory '{githubWorkspace}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) when (tokenSource.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw new TimeoutException($"hashFiles('{ExpressionUtility.StringEscape(string.Join(", ", patterns))}') couldn't finish within {_hashFileTimeoutSeconds} seconds.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashResult;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class HashFilesTrace : ITraceWriter
|
private sealed class HashFilesTrace : ITraceWriter
|
||||||
|
|||||||
@@ -352,15 +352,24 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
if (File.Exists(gitConfigPath))
|
if (File.Exists(gitConfigPath))
|
||||||
{
|
{
|
||||||
// Check if the config contains the workflow repository url
|
// Check if the config contains the workflow repository url
|
||||||
var qualifiedRepository = _executionContext.GetGitHubContext("repository");
|
var serverUrl = _executionContext.GetGitHubContext("server_url");
|
||||||
var configMatch = $"url = https://github.com/{qualifiedRepository}";
|
serverUrl = !string.IsNullOrEmpty(serverUrl) ? serverUrl : "https://github.com";
|
||||||
|
var host = new Uri(serverUrl, UriKind.Absolute).Host;
|
||||||
|
var nameWithOwner = _executionContext.GetGitHubContext("repository");
|
||||||
|
var patterns = new[] {
|
||||||
|
$"url = {serverUrl}/{nameWithOwner}",
|
||||||
|
$"url = git@{host}:{nameWithOwner}.git",
|
||||||
|
};
|
||||||
var content = File.ReadAllText(gitConfigPath);
|
var content = File.ReadAllText(gitConfigPath);
|
||||||
foreach (var line in content.Split("\n").Select(x => x.Trim()))
|
foreach (var line in content.Split("\n").Select(x => x.Trim()))
|
||||||
{
|
{
|
||||||
if (String.Equals(line, configMatch, StringComparison.OrdinalIgnoreCase))
|
foreach (var pattern in patterns)
|
||||||
{
|
{
|
||||||
repositoryPath = directoryPath;
|
if (String.Equals(line, pattern, StringComparison.OrdinalIgnoreCase))
|
||||||
break;
|
{
|
||||||
|
repositoryPath = directoryPath;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
|
||||||
{
|
|
||||||
public static class IStepExtensions
|
|
||||||
{
|
|
||||||
public static string GetRefName(this IStep step, string defaultRefName = null)
|
|
||||||
{
|
|
||||||
// TODO: Really check a feature flag.
|
|
||||||
if (s_featureFlagEnabled)
|
|
||||||
{
|
|
||||||
if (step is JobExtensionRunner extensionRunner && extensionRunner.RepositoryRef != null)
|
|
||||||
{
|
|
||||||
return JsonConvert.SerializeObject(extensionRunner.RepositoryRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step is IActionRunner actionRunner && actionRunner.Action?.Reference != null)
|
|
||||||
{
|
|
||||||
return JsonConvert.SerializeObject(actionRunner.Action.Reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
// RefName should always be valid json or null.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultRefName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool s_featureFlagEnabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -213,10 +213,9 @@ namespace GitHub.Runner.Worker
|
|||||||
containers.AddRange(jobContext.ServiceContainers);
|
containers.AddRange(jobContext.ServiceContainers);
|
||||||
|
|
||||||
preJobSteps.Add(new JobExtensionRunner(runAsync: containerProvider.StartContainersAsync,
|
preJobSteps.Add(new JobExtensionRunner(runAsync: containerProvider.StartContainersAsync,
|
||||||
condition: $"{PipelineTemplateConstants.Success}()",
|
condition: $"{PipelineTemplateConstants.Success}()",
|
||||||
displayName: "Initialize containers",
|
displayName: "Initialize containers",
|
||||||
data: (object)containers,
|
data: (object)containers));
|
||||||
repositoryRef: null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add action steps
|
// Add action steps
|
||||||
@@ -261,19 +260,18 @@ namespace GitHub.Runner.Worker
|
|||||||
// Create execution context for pre-job steps
|
// Create execution context for pre-job steps
|
||||||
foreach (var step in preJobSteps)
|
foreach (var step in preJobSteps)
|
||||||
{
|
{
|
||||||
if (step is JobExtensionRunner extensionStep)
|
if (step is JobExtensionRunner)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(extensionStep, step.DisplayName);
|
JobExtensionRunner extensionStep = step as JobExtensionRunner;
|
||||||
|
ArgUtil.NotNull(extensionStep, extensionStep.DisplayName);
|
||||||
Guid stepId = Guid.NewGuid();
|
Guid stepId = Guid.NewGuid();
|
||||||
var refName = step.GetRefName(defaultRefName: null);
|
extensionStep.ExecutionContext = jobContext.CreateChild(stepId, extensionStep.DisplayName, null, null, stepId.ToString("N"));
|
||||||
extensionStep.ExecutionContext = jobContext.CreateChild(stepId, extensionStep.DisplayName, refName, null, stepId.ToString("N"));
|
|
||||||
}
|
}
|
||||||
else if (step is IActionRunner actionStep)
|
else if (step is IActionRunner actionStep)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(actionStep, step.DisplayName);
|
ArgUtil.NotNull(actionStep, step.DisplayName);
|
||||||
Guid stepId = Guid.NewGuid();
|
Guid stepId = Guid.NewGuid();
|
||||||
var refName = step.GetRefName(defaultRefName: stepId.ToString("N"));
|
actionStep.ExecutionContext = jobContext.CreateChild(stepId, actionStep.DisplayName, stepId.ToString("N"), null, null, intraActionStates[actionStep.Action.Id]);
|
||||||
actionStep.ExecutionContext = jobContext.CreateChild(stepId, actionStep.DisplayName, refName, null, null, intraActionStates[actionStep.Action.Id]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,8 +282,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
ArgUtil.NotNull(actionStep, step.DisplayName);
|
ArgUtil.NotNull(actionStep, step.DisplayName);
|
||||||
intraActionStates.TryGetValue(actionStep.Action.Id, out var intraActionState);
|
intraActionStates.TryGetValue(actionStep.Action.Id, out var intraActionState);
|
||||||
var refName = step.GetRefName(defaultRefName: actionStep.Action.Name);
|
actionStep.ExecutionContext = jobContext.CreateChild(actionStep.Action.Id, actionStep.DisplayName, actionStep.Action.Name, actionStep.Action.ScopeName, actionStep.Action.ContextName, intraActionState);
|
||||||
actionStep.ExecutionContext = jobContext.CreateChild(actionStep.Action.Id, actionStep.DisplayName, refName, actionStep.Action.ScopeName, actionStep.Action.ContextName, intraActionState);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.DistributedTask.Expressions2;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
using GitHub.DistributedTask.Pipelines;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
@@ -9,26 +9,22 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
private readonly object _data;
|
private readonly object _data;
|
||||||
private readonly Func<IExecutionContext, object, Task> _runAsync;
|
private readonly Func<IExecutionContext, object, Task> _runAsync;
|
||||||
private readonly RepositoryPathReference _repositoryRef;
|
|
||||||
|
|
||||||
public JobExtensionRunner(
|
public JobExtensionRunner(
|
||||||
Func<IExecutionContext, object, Task> runAsync,
|
Func<IExecutionContext, object, Task> runAsync,
|
||||||
string condition,
|
string condition,
|
||||||
string displayName,
|
string displayName,
|
||||||
object data,
|
object data)
|
||||||
RepositoryPathReference repositoryRef)
|
|
||||||
{
|
{
|
||||||
_runAsync = runAsync;
|
_runAsync = runAsync;
|
||||||
Condition = condition;
|
Condition = condition;
|
||||||
DisplayName = displayName;
|
DisplayName = displayName;
|
||||||
_data = data;
|
_data = data;
|
||||||
_repositoryRef = repositoryRef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Condition { get; set; }
|
public string Condition { get; set; }
|
||||||
public TemplateToken ContinueOnError => new BooleanToken(null, null, null, false);
|
public TemplateToken ContinueOnError => new BooleanToken(null, null, null, false);
|
||||||
public string DisplayName { get; set; }
|
public string DisplayName { get; set; }
|
||||||
public RepositoryPathReference RepositoryRef => _repositoryRef;
|
|
||||||
public IExecutionContext ExecutionContext { get; set; }
|
public IExecutionContext ExecutionContext { get; set; }
|
||||||
public TemplateToken Timeout => new NumberToken(null, null, null, 0);
|
public TemplateToken Timeout => new NumberToken(null, null, null, 0);
|
||||||
public object Data => _data;
|
public object Data => _data;
|
||||||
|
|||||||
@@ -5,21 +5,13 @@ using GitHub.Services.Common;
|
|||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
@@ -122,13 +114,6 @@ namespace GitHub.Runner.Worker
|
|||||||
_tempDirectoryManager = HostContext.GetService<ITempDirectoryManager>();
|
_tempDirectoryManager = HostContext.GetService<ITempDirectoryManager>();
|
||||||
_tempDirectoryManager.InitializeTempDirectory(jobContext);
|
_tempDirectoryManager.InitializeTempDirectory(jobContext);
|
||||||
|
|
||||||
// // Expand container properties
|
|
||||||
// jobContext.Container?.ExpandProperties(jobContext.Variables);
|
|
||||||
// foreach (var sidecar in jobContext.SidecarContainers)
|
|
||||||
// {
|
|
||||||
// sidecar.ExpandProperties(jobContext.Variables);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Get the job extension.
|
// Get the job extension.
|
||||||
Trace.Info("Getting job extension.");
|
Trace.Info("Getting job extension.");
|
||||||
IJobExtension jobExtension = HostContext.CreateService<IJobExtension>();
|
IJobExtension jobExtension = HostContext.CreateService<IJobExtension>();
|
||||||
@@ -254,6 +239,12 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Error(ex);
|
Trace.Error(ex);
|
||||||
return TaskResult.Failed;
|
return TaskResult.Failed;
|
||||||
}
|
}
|
||||||
|
catch (TaskOrchestrationPlanTerminatedException ex)
|
||||||
|
{
|
||||||
|
Trace.Error($"TaskOrchestrationPlanTerminatedException received, while attempting to raise JobCompletedEvent for job {message.JobId}.");
|
||||||
|
Trace.Error(ex);
|
||||||
|
return TaskResult.Failed;
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Trace.Error($"Catch exception while attempting to raise JobCompletedEvent for job {message.JobId}, job request {message.RequestId}.");
|
Trace.Error($"Catch exception while attempting to raise JobCompletedEvent for job {message.JobId}, job request {message.RequestId}.");
|
||||||
|
|||||||
@@ -98,124 +98,139 @@ namespace GitHub.Runner.Worker
|
|||||||
envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty);
|
envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool evaluateStepEnvFailed = false;
|
||||||
if (step is IActionRunner actionStep)
|
if (step is IActionRunner actionStep)
|
||||||
{
|
{
|
||||||
// Set GITHUB_ACTION
|
// Set GITHUB_ACTION
|
||||||
step.ExecutionContext.SetGitHubContext("action", actionStep.Action.Name);
|
step.ExecutionContext.SetGitHubContext("action", actionStep.Action.Name);
|
||||||
|
|
||||||
// Evaluate and merge action's env block to env context
|
try
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
|
|
||||||
var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, VarUtil.EnvironmentVariableKeyComparer);
|
|
||||||
foreach (var env in actionEnvironment)
|
|
||||||
{
|
{
|
||||||
envContext[env.Key] = new StringContextData(env.Value ?? string.Empty);
|
// Evaluate and merge action's env block to env context
|
||||||
}
|
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
|
||||||
}
|
var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, VarUtil.EnvironmentVariableKeyComparer);
|
||||||
|
foreach (var env in actionEnvironment)
|
||||||
try
|
|
||||||
{
|
|
||||||
// Register job cancellation call back only if job cancellation token not been fire before each step run
|
|
||||||
if (!jobContext.CancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
// Test the condition again. The job was canceled after the condition was originally evaluated.
|
|
||||||
jobCancelRegister = jobContext.CancellationToken.Register(() =>
|
|
||||||
{
|
{
|
||||||
// mark job as cancelled
|
envContext[env.Key] = new StringContextData(env.Value ?? string.Empty);
|
||||||
jobContext.Result = TaskResult.Canceled;
|
|
||||||
jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
|
|
||||||
|
|
||||||
step.ExecutionContext.Debug($"Re-evaluate condition on job cancellation for step: '{step.DisplayName}'.");
|
|
||||||
var conditionReTestTraceWriter = new ConditionTraceWriter(Trace, null); // host tracing only
|
|
||||||
var conditionReTestResult = false;
|
|
||||||
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
step.ExecutionContext.Debug($"Skip Re-evaluate condition on runner shutdown.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionReTestTraceWriter);
|
|
||||||
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
|
||||||
conditionReTestResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// Cancel the step since we get exception while re-evaluate step condition.
|
|
||||||
Trace.Info("Caught exception from expression when re-test condition on job cancellation.");
|
|
||||||
step.ExecutionContext.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!conditionReTestResult)
|
|
||||||
{
|
|
||||||
// Cancel the step.
|
|
||||||
Trace.Info("Cancel current running step.");
|
|
||||||
step.ExecutionContext.CancelToken();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (jobContext.Result != TaskResult.Canceled)
|
|
||||||
{
|
|
||||||
// mark job as cancelled
|
|
||||||
jobContext.Result = TaskResult.Canceled;
|
|
||||||
jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
// Evaluate condition.
|
|
||||||
step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'");
|
|
||||||
var conditionTraceWriter = new ConditionTraceWriter(Trace, step.ExecutionContext);
|
|
||||||
var conditionResult = false;
|
|
||||||
var conditionEvaluateError = default(Exception);
|
|
||||||
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
step.ExecutionContext.Debug($"Skip evaluate condition on runner shutdown.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionTraceWriter);
|
|
||||||
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
|
||||||
conditionResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.Info("Caught exception from expression.");
|
|
||||||
Trace.Error(ex);
|
|
||||||
conditionEvaluateError = ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no evaluate error but condition is false
|
|
||||||
if (!conditionResult && conditionEvaluateError == null)
|
|
||||||
{
|
|
||||||
// Condition == false
|
|
||||||
Trace.Info("Skipping step due to condition evaluation.");
|
|
||||||
CompleteStep(step, nextStep, TaskResult.Skipped, resultCode: conditionTraceWriter.Trace);
|
|
||||||
}
|
|
||||||
else if (conditionEvaluateError != null)
|
|
||||||
{
|
{
|
||||||
// fail the step since there is an evaluate error.
|
// fail the step since there is an evaluate error.
|
||||||
step.ExecutionContext.Error(conditionEvaluateError);
|
Trace.Info("Caught exception from expression for step.env");
|
||||||
|
evaluateStepEnvFailed = true;
|
||||||
|
step.ExecutionContext.Error(ex);
|
||||||
CompleteStep(step, nextStep, TaskResult.Failed);
|
CompleteStep(step, nextStep, TaskResult.Failed);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Run the step.
|
|
||||||
await RunStepAsync(step, jobContext.CancellationToken);
|
|
||||||
CompleteStep(step, nextStep);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
|
if (!evaluateStepEnvFailed)
|
||||||
{
|
{
|
||||||
if (jobCancelRegister != null)
|
try
|
||||||
{
|
{
|
||||||
jobCancelRegister?.Dispose();
|
// Register job cancellation call back only if job cancellation token not been fire before each step run
|
||||||
jobCancelRegister = null;
|
if (!jobContext.CancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
// Test the condition again. The job was canceled after the condition was originally evaluated.
|
||||||
|
jobCancelRegister = jobContext.CancellationToken.Register(() =>
|
||||||
|
{
|
||||||
|
// mark job as cancelled
|
||||||
|
jobContext.Result = TaskResult.Canceled;
|
||||||
|
jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
|
||||||
|
|
||||||
|
step.ExecutionContext.Debug($"Re-evaluate condition on job cancellation for step: '{step.DisplayName}'.");
|
||||||
|
var conditionReTestTraceWriter = new ConditionTraceWriter(Trace, null); // host tracing only
|
||||||
|
var conditionReTestResult = false;
|
||||||
|
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
step.ExecutionContext.Debug($"Skip Re-evaluate condition on runner shutdown.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionReTestTraceWriter);
|
||||||
|
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
||||||
|
conditionReTestResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Cancel the step since we get exception while re-evaluate step condition.
|
||||||
|
Trace.Info("Caught exception from expression when re-test condition on job cancellation.");
|
||||||
|
step.ExecutionContext.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!conditionReTestResult)
|
||||||
|
{
|
||||||
|
// Cancel the step.
|
||||||
|
Trace.Info("Cancel current running step.");
|
||||||
|
step.ExecutionContext.CancelToken();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (jobContext.Result != TaskResult.Canceled)
|
||||||
|
{
|
||||||
|
// mark job as cancelled
|
||||||
|
jobContext.Result = TaskResult.Canceled;
|
||||||
|
jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate condition.
|
||||||
|
step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'");
|
||||||
|
var conditionTraceWriter = new ConditionTraceWriter(Trace, step.ExecutionContext);
|
||||||
|
var conditionResult = false;
|
||||||
|
var conditionEvaluateError = default(Exception);
|
||||||
|
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
step.ExecutionContext.Debug($"Skip evaluate condition on runner shutdown.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionTraceWriter);
|
||||||
|
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
||||||
|
conditionResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Info("Caught exception from expression.");
|
||||||
|
Trace.Error(ex);
|
||||||
|
conditionEvaluateError = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no evaluate error but condition is false
|
||||||
|
if (!conditionResult && conditionEvaluateError == null)
|
||||||
|
{
|
||||||
|
// Condition == false
|
||||||
|
Trace.Info("Skipping step due to condition evaluation.");
|
||||||
|
CompleteStep(step, nextStep, TaskResult.Skipped, resultCode: conditionTraceWriter.Trace);
|
||||||
|
}
|
||||||
|
else if (conditionEvaluateError != null)
|
||||||
|
{
|
||||||
|
// fail the step since there is an evaluate error.
|
||||||
|
step.ExecutionContext.Error(conditionEvaluateError);
|
||||||
|
CompleteStep(step, nextStep, TaskResult.Failed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Run the step.
|
||||||
|
await RunStepAsync(step, jobContext.CancellationToken);
|
||||||
|
CompleteStep(step, nextStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (jobCancelRegister != null)
|
||||||
|
{
|
||||||
|
jobCancelRegister?.Dispose();
|
||||||
|
jobCancelRegister = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace GitHub.DistributedTask.Pipelines
|
|||||||
[DataContract]
|
[DataContract]
|
||||||
[KnownType(typeof(ContainerRegistryReference))]
|
[KnownType(typeof(ContainerRegistryReference))]
|
||||||
[KnownType(typeof(RepositoryPathReference))]
|
[KnownType(typeof(RepositoryPathReference))]
|
||||||
[KnownType(typeof(ScriptReference))]
|
[KnownType(typeof(ScriptReference))]
|
||||||
[JsonConverter(typeof(ActionStepDefinitionReferenceConverter))]
|
[JsonConverter(typeof(ActionStepDefinitionReferenceConverter))]
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public abstract class ActionStepDefinitionReference
|
public abstract class ActionStepDefinitionReference
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -328,8 +328,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Assert.Equal("invalid1", finialInputs["invalid1"]);
|
Assert.Equal("invalid1", finialInputs["invalid1"]);
|
||||||
Assert.Equal("invalid2", finialInputs["invalid2"]);
|
Assert.Equal("invalid2", finialInputs["invalid2"]);
|
||||||
|
|
||||||
_ec.Verify(x => x.AddIssue(It.Is<Issue>(s => s.Message.Contains("Unexpected input 'invalid1'")), It.IsAny<string>()), Times.Once);
|
_ec.Verify(x => x.AddIssue(It.Is<Issue>(s => s.Message.Contains("Unexpected input(s) 'invalid1', 'invalid2'")), It.IsAny<string>()), Times.Once);
|
||||||
_ec.Verify(x => x.AddIssue(It.Is<Issue>(s => s.Message.Contains("Unexpected input 'invalid2'")), It.IsAny<string>()), Times.Once);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Setup([CallerMemberName] string name = "")
|
private void Setup([CallerMemberName] string name = "")
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
jobExtension.Initialize(hc);
|
jobExtension.Initialize(hc);
|
||||||
|
|
||||||
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>()))
|
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>()))
|
||||||
.Returns(Task.FromResult(new PrepareResult(new List<JobExtensionRunner>() { new JobExtensionRunner(null, "", "prepare1", null, null), new JobExtensionRunner(null, "", "prepare2", null, null) }, new Dictionary<Guid, IActionRunner>())));
|
.Returns(Task.FromResult(new PrepareResult(new List<JobExtensionRunner>() { new JobExtensionRunner(null, "", "prepare1", null), new JobExtensionRunner(null, "", "prepare2", null) }, new Dictionary<Guid, IActionRunner>())));
|
||||||
|
|
||||||
List<IStep> result = await jobExtension.InitializeJob(_jobEc, _message);
|
List<IStep> result = await jobExtension.InitializeJob(_jobEc, _message);
|
||||||
|
|
||||||
|
|||||||
@@ -686,14 +686,17 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
// <WORKSPACE>/workflow-repo/nested-other-repo
|
// <WORKSPACE>/workflow-repo/nested-other-repo
|
||||||
// <WORKSPACE>/other-repo
|
// <WORKSPACE>/other-repo
|
||||||
// <WORKSPACE>/other-repo/nested-workflow-repo
|
// <WORKSPACE>/other-repo/nested-workflow-repo
|
||||||
|
// <WORKSPACE>/workflow-repo-using-ssh
|
||||||
var workflowRepository = Path.Combine(workspaceDirectory, "workflow-repo");
|
var workflowRepository = Path.Combine(workspaceDirectory, "workflow-repo");
|
||||||
var nestedOtherRepository = Path.Combine(workspaceDirectory, "workflow-repo", "nested-other-repo");
|
var nestedOtherRepository = Path.Combine(workspaceDirectory, "workflow-repo", "nested-other-repo");
|
||||||
var otherRepository = Path.Combine(workspaceDirectory, workflowRepository, "nested-other-repo");
|
var otherRepository = Path.Combine(workspaceDirectory, workflowRepository, "nested-other-repo");
|
||||||
var nestedWorkflowRepository = Path.Combine(workspaceDirectory, "other-repo", "nested-workflow-repo");
|
var nestedWorkflowRepository = Path.Combine(workspaceDirectory, "other-repo", "nested-workflow-repo");
|
||||||
|
var workflowRepositoryUsingSsh = Path.Combine(workspaceDirectory, "workflow-repo-using-ssh");
|
||||||
await CreateRepository(hostContext, workflowRepository, "https://github.com/my-org/workflow-repo");
|
await CreateRepository(hostContext, workflowRepository, "https://github.com/my-org/workflow-repo");
|
||||||
await CreateRepository(hostContext, nestedOtherRepository, "https://github.com/my-org/other-repo");
|
await CreateRepository(hostContext, nestedOtherRepository, "https://github.com/my-org/other-repo");
|
||||||
await CreateRepository(hostContext, otherRepository, "https://github.com/my-org/other-repo");
|
await CreateRepository(hostContext, otherRepository, "https://github.com/my-org/other-repo");
|
||||||
await CreateRepository(hostContext, nestedWorkflowRepository, "https://github.com/my-org/workflow-repo");
|
await CreateRepository(hostContext, nestedWorkflowRepository, "https://github.com/my-org/workflow-repo");
|
||||||
|
await CreateRepository(hostContext, workflowRepositoryUsingSsh, "git@github.com:my-org/workflow-repo.git");
|
||||||
|
|
||||||
// Create test files
|
// Create test files
|
||||||
var file_noRepository = Path.Combine(workspaceDirectory, "no-repo.txt");
|
var file_noRepository = Path.Combine(workspaceDirectory, "no-repo.txt");
|
||||||
@@ -703,7 +706,8 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var file_nestedOtherRepository = Path.Combine(nestedOtherRepository, "nested-other-repo");
|
var file_nestedOtherRepository = Path.Combine(nestedOtherRepository, "nested-other-repo");
|
||||||
var file_otherRepository = Path.Combine(otherRepository, "other-repo.txt");
|
var file_otherRepository = Path.Combine(otherRepository, "other-repo.txt");
|
||||||
var file_nestedWorkflowRepository = Path.Combine(nestedWorkflowRepository, "nested-workflow-repo.txt");
|
var file_nestedWorkflowRepository = Path.Combine(nestedWorkflowRepository, "nested-workflow-repo.txt");
|
||||||
foreach (var file in new[] { file_noRepository, file_workflowRepository, file_workflowRepository_nestedDirectory, file_workflowRepository_failsafe, file_nestedOtherRepository, file_otherRepository, file_nestedWorkflowRepository })
|
var file_workflowRepositoryUsingSsh = Path.Combine(workflowRepositoryUsingSsh, "workflow-repo-using-ssh.txt");
|
||||||
|
foreach (var file in new[] { file_noRepository, file_workflowRepository, file_workflowRepository_nestedDirectory, file_workflowRepository_failsafe, file_nestedOtherRepository, file_otherRepository, file_nestedWorkflowRepository, file_workflowRepositoryUsingSsh })
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(file));
|
Directory.CreateDirectory(Path.GetDirectoryName(file));
|
||||||
File.WriteAllText(file, "");
|
File.WriteAllText(file, "");
|
||||||
@@ -718,8 +722,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process($"{file_nestedOtherRepository}: some error 6");
|
Process($"{file_nestedOtherRepository}: some error 6");
|
||||||
Process($"{file_otherRepository}: some error 7");
|
Process($"{file_otherRepository}: some error 7");
|
||||||
Process($"{file_nestedWorkflowRepository}: some error 8");
|
Process($"{file_nestedWorkflowRepository}: some error 8");
|
||||||
|
Process($"{file_workflowRepositoryUsingSsh}: some error 9");
|
||||||
|
|
||||||
Assert.Equal(8, _issues.Count);
|
Assert.Equal(9, _issues.Count);
|
||||||
|
|
||||||
Assert.Equal("some error 1", _issues[0].Item1.Message);
|
Assert.Equal("some error 1", _issues[0].Item1.Message);
|
||||||
Assert.False(_issues[0].Item1.Data.ContainsKey("file"));
|
Assert.False(_issues[0].Item1.Data.ContainsKey("file"));
|
||||||
@@ -744,6 +749,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
Assert.Equal("some error 8", _issues[7].Item1.Message);
|
Assert.Equal("some error 8", _issues[7].Item1.Message);
|
||||||
Assert.Equal(file_nestedWorkflowRepository.Substring(nestedWorkflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[7].Item1.Data["file"]);
|
Assert.Equal(file_nestedWorkflowRepository.Substring(nestedWorkflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[7].Item1.Data["file"]);
|
||||||
|
|
||||||
|
Assert.Equal("some error 9", _issues[8].Item1.Message);
|
||||||
|
Assert.Equal(file_workflowRepositoryUsingSsh.Substring(workflowRepositoryUsingSsh.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[8].Item1.Data["file"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment.SetEnvironmentVariable("RUNNER_TEST_GET_REPOSITORY_PATH_FAILSAFE", "");
|
Environment.SetEnvironmentVariable("RUNNER_TEST_GET_REPOSITORY_PATH_FAILSAFE", "");
|
||||||
|
|||||||
51
src/dev.sh
51
src/dev.sh
@@ -173,6 +173,57 @@ function package ()
|
|||||||
powershell -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "Add-Type -Assembly \"System.IO.Compression.FileSystem\"; [System.IO.Compression.ZipFile]::CreateFromDirectory(\"${window_path}\", \"${zip_name}\")"
|
powershell -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "Add-Type -Assembly \"System.IO.Compression.FileSystem\"; [System.IO.Compression.ZipFile]::CreateFromDirectory(\"${window_path}\", \"${zip_name}\")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
runner_patch_pkg_name="actions-runner-${RUNTIME_ID}-${runner_ver}-patch"
|
||||||
|
|
||||||
|
heading "Packaging Patch Version ${runner_patch_pkg_name}"
|
||||||
|
|
||||||
|
echo "Downloading latest runner ..."
|
||||||
|
|
||||||
|
mkdir -p "_temp"
|
||||||
|
pushd "_temp" > /dev/null
|
||||||
|
|
||||||
|
latest_version_label=$(curl -s -X GET 'https://api.github.com/repos/actions/runner/releases/latest' | jq -r '.tag_name')
|
||||||
|
latest_version=$(echo ${latest_version_label:1})
|
||||||
|
latest_version_runner_file=""
|
||||||
|
if [[ ("$CURRENT_PLATFORM" == "linux") || ("$CURRENT_PLATFORM" == "darwin") ]]; then
|
||||||
|
latest_version_runner_file="actions-runner-${RUNTIME_ID}-${latest_version}.tar.gz"
|
||||||
|
elif [[ ("$CURRENT_PLATFORM" == "windows") ]]; then
|
||||||
|
latest_version_runner_file="actions-runner-${RUNTIME_ID}-${latest_version}.zip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
latest_version_download_url="https://github.com/actions/runner/releases/download/${latest_version_label}/${latest_version_runner_file}"
|
||||||
|
|
||||||
|
echo "Downloading ${latest_version_label} for ${RUNTIME_ID} ..."
|
||||||
|
echo $latest_version_download_url
|
||||||
|
|
||||||
|
curl -O -L ${latest_version_download_url}
|
||||||
|
|
||||||
|
mkdir -p "latest_runner"
|
||||||
|
if [[ ("$CURRENT_PLATFORM" == "linux") || ("$CURRENT_PLATFORM" == "darwin") ]]; then
|
||||||
|
tar xzf "./${latest_version_runner_file}" -C latest_runner
|
||||||
|
elif [[ ("$CURRENT_PLATFORM" == "windows") ]]; then
|
||||||
|
powershell -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "Add-Type -Assembly \"System.IO.Compression.FileSystem\"; [System.IO.Compression.ZipFile]::ExtractToDirectory(\"./${latest_version_runner_file}\", \"latest_runner\")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "_patch"
|
||||||
|
diff -qrN "${LAYOUT_DIR}" "latest_runner" | cut -d " " -f 2 | xargs -t -I file cp file "_patch/"$(echo file | cut -c ${#LAYOUT_DIR}- | cut -c 3-)
|
||||||
|
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
if [[ ("$CURRENT_PLATFORM" == "linux") || ("$CURRENT_PLATFORM" == "darwin") ]]; then
|
||||||
|
patch_tar_name="${runner_patch_pkg_name}.tar.gz"
|
||||||
|
echo "Creating $patch_tar_name in ${PACKAGE_DIR}/_temp/_patch"
|
||||||
|
tar -czf "${patch_tar_name}" -C "${PACKAGE_DIR}/_temp/_patch" .
|
||||||
|
elif [[ ("$CURRENT_PLATFORM" == "windows") ]]; then
|
||||||
|
patch_zip_name="${runner_patch_pkg_name}.zip"
|
||||||
|
echo "Convert ${PACKAGE_DIR} to Windows style path"
|
||||||
|
window_path=${PACKAGE_DIR:1}
|
||||||
|
window_path=${window_path:0:1}:${window_path:1}
|
||||||
|
echo "Creating $patch_zip_name in ${window_path}/_temp/_patch"
|
||||||
|
powershell -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "Add-Type -Assembly \"System.IO.Compression.FileSystem\"; [System.IO.Compression.ZipFile]::CreateFromDirectory(\"${window_path}\", \"${patch_zip_name}\")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -Rf "${PACKAGE_DIR}/_temp"
|
||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.262.0
|
2.263.0
|
||||||
|
|||||||
Reference in New Issue
Block a user