Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
54 changes: 54 additions & 0 deletions .github/ISSUE_TEMPLATE/add-adopter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: "Add Adopter"
description: "Add your organization to the Parseable adopters list"
title: "Add adopter: "
labels: ["new-adopter"]
body:
- type: markdown
attributes:
value: |
Thanks for using Parseable! Fill out the form below to add your organization to our adopters list.
A PR will be created automatically — no fork needed.

- type: input
id: org_name
attributes:
label: Organization Name
description: "The name of your organization"
placeholder: "Acme Corp"
validations:
required: true

- type: input
id: org_url
attributes:
label: Organization URL
description: "Your organization's website"
placeholder: "https://example.com"
validations:
required: true

- type: input
id: contact
attributes:
label: Contact
description: "GitHub @handle or name of the contact person"
placeholder: "@username"
validations:
required: true

- type: textarea
id: description
attributes:
label: Description of Use
description: "How does your organization use Parseable?"
placeholder: "We use Parseable for centralized logging of our microservices..."
validations:
required: true

- type: checkboxes
id: confirmation
attributes:
label: Confirmation
options:
- label: "I am authorized to represent this organization"
required: true
8 changes: 8 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Slack Community
url: https://logg.ing/community
about: Join the Parseable Slack community for questions and discussions
- name: Documentation
url: https://www.parseable.com/docs
about: Check our documentation for guides and references
165 changes: 165 additions & 0 deletions .github/workflows/add-adopter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
name: Add Adopter

on:
issues:
types: [opened]

permissions:
contents: write
issues: write
pull-requests: write

jobs:
add-adopter:
if: contains(github.event.issue.labels.*.name, 'new-adopter')
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Parse issue and create PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const issue = context.payload.issue;
const body = issue.body || '';

// Parse structured fields from issue body
function parseField(body, heading) {
const regex = new RegExp(`### ${heading}\\s*\\n\\s*([\\s\\S]*?)(?=\\n### |$)`);
const match = body.match(regex);
return match ? match[1].trim() : '';
}

const orgName = parseField(body, 'Organization Name');
const orgUrl = parseField(body, 'Organization URL');
const contact = parseField(body, 'Contact');
const description = parseField(body, 'Description of Use');

// Validate fields
const errors = [];
if (!orgName) errors.push('- **Organization Name** is missing');
if (!orgUrl) errors.push('- **Organization URL** is missing');
if (!orgUrl.startsWith('https://')) errors.push('- **Organization URL** must start with `https://`');
if (!contact) errors.push('- **Contact** is missing');
if (!description) errors.push('- **Description of Use** is missing');

if (errors.length > 0) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `👋 Thanks for your interest in being listed as a Parseable adopter!\n\nUnfortunately, there were some issues with your submission:\n\n${errors.join('\n')}\n\nPlease close this issue and [open a new one](https://github.com/${context.repo.owner}/${context.repo.repo}/issues/new?template=add-adopter.yml) with the corrected information.`
});
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ['invalid']
});
return;
}

// Read USERS.md and check for duplicates
const { data: fileData } = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: 'USERS.md',
ref: 'main'
});
const usersContent = Buffer.from(fileData.content, 'base64').toString('utf-8');
const orgNameLower = orgName.toLowerCase().trim();

// Parse existing org names from USERS.md for exact match
const existingOrgs = usersContent.split('\n')
.filter(line => line.startsWith('|'))
.map(line => {
const match = line.match(/\|\s*\[([^\]]+)\]/);
return match ? match[1].toLowerCase().trim() : null;
})
.filter(Boolean);

if (existingOrgs.includes(orgNameLower)) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `👋 Thanks for your interest!\n\nIt looks like **${orgName}** is already listed in our adopters list. If you need to update the existing entry, please open a PR directly.\n\nClosing this issue as duplicate.`
});
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ['duplicate']
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed'
});
return;
}

// Sanitize user input for markdown table
const sanitize = (str) => str.replace(/\|/g, '\\|').replace(/\n/g, ' ').trim();

