Skip to content

Commit

Permalink
Merge pull request #260 from pulsar-edit/use-refs-to-collect-package-…
Browse files Browse the repository at this point in the history
…data

Collect package data from specific tags
  • Loading branch information
confused-Techie authored Jun 28, 2024
2 parents 4a3f94f + 3aa6c7e commit ce3ca97
Show file tree
Hide file tree
Showing 12 changed files with 799 additions and 322 deletions.
35 changes: 29 additions & 6 deletions src/controllers/postPackagesPackageNameVersions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ module.exports = {
summary: "Creates a new package version.",
responses: {
201: {
description: "The package details indicating success.",
content: {
"application/json": "$packageObjectFull",
},
description: "An object with a key 'message' indicating what version has been published.",
},
},
},
Expand All @@ -37,9 +34,30 @@ module.exports = {
packageName: (context, req) => {
return context.query.packageName(req);
},
tag: (context, req) => {
return context.query.tag(req);
}
},
async postReturnHTTP(req, res, context, obj) {
// We use postReturnHTTP to ensure the user doesn't wait on these other actions

// Lets bail early in case these values don't exist.
// Such as the original request failing

if (typeof obj?.webhook?.pack !== "string" || typeof obj?.webhook?.user !== "string") {
// This data isn't defined, and we cannot work with it
return;
}

if (
typeof obj?.featureDetection?.user !== "string" ||
typeof obj?.featureDetection?.ownerRepo !== "string" ||
typeof obj?.featureDetection?.service !== "string"
) {
// This data isn't defined, and we cannot work with it
return;
}

await context.webhook.alertPublishVersion(
obj.webhook.pack,
obj.webhook.user
Expand Down Expand Up @@ -145,6 +163,7 @@ module.exports = {
let packMetadata = await context.vcs.newVersionData(
user.content,
ownerRepo,
params.tag,
"git"
);

Expand All @@ -153,7 +172,11 @@ module.exports = {
if (!packMetadata.ok) {
const sso = new context.sso();

return sso.notOk().addContent(packMetadata).assignCalls(callStack);
return sso
.notOk()
.addContent(packMetadata)
.addMessage(packMetadata.content) // Trust the output of VCS as an error message
.assignCalls(callStack);
}

const newName = packMetadata.content.name;
Expand Down Expand Up @@ -267,6 +290,6 @@ module.exports = {
ownerRepo: ownerRepo,
};

return sso.isOk().addContent(addVer.content);
return sso.isOk().addContent(addVer).addMessage(addVer.content);
},
};
48 changes: 36 additions & 12 deletions src/vcs.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* function.
*/

const semver = require("semver");
const query = require("./query_parameters/index.js").logic;
const utils = require("./utils.js");
const constructNewPackagePublishData = require("./models/constructNewPackagePublishData.js");
Expand Down Expand Up @@ -123,28 +124,36 @@ async function newPackageData(userObj, ownerRepo, service) {
.build();
}

let pack = await provider.packageJSON(userObj, ownerRepo);
// We will get tags first so that we can utilize specific tags when asking
// for further information about a package, rather than use the default branch
// information.
// See: https://github.com/pulsar-edit/package-backend/issues/205

if (!pack.ok) {
const tags = await provider.tags(userObj, ownerRepo);

if (!tags.ok) {
return new ServerStatus()
.notOk()
.setContent(`Failed to get gh package for ${ownerRepo} - ${pack.short}`)
.setShort("Bad Package")
.setContent(`Failed to get gh tags for ${ownerRepo} - ${tags.short}`)
.setShort("Server Error")
.build();
}

const tags = await provider.tags(userObj, ownerRepo);
// Sort the tags into descending order
tags.content.sort((a, b) => { return semver.rcompare(a.name, b.name)} );

if (!tags.ok) {
let pack = await provider.packageJSON(userObj, ownerRepo, tags.content[0]?.name);

if (!pack.ok) {
return new ServerStatus()
.notOk()
.setContent(`Failed to get gh tags for ${ownerRepo} - ${tags.short}`)
.setShort("Server Error")
.setContent(`Failed to get gh package for ${ownerRepo} - ${pack.short}`)
.setShort("Bad Package")
.build();
}

// Now to get our Readme
const readme = await provider.readme(userObj, ownerRepo);
const readme = await provider.readme(userObj, ownerRepo, tags.content[0]?.name);

if (!readme.ok) {
return new ServerStatus()
Expand Down Expand Up @@ -222,13 +231,15 @@ async function newPackageData(userObj, ownerRepo, service) {
* @param {object} userObj - The Full User Object as returned by `auth.verifyAuth()`
* @param {string} ownerRepo - The Owner Repo Combo of the package affected.
* Such as `pulsar-edit/pulsar`
* @param {string} tagRef - The version number or ref where data should be sought
* from the remote resource.
* @param {string} service - The service to use as expected to be returned
* by `vcs.determineProvider()`. Currently should be hardcoded to "git"
* @returns {SSO_VCS_newVersionData} A Server Status Object, which when `ok: true`
* returns all data that would be needed to update a package on the DB, and
* upload a new version.
*/
async function newVersionData(userObj, ownerRepo, service) {
async function newVersionData(userObj, ownerRepo, tagRef, service) {
// Originally when publishing a new version the responsibility to collect
// all package data fell onto the package_handler itself
// Including collecting readmes and tags, now this function should encapsulate
Expand All @@ -244,7 +255,20 @@ async function newVersionData(userObj, ownerRepo, service) {
provider = new GitHub();
}

let pack = await provider.packageJSON(userObj, ownerRepo);
let exists = await provider.exists(userObj, ownerRepo);

if (!exists.ok) {
// Could be due to an error, or it doesn't exist at all.
// For now until we support custom error messages will do a catch all
// return.
return new ServerStatus()
.notOk()
.setContent(`Failed to get repo: ${ownerRepo} - ${exists.short}`)
.setShort("Bad Repo")
.build();
}

let pack = await provider.packageJSON(userObj, ownerRepo, tagRef);

if (!pack.ok) {
return {
Expand All @@ -257,7 +281,7 @@ async function newVersionData(userObj, ownerRepo, service) {
// Now we will also need to get the packages data to update on the DB
// during verison pushes.

let readme = await provider.readme(userObj, ownerRepo);
let readme = await provider.readme(userObj, ownerRepo, tagRef);

if (!readme.ok) {
return {
Expand Down
71 changes: 60 additions & 11 deletions src/vcs_providers/github.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

const Git = require("./git.js");
const CSON = require("cson");
const semver = require("semver");

/**
* @class GitHub
Expand Down Expand Up @@ -172,12 +173,19 @@ class GitHub extends Git {
* the specified users credentials.
* @param {object} userObj - The Raw User Object after verification.
* @param {string} ownerRepo - The `owner/repo` combo of the repository to get.
* @param {string} [ver] - A version string indicating the version of data we wish to collect.
* @returns {object} A Server Status Object where content is the Markdown text of a readme.
*/
async readme(userObj, ownerRepo) {
async readme(userObj, ownerRepo, ver) {
try {
let reqString = `/repos/${ownerRepo}/readme`;

if (ver) {
reqString += `?ref=${ver}`;
}

const readmeRaw = await this._webRequestAuth(
`/repos/${ownerRepo}/readme`,
reqString,
userObj.token
);
// Using just `/readme` will let GitHub attempt to get the repos prefferred readme file,
Expand Down Expand Up @@ -289,13 +297,20 @@ class GitHub extends Git {
* @desc Returns the JSON Parsed text of the `package.json` on a GitHub repo.
* @param {object} userObj - The Full User Object as received after verification.
* @param {string} ownerRepo - The String combo of `owner/repo` for the package
* @param {string} [ver] - A version string indicating the version of data we wish to collect.
* @returns {object} A Server Status Object, which when successfully, whose `content`
* Is the JSON parsed `package.json` of the repo specified.
*/
async packageJSON(userObj, ownerRepo) {
async packageJSON(userObj, ownerRepo, ver) {
try {
let reqString = `/repos/${ownerRepo}/contents/package.json`;

if (ver) {
reqString += `?ref=${ver}`;
}

const raw = await this._webRequestAuth(
`/repos/${ownerRepo}/contents/package.json`,
reqString,
userObj.token
);

Expand Down Expand Up @@ -412,10 +427,16 @@ class GitHub extends Git {
*/
async featureDetection(userObj, ownerRepo) {
// First lets declare the functions we will rely on within this
const providesSnippets = async () => {
const providesSnippets = async (ref) => {
try {
let reqString = `/repos/${ownerRepo}/contents/snippets`;

if (ref) {
reqString += `?ref=${ref}`;
}

const raw = await this._webRequestAuth(
`/repos/${ownerRepo}/contents/snippets`,
reqString,
userObj.token
);

Expand All @@ -435,10 +456,16 @@ class GitHub extends Git {
}
};

const getGrammars = async () => {
const getGrammars = async (ref) => {
try {
let reqString = `/repos/${ownerRepo}/contents/grammars`;

if (ref) {
reqString += `?ref=${ref}`;
}

const raw = await this._webRequestAuth(
`/repos/${ownerRepo}/contents/grammars`,
ref,
userObj.token
);

Expand All @@ -456,8 +483,14 @@ class GitHub extends Git {
let supportedLanguages = [];

for (let i = 0; i < raw.content.body.length; i++) {
let innerReqString = `/repos/${ownerRepo}/contents/grammars/${res.body[i].name}`;

if (ref) {
innerReqString += `?ref=${ref}`;
}

const rawInner = this._webRequestAuth(
`/repos/${ownerRepo}/contents/grammars/${res.body[i].name}`,
innerReqString,
userObj.token
);

Expand Down Expand Up @@ -504,8 +537,24 @@ class GitHub extends Git {

// Now with our utility functions here defined, lets call them and build
// our featureObject
let grammars = await getGrammars();
let snippets = await providesSnippets();
let tags = await this.tags(userObj, ownerRepo);

if (!tags.ok) {
// We failed to get the tags data for featureDetection.
// This would be rather difficult to occur in real life, but this safety check
// becomes necessary in testing, as the mocked endpoints won't stay alive
// after the HTTP request returns.
return {
ok: false,
content: tags
};
}

// Sort the tags into descending order
tags.content.sort((a, b) => { return semver.rcompare(a.name, b.name)} );

const grammars = await getGrammars(tags.content[0]?.name);
const snippets = await providesSnippets(tags.content[0]?.name);

let featureObject = {};

Expand Down
11 changes: 11 additions & 0 deletions tests/full/fixtures/d-pulsar-package/initial-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "d-pulsar-package",
"version": "1.0.0",
"description": "A new package for stuff",
"main": "./lib/main.js",
"engines": {
"atom": "*"
},
"repository": "https://github.com/confused-Techie/d-pulsar-package",
"license": "MIT"
}
10 changes: 10 additions & 0 deletions tests/full/fixtures/d-pulsar-package/initial-tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = [
{
name: "v1.0.0",
tarball_url: "https://api.github.com/repos/confused-Techie/d-pulsar-package/tarball/refs/tags/v1.0.0",
commit: {
sha: "09f",
url: "https://api.github.com/repos/confused-Techie/d-pulsar-package/commits/09f"
}
}
];
50 changes: 50 additions & 0 deletions tests/full/fixtures/d-pulsar-package/match.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module.exports = {
name: "d-pulsar-package",
owner: "confused-Techie",
readme: expect.stringContaining("I'm a readme!"),
metadata: {
main: "./lib/main.js",
name: "d-pulsar-package",
engines: { atom: "*" },
license: "MIT",
version: "2.0.0",
repository: "https://github.com/confused-Techie/d-pulsar-package",
description: "An old package for stuff"
},
releases: { latest: "2.0.0" },
versions: {
"2.0.0": {
dist: {
tarball: expect.stringContaining(
"/api/packages/d-pulsar-package/versions/2.0.0/tarball"
),
},
main: "./lib/main.js",
name: "d-pulsar-package",
license: "MIT",
version: "2.0.0",
repository: "https://github.com/confused-Techie/d-pulsar-package",
description: "An old package for stuff"
},
"1.0.0": {
dist: {
tarball: expect.stringContaining(
"/api/packages/d-pulsar-package/versions/1.0.0/tarball"
),
},
main: "./lib/main.js",
name: "d-pulsar-package",
license: "MIT",
version: "1.0.0",
repository: "https://github.com/confused-Techie/d-pulsar-package",
description: "A new package for stuff"
}
},
repository: {
url: "https://github.com/confused-Techie/d-pulsar-package",
type: "git"
},
downloads: "0",
stargazers_count: "0",
badges: [{ title: "Made for Pulsar!", type: "success" }],
};
11 changes: 11 additions & 0 deletions tests/full/fixtures/d-pulsar-package/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "d-pulsar-package",
"version": "2.0.0",
"description": "An old package for stuff",
"main": "./lib/main.js",
"engines": {
"atom": "*"
},
"repository": "https://github.com/confused-Techie/d-pulsar-package",
"license": "MIT"
}
3 changes: 3 additions & 0 deletions tests/full/fixtures/d-pulsar-package/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# d-pulsar-package

I'm a readme!
Loading

0 comments on commit ce3ca97

Please sign in to comment.