Skip to content

Commit ed21eeb

Browse files
authored
Merge branch 'main' into add-workflow-permissions
2 parents 83f609a + a81428f commit ed21eeb

File tree

23 files changed

+396
-50
lines changed

23 files changed

+396
-50
lines changed

.github/workflows/CI.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ jobs:
159159
checks: write
160160
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == 'github'
161161
needs: [build-for-e2e-test]
162+
permissions:
163+
checks: write
164+
contents: read
162165
strategy:
163166
fail-fast: false
164167
matrix:
@@ -177,7 +180,7 @@ jobs:
177180
global-json-file: global.json
178181

179182
- name: Download Binaries
180-
uses: actions/download-artifact@v4
183+
uses: actions/download-artifact@v6
181184
with:
182185
name: binaries-${{ matrix.runner-os }}
183186
path: dist
@@ -340,10 +343,12 @@ jobs:
340343
./dist/ado2gh.*.win-x64.zip
341344
./dist/ado2gh.*.win-x86.zip
342345
./dist/ado2gh.*.linux-x64.tar.gz
346+
./dist/ado2gh.*.linux-arm64.tar.gz
343347
./dist/ado2gh.*.osx-x64.tar.gz
344348
./dist/win-x64/gei-windows-amd64.exe
345349
./dist/win-x86/gei-windows-386.exe
346350
./dist/linux-x64/gei-linux-amd64
351+
./dist/linux-arm64/gei-linux-arm64
347352
./dist/osx-x64/gei-darwin-amd64
348353
349354
- name: Create gh-ado2gh Release
@@ -356,6 +361,7 @@ jobs:
356361
./dist/win-x86/ado2gh-windows-386.exe
357362
./dist/win-x64/ado2gh-windows-amd64.exe
358363
./dist/linux-x64/ado2gh-linux-amd64
364+
./dist/linux-arm64/ado2gh-linux-arm64
359365
./dist/osx-x64/ado2gh-darwin-amd64
360366
361367
- name: Create gh-bbs2gh Release
@@ -368,6 +374,7 @@ jobs:
368374
./dist/win-x86/bbs2gh-windows-386.exe
369375
./dist/win-x64/bbs2gh-windows-amd64.exe
370376
./dist/linux-x64/bbs2gh-linux-amd64
377+
./dist/linux-arm64/bbs2gh-linux-arm64
371378
./dist/osx-x64/bbs2gh-darwin-amd64
372379
373380
- name: Archive Release Notes

.github/workflows/integration-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ jobs:
113113
global-json-file: global.json
114114

115115
- name: Download Binaries
116-
uses: actions/download-artifact@v4
116+
uses: actions/download-artifact@v6
117117
with:
118118
name: binaries-${{ matrix.runner-os }}
119119
path: dist

.github/workflows/publish-test-results.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,9 @@ jobs:
3535
3636
- name: Extract PR Number
3737
run: |
38-
eventjson=`cat 'artifacts/Event File/event.json'`
39-
prnumber=`echo $(jq -r '.pull_request.number' <<< "$eventjson")`
40-
echo "PR_NUMBER=$(echo $prnumber | tr -cd '0-9')" >> $GITHUB_ENV
41-
38+
prnumber=$(jq -r '.pull_request.number' < 'artifacts/Event File/event.json')
39+
sanitized_prnumber=$(grep -E '^[0-9]+$' <<< "$prnumber")
40+
echo "PR_NUMBER=$sanitized_prnumber" >> "$GITHUB_ENV"
4241
- name: Publish Unit Test Results
4342
uses: EnricoMi/publish-unit-test-result-action@v2
4443
with:

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@ When the CLI is launched, it logs if a newer version of the CLI is available. Yo
9595