// Build contact link
let contactCell = sanitize(contact);
if (contact.startsWith('@')) {
const handle = contact.substring(1).trim();
contactCell = `[@${handle}](https://github.com/${handle})`;
}

// Append new row to USERS.md
const safeDesc = sanitize(description);
const safeOrgName = sanitize(orgName);
const newRow = `| [${safeOrgName}](${orgUrl}) | ${contactCell} | ${safeDesc} |`;
const updatedContent = usersContent.trimEnd() + '\n' + newRow + '\n';

// Create branch
const slug = orgName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
const branchName = `adopter/add-${slug}-${issue.number}`;

const { data: ref } = await github.rest.git.getRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'heads/main'
});

await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/heads/${branchName}`,
sha: ref.object.sha
});

// Commit updated USERS.md
await github.rest.repos.createOrUpdateFileContents({
owner: context.repo.owner,
repo: context.repo.repo,
path: 'USERS.md',
message: `Add ${orgName} to adopters list`,
content: Buffer.from(updatedContent).toString('base64'),
sha: fileData.sha,
branch: branchName
});

// Create PR
const { data: pr } = await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Add ${orgName} to adopters list`,
head: branchName,
base: 'main',
body: `## New Adopter\n\n| Field | Value |\n|-------|-------|\n| **Organization** | [${orgName}](${orgUrl}) |\n| **Contact** | ${contactCell} |\n| **Description** | ${description} |\n\nCloses #${issue.number}`
});

// Comment on issue
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `PR created: ${pr.html_url}\n\nA maintainer will review and merge it shortly. Thanks for using Parseable!`
});
2 changes: 1 addition & 1 deletion .github/workflows/cla.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
path-to-document: 'https://github.com/parseablehq/.github/blob/main/CLA.md' # e.g. a CLA or a DCO document
# branch should not be protected
branch: 'main'
allowlist: dependabot[bot],deepsource-autofix[bot],deepsourcebot
allowlist: dependabot[bot],deepsource-autofix[bot],deepsourcebot,github-actions[bot]

# the followings are the optional inputs - If the optional inputs are not given, then default values will be taken
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
Expand Down
74 changes: 74 additions & 0 deletions .github/workflows/sync-adopters.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Sync Adopters to README

on:
push:
branches: [main]
paths: [USERS.md]

permissions:
contents: write

jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Extract adopters and update README
run: |
python3 - <<'SCRIPT'
import re

# Read USERS.md and extract Organization + Description columns
with open("USERS.md") as f:
lines = f.read().strip().split("\n")

def esc_cell(value: str) -> str:
return value.replace("\n", " ").replace("|", r"\|").strip()

rows = []
for line in lines:
if not line.startswith("|"):
continue
parts = [p.strip() for p in line.split("|")]
# parts: ['', org, contact, desc, '']
if len(parts) < 4:
continue
org = parts[1]
if org == "Organization" or org.startswith("---") or org.startswith("--"):
continue
desc = parts[3]
rows.append(f"| {esc_cell(org)} | {esc_cell(desc)} |")

table = "| Organization | Description of Use |\n| --- | --- |\n" + "\n".join(rows)

# Replace content between markers in README.md
with open("README.md") as f:
readme = f.read()

pattern = re.compile(
r"(<!-- ADOPTERS:START -->\n).*?(\n<!-- ADOPTERS:END -->)",
flags=re.DOTALL,
)
readme, replaced = pattern.subn(
rf"\g<1>{table}\g<2>", readme, count=1
)
if replaced != 1:
raise SystemExit("Expected exactly one ADOPTERS block in README.md")

with open("README.md", "w") as f:
f.write(readme)
SCRIPT

- name: Check for changes
id: diff
run: git diff --quiet README.md || echo "changed=true" >> "$GITHUB_OUTPUT"

