Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(syncer): Fix for windows binaries in action runner syncer #1716

Merged
merged 10 commits into from
Feb 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/windows/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,22 @@ jest.mock('aws-sdk', () => ({
}));

const bucketName = 'my-bucket';
const bucketObjectKey = 'actions-runner-linux.tar.gz';
const objectExtension: Record<string, string> = {
linux: '.tar.gz',
win: '.zip',
};
const bucketObjectNames: Record<string, string> = {
linux: `actions-runner-linux${objectExtension['linux']}`,
win: `actions-runner-windows${objectExtension['win']}`,
};

const bucketObjectKey = (os: string) => bucketObjectNames[os];

const runnerOs = [['linux'], ['win']];

const latestRelease = '2.287.0';
const latestPreRelease = '2.287.1';

beforeEach(() => {
jest.clearAllMocks();
});
Expand All @@ -51,19 +66,22 @@ jest.setTimeout(60 * 1000);
describe('Synchronize action distribution.', () => {
beforeEach(() => {
process.env.S3_BUCKET_NAME = bucketName;
process.env.S3_OBJECT_KEY = bucketObjectKey;
process.env.GITHUB_RUNNER_ALLOW_PRERELEASE_BINARIES = 'false';

mockOctokit.repos.listReleases.mockImplementation(() => ({
data: listReleases,
}));
});

it('Distribution is up-to-date with latest release.', async () => {
test.each(runnerOs)('%p Distribution is up-to-date with latest release.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
return Promise.resolve({ TagSet: [{ Key: 'name', Value: 'actions-runner-linux-x64-2.285.1.tar.gz' }] });
return Promise.resolve({
TagSet: [{ Key: 'name', Value: `actions-runner-${os}-x64-${latestRelease}${objectExtension[os]}` }],
});
},
};
});
Expand All @@ -72,22 +90,52 @@ describe('Synchronize action distribution.', () => {
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey,
Key: bucketObjectKey(os),
});
expect(mockS3.upload).toBeCalledTimes(0);
});

it('Distribution is up-to-date with latest release when there are no prereleases.', async () => {
test.each(runnerOs)(
'%p Distribution is up-to-date with latest release when there are no prereleases.',
async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
process.env.GITHUB_RUNNER_ALLOW_PRERELEASE_BINARIES = 'true';
const releases = listReleases.slice(1);

mockOctokit.repos.listReleases.mockImplementation(() => ({
data: releases,
}));
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
return Promise.resolve({
TagSet: [{ Key: 'name', Value: `actions-runner-${os}-x64-${latestRelease}${objectExtension[os]}` }],
});
},
};
});

await sync();
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey(os),
});
expect(mockS3.upload).toBeCalledTimes(0);
},
);

test.each(runnerOs)('%p Distribution is up-to-date with latest prerelease.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
process.env.GITHUB_RUNNER_ALLOW_PRERELEASE_BINARIES = 'true';
const releases = listReleases.slice(1);

mockOctokit.repos.listReleases.mockImplementation(() => ({
data: releases,
}));
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
return Promise.resolve({ TagSet: [{ Key: 'name', Value: 'actions-runner-linux-x64-2.285.1.tar.gz' }] });
return Promise.resolve({
TagSet: [{ Key: 'name', Value: `actions-runner-${os}-x64-${latestPreRelease}${objectExtension[os]}` }],
});
},
};
});
Expand All @@ -96,17 +144,20 @@ describe('Synchronize action distribution.', () => {
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey,
Key: bucketObjectKey(os),
});
expect(mockS3.upload).toBeCalledTimes(0);
});

it('Distribution is up-to-date with latest prerelease.', async () => {
process.env.GITHUB_RUNNER_ALLOW_PRERELEASE_BINARIES = 'true';
test.each(runnerOs)('%p Distribution should update to release.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
return Promise.resolve({ TagSet: [{ Key: 'name', Value: 'actions-runner-linux-x64-2.286.0.tar.gz' }] });
return Promise.resolve({
TagSet: [{ Key: 'name', Value: `actions-runner-${os}-x64-0${objectExtension[os]}` }],
});
},
};
});
Expand All @@ -115,32 +166,16 @@ describe('Synchronize action distribution.', () => {
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey,
});
expect(mockS3.upload).toBeCalledTimes(0);
});