9696
When the CLI is launched, it logs a warning if there are any ongoing [GitHub incidents](https://www.githubstatus.com/) that might affect your use of the CLI. You can skip this check by setting the `GEI_SKIP_STATUS_CHECK` environment variable to `true`.
9797

98+
### Configuring multipart upload chunk size
99+
100+
Set the `GITHUB_OWNED_STORAGE_MULTIPART_MEBIBYTES` environment variable to change the archive upload part size. Provide the value in mebibytes (MiB); For example:
101+
102+
```powershell
103+
# Windows PowerShell
104+
$env:GITHUB_OWNED_STORAGE_MULTIPART_MEBIBYTES = "10"
105+
```
106+
107+
```bash
108+
# macOS/Linux
109+
export GITHUB_OWNED_STORAGE_MULTIPART_MEBIBYTES=10
110+
```
111+
112+
This sets the chunk size to 10 MiB (10,485,760 bytes). The minimum supported value is 5 MiB, and the default remains 100 MiB.
113+
114+
This might be needed to improve upload reliability in environments with proxies or very slow connections.
115+
98116
## Contributions
99117

100118
See [Contributing](CONTRIBUTING.md) for more info on how to get involved.

RELEASENOTES.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
1+
- Added support for linux-arm64 architecture for all CLI binaries (gei, ado2gh, bbs2gh), enabling users to run GEI on ARM-based systems including MacOS with Apple Silicon inside ARC runners
2+
- Fixed issue where alert migration commands (migrate-code-scanning-alerts, migrate-secret-alerts) required GH_PAT environment variable even when GitHub tokens were provided via command-line arguments (--github-source-pat, --github-target-pat). These commands now work correctly with CLI-only token authentication.
3+
- Added support for configurable multipart upload chunk size for GitHub-owned storage uploads via `GITHUB_OWNED_STORAGE_MULTIPART_MEBIBYTES` environment variable (minimum 5 MiB, default 100 MiB) to improve upload reliability in environments with proxies or slow connections

publish.ps1

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,21 @@ else {
5959
}
6060

6161
Copy-Item ./dist/linux-x64/ado2gh ./dist/linux-x64/ado2gh-linux-amd64
62+
63+
# linux-arm64 build
64+
dotnet publish src/ado2gh/ado2gh.csproj -c Release -o dist/linux-arm64/ -r linux-arm64 -p:PublishSingleFile=true -p:PublishTrimmed=true -p:TrimMode=partial --self-contained true /p:DebugType=None /p:IncludeNativeLibrariesForSelfExtract=true /p:VersionPrefix=$AssemblyVersion
65+
66+
if ($LASTEXITCODE -ne 0) {
67+
exit $LASTEXITCODE
68+
}
69+
70+
tar -cvzf ./dist/ado2gh.$AssemblyVersion.linux-arm64.tar.gz -C ./dist/linux-arm64 ado2gh
71+
72+
if (Test-Path -Path ./dist/linux-arm64/ado2gh-linux-arm64) {
73+
Remove-Item ./dist/linux-arm64/ado2gh-linux-arm64
74+
}
75+
76+
Copy-Item ./dist/linux-arm64/ado2gh ./dist/linux-arm64/ado2gh-linux-arm64
6277
}
6378

6479
if ((Test-Path env:SKIP_MACOS) -And $env:SKIP_MACOS.ToUpper() -eq "TRUE") {
@@ -126,6 +141,19 @@ else {
126141
}
127142

128143
Rename-Item ./dist/linux-x64/gei gei-linux-amd64
144+
145+
# linux-arm64 build
146+
dotnet publish src/gei/gei.csproj -c Release -o dist/linux-arm64/ -r linux-arm64 -p:PublishSingleFile=true -p:PublishTrimmed=true -p:TrimMode=partial --self-contained true /p:DebugType=None /p:IncludeNativeLibrariesForSelfExtract=true /p:VersionPrefix=$AssemblyVersion
147+
148+
if ($LASTEXITCODE -ne 0) {
149+
exit $LASTEXITCODE
150+
}
151+
152+
if (Test-Path -Path ./dist/linux-arm64/gei-linux-arm64) {
153+
Remove-Item ./dist/linux-arm64/gei-linux-arm64
154+
}
155+
156+
Rename-Item ./dist/linux-arm64/gei gei-linux-arm64
129157
}
130158

131159
if ((Test-Path env:SKIP_MACOS) -And $env:SKIP_MACOS.ToUpper() -eq "TRUE") {
@@ -190,6 +218,19 @@ else {
190218
}
191219

192220
Rename-Item ./dist/linux-x64/bbs2gh bbs2gh-linux-amd64
221+
222+
# linux-arm64 build
223+
dotnet publish src/bbs2gh/bbs2gh.csproj -c Release -o dist/linux-arm64/ -r linux-arm64 -p:PublishSingleFile=true -p:PublishTrimmed=true -p:TrimMode=partial --self-contained true /p:DebugType=None /p:IncludeNativeLibrariesForSelfExtract=true /p:VersionPrefix=$AssemblyVersion
224+
225+
if ($LASTEXITCODE -ne 0) {
226+
exit $LASTEXITCODE
227+
}
228+
229+
if (Test-Path -Path ./dist/linux-arm64/bbs2gh-linux-arm64) {
230+
Remove-Item ./dist/linux-arm64/bbs2gh-linux-arm64
231+
}
232+
233+
Rename-Item ./dist/linux-arm64/bbs2gh bbs2gh-linux-arm64
193234
}
194235

