Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
55 changes: 55 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -342,3 +342,58 @@ jobs:
repo: getsentry/action-release
commit: ${{ github.sha }}
previous_commit: ${{ github.sha }}

test-upload-debug-files:
needs: docker-build
strategy:
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
name: Test debug files upload
permissions:
contents: read
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0

# Breakpad symbol files are plain text, so we can create one on every OS
# without a compiler. A random debug ID per run makes sure we find this
# upload and not one from an earlier run.
- name: Create a Breakpad debug file
id: dif
shell: bash
run: |
HEX=$(od -An -N16 -tx1 /dev/urandom | tr -d ' \n' | tr 'a-f' 'A-F')
mkdir -p e2e-debug-files
printf 'MODULE Linux x86_64 %s0 action-release-e2e\nFILE 0 main.c\nFUNC 1000 10 0 main\n1000 10 1 0\n' "$HEX" > e2e-debug-files/action-release-e2e.sym
DEBUG_ID=$(echo "$HEX" | tr 'A-F' 'a-f' | sed -E 's/(.{8})(.{4})(.{4})(.{4})(.{12})/\1-\2-\3-\4-\5/')
echo "debug_id=$DEBUG_ID" >> $GITHUB_OUTPUT

- name: Create a release and upload debug files
uses: ./
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_LOG_LEVEL: debug
with:
ignore_missing: true
debug_files: ./e2e-debug-files

- name: Check that Sentry has the debug file
shell: bash
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
DEBUG_ID: ${{ steps.dif.outputs.debug_id }}
run: |
for i in 1 2 3 4 5; do
# Use the jq exit code, not its output: jq on Windows writes CRLF.
if curl -sf -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
"https://sentry.io/api/0/projects/$SENTRY_ORG/$SENTRY_PROJECT/files/dsyms/?query=$DEBUG_ID" \
| jq -e --arg id "$DEBUG_ID" 'any(.[]; .debugId == $id)' > /dev/null; then
echo "SUCCESS: Found debug file $DEBUG_ID"
exit 0
fi
sleep 5
done
echo "ERROR: Debug file $DEBUG_ID not found in Sentry"
exit 1
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Adding the following to your workflow will create a new Sentry release and tell
| `environment` | Set the environment for this release. E.g. "production" or "staging". Omit to skip adding deploy to release. | - |
| `sourcemaps` | Space-separated list of paths to JavaScript sourcemaps. Omit to skip uploading sourcemaps. | - |
| `inject` | Injects Debug IDs into source files and source maps to ensure proper un-minifcation of your stacktraces. Does nothing if `sourcemaps` was not set. | `true` |
| `debug_files` | Space-separated list of paths to debug information files (e.g. dSYM, PDB, ELF, Breakpad). Omit to skip uploading debug files. | - |
| `finalize` | When false, omit marking the release as finalized and released. | `true` |
| `ignore_missing` | When the flag is set and the previous release commit was not found in the repository, will create a release with the default commits count instead of failing the command. | `false` |
| `ignore_empty` | When the flag is set, command will not fail and just exit silently if no new commits for a given release have been found. | `false` |
Expand Down Expand Up @@ -103,6 +104,15 @@ Adding the following to your workflow will create a new Sentry release and tell
sourcemaps: './dist'
```

- Create a new Sentry release and upload debug information files for a native app.

```yaml
- uses: getsentry/action-release@v3
with:
environment: 'production'
debug_files: './build/app.pdb ./build/app.dSYM'
```

- Create a new Sentry release for the `production` environment of your project at version `v1.0.1`.

```yaml
Expand Down
16 changes: 16 additions & 0 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getBooleanOption,
getDist,
getSourcemaps,
getDebugFiles,
getStartedAt,
getRelease,
getSetCommitsOption,
Expand Down Expand Up @@ -68,6 +69,21 @@ describe('options', () => {
});
});

describe('getDebugFiles', () => {
afterEach(() => {
delete process.env['INPUT_DEBUG_FILES'];
});

test('should return empty list when debug_files is omitted', () => {
expect(getDebugFiles()).toEqual([]);
});

test('should split space-separated paths', () => {
process.env['INPUT_DEBUG_FILES'] = './build/app.pdb ./build/app.dSYM';
expect(getDebugFiles()).toEqual(['./build/app.pdb', './build/app.dSYM']);
});
});

