Skip to content

Commit 0db9b7e

Browse files
authored
Merge pull request #5 from dhensby/pulls/installers
feat: add ODBC driver install step
2 parents 7694a7e + 62dde57 commit 0db9b7e

19 files changed

+651
-58
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ jobs:
146146
with:
147147
sqlserver-version: ${{ matrix.sqlserver }}
148148
native-client-version: 11
149+
odbc-version: 17
149150
release:
150151
name: Release
151152
concurrency: release

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,25 @@ See [action.yml](./action.yml):
1111
with:
1212
# Skip OS checks that will stop installation attempts preemptively.
1313
# Default: false
14-
skip-os-check: ''
14+
skip-os-check: false
1515

1616
# Version to use. Examples: 2008, 2012, 2014, etc. "latest" can also be used.
1717
# Default: latest
18-
sqlserver-version: ''
18+
sqlserver-version: 'latest'
1919

20-
# Version of native client to installer. Only 11 is supported.
20+
# Version of native client to install. Only 11 is supported.
2121
native-client-version: ''
2222

23+
# Version of ODBC to install. Supported versions: 17, 18.
24+
odbc-version: ''
25+
2326
# The SA user password to use.
2427
# Default: yourStrong(!)Password
25-
sa-password: ''
28+
sa-password: 'yourStrong(!)Password'
2629

2730
# The database collation to use.
2831
# Default: SQL_Latin1_General_CP1_CI_AS
29-
db-collation: ''
32+
db-collation: 'SQL_Latin1_General_CP1_CI_AS'
3033

3134
# Any custom install arguments you wish to use. These must be in the format of
3235
# "/ARG=VAL".
@@ -35,7 +38,7 @@ See [action.yml](./action.yml):
3538
# Wait for the database to respond successfully to queries before completing the
3639
# action. A maximum of 10 attempts is made.
3740
# Default: true
38-
wait-for-ready: ''
41+
wait-for-ready: true
3942
```
4043
<!-- end usage -->
4144

action.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ inputs:
99
description: 'Version to use. Examples: 2008, 2012, 2014, etc. "latest" can also be used.'
1010
default: 'latest'
1111
native-client-version:
12-
description: 'Version of native client to installer. Only 11 is supported.'
12+
description: 'Version of native client to install. Only 11 is supported.'
13+
odbc-version:
14+
description: 'Version of ODBC to install. Supported versions: 17, 18.'
1315
sa-password:
1416
description: 'The SA user password to use.'
1517
default: 'yourStrong(!)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.

misc/generate-docs.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ function updateUsage(
9595
// Constrain the width of the description
9696
const width = 80;
9797
let description = (input.description as string)
98-
.trimRight()
98+
.trimEnd()
9999
.replace(/\r\n/g, '\n') // Convert CR to LF
100100
.replace(/ +/g, ' ') // Squash consecutive spaces
101101
.replace(/ \n/g, '\n'); // Squash space followed by newline
@@ -123,15 +123,15 @@ function updateUsage(
123123
}
124124

125125
// Append segment
126-
newReadme.push(` # ${segment}`.trimRight());
126+
newReadme.push(` # ${segment}`.trimEnd());
127127

128128
// Remaining
129129
description = description.substr(segment.length);
130130
}
131131

