Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add kv binding in actions for referral tracker #163

Open
wants to merge 8 commits into
base: development
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions .dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
WEBHOOK_PROXY_URL=https://smee.io/new
APP_WEBHOOK_SECRET=xxxxxx
APP_ID=123456
ENVIRONMENT=development | production
34 changes: 33 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,43 @@ on:
types:
- completed

permissions:
contents: read

jobs:
deploy-to-cloudflare:
name: Automatic Cloudflare Deploy
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20.10.0

- name: Run setup script
run: |
yarn install
yarn setup-kv
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

- name: Update wrangler.toml Name Field
run: |
branch_name=$(echo '${{ github.event.ref }}' | sed 's#refs/heads/##' | sed 's#[^a-zA-Z0-9]#-#g')
# Extract base name from wrangler.toml
base_name=$(grep '^name = ' wrangler.toml | sed 's/^name = "\(.*\)"$/\1/')
# Concatenate branch name with base name
new_name="${base_name}-${branch_name}"
# Truncate the new name to 63 characters for RFC 1035
new_name=$(echo "$new_name" | cut -c 1-63)
# Update the wrangler.toml file
sed -i "s/^name = .*/name = \"$new_name\"/" wrangler.toml
echo "Updated wrangler.toml name to: $new_name"

- name: Deploy to Cloudflare
if: ${{ github.event.workflow_run.conclusion == 'success' }}
uses: ubiquity/cloudflare-deploy-action@main
Expand All @@ -25,4 +57,4 @@ jobs:
commit_sha: ${{ github.event.workflow_run.head_sha }}
workflow_run_id: ${{ github.event.workflow_run.id }}
app_id: ${{ secrets.APP_ID }}
app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ node_modules
.pnp.loader.mjs
static/dist
.env
.dev.vars
.wrangler/

cypress/screenshots
Expand Down
108 changes: 108 additions & 0 deletions deploy/setup-kv-namespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// This file is a fork from: https://github.com/ubiquity-os/ubiquity-os-kernel

/**
* The purpose of the script is to ensure that the KV for the worker is properly set on deployment.
* There is currently a bug that makes the environment reset on each deploy, because of a problem with Wrangler not
* parsing the TOML configuration properly. See https://github.com/cloudflare/workers-sdk/issues/5634
* It seems to only work when the values are set at the root of the TOML, not withing the environments.
* This scripts takes out the Production values for kv_namespaces and rewrites them at the root of the TOML file.
*/

import { execSync } from "child_process";
import * as fs from "fs";
import * as toml from "toml";
// @ts-expect-error No typings exist for this package
import * as tomlify from "tomlify-j0.4";

const tomlFilePath = "./wrangler.toml";
const wranglerToml: WranglerConfiguration = toml.parse(fs.readFileSync(tomlFilePath, "utf-8"));

const NAMESPACE_TITLE = "kv";
const NAMESPACE_TITLE_WITH_PREFIX = `${wranglerToml.name}-${NAMESPACE_TITLE}`;
const BINDING_NAME = "REFERRAL_TRACKING";

interface Namespace {
id: string;
title: string;
}

interface WranglerConfiguration {
name: string;
env: {
production: {
kv_namespaces?: {
id: string;
binding: string;
}[];
};
dev: {
kv_namespaces?: {
id: string;
binding: string;
}[];
};
};
kv_namespaces: {
id: string;
binding: string;
}[];
}

function updateWranglerToml(namespaceId: string) {
// Ensure kv_namespaces array exists
if (!wranglerToml.kv_namespaces) {
wranglerToml.kv_namespaces = [];
}
if (wranglerToml.env.production.kv_namespaces) {
wranglerToml.kv_namespaces = wranglerToml.env.production.kv_namespaces;
delete wranglerToml.env.production.kv_namespaces;
}
if (wranglerToml.env.dev.kv_namespaces) {
delete wranglerToml.env.dev.kv_namespaces;
}

const existingNamespace = wranglerToml.kv_namespaces.find((o) => o.binding === BINDING_NAME);
if (existingNamespace) {
existingNamespace.id = namespaceId;
} else {
wranglerToml.kv_namespaces.push({
binding: BINDING_NAME,
id: namespaceId,
});
}

fs.writeFileSync(tomlFilePath, tomlify.toToml(wranglerToml, { space: 1 }));
}