it('Distribution should update to release.', async () => {
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
return Promise.resolve({ TagSet: [{ Key: 'name', Value: 'actions-runner-linux-x64-0.tar.gz' }] });
},
};
});

await sync();
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey,
Key: bucketObjectKey(os),
});
expect(mockS3.upload).toBeCalledTimes(1);
const s3JsonBody = mockS3.upload.mock.calls[0][0];
expect(s3JsonBody['Tagging']).toEqual('name=actions-runner-linux-x64-2.285.1.tar.gz');
expect(s3JsonBody['Tagging']).toEqual(`name=actions-runner-${os}-x64-${latestRelease}${objectExtension[os]}`);
});

it('Distribution should update to release if there are no pre-releases.', async () => {
test.each(runnerOs)('%p Distribution should update to release if there are no pre-releases.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
process.env.GITHUB_RUNNER_ALLOW_PRERELEASE_BINARIES = 'true';
const releases = listReleases.slice(1);

Expand All @@ -150,7 +185,9 @@ describe('Synchronize action distribution.', () => {
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
return Promise.resolve({ TagSet: [{ Key: 'name', Value: 'actions-runner-linux-x64-0.tar.gz' }] });
return Promise.resolve({
TagSet: [{ Key: 'name', Value: `actions-runner-${os}-x64-0${objectExtension[os]}` }],
});
},
};
});
Expand All @@ -159,19 +196,23 @@ describe('Synchronize action distribution.', () => {
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey,
Key: bucketObjectKey(os),
});
expect(mockS3.upload).toBeCalledTimes(1);
const s3JsonBody = mockS3.upload.mock.calls[0][0];
expect(s3JsonBody['Tagging']).toEqual('name=actions-runner-linux-x64-2.285.1.tar.gz');
expect(s3JsonBody['Tagging']).toEqual(`name=actions-runner-${os}-x64-${latestRelease}${objectExtension[os]}`);
});

it('Distribution should update to prerelease.', async () => {
test.each(runnerOs)('%p Distribution should update to prerelease.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
process.env.GITHUB_RUNNER_ALLOW_PRERELEASE_BINARIES = 'true';
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
return Promise.resolve({ TagSet: [{ Key: 'name', Value: 'actions-runner-linux-x64-0.tar.gz' }] });
return Promise.resolve({
TagSet: [{ Key: 'name', Value: `actions-runner-${os}-x64-0${objectExtension[os]}` }],
});
},
};
});
Expand All @@ -180,14 +221,16 @@ describe('Synchronize action distribution.', () => {
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey,
Key: bucketObjectKey(os),
});
expect(mockS3.upload).toBeCalledTimes(1);
const s3JsonBody = mockS3.upload.mock.calls[0][0];
expect(s3JsonBody['Tagging']).toEqual('name=actions-runner-linux-x64-2.286.0.tar.gz');
expect(s3JsonBody['Tagging']).toEqual(`name=actions-runner-${os}-x64-${latestPreRelease}${objectExtension[os]}`);
});

it('Distribution should not update to prerelease if there is a newer release.', async () => {
test.each(runnerOs)('%p Distribution should not update to prerelease if there is a newer release.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
process.env.GITHUB_RUNNER_ALLOW_PRERELEASE_BINARIES = 'true';
const releases = listReleases;
releases[0].prerelease = false;
Expand All @@ -199,7 +242,9 @@ describe('Synchronize action distribution.', () => {
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
return Promise.resolve({ TagSet: [{ Key: 'name', Value: 'actions-runner-linux-x64-0.tar.gz' }] });
return Promise.resolve({
TagSet: [{ Key: 'name', Value: `actions-runner-${os}-x64-0${objectExtension[os]}` }],
});
},
};
});
Expand All @@ -208,14 +253,16 @@ describe('Synchronize action distribution.', () => {
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey,
Key: bucketObjectKey(os),
});
expect(mockS3.upload).toBeCalledTimes(1);
const s3JsonBody = mockS3.upload.mock.calls[0][0];
expect(s3JsonBody['Tagging']).toEqual('name=actions-runner-linux-x64-2.286.0.tar.gz');
expect(s3JsonBody['Tagging']).toEqual(`name=actions-runner-${os}-x64-${latestPreRelease}${objectExtension[os]}`);
});