132132
if (input.default !== undefined) {
133133
// Append blank line if description had paragraphs
134-
if ((input.description as string).trimRight().match(/\n[ ]*\r?\n/)) {
134+
if ((input.description as string).trimEnd().match(/\n[ ]*\r?\n/)) {
135135
newReadme.push(` #`);
136136
}
137137

@@ -140,7 +140,16 @@ function updateUsage(
140140
}
141141

142142
// Input name
143-
newReadme.push(` ${key}: ''`);
143+
let inputValue: string;
144+
switch (input.default) {
145+
case 'true':
146+
case 'false':
147+
inputValue = input.default;
148+
break;
149+
default:
150+
inputValue = `'${input.default ?? ''}'`;
151+
}
152+
newReadme.push(` ${key}: ${inputValue}`);
144153

145154
firstInput = false;
146155
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"lint": "eslint --config ./.eslintrc.json ./src ./misc ./test",
1111
"lint:fix": "npm run lint -- --fix",
1212
"prepare": "npm run build",
13-
"test": "mocha -r ts-node/register './test/**.ts'",
13+
"test": "mocha -r ts-node/register './test/**/**.ts'",
1414
"test:coverage": "nyc --all npm run test --silent"
1515
},
1616
"files": [

src/install-native-client.ts

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,24 @@
1-
import * as core from '@actions/core';
2-
import * as tc from '@actions/tool-cache';
3-
import * as exec from '@actions/exec';
4-
import { downloadTool } from './utils';
5-
import { join as joinPaths } from 'path';
1+
import { MsiInstaller, Urls } from './installers';
62

7-
const x64_URL = 'https://download.microsoft.com/download/B/E/D/BED73AAC-3C8A-43F5-AF4F-EB4FEA6C8F3A/ENU/x64/sqlncli.msi';
8-
const x86_URL = 'https://download.microsoft.com/download/B/E/D/BED73AAC-3C8A-43F5-AF4F-EB4FEA6C8F3A/ENU/x86/sqlncli.msi';
9-
10-
export default async function installNativeClient(version: number) {
11-
if (version !== 11) {
12-
throw new Error('Unsupported Native Client version, only 11 is valid.');
13-
}
14-
const arch = process.arch === 'x64' ? 'x64' : 'x86';
15-
let path = tc.find('sqlncli', '11.0', arch);
16-
if (!path) {
17-
core.info(`Downloading client installer for ${arch}.`);
18-
path = await downloadTool(arch === 'x64' ? x64_URL : x86_URL).then((tmp) => {
19-
return tc.cacheFile(tmp, 'sqlncli.msi', 'sqlncli', '11.0', arch);
20-
});
21-
} else {
22-
core.info('Loaded client installer from cache.');
3+
const VERSIONS = new Map<string, Urls>([
4+
['11', {
5+
x64: 'https://download.microsoft.com/download/B/E/D/BED73AAC-3C8A-43F5-AF4F-EB4FEA6C8F3A/ENU/x64/sqlncli.msi',
6+
x86: 'https://download.microsoft.com/download/B/E/D/BED73AAC-3C8A-43F5-AF4F-EB4FEA6C8F3A/ENU/x86/sqlncli.msi',
7+
}],
8+
]);
9+
export default async function installNativeClient(version: string) {
10+
if (!VERSIONS.has(version)) {
11+
throw new TypeError(`Invalid native client version supplied ${version}. Must be one of ${Array.from(VERSIONS.keys()).join(', ')}.`);
2312
}
24-
path = joinPaths(path, 'sqlncli.msi');
25-
core.info('Installing SQL Native Client 11.0');
2613
// see https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2012/ms131321(v=sql.110)
27-
await exec.exec('msiexec', [
28-
'/passive',
29-
'/i',
30-
path,
31-
'APPGUID={0CC618CE-F36A-415E-84B4-FB1BFF6967E1}',
32-
'IACCEPTSQLNCLILICENSETERMS=YES',
33-
], {
34-
windowsVerbatimArguments: true,
14+
const installer = new MsiInstaller({
15+
name: 'sqlncli',
16+
urls: VERSIONS.get(version)!,
17+
appGuid: '0CC618CE-F36A-415E-84B4-FB1BFF6967E1',
18+
version,
19+
extraArgs: [
20+
'IACCEPTSQLNCLILICENSETERMS=YES',
21+
],
3522
});
23+
return installer.install();
3624
}

src/install-odbc.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { MsiInstaller, Urls } from './installers';
2+
3+
// https://learn.microsoft.com/en-us/sql/connect/odbc/download-odbc-driver-for-sql-server?view=sql-server-ver16
4+
const VERSIONS = new Map<string, Urls>([
5+
['18', {
6+
x64: 'https://go.microsoft.com/fwlink/?linkid=2242886',
7+
x86: 'https://go.microsoft.com/fwlink/?linkid=2242980',
8+
}],
9+
['17', {
10+
x64: 'https://go.microsoft.com/fwlink/?linkid=2239168',
11+
x86: 'https://go.microsoft.com/fwlink/?linkid=2238791',
12+
}],
13+
]);
14+
15+
export default async function installOdbc(version: string) {
16+
if (!VERSIONS.has(version)) {
17+
throw new TypeError(`Invalid ODBC version supplied ${version}. Must be one of ${Array.from(VERSIONS.keys()).join(', ')}.`);
18+
}
19+
const installer = new MsiInstaller({
20+
name: 'msodbcsql',
21+
urls: VERSIONS.get(version)!,
22+
version,
23+
extraArgs: [
24+
'IACCEPTMSODBCSQLLICENSETERMS=YES',
25+
],
26+
});
27+
return installer.install();
28+
}

src/install.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
waitForDatabase,
1515
} from './utils';
1616
import installNativeClient from './install-native-client';
17+
import installOdbc from './install-odbc';
1718

1819
/**
1920
* Attempt to load the installer from the tool-cache, otherwise, fetch it.
@@ -42,6 +43,7 @@ export default async function install() {
4243
wait,
4344
skipOsCheck,
4445
nativeClientVersion,
46+
odbcVersion,
4547
} = gatherInputs();
4648
// we only support windows for now. But allow crazy people to skip this check if they like...
4749
if (!skipOsCheck && os.platform() !== 'win32') {
@@ -77,7 +79,10 @@ export default async function install() {
7779
}
7880
}
7981
if (nativeClientVersion) {
80-
await core.group('Installing SQL Native Client', () => installNativeClient(parseInt(nativeClientVersion, 10)));
82+
await core.group('Installing SQL Native Client', () => installNativeClient(nativeClientVersion));
83+
}
84+
if (odbcVersion) {
85+
await core.group('Installing ODBC', () => installOdbc(odbcVersion));
8186
}
8287
// Initial checks complete - fetch the installer
8388
const toolPath = await core.group(`Fetching install media for ${version}`, () => findOrDownloadTool(config));

src/installers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './msi-installer';

0 commit comments

Comments
 (0)