Skip to content

Commit 263c2eb

Browse files
committed
feat: add cumulative update support
1 parent 896253f commit 263c2eb

File tree

7 files changed

+2011
-2616
lines changed

7 files changed

+2011
-2616
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ See [action.yml](./action.yml):
3939
# action. A maximum of 10 attempts is made.
4040
# Default: true
4141
wait-for-ready: true
42+
43+
# Attempt to install latest cumulative updates during the installation process
44+
# (not available for all versions).
45+
# Default: false
46+
install-updates: false
4247
```
4348
<!-- end usage -->
4449

action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ inputs:
2424
description: 'Wait for the database to respond successfully to queries before completing the action. A maximum of 10 attempts is made.'
2525
default: 'true'
2626
install-updates:
27-
description: 'Opt-in to install latest updates during the isntallation process'
27+
description: 'Attempt to install latest cumulative updates during the installation process (not available for all versions).'
2828
default: 'false'
2929
outputs:
3030
sa-password:

lib/main/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 1940 additions & 2612 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"@actions/core": "^1.10.0",
5858
"@actions/exec": "^1.1.1",
5959
"@actions/glob": "^0.4.0",
60+
"@actions/http-client": "^2.2.1",
6061
"@actions/io": "^1.1.3",
6162
"@actions/tool-cache": "^2.0.1"
6263
}

src/install.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import os from 'os';
2-
import { basename, join as joinPaths } from 'path';
2+
import { basename, dirname, join as joinPaths } from 'path';
33
import { readFile } from 'fs/promises';
44
import * as core from '@actions/core';
55
import * as exec from '@actions/exec';
@@ -8,6 +8,7 @@ import { VersionConfig, VERSIONS } from './versions';
88
import {
99
downloadBoxInstaller,
1010
downloadExeInstaller,
11+
downloadUpdateInstaller,
1112
gatherInputs,
1213
gatherSummaryFiles,
1314
getOsVersion,
@@ -33,6 +34,15 @@ function findOrDownloadTool(config: VersionConfig): Promise<string> {
3334
return downloadExeInstaller(config);
3435
}
3536

37+
function findOrDownloadUpdates(config: VersionConfig): Promise<string> {
38+
const toolPath = tc.find('sqlupdate', config.version);
39+
if (toolPath) {
40+
core.info(`Found in cache @ ${toolPath}`);
41+
return Promise.resolve(joinPaths(toolPath, 'sqlupdate.exe'));
42+
}
43+
return downloadUpdateInstaller(config);
44+
}
45+
3646
export default async function install() {
3747
let threw = false;
3848
const {
@@ -44,6 +54,7 @@ export default async function install() {
4454
skipOsCheck,
4555
nativeClientVersion,
4656
odbcVersion,
57+
installUpdates,
4758
} = gatherInputs();
4859
// we only support windows for now. But allow crazy people to skip this check if they like...
4960
if (!skipOsCheck && os.platform() !== 'win32') {
@@ -86,6 +97,16 @@ export default async function install() {
8697
}
8798
// Initial checks complete - fetch the installer
8899
const toolPath = await core.group(`Fetching install media for ${version}`, () => findOrDownloadTool(config));
100+
if (installUpdates) {
101+
if (!config.updateUrl) {
102+
core.info('Skipping update installation - version not supported');
103+
} else {
104+
const updatePath = await core.group(`Fetching cumulative updates for ${version}`, () => findOrDownloadUpdates(config));
105+
if (updatePath) {
106+
installArgs.push('/UPDATEENABLED=1', `/UpdateSource=${dirname(updatePath)}`);
107+
}
108+
}
109+
}
89110
const instanceName = 'MSSQLSERVER';
90111
try {
91112
// @todo - make sure that the arguments are unique / don't conflict

src/utils.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as exec from '@actions/exec';
22
import * as core from '@actions/core';
33
import * as tc from '@actions/tool-cache';
44
import * as io from '@actions/io';
5+
import * as http from '@actions/http-client';
56
import { basename, extname, dirname, join as joinPaths } from 'path';
67
import { VersionConfig } from './versions';
78
import { generateFileHash } from './crypto';
@@ -50,6 +51,7 @@ export interface Inputs {
5051
skipOsCheck: boolean;
5152
nativeClientVersion: string;
5253
odbcVersion: string;
54+
installUpdates: boolean;
5355
}
5456

5557
/**
@@ -68,6 +70,7 @@ export function gatherInputs(): Inputs {
6870
skipOsCheck: core.getBooleanInput('skip-os-check'),
6971
nativeClientVersion: core.getInput('native-client-version'),
7072
odbcVersion: core.getInput('odbc-version'),
73+
installUpdates: core.getBooleanInput('install-updates'),
7174
};
7275
}
7376

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

173-
176+
/**
177+
* Downloads cumulative updates for supported versions.
178+
*
179+
* @param {VersionConfig} config
180+
* @returns {Promise<string>}
181+
*/
182+
export async function downloadUpdateInstaller(config: VersionConfig): Promise<string> {
183+
if (!config.updateUrl) {
184+
throw new Error('No update url provided');
185+
}
186+
// resolve download url
187+
let downloadLink: string | null = null;
188+
if (!config.updateUrl.endsWith('.exe')) {
189+
const client = new http.HttpClient();
190+
const res = await client.get(config.updateUrl);
191+
if (res.message.statusCode && res.message.statusCode >= 200 && res.message.statusCode < 300) {
192+
const body = await res.readBody();
193+
const [, link] = body.match(/\s+href\s*=\s*["'](https:\/\/download\.microsoft\.com\/.*\.exe)['"]/) ?? [];
194+
if (link) {
195+
core.info(`Found download link: ${link}`);
196+
downloadLink = link;
197+
}
198+
}
199+
if (!downloadLink) {
200+
core.warning('Unable to download cumulative updates');
201+
return '';
202+
}
203+
}
204+
const updatePath = await downloadTool(downloadLink ?? config.updateUrl);
205+
if (core.isDebug()) {
206+
const hash = await generateFileHash(updatePath);
207+
core.debug(`Got update file with hash SHA256=${hash.toString('base64')}`);
208+
}
209+
core.info('Adding to the cache');
210+
const toolPath = await tc.cacheFile(updatePath, 'sqlupdate.exe', 'sqlupdate', config.version);
211+
core.debug(`Cached @ ${toolPath}`);
212+
return joinPaths(toolPath, 'sqlupdate.exe');
213+
}
174214

175215
/**
176216
* Gather installation summary file. Used after installation to output summary data.

0 commit comments

Comments
 (0)