describe('getDist', () => {
afterEach(() => {
delete process.env['INPUT_DIST'];
Expand Down
10 changes: 9 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ inputs:
Does nothing if "sourcemaps" was not set.
default: true
required: false
debug_files:
description: |-
Space-separated list of paths to debug information files (e.g. dSYM, PDB,
ELF, Breakpad). Uploaded with "sentry-cli debug-files upload".
Omit to skip uploading debug files.
required: false
dist:
description: |-
Unique identifier for the distribution, used to further segment your
Expand Down Expand Up @@ -148,6 +154,7 @@ runs:
INPUT_ENVIRONMENT: ${{ inputs.environment }}
INPUT_INJECT: ${{ inputs.inject }}
INPUT_SOURCEMAPS: ${{ inputs.sourcemaps }}
INPUT_DEBUG_FILES: ${{ inputs.debug_files }}
INPUT_DIST: ${{ inputs.dist }}
INPUT_FINALIZE: ${{ inputs.finalize }}
INPUT_IGNORE_MISSING: ${{ inputs.ignore_missing }}
Expand All @@ -167,7 +174,7 @@ runs:
INPUT_WORKING_DIRECTORY: ${{ inputs.working_directory }}
INPUT_DISABLE_TELEMETRY: ${{ inputs.disable_telemetry }}
INPUT_DISABLE_SAFE_DIRECTORY: ${{ inputs.disable_safe_directory }}
uses: docker://ghcr.io/getsentry/action-release-image:ab-migrate-to-vitest
uses: docker://ghcr.io/getsentry/action-release-image:ab-upload-debug-files

# For actions running on macos or windows runners, we use a composite
# action approach which allows us to install the arch specific sentry-cli
Expand Down Expand Up @@ -214,6 +221,7 @@ runs:
INPUT_ENVIRONMENT: ${{ inputs.environment }}
INPUT_INJECT: ${{ inputs.inject }}
INPUT_SOURCEMAPS: ${{ inputs.sourcemaps }}
INPUT_DEBUG_FILES: ${{ inputs.debug_files }}
INPUT_DIST: ${{ inputs.dist }}
INPUT_FINALIZE: ${{ inputs.finalize }}
INPUT_IGNORE_MISSING: ${{ inputs.ignore_missing }}
Expand Down
25 changes: 24 additions & 1 deletion dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -99836,6 +99836,7 @@ const telemetry_1 = __nccwpck_require__(12417);
const environment = options.getEnvironment();
const inject = options.getBooleanOption('inject', true);
const sourcemaps = options.getSourcemaps();
const debugFiles = options.getDebugFiles();
const dist = options.getDist();
const shouldFinalize = options.getBooleanOption('finalize', true);
const ignoreMissing = options.getBooleanOption('ignore_missing', false);
Expand Down Expand Up @@ -99904,6 +99905,16 @@ const telemetry_1 = __nccwpck_require__(12417);
Sentry.setTag('sourcemaps-uploaded', true);
}));
}
Sentry.setTag('debug-files', debugFiles.length > 0);
if (debugFiles.length) {
yield (0, telemetry_1.traceStep)('upload-debug-files', () => __awaiter(void 0, void 0, void 0, function* () {
core.debug(`Uploading debug files`);
// Debug files belong to a project, not a release, so upload them for each project
for (const project of projects) {
yield (0, cli_1.getCLI)().execute(['debug-files', 'upload', '--project', project, ...debugFiles], true);
}
}));
}
if (environment) {
yield (0, telemetry_1.traceStep)('add-environment', () => __awaiter(void 0, void 0, void 0, function* () {
core.debug(`Adding deploy to release`);
Expand Down Expand Up @@ -99976,7 +99987,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getWorkingDirectory = exports.getUrlPrefixOption = exports.getProjects = exports.checkEnvironmentVariables = exports.getSetCommitsManualOptions = exports.getSetCommitsOption = exports.getBooleanOption = exports.getDist = exports.getSourcemaps = exports.getStartedAt = exports.getEnvironment = exports.getRelease = void 0;
exports.getWorkingDirectory = exports.getUrlPrefixOption = exports.getProjects = exports.checkEnvironmentVariables = exports.getSetCommitsManualOptions = exports.getSetCommitsOption = exports.getBooleanOption = exports.getDist = exports.getDebugFiles = exports.getSourcemaps = exports.getStartedAt = exports.getEnvironment = exports.getRelease = void 0;
const core = __importStar(__nccwpck_require__(42186));
const path_1 = __importDefault(__nccwpck_require__(71017));
const cli_1 = __nccwpck_require__(56733);
Expand Down Expand Up @@ -100061,6 +100072,18 @@ const getSourcemaps = () => {
return sourcemapsOption.split(' ');
};
exports.getSourcemaps = getSourcemaps;
/**
* Debug files are optional, but there may be several as a space-separated list.
* @returns string[]
*/
const getDebugFiles = () => {
const debugFilesOption = core.getInput('debug_files');
if (!debugFilesOption) {
return [];
}
return debugFilesOption.split(' ');
};
exports.getDebugFiles = getDebugFiles;
/**
* Dist is optional, but should be a string when provided.
* @returns string
Expand Down
13 changes: 13 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ withTelemetry(
const environment = options.getEnvironment();
const inject = options.getBooleanOption('inject', true);
const sourcemaps = options.getSourcemaps();
const debugFiles = options.getDebugFiles();
const dist = options.getDist();
const shouldFinalize = options.getBooleanOption('finalize', true);
const ignoreMissing = options.getBooleanOption('ignore_missing', false);
Expand Down Expand Up @@ -114,6 +115,18 @@ withTelemetry(
});
}

Sentry.setTag('debug-files', debugFiles.length > 0);

if (debugFiles.length) {
await traceStep('upload-debug-files', async () => {
core.debug(`Uploading debug files`);
// Debug files belong to a project, not a release, so upload them for each project
for (const project of projects) {
await getCLI().execute(['debug-files', 'upload', '--project', project, ...debugFiles], true);
}
});
}

if (environment) {
await traceStep('add-environment', async () => {
core.debug(`Adding deploy to release`);
Expand Down
13 changes: 13 additions & 0 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,19 @@ export const getSourcemaps = (): string[] => {
return sourcemapsOption.split(' ');
};

/**
* Debug files are optional, but there may be several as a space-separated list.
* @returns string[]
*/
export const getDebugFiles = (): string[] => {
const debugFilesOption: string = core.getInput('debug_files');
if (!debugFilesOption) {
return [];
}

return debugFilesOption.split(' ');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these files themselves have spaces?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or like empty strings

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed empty strings, but files with spaces are just not supported, same as with our sourcemaps. That's just a limitation we have.

};

/**
* Dist is optional, but should be a string when provided.
* @returns string
Expand Down
Loading