195236
if ((Test-Path env:SKIP_MACOS) -And $env:SKIP_MACOS.ToUpper() -eq "TRUE") {

src/Octoshift/Factories/GithubApiFactory.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ GithubApi ISourceGithubApiFactory.Create(string apiUrl, string uploadsUrl, strin
3232
uploadsUrl ??= DEFAULT_UPLOADS_URL;
3333
sourcePersonalAccessToken ??= _environmentVariableProvider.SourceGithubPersonalAccessToken();
3434
var githubClient = new GithubClient(_octoLogger, _clientFactory.CreateClient("Default"), _versionProvider, _retryPolicy, _dateTimeProvider, sourcePersonalAccessToken);
35-
var multipartUploader = new ArchiveUploader(githubClient, uploadsUrl, _octoLogger, _retryPolicy);
35+
var multipartUploader = new ArchiveUploader(githubClient, uploadsUrl, _octoLogger, _retryPolicy, _environmentVariableProvider);
3636
return new GithubApi(githubClient, apiUrl, _retryPolicy, multipartUploader);
3737
}
3838

@@ -42,7 +42,7 @@ GithubApi ISourceGithubApiFactory.CreateClientNoSsl(string apiUrl, string upload
4242
uploadsUrl ??= DEFAULT_UPLOADS_URL;
4343
sourcePersonalAccessToken ??= _environmentVariableProvider.SourceGithubPersonalAccessToken();
4444
var githubClient = new GithubClient(_octoLogger, _clientFactory.CreateClient("NoSSL"), _versionProvider, _retryPolicy, _dateTimeProvider, sourcePersonalAccessToken);
45-
var multipartUploader = new ArchiveUploader(githubClient, uploadsUrl, _octoLogger, _retryPolicy);
45+
var multipartUploader = new ArchiveUploader(githubClient, uploadsUrl, _octoLogger, _retryPolicy, _environmentVariableProvider);
4646
return new GithubApi(githubClient, apiUrl, _retryPolicy, multipartUploader);
4747
}
4848

@@ -52,7 +52,7 @@ GithubApi ITargetGithubApiFactory.Create(string apiUrl, string uploadsUrl, strin
5252
uploadsUrl ??= DEFAULT_UPLOADS_URL;
5353
targetPersonalAccessToken ??= _environmentVariableProvider.TargetGithubPersonalAccessToken();
5454
var githubClient = new GithubClient(_octoLogger, _clientFactory.CreateClient("Default"), _versionProvider, _retryPolicy, _dateTimeProvider, targetPersonalAccessToken);
55-
var multipartUploader = new ArchiveUploader(githubClient, uploadsUrl, _octoLogger, _retryPolicy);
55+
var multipartUploader = new ArchiveUploader(githubClient, uploadsUrl, _octoLogger, _retryPolicy, _environmentVariableProvider);
5656
return new GithubApi(githubClient, apiUrl, _retryPolicy, multipartUploader);
5757
}
5858
}

src/Octoshift/Services/ArchiveUploader.cs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,26 @@ namespace OctoshiftCLI.Services;
1111

