Skip to content

Commit

Permalink
feat: add cumulative update installation for supported versions
Browse files Browse the repository at this point in the history
  • Loading branch information
dhensby committed Aug 8, 2024
1 parent 200d7c9 commit fdf5fad
Show file tree
Hide file tree
Showing 11 changed files with 2,039 additions and 2,615 deletions.
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ jobs:
sqlserver-version: ${{ matrix.sqlserver }}
native-client-version: 11
odbc-version: 17
install-updates: true
release:
name: Release
concurrency: release
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ See [action.yml](./action.yml):
# action. A maximum of 10 attempts is made.
# Default: true
wait-for-ready: true

# Attempt to install latest cumulative updates during the installation process
# (not available for all versions).
# Default: false
install-updates: false
```
<!-- end usage -->
Expand Down
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ inputs:
wait-for-ready:
description: 'Wait for the database to respond successfully to queries before completing the action. A maximum of 10 attempts is made.'
default: 'true'
install-updates:
description: 'Attempt to install latest cumulative updates during the installation process (not available for all versions).'
default: 'false'
outputs:
sa-password:
description: 'The SA password, this will be the same as the input, but can be useful when relying on the default value.'
Expand Down
2 changes: 1 addition & 1 deletion lib/main/index.js

Large diffs are not rendered by default.

4,552 changes: 1,940 additions & 2,612 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"@actions/core": "^1.10.0",
"@actions/exec": "^1.1.1",
"@actions/glob": "^0.4.0",
"@actions/http-client": "^2.2.1",
"@actions/io": "^1.1.3",
"@actions/tool-cache": "^2.0.1"
}
Expand Down
23 changes: 22 additions & 1 deletion src/install.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os from 'os';
import { basename, join as joinPaths } from 'path';
import { basename, dirname, join as joinPaths } from 'path';
import { readFile } from 'fs/promises';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
Expand All @@ -8,6 +8,7 @@ import { VersionConfig, VERSIONS } from './versions';
import {
downloadBoxInstaller,
downloadExeInstaller,
downloadUpdateInstaller,
gatherInputs,
gatherSummaryFiles,
getOsVersion,
Expand All @@ -33,6 +34,15 @@ function findOrDownloadTool(config: VersionConfig): Promise<string> {
return downloadExeInstaller(config);
}

function findOrDownloadUpdates(config: VersionConfig): Promise<string> {
const toolPath = tc.find('sqlupdate', config.version);
if (toolPath) {
core.info(`Found in cache @ ${toolPath}`);
return Promise.resolve(joinPaths(toolPath, 'sqlupdate.exe'));
}
return downloadUpdateInstaller(config);
}

export default async function install() {
let threw = false;
const {
Expand All @@ -44,6 +54,7 @@ export default async function install() {
skipOsCheck,
nativeClientVersion,
odbcVersion,
installUpdates,
} = gatherInputs();
// we only support windows for now. But allow crazy people to skip this check if they like...
if (!skipOsCheck && os.platform() !== 'win32') {
Expand Down Expand Up @@ -86,6 +97,16 @@ export default async function install() {
}
// Initial checks complete - fetch the installer
const toolPath = await core.group(`Fetching install media for ${version}`, () => findOrDownloadTool(config));
if (installUpdates) {
if (!config.updateUrl) {
core.info('Skipping update installation - version not supported');
} else {
const updatePath = await core.group(`Fetching cumulative updates for ${version}`, () => findOrDownloadUpdates(config));
if (updatePath) {
installArgs.push('/UPDATEENABLED=1', `/UpdateSource=${dirname(updatePath)}`);
}
}
}
const instanceName = 'MSSQLSERVER';
try {
// @todo - make sure that the arguments are unique / don't conflict
Expand Down
42 changes: 41 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as exec from '@actions/exec';
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import * as io from '@actions/io';
import * as http from '@actions/http-client';
import { basename, extname, dirname, join as joinPaths } from 'path';
import { VersionConfig } from './versions';
import { generateFileHash } from './crypto';
Expand Down Expand Up @@ -50,6 +51,7 @@ export interface Inputs {
skipOsCheck: boolean;
nativeClientVersion: string;
odbcVersion: string;
installUpdates: boolean;
}

/**
Expand All @@ -68,6 +70,7 @@ export function gatherInputs(): Inputs {
skipOsCheck: core.getBooleanInput('skip-os-check'),
nativeClientVersion: core.getInput('native-client-version'),
odbcVersion: core.getInput('odbc-version'),
installUpdates: core.getBooleanInput('install-updates'),
};
}

Expand Down Expand Up @@ -170,7 +173,44 @@ export async function downloadExeInstaller(config: VersionConfig): Promise<strin
return joinPaths(toolPath, 'setup.exe');
}


/**
* Downloads cumulative updates for supported versions.
*
* @param {VersionConfig} config
* @returns {Promise<string>}
*/
export async function downloadUpdateInstaller(config: VersionConfig): Promise<string> {
if (!config.updateUrl) {
throw new Error('No update url provided');
}
// resolve download url
let downloadLink: string | null = null;
if (!config.updateUrl.endsWith('.exe')) {
const client = new http.HttpClient();
const res = await client.get(config.updateUrl);
if (res.message.statusCode && res.message.statusCode >= 200 && res.message.statusCode < 300) {
const body = await res.readBody();
const [, link] = body.match(/\s+href\s*=\s*["'](https:\/\/download\.microsoft\.com\/.*\.exe)['"]/) ?? [];
if (link) {
core.info(`Found download link: ${link}`);
downloadLink = link;
}
}
if (!downloadLink) {
core.warning('Unable to download cumulative updates');
return '';
}
}
const updatePath = await downloadTool(downloadLink ?? config.updateUrl);
if (core.isDebug()) {
const hash = await generateFileHash(updatePath);
core.debug(`Got update file with hash SHA256=${hash.toString('base64')}`);
}
core.info('Adding to the cache');
const toolPath = await tc.cacheFile(updatePath, 'sqlupdate.exe', 'sqlupdate', config.version);
core.debug(`Cached @ ${toolPath}`);
return joinPaths(toolPath, 'sqlupdate.exe');
}

/**
* Gather installation summary file. Used after installation to output summary data.
Expand Down
5 changes: 5 additions & 0 deletions src/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface Config {
export interface VersionConfig extends Config {
exeUrl: string;
boxUrl?: string;
updateUrl?: string;
}

export const VERSIONS = new Map<string, VersionConfig>(
Expand All @@ -20,21 +21,25 @@ export const VERSIONS = new Map<string, VersionConfig>(
version: '2022',
exeUrl: 'https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLServer2022-DEV-x64-ENU.exe',
boxUrl: 'https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLServer2022-DEV-x64-ENU.box',
updateUrl: 'https://www.microsoft.com/en-us/download/details.aspx?id=105013',
}],
['2019', {
version: '2019',
exeUrl: 'https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLServer2019-DEV-x64-ENU.exe',
boxUrl: 'https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLServer2019-DEV-x64-ENU.box',
updateUrl: 'https://www.microsoft.com/en-us/download/details.aspx?id=100809',
}],
['2017', {
version: '2017',
exeUrl: 'https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLServer2017-DEV-x64-ENU.exe',
boxUrl: 'https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLServer2017-DEV-x64-ENU.box',
updateUrl: 'https://www.microsoft.com/en-us/download/details.aspx?id=56128',
}],
['2016', {
version: '2016',
exeUrl: 'https://download.microsoft.com/download/4/1/A/41AD6EDE-9794-44E3-B3D5-A1AF62CD7A6F/sql16_sp2_dlc/en-us/SQLServer2016SP2-FullSlipstream-DEV-x64-ENU.exe',
boxUrl: 'https://download.microsoft.com/download/4/1/A/41AD6EDE-9794-44E3-B3D5-A1AF62CD7A6F/sql16_sp2_dlc/en-us/SQLServer2016SP2-FullSlipstream-DEV-x64-ENU.box',
updateUrl: 'https://download.microsoft.com/download/a/7/7/a77b5753-8fe7-4804-bfc5-591d9a626c98/SQLServer2016SP3-KB5003279-x64-ENU.exe',
}],
['2014', {
osSupport: {
Expand Down
12 changes: 12 additions & 0 deletions test/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
utilsStub.getOsVersion.resolves(2022);
utilsStub.gatherSummaryFiles.resolves([]);
Expand Down Expand Up @@ -115,6 +116,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
try {
await install();
Expand All @@ -138,6 +140,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
await install();
expect(execStub.exec).to.have.been.calledWith('"C:/tmp/exe/setup.exe"', match.array, { windowsVerbatimArguments: true });
Expand All @@ -157,6 +160,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
try {
await install();
Expand All @@ -177,6 +181,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
try {
await install();
Expand All @@ -197,6 +202,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
try {
await install();
Expand All @@ -217,6 +223,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
await install();
expect(execStub.exec).to.have.been.calledWith('"C:/tmp/exe/setup.exe"', match.array, { windowsVerbatimArguments: true });
Expand All @@ -232,6 +239,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
await install();
expect(execStub.exec).to.have.been.calledWith('"C:/tmp/exe/setup.exe"', match.array, { windowsVerbatimArguments: true });
Expand All @@ -246,6 +254,7 @@ describe('install', () => {
skipOsCheck: true,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
await install();
expect(execStub.exec).to.have.been.calledWith('"C:/tmp/exe/setup.exe"', match.array, { windowsVerbatimArguments: true });
Expand Down Expand Up @@ -282,6 +291,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
const stubReadfile = stub(fs, 'readFile');
stubReadfile.resolves(Buffer.from('test data'));
Expand Down Expand Up @@ -327,6 +337,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '11',
odbcVersion: '',
installUpdates: false,
});
await install();
expect(stubNc.default).to.have.been.calledOnceWith('11');
Expand All @@ -341,6 +352,7 @@ describe('install', () => {
skipOsCheck: false,
nativeClientVersion: '11',
odbcVersion: '18',
installUpdates: false,
});
await install();
expect(stubNc.default).to.have.been.calledOnceWith('11');
Expand Down
8 changes: 8 additions & 0 deletions test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ describe('utils', () => {
coreStub.getMultilineInput.withArgs('install-arguments').returns([]);
coreStub.getBooleanInput.withArgs('wait-for-ready').returns(true);
coreStub.getBooleanInput.withArgs('skip-os-check').returns(false);
coreStub.getBooleanInput.withArgs('install-updates').returns(false);
const res = utils.gatherInputs();
expect(res).to.deep.equal({
version: '2022',
Expand All @@ -202,6 +203,7 @@ describe('utils', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
});
it('constructs input object with no sql- prefix', () => {
Expand All @@ -213,6 +215,7 @@ describe('utils', () => {
coreStub.getMultilineInput.withArgs('install-arguments').returns([]);
coreStub.getBooleanInput.withArgs('wait-for-ready').returns(true);
coreStub.getBooleanInput.withArgs('skip-os-check').returns(false);
coreStub.getBooleanInput.withArgs('install-updates').returns(false);
const res = utils.gatherInputs();
expect(res).to.deep.equal({
version: '2022',
Expand All @@ -223,6 +226,7 @@ describe('utils', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
});
it('constructs input object with "latest" version', () => {
Expand All @@ -234,6 +238,7 @@ describe('utils', () => {
coreStub.getMultilineInput.withArgs('install-arguments').returns([]);
coreStub.getBooleanInput.withArgs('wait-for-ready').returns(true);
coreStub.getBooleanInput.withArgs('skip-os-check').returns(false);
coreStub.getBooleanInput.withArgs('install-updates').returns(false);
const res = utils.gatherInputs();
expect(res).to.deep.equal({
version: '2022',
Expand All @@ -244,6 +249,7 @@ describe('utils', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
});
it('constructs input object with default version', () => {
Expand All @@ -255,6 +261,7 @@ describe('utils', () => {
coreStub.getMultilineInput.withArgs('install-arguments').returns([]);
coreStub.getBooleanInput.withArgs('wait-for-ready').returns(true);
coreStub.getBooleanInput.withArgs('skip-os-check').returns(false);
coreStub.getBooleanInput.withArgs('install-updates').returns(false);
const res = utils.gatherInputs();
expect(res).to.deep.equal({
version: '2022',
Expand All @@ -265,6 +272,7 @@ describe('utils', () => {
skipOsCheck: false,
nativeClientVersion: '',
odbcVersion: '',
installUpdates: false,
});
});
});
Expand Down

0 comments on commit fdf5fad

Please sign in to comment.