async function main() {
// Check if the namespace exists or create a new one
let namespaceId: string;
try {
const res = execSync(`wrangler kv namespace create ${NAMESPACE_TITLE}`).toString();
console.log(res);
const newId = res.match(/id = \s*"([^"]+)"/)?.[1];
if (!newId) {
throw new Error(`The new ID could not be found.`);
}
namespaceId = newId;
console.log(`Namespace created with ID: ${namespaceId}`);
} catch (error) {
console.error(error);
const listOutput = JSON.parse(execSync(`wrangler kv namespace list`).toString()) as Namespace[];
const existingNamespace = listOutput.find((o) => o.title === NAMESPACE_TITLE_WITH_PREFIX);
if (!existingNamespace) {
throw new Error(`Error creating namespace: ${error}`);
}
namespaceId = existingNamespace.id;
console.log(`Namespace ${NAMESPACE_TITLE_WITH_PREFIX} already exists with ID: ${namespaceId}`);
}

updateWranglerToml(namespaceId);
}

main()
.then(() => console.log("Successfully bound namespace."))
.catch((e) => {
console.error("Error checking or creating namespace:\n", e);
process.exit(1);
});
10 changes: 5 additions & 5 deletions functions/referral-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async function handleSet(env: Env, request: Request): Promise<Response> {

const { gitHubUserId, referralCode } = result;

const oldRefCode = await env.KVNamespace.get(gitHubUserId);
const oldRefCode = await env.REFERRAL_TRACKING.get(gitHubUserId);

if (oldRefCode) {
return new Response(`Key '${gitHubUserId}' already has a referral code: '${oldRefCode}'`, {
Expand All @@ -68,7 +68,7 @@ async function handleSet(env: Env, request: Request): Promise<Response> {
});
}

await env.KVNamespace.put(gitHubUserId, referralCode);
await env.REFERRAL_TRACKING.put(gitHubUserId, referralCode);

return new Response(`Key '${gitHubUserId}' added with value '${referralCode}'`, {
headers: corsHeaders,
Expand All @@ -77,7 +77,7 @@ async function handleSet(env: Env, request: Request): Promise<Response> {
}

async function handleGet(gitHubUserId: string, env: Env): Promise<Response> {
const referralCode = await env.KVNamespace.get(gitHubUserId);
const referralCode = await env.REFERRAL_TRACKING.get(gitHubUserId);
if (referralCode) {
return new Response(`Value for '${gitHubUserId}': ${referralCode}`, {
headers: corsHeaders,
Expand All @@ -92,11 +92,11 @@ async function handleGet(gitHubUserId: string, env: Env): Promise<Response> {
}

async function handleList(env: Env): Promise<Response> {
const gitHubUsersIds = await env.KVNamespace.list();
const gitHubUsersIds = await env.REFERRAL_TRACKING.list();
const referrals: Record<string, string | null> = {};

for (const { name: userId } of gitHubUsersIds.keys) {
const referralCode = await env.KVNamespace.get(userId);
const referralCode = await env.REFERRAL_TRACKING.get(userId);
referrals[userId] = referralCode;
}

Expand Down
2 changes: 1 addition & 1 deletion functions/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EventContext, KVNamespace } from "@cloudflare/workers-types";

export interface Env {
KVNamespace: KVNamespace;
REFERRAL_TRACKING: KVNamespace;
}

export interface POSTRequestBody {
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"prepare": "husky install",
"test": "jest --setupFiles dotenv/config --coverage",
"cy:open": "cypress open",
"cy:run": "cypress run"
"cy:run": "cypress run",
"setup-kv": "tsx --env-file=.dev.vars deploy/setup-kv-namespace.ts"
},
"keywords": [
"typescript",
Expand Down Expand Up @@ -57,6 +58,8 @@
"lint-staged": "^15.1.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.2.5",
"toml": "3.0.0",
"tomlify-j0.4": "3.0.0",
"ts-jest": "29.1.2",
"tsx": "^4.7.1",
"typescript": "^5.3.3"
Expand Down
8 changes: 1 addition & 7 deletions src/home/fetch-github/fetch-and-display-previews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,7 @@ export async function displayGitHubIssues({
applyAvatarsToIssues();
}

export async function searchDisplayGitHubIssues({
searchText,
skipAnimation = false,
}: {
searchText: string;
skipAnimation?: boolean;
}) {
export async function searchDisplayGitHubIssues({ searchText, skipAnimation = false }: { searchText: string; skipAnimation?: boolean }) {
const searchResult = filterIssuesBySearch(searchText);
let filteredIssues = searchResult.filter(getProposalsOnlyFilter(isProposalOnlyViewer));
filteredIssues = filterIssuesByOrganization(filteredIssues);
Expand Down
16 changes: 6 additions & 10 deletions src/home/search/string-similarity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,23 @@ export class StringSimilarity {
public static calculate(str1: string, str2: string): number {
const maxLen = Math.max(str1.length, str2.length);
if (maxLen === 0) return 1.0;

const distance = this._calculateLevenshteinDistance(str1, str2);
return 1 - (distance / maxLen);
return 1 - distance / maxLen;
}

private static _calculateLevenshteinDistance(str1: string, str2: string): number {
const matrix: number[][] = Array(str2.length + 1).fill(null).map(() =>
Array(str1.length + 1).fill(null)
);
const matrix: number[][] = Array(str2.length + 1)
.fill(null)
.map(() => Array(str1.length + 1).fill(null));

for (let i = 0; i <= str1.length; i++) matrix[0][i] = i;
for (let j = 0; j <= str2.length; j++) matrix[j][0] = j;

for (let j = 1; j <= str2.length; j++) {
for (let i = 1; i <= str1.length; i++) {
const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1;
matrix[j][i] = Math.min(
matrix[j][i - 1] + 1,
matrix[j - 1][i] + 1,
matrix[j - 1][i - 1] + indicator
);
matrix[j][i] = Math.min(matrix[j][i - 1] + 1, matrix[j - 1][i] + 1, matrix[j - 1][i - 1] + indicator);
}
}

Expand Down
11 changes: 1 addition & 10 deletions wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,5 @@ compatibility_date = "2024-10-23"

pages_build_output_dir = "./static"

[[kv_namespaces]]
binding = "KVNamespace"
id = "0a6aaf0a6edb428189606b116da58ef7"

[vars]
YARN_VERSION = "1.22.22"

# These secrets need to be configured via Cloudflare dashboard:
# SUPABASE_URL = ""
# SUPABASE_ANON_KEY = ""

YARN_VERSION = "1.22.22"
16 changes: 16 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,8 @@ __metadata:
marked: "npm:^11.0.0"
npm-run-all: "npm:^4.1.5"
prettier: "npm:^3.2.5"
toml: "npm:3.0.0"
tomlify-j0.4: "npm:3.0.0"
ts-jest: "npm:29.1.2"
tsx: "npm:^4.7.1"
typescript: "npm:^5.3.3"
Expand Down Expand Up @@ -7538,6 +7540,20 @@ __metadata:
languageName: node
linkType: hard

"toml@npm:3.0.0":
version: 3.0.0
resolution: "toml@npm:3.0.0"
checksum: 8d7ed3e700ca602e5419fca343e1c595eb7aa177745141f0761a5b20874b58ee5c878cd045c408da9d130cb2b611c639912210ba96ce2f78e443569aa8060c18
languageName: node
linkType: hard

"tomlify-j0.4@npm:3.0.0":
version: 3.0.0
resolution: "tomlify-j0.4@npm:3.0.0"
checksum: 78349675ac24e4aa7b518f54cb3b55884d9f5d5a6a44fdeff63b3c55887ccce7c491802f2a527ee38a559d259adc5a14b431f926f892179f020db3d5025d9a94
languageName: node
linkType: hard

"tough-cookie@npm:^5.0.0":
version: 5.0.0
resolution: "tough-cookie@npm:5.0.0"
Expand Down
Loading