Skip to content

Commit

Permalink
Merge branch 'resolution' into staging
Browse files Browse the repository at this point in the history
  • Loading branch information
Bobinstein committed Nov 8, 2024
2 parents c98c94e + 39befa8 commit 35dcd2e
Show file tree
Hide file tree
Showing 10 changed files with 2,607 additions and 4,939 deletions.
1 change: 1 addition & 0 deletions .github/workflows/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
13 changes: 9 additions & 4 deletions .github/workflows/arweave-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,16 @@ jobs:
yarn build
cd ..
- name: Install dependencies for deployment script
run: |
cd .github/workflows/scripts
yarn install
cd ../..
- name: Run deployment script
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
DEPLOY_ANT_PROCESS_ID: ${{ secrets.DEPLOY_ANT_PROCESS_ID}}
DEPLOY_ANT_PROCESS_ID: ${{ secrets.DEPLOY_ANT_PROCESS_ID }}
run: |
cd docs
yarn deploy
cd .github/workflows/scripts
node arweave-deploy.js
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Production Deploy
on:
push:
branches:
- main
- test

jobs:
prod-deploy:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/scripts/.yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ignore-engines true
258 changes: 74 additions & 184 deletions .github/workflows/scripts/arweave-deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,200 +10,90 @@ const axios = require("axios");
const crypto = require("crypto"); // For generating file hashes
const { Readable } = require("stream");

