Files
Tanya GrayandArmen Zambrano G 455699b451 feat: Add option to set dist on sourcemaps (#125)
Adds support for `dist` as input value for GitHub Action:

```yaml
    - uses: getsentry/action-release@v1
      with:
        environment: 'production'
        sourcemaps: './lib'
        dist: ${{ github.sha }}
```

Note that this repo uses `@sentry/cli@^1.67.2` and there is a related fix in `2.3.1`:

> fix: move dist option to SentryCliUploadSourceMapsOptions (#1269) by @ikenfin
> [changelog](https://github.com/getsentry/sentry-cli/blob/master/CHANGELOG.md#231)

The fix was to move the `dist` option from being under `SentryCliOptions` (incorrect) to be under `SentryCliUploadSourceMapsOptions` (correct)

This does not affect the GH action as those types are not referenced directly by the action.

Resolves getsentry/action-release#74

---------

Co-authored-by: Armen Zambrano G <[email protected]>
2023-04-04 12:57:46 -04:00

232 lines
7.0 KiB
TypeScript

import {execSync} from 'child_process';
import * as path from 'path';
import * as process from 'process';
import {
getBooleanOption,
getDist,
getSourcemaps,
getStartedAt,
getVersion,
getSetCommitsOption,
getProjects,
getUrlPrefixOption,
} from '../src/options';
describe('options', () => {
beforeAll(() => {
process.env['MOCK'] = 'true';
});
describe('getBooleanOption', () => {
const option = 'finalize';
const defaultValue = true;
const errorMessage = `${option} is not a boolean`;
afterEach(() => {
delete process.env['INPUT_FINALIZE'];
});
test('should throw an error when option type is not a boolean', () => {
process.env['INPUT_FINALIZE'] = 'error';
expect(() => getBooleanOption(option, defaultValue)).toThrow(
errorMessage
);
});
test('should return defaultValue if option is omitted', () => {
expect(getBooleanOption(option, defaultValue)).toBe(true);
});
test('should return true when option is true or 1', () => {
process.env['INPUT_FINALIZE'] = 'true';
expect(getBooleanOption(option, defaultValue)).toBe(true);
process.env['INPUT_FINALIZE'] = '1';
expect(getBooleanOption(option, defaultValue)).toBe(true);
});
test('should return false when option is false or 0', () => {
process.env['INPUT_FINALIZE'] = 'false';
expect(getBooleanOption(option, defaultValue)).toBe(false);
process.env['INPUT_FINALIZE'] = '0';
expect(getBooleanOption(option, defaultValue)).toBe(false);
});
});
describe('getSourcemaps', () => {
afterEach(() => {
delete process.env['INPUT_SOURCEMAPS'];
});
test('should return empty list when sourcemaps is omitted', async () => {
expect(getSourcemaps()).toEqual([]);
});
test('should return array when sourcemaps is false', () => {
process.env['INPUT_SOURCEMAPS'] = './lib';
expect(getSourcemaps()).toEqual(['./lib']);
});
});
describe('getDist', () => {
afterEach(() => {
delete process.env['INPUT_DIST'];
});
test('should return null when dist is omitted', async () => {
expect(getDist()).toBeNull();
});
test('should return a string when dist is provided', () => {
process.env['INPUT_DIST'] = 'foo-dist';
expect(getDist()).toEqual('foo-dist');
});
});
describe('getStartedAt', () => {
const errorMessage =
'started_at not in valid format. Unix timestamp or ISO 8601 date expected';
afterEach(() => {
delete process.env['INPUT_STARTED_AT'];
});
test('should throw an error when started_at is negative', async () => {
process.env['INPUT_STARTED_AT'] = '-1';
expect(() => getStartedAt()).toThrow(errorMessage);
});
test('should throw an error when started_at is invalid', async () => {
process.env['INPUT_STARTED_AT'] = 'error';
expect(() => getStartedAt()).toThrow(errorMessage);
});
test('should return null when started_at is omitted', async () => {
expect(getStartedAt()).toBeNull();
});
test('should return an integer when started_at is an ISO8601 string.', async () => {
process.env['INPUT_STARTED_AT'] = '2017-07-13T19:40:00';
expect(getStartedAt()).toEqual(1500000000);
});
test('should return an integer when started_at is an truncated ISO8601 string.', async () => {
process.env['INPUT_STARTED_AT'] = '2017-07-13';
expect(getStartedAt()).toEqual(1499904000);
});
test('should return an integer when started_at is an integer.', async () => {
process.env['INPUT_STARTED_AT'] = '1500000000';
expect(getStartedAt()).toEqual(1500000000);
});
});
describe('getVersion', () => {
const MOCK_VERSION = 'releases propose-version';
afterEach(() => {
delete process.env['INPUT_VERSION'];
delete process.env['INPUT_VERSION_PREFIX'];
});
test('should strip refs from version', async () => {
process.env['INPUT_VERSION'] = 'refs/tags/v1.0.0';
expect(await getVersion()).toBe('v1.0.0');
});
test('should get version from inputs', async () => {
process.env['INPUT_VERSION'] = 'v1.0.0';
expect(await getVersion()).toBe('v1.0.0');
});
test('should propose-version when version is omitted', async () => {
expect(await getVersion()).toBe(MOCK_VERSION);
});
test('should include prefix in version', async () => {
process.env['INPUT_VERSION_PREFIX'] = 'prefix-';
expect(await getVersion()).toBe(`prefix-${MOCK_VERSION}`);
});
test('should include prefix in version with user provided version', async () => {
process.env['INPUT_VERSION'] = 'v1.0.0';
process.env['INPUT_VERSION_PREFIX'] = 'prefix-';
expect(await getVersion()).toBe(`prefix-v1.0.0`);
});
});
describe('getSetCommitsOption', () => {
afterEach(() => {
delete process.env['INPUT_SET_COMMITS'];
});
it('no option', () => {
expect(getSetCommitsOption()).toBe('auto');
});
it('auto', () => {
process.env['INPUT_SET_COMMITS'] = 'auto';
expect(getSetCommitsOption()).toBe('auto');
});
it('skip', () => {
process.env['INPUT_SET_COMMITS'] = 'skip';
expect(getSetCommitsOption()).toBe('skip');
});
it('bad option', () => {
const errorMessage = 'set_commits must be "auto" or "skip"';
process.env['INPUT_SET_COMMITS'] = 'bad';
expect(() => getSetCommitsOption()).toThrow(errorMessage);
});
});
describe('getProjects', () => {
afterEach(() => {
delete process.env['SENTRY_PROJECT'];
delete process.env['INPUT_PROJECTS'];
});
it('read from env variable', () => {
process.env['SENTRY_PROJECT'] = 'my-proj';
expect(getProjects()).toEqual(['my-proj']);
});
it('read from option', () => {
process.env['INPUT_PROJECTS'] = 'my-proj1 my-proj2';
expect(getProjects()).toEqual(['my-proj1', 'my-proj2']);
});
it('option overwites env variable', () => {
process.env['SENTRY_PROJECT'] = 'my-proj';
process.env['INPUT_PROJECTS'] = 'my-proj1 my-proj2';
expect(getProjects()).toEqual(['my-proj1', 'my-proj2']);
});
it('throws error if no project', () => {
expect(() => getProjects()).toThrowError(
'Environment variable SENTRY_PROJECT is missing a project slug and no projects are specified with the "projects" option'
);
});
});
describe('getUrlPrefixOption', () => {
afterEach(() => {
delete process.env['URL_PREFIX'];
});
it('get url prefix', () => {
process.env['INPUT_URL_PREFIX'] = 'build';
expect(getUrlPrefixOption()).toEqual('build');
});
});
});
// shows how the runner will run a javascript action with env / stdout protocol
test('test runs', () => {
const output = execSync(
`node ${path.join(__dirname, '..', 'dist', 'index.js')}`,
{
env: {
...process.env,
INPUT_ENVIRONMENT: 'production',
MOCK: 'true',
SENTRY_AUTH_TOKEN: 'test_token',
SENTRY_ORG: 'test_org',
SENTRY_PROJECT: 'test_project',
},
}
);
console.log(output.toString());
});