it('No tag in S3, distribution should update.', async () => {
test.each(runnerOs)('%p No tag in S3, distribution should update.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
Expand All @@ -228,12 +275,14 @@ describe('Synchronize action distribution.', () => {
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey,
Key: bucketObjectKey(os),
});
expect(mockS3.upload).toBeCalledTimes(1);
});

it('Tags, but no version, distribution should update.', async () => {
test.each(runnerOs)('%p Tags, but no version, distribution should update.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
mockS3.getObjectTagging.mockImplementation(() => {
return {
promise() {
Expand All @@ -246,7 +295,7 @@ describe('Synchronize action distribution.', () => {
expect(mockOctokit.repos.listReleases).toBeCalledTimes(1);
expect(mockS3.getObjectTagging).toBeCalledWith({
Bucket: bucketName,
Key: bucketObjectKey,
Key: bucketObjectKey(os),
});
expect(mockS3.upload).toBeCalledTimes(1);
});
Expand All @@ -256,7 +305,7 @@ describe('No release assets found.', () => {
const errorMessage = 'Cannot find GitHub release asset.';
beforeEach(() => {
process.env.S3_BUCKET_NAME = bucketName;
process.env.S3_OBJECT_KEY = bucketObjectKey;
process.env.S3_OBJECT_KEY = bucketObjectKey('linux');
});

it('Empty list of assets.', async () => {
Expand All @@ -267,7 +316,9 @@ describe('No release assets found.', () => {
await expect(sync()).rejects.toThrow(errorMessage);
});

it('No linux x64 asset.', async () => {
test.each(runnerOs)('No %p x64 asset.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
mockOctokit.repos.listReleases.mockImplementation(() => ({
data: [listReleasesNoLinux],
}));
Expand All @@ -293,7 +344,7 @@ describe('Invalid config', () => {
});
it('No bucket.', async () => {
delete process.env.S3_BUCKET_NAME;
process.env.S3_OBJECT_KEY = bucketObjectKey;
process.env.S3_OBJECT_KEY = bucketObjectKey('linux');
await expect(sync()).rejects.toThrow(errorMessage);
});
it('No object key.', async () => {
Expand All @@ -307,35 +358,16 @@ describe('Synchronize action distribution for arm64.', () => {
const errorMessage = 'Cannot find GitHub release asset.';
beforeEach(() => {
process.env.S3_BUCKET_NAME = bucketName;
process.env.S3_OBJECT_KEY = bucketObjectKey;
process.env.GITHUB_RUNNER_ARCHITECTURE = 'arm64';
});

it('No linux arm64 asset.', async () => {
test.each(runnerOs)('No %p arm64 asset.', async (os) => {
process.env.S3_OBJECT_KEY = bucketObjectKey(os);
process.env.GITHUB_RUNNER_OS = os;
mockOctokit.repos.listReleases.mockImplementation(() => ({
data: [listReleasesNoArm64],
}));

await expect(sync()).rejects.toThrow(errorMessage);
});
});

describe('Synchronize action distribution for windows.', () => {
const errorMessage = 'Cannot find GitHub release asset.';
beforeEach(() => {
process.env.S3_BUCKET_NAME = bucketName;
process.env.S3_OBJECT_KEY = bucketObjectKey;
process.env.GITHUB_RUNNER_OS = 'win';
});

it('No win asset.', async () => {
mockOctokit.repos.listReleases.mockImplementation(() => ({
data: listReleases.map((release) => ({
...release,
assets: release.assets.filter((asset) => !asset.name.includes('win')),
})),
}));

await expect(sync()).rejects.toThrow(errorMessage);
});
});
Loading