async function main() {
const mime = (await import("mime")).default;

const jwkBase64 = process.env.DEPLOY_KEY;
if (!jwkBase64) {
throw new Error(
"The Arweave wallet key (DEPLOY_KEY) is missing or not accessible. Please ensure it is set as an environment variable."
);
const undername = process.env.UNDERNAME || '@'
async function main() {
const distFolderPath = path.resolve(__dirname, '../../../docs/src/.vuepress/dist');

// Load the contents of permalinks.json
const permalinksPath = path.join(distFolderPath, 'permalinks.json');
let permalinks;
try {
const permalinksData = fs.readFileSync(permalinksPath, 'utf-8');
permalinks = JSON.parse(permalinksData);
} catch (error) {
console.error('Failed to load permalinks.json:', error);
process.exit(1);
}

// Decode the Base64 string
const decodedJwk = Buffer.from(jwkBase64, "base64").toString("utf8");

// Parse the decoded string as JSON
const parsedKey = JSON.parse(decodedJwk);
const turbo = TurboFactory.authenticated({ privateKey: parsedKey });

const distPath = path.join(__dirname, "../../../docs/src/.vuepress/dist");

let newManifest = {
manifest: "arweave/paths",
version: "0.2.0",
index: { path: "index.html" },
fallback: { id: "CepHEnswMe-cZVsItlg9mf971DWWbzMsQ9K0InnIGLM" },
paths: {},
};

const ant = ANT.init({
signer: new ArweaveSigner(parsedKey),
processId: "1-Bu7KDRqqKmX68XxAHmeDlYSlz6qjKXNYOQOBGrDMQ",
});

const records = await ant.getRecords();
const arIoRecord = records["@"].transactionId;
const url = `https://arweave.net/raw/${arIoRecord}`;
let jwk = JSON.parse(Buffer.from(process.env.DEPLOY_KEY, 'base64').toString('utf-8'));
const turbo = TurboFactory.authenticated({ privateKey: jwk });

async function fetchAndParseJson(url) {
try {
const response = await axios.get(url);
let data = response.data;

if (typeof data === "string") {
try {
data = JSON.parse(data);
} catch {
console.warn(
"Warning: Received data is not a valid JSON string. Returning empty object."
);
return {};
}
}

if (typeof data === "object" && data !== null) {
return data;
} else {
console.warn(
"Warning: Received data is not a valid JSON object. Returning empty object."
);
return {};
}
} catch (error) {
console.error("Error fetching data:", error);
return {};
let { manifest, manifestResponse } = await turbo.uploadFolder({
folderPath: distFolderPath,
dataItemOpts: {
tags: [
{ name: "App-Name", value: "ar.io vuepress deploy" }
]
}
}

const oldManifest = await fetchAndParseJson(url);

async function isIdentical(localFilePath, arweaveFileUrl) {
try {
const localFileBuffer = fs.readFileSync(localFilePath);
const localHash = crypto
.createHash("sha256")
.update(localFileBuffer)
.digest("hex");

const response = await axios.get(arweaveFileUrl, {
responseType: "arraybuffer",
});
const arweaveFileBuffer = Buffer.from(response.data);
const arweaveHash = crypto
.createHash("sha256")
.update(arweaveFileBuffer)
.digest("hex");
});

return localHash === arweaveHash;
} catch (error) {
console.error("Error comparing files:", error);
return false;
// Iterate over manifest.paths and update based on permalinks
for (const key of Object.keys(manifest.paths)) {
const matchingPermalink = permalinks.find(p => p.buildFilePath.replace(/^\//, '') === key);
if (matchingPermalink) {
const permalinkKey = matchingPermalink.permalink.replace(/^\//, '').replace(/\/$/, '');
manifest.paths[permalinkKey] = manifest.paths[key];
console.log(`Match found and added: ${permalinkKey} -> ${key}`);
}
}

function getContentType(filePath) {
return mime.getType(filePath) || "application/octet-stream";
}
console.log(manifest);
console.log(manifestResponse)

async function uploadManifest(manifest) {
try {
const manifestString = JSON.stringify(manifest);
const uploadResult = await turbo.uploadFile({
fileStreamFactory: () => Readable.from(Buffer.from(manifestString)),
fileSizeFactory: () => Buffer.byteLength(manifestString),
signal: AbortSignal.timeout(10_000),
dataItemOpts: {
tags: [
{
name: "Content-Type",
value: "application/x.arweave-manifest+json",
},
],
},
});
console.log("Uploaded manifest:", JSON.stringify(uploadResult, null, 2));
return uploadResult.id;
} catch (error) {
console.error("Error uploading manifest:", error);
return null;
}
}

async function processFiles(dir) {
const files = fs.readdirSync(dir);

for (const file of files) {
const filePath = path.join(dir, file);
const relativePath = path.relative(distPath, filePath);

if (fs.statSync(filePath).isDirectory()) {
await processFiles(filePath); // Recursively process subdirectories
} else {
try {
const oldManifestEntry = oldManifest.paths[relativePath];

if (oldManifestEntry) {
const arweaveFileUrl = `https://arweave.net/raw/${oldManifestEntry.id}`;
const identical = await isIdentical(filePath, arweaveFileUrl);

if (identical) {
newManifest.paths[relativePath] = oldManifestEntry;
console.log(`File unchanged: ${relativePath}`);
continue;
}
}
} catch (err) {
console.error(err);
}

console.log(`File to upload: ${relativePath}`);
try {
const fileSize = fs.statSync(filePath).size;
const contentType = getContentType(filePath);
const uploadResult = await turbo.uploadFile({
fileStreamFactory: () => fs.createReadStream(filePath),
fileSizeFactory: () => fileSize,
signal: AbortSignal.timeout(10_000), // cancel the upload after 10 seconds
dataItemOpts: {
tags: [
{ name: "Content-Type", value: contentType },
{ name: "App-Name", value: "PermaDocsDeploy" },
],
},
});

console.log(
`Uploaded ${relativePath}:`,
JSON.stringify(uploadResult, null, 2)
);
newManifest.paths[relativePath] = { id: uploadResult.id };
} catch (uploadError) {
console.error(`Error uploading file ${relativePath}:`, uploadError);
}
}
}
}

await processFiles(distPath);

console.log("New manifest:", newManifest);

const manifestId = await uploadManifest(newManifest);
if (manifestId) {
console.log(`New manifest uploaded with transaction ID: ${manifestId}`);
const recordSet = await ant.setRecord(
{
undername: "@",
transactionId: manifestId,
ttlSeconds: 900,
},
{ tags: [{ name: "App-Name", value: "PermaDocsDeploy" }] }
);
console.log(recordSet);
} else {
console.error("Failed to upload new manifest.");
}
try {
const manifestString = JSON.stringify(manifest);
const uploadResult = await turbo.uploadFile({
fileStreamFactory: () => Readable.from(Buffer.from(manifestString)),
fileSizeFactory: () => Buffer.byteLength(manifestString),
signal: AbortSignal.timeout(10_000),
dataItemOpts: {
tags: [
{
name: 'Content-Type',
value: 'application/x.arweave-manifest+json',
},
{
name: 'App-Name',
value: 'ar.io vuepress deploy',
},
],
},
});
return uploadResult.id;
} catch (error) {
console.error('Error uploading manifest:', error);
return null;
}
}

const manifestId = await uploadManifest(manifest)

console.log(manifestId)

const signer = new ArweaveSigner(jwk)
const ant = ANT.init({processId: process.env.ANT_PROCESS, signer})

const response = await ant.setRecord({
undername: "test",
transactionId: manifestId,
ttlSeconds: 900
})
console.log(response)
}

main();
main().catch((error) => {
console.error('An error occurred:', error);
process.exit(1);
});
Loading

0 comments on commit 35dcd2e

Please sign in to comment.