- name: Commit and push
if: steps.diff.outputs.changed == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add README.md
git commit -m "docs: sync adopters from USERS.md to README"
git push
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,18 @@
[![Docs](https://img.shields.io/badge/stable%20docs-parseable.com%2Fdocs-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://logg.ing/docs)
[![Build](https://img.shields.io/github/checks-status/parseablehq/parseable/main?style=flat&color=%2373DC8C&label=Checks)](https://github.com/parseablehq/parseable/actions)

[Key Concepts](https://www.parseable.com/docs/key-concepts) | [Features](https://www.parseable.com/docs/features/alerts) | [Documentation](https://www.parseable.com/docs) | [Demo](https://demo.parseable.com/login) | [FAQ](https://www.parseable.com/docs/key-concepts/data-model#faq)
[Key Concepts](https://www.parseable.com/docs/key-concepts) | [Features](https://www.parseable.com/docs/features/alerts) | [Documentation](https://www.parseable.com/docs) | [Demo](https://app.parseable.com) | [FAQ](https://www.parseable.com/docs/key-concepts/data-model#faq)

</div>

Parseable is a full stack observability platform built to ingest, analyze and extract insights from all types of telemetry (MELT) data. You can run Parseable on your local machine, in the cloud, or as a managed service. To experience Parseable UI, checkout [demo.parseable.com ↗︎](https://demo.parseable.com/login).
Parseable is a full-stack observability platform built to ingest, analyze and extract insights from all types of telemetry (MELT) data. You can run Parseable on your local machine, in the cloud, or use [Parseable Cloud](https://app.parseable.com) — the fully managed service. To experience Parseable UI, checkout [app.parseable.com ↗︎](https://app.parseable.com).
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix verb form: "check out" (two words).

"checkout" should be "check out" when used as a verb. As a noun or adjective it's one word, but here it's a verb phrase.

✏️ Proposed fix
-Parseable is a full-stack observability platform built to ingest, analyze and extract insights from all types of telemetry (MELT) data. You can run Parseable on your local machine, in the cloud, or use [Parseable Cloud](https://app.parseable.com) — the fully managed service. To experience Parseable UI, checkout [app.parseable.com ↗︎](https://app.parseable.com).
+Parseable is a full-stack observability platform built to ingest, analyze and extract insights from all types of telemetry (MELT) data. You can run Parseable on your local machine, in the cloud, or use [Parseable Cloud](https://app.parseable.com) — the fully managed service. To experience Parseable UI, check out [app.parseable.com ↗︎](https://app.parseable.com).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 20, Replace the verb "checkout" with the correct two-word
verb phrase "check out" in the README sentence that invites users to experience
Parseable UI (the sentence containing "To experience Parseable UI, checkout
[app.parseable.com ↗︎](https://app.parseable.com)"). Update the text so it reads
"To experience Parseable UI, check out [app.parseable.com
↗︎](https://app.parseable.com)".


<div align="center">
<h3>
<a href="https://app.parseable.com">Try Parseable Cloud — Start Free ↗︎</a>
</h3>
<p><i>The fastest way to get started. No infrastructure to manage.</i></p>
</div>

<div align="center">
<a href="http://www.youtube.com/watch?feature=player_embedded&v=gYn3pFAfrVA" target="_blank">
Expand Down Expand Up @@ -103,6 +110,17 @@ This section elaborates available options to run Parseable in production or deve
- [OAuth2 support ↗︎](https://www.parseable.com/docs/features/oepnid)
- [OpenTelemetry support ↗︎](https://www.parseable.com/docs/OpenTelemetry/logs)

## Adopters :handshake:

Organizations using Parseable in production. [Add yours here](https://github.com/parseablehq/parseable/issues/new?template=add-adopter.yml) — no fork needed!

<!-- ADOPTERS:START -->
| Organization | Description of Use |
| --- | --- |
| [HireXL](https://www.hirexl.in/) | Frontend application logging |
| [Elfsquad](https://elfsquad.io) | Centralized application/infrastructure logging |
<!-- ADOPTERS:END -->

## Verify images :writing_hand:

Parseable builds are attested for build provenance and integrity using the [attest-build-provenance](https://github.com/actions/attest-build-provenance) action. The attestations can be verified by having the latest version of [GitHub CLI](https://github.com/cli/cli/releases/latest) installed in your system. Then, execute the following command:
Expand Down
Loading