1212
public class ArchiveUploader
1313
{
14+
private const int BYTES_PER_MEBIBYTE = 1024 * 1024;
15+
private const int MIN_MULTIPART_MEBIBYTES = 5; // 5 MiB minimum size for multipart upload. Don't allow overrides smaller than this.
16+
private const int DEFAULT_MULTIPART_MEBIBYTES = 100;
17+
1418
private readonly GithubClient _client;
1519
private readonly string _uploadsUrl;
1620
private readonly OctoLogger _log;
17-
internal int _streamSizeLimit = 100 * 1024 * 1024; // 100 MiB
21+
private readonly EnvironmentVariableProvider _environmentVariableProvider;
22+
internal int _streamSizeLimit = DEFAULT_MULTIPART_MEBIBYTES * BYTES_PER_MEBIBYTE; // 100 MiB stored in bytes
1823
private readonly RetryPolicy _retryPolicy;
1924

20-
public ArchiveUploader(GithubClient client, string uploadsUrl, OctoLogger log, RetryPolicy retryPolicy)
25+
public ArchiveUploader(GithubClient client, string uploadsUrl, OctoLogger log, RetryPolicy retryPolicy, EnvironmentVariableProvider environmentVariableProvider)
2126
{
2227
_client = client;
2328
_uploadsUrl = uploadsUrl;
2429
_log = log;
2530
_retryPolicy = retryPolicy;
31+
_environmentVariableProvider = environmentVariableProvider;
32+
33+
SetStreamSizeLimitFromEnvironment();
2634
}
2735
public virtual async Task<string> Upload(Stream archiveContent, string archiveName, string orgDatabaseId)
2836
{
@@ -160,4 +168,23 @@ private Uri GetNextUrl(IEnumerable<KeyValuePair<string, IEnumerable<string>>> he
160168
}
161169
throw new OctoshiftCliException("Location header is missing in the response, unable to retrieve next URL for multipart upload.");
162170
}
171+
172+
private void SetStreamSizeLimitFromEnvironment()
173+
{
174+
var envValue = _environmentVariableProvider.GithubOwnedStorageMultipartMebibytes();
175+
if (!int.TryParse(envValue, out var limitInMebibytes) || limitInMebibytes <= 0)
176+
{
177+
return;
178+
}
179+
180+
if (limitInMebibytes < MIN_MULTIPART_MEBIBYTES)
181+
{
182+
_log.LogWarning($"GITHUB_OWNED_STORAGE_MULTIPART_MEBIBYTES is set to {limitInMebibytes} MiB, but the minimum value is {MIN_MULTIPART_MEBIBYTES} MiB. Using default value of {DEFAULT_MULTIPART_MEBIBYTES} MiB.");
183+
return;
184+
}
185+
186+
var limitBytes = (int)((long)limitInMebibytes * BYTES_PER_MEBIBYTE);
187+
_streamSizeLimit = limitBytes;
188+
_log.LogInformation($"Multipart upload part size set to {limitInMebibytes} MiB.");
189+
}
163190
}

src/Octoshift/Services/EnvironmentVariableProvider.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class EnvironmentVariableProvider
1818
private const string SMB_PASSWORD = "SMB_PASSWORD";
1919
private const string GEI_SKIP_STATUS_CHECK = "GEI_SKIP_STATUS_CHECK";
2020
private const string GEI_SKIP_VERSION_CHECK = "GEI_SKIP_VERSION_CHECK";
21+
private const string GITHUB_OWNED_STORAGE_MULTIPART_MEBIBYTES = "GITHUB_OWNED_STORAGE_MULTIPART_MEBIBYTES";
2122

2223
private readonly OctoLogger _logger;
2324

@@ -65,6 +66,9 @@ public virtual string SkipStatusCheck(bool throwIfNotFound = false) =>
6566
public virtual string SkipVersionCheck(bool throwIfNotFound = false) =>
6667
GetValue(GEI_SKIP_VERSION_CHECK, throwIfNotFound);
6768

69+
public virtual string GithubOwnedStorageMultipartMebibytes(bool throwIfNotFound = false) =>
70+
GetValue(GITHUB_OWNED_STORAGE_MULTIPART_MEBIBYTES, throwIfNotFound);
71+
6872
private string GetValue(string name, bool throwIfNotFound)
6973
{
7074
var value = Environment.GetEnvironmentVariable(name);

src/OctoshiftCLI.IntegrationTests/BbsToGithub.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ public BbsToGithub(ITestOutputHelper output)
6060
_targetGithubHttpClient = new HttpClient();
6161
_targetGithubClient = new GithubClient(_logger, _targetGithubHttpClient, new VersionChecker(_versionClient, _logger), new RetryPolicy(_logger), new DateTimeProvider(), targetGithubToken);
6262
var retryPolicy = new RetryPolicy(_logger);
63-
_archiveUploader = new ArchiveUploader(_targetGithubClient, UPLOADS_URL, _logger, retryPolicy);
63+
var environmentVariableProvider = new EnvironmentVariableProvider(_logger);
64+
_archiveUploader = new ArchiveUploader(_targetGithubClient, UPLOADS_URL, _logger, retryPolicy, environmentVariableProvider);
6465
_targetGithubApi = new GithubApi(_targetGithubClient, "https://api.github.com", new RetryPolicy(_logger), _archiveUploader);
6566

6667
_blobServiceClient = new BlobServiceClient(_azureStorageConnectionString);

0 commit comments

Comments
 (0)