(client, kvs)
| 212 | // open PRs. Verifies dbt_project.yml is reachable at repo/branch/subpath with the install |
| 213 | // token BEFORE writing, and preserves compiler-base fields (target/environment/selector). |
| 214 | async function stepDbtRepoRepoint(client, kvs) { |
| 215 | const secret = need('RUNNING_SECRET'); |
| 216 | const org = await orgUuid(client); |
| 217 | const repo = (kvs.repo || '').trim(); |
| 218 | const branch = (kvs.branch || 'main').trim(); |
| 219 | let subpath = (kvs.subpath || '/dbt').trim(); |
| 220 | if (!subpath.startsWith('/')) subpath = `/${subpath}`; |
| 221 | if (!repo || repo.indexOf('/') < 0) throw new Error('repoint requires repo=owner/name'); |
| 222 | |
| 223 | const { id, token } = await installationToken(client); |
| 224 | |
| 225 | const clean = subpath.replace(/^\/+|\/+$/g, ''); |
| 226 | const ymlPath = `${clean ? `${clean}/` : ''}dbt_project.yml`; |
| 227 | const check = await fetch(`https://api.github.com/repos/${repo}/contents/${ymlPath}?ref=${encodeURIComponent(branch)}`, { |
| 228 | headers: { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28' }, |
| 229 | }); |
| 230 | if (check.status !== 200) throw new Error(`dbt_project.yml not found at ${repo}:${branch}/${ymlPath} (HTTP ${check.status}) — check repo/branch/subpath and that the App installation covers this repo`); |
| 231 | |
| 232 | const r = await client.query( |
| 233 | `SELECT project_uuid, encode(dbt_connection,'hex') AS hex |
| 234 | FROM projects WHERE organization_id=(SELECT organization_id FROM organizations WHERE organization_uuid=$1) |
| 235 | ORDER BY project_id LIMIT 1`, [org]); |
| 236 | if (!r.rows.length) throw new Error('no project to repoint'); |
| 237 | let cur = {}; |
| 238 | try { cur = JSON.parse(decrypt(Buffer.from(r.rows[0].hex, 'hex'), secret)); } catch (_) {} |
| 239 | const next = { |
| 240 | type: 'github', |
| 241 | authorization_method: 'installation_id', |
| 242 | installation_id: String(id), |
| 243 | repository: repo, |
| 244 | branch, |
| 245 | project_sub_path: subpath, |
| 246 | }; |
| 247 | if (cur.target) next.target = cur.target; |
| 248 | if (cur.environment) next.environment = cur.environment; |
| 249 | if (cur.selector) next.selector = cur.selector; |
| 250 | if (cur.host_domain) next.host_domain = cur.host_domain; |
| 251 | const enc = encrypt(JSON.stringify(next), secret); |
| 252 | // Two columns hold the type: the encrypted dbt_connection blob AND the plaintext |
| 253 | // dbt_connection_type that ProjectModel maintains and the writeback gate reads. Both |
| 254 | // must change or proposeWriteback still sees 'dbt' and ParameterErrors. |
| 255 | await client.query( |
| 256 | 'UPDATE projects SET dbt_connection=$1, dbt_connection_type=$2 WHERE project_uuid=$3', |
| 257 | [enc, 'github', r.rows[0].project_uuid]); |
| 258 | console.log(`OK: repointed project ${r.rows[0].project_uuid} dbt_connection -> github ${repo}@${branch}${subpath} (installation_id=${id})`); |
| 259 | } |
| 260 | |
| 261 | async function stepVerifyToken(client) { |
| 262 | const secret = need('RUNNING_SECRET'); |
no test coverage detected