Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 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
6 changes: 5 additions & 1 deletion src/controllers/postPackages.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ module.exports = {
repository: (context, req) => {
return context.query.repository(req);
},
tag: (context, req) => {
return context.query.tag(req);
},
auth: (context, req) => {
return context.query.auth(req);
},
Expand Down Expand Up @@ -148,7 +151,8 @@ module.exports = {
const newPack = await context.vcs.newPackageData(
user.content,
ownerRepo,
"git"
"git",
params.tag
);

callStack.addCall("vcs.newPackageData", newPack);
Expand Down
39 changes: 7 additions & 32 deletions src/models/constructNewPackagePublishData.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module.exports = function constructNewPackagePublishData(opts = {}) {
// ownerRepo = OWNER/REPO (string)
// provider = Provider object from VCS
// packageJson = The full `package.json` from the latest version
// tags = The GitHub API return of tag information
// tag = The GitHub API return of tag information
// readme = The full text readme

let out = {};
Expand All @@ -39,15 +39,15 @@ module.exports = function constructNewPackagePublishData(opts = {}) {

// Now lets setup some constants that we will use over and over
let PACK_NAME = findPackName(opts);
let LATEST_VER = findLatestVer(opts);
let PACKAGE_VER = findLatestVer(opts);

out.name = PACK_NAME;
out.owner = findOwner(opts);
out.readme = typeof opts.readme === "string" ? opts.readme : "";
out.repository = opts.provider;
out.metadata = buildMeta(opts);
out.releases = {
latest: LATEST_VER,
latest: PACKAGE_VER,
};

// From here we want to build or version objects, except we don't have the
Expand All @@ -59,15 +59,8 @@ module.exports = function constructNewPackagePublishData(opts = {}) {
out.versions = {};
// So lets loop through all versions, we will use the same meta object for the
// latest, while getting mandatory only fields for the rest
out.versions[LATEST_VER] = buildMeta(opts);

for (let i = 0; i < opts.tags.length; i++) {
let curVer = semver.clean(opts.tags[i].name);
if (curVer && curVer !== LATEST_VER) {
out.versions[curVer] = buildAbsentVer(curVer, opts);
}
}

out.versions[PACKAGE_VER] = buildMeta(opts);
buildAbsentVer(PACKAGE_VER, opts)

Check notice

Code scanning / CodeQL

Semicolon insertion

Avoid automated semicolon insertion (95% of all statements in [the enclosing function](1) have an explicit semicolon).
// Now we should be good to go

return out;
Expand Down Expand Up @@ -155,7 +148,7 @@ function buildMeta(opts) {
out.engines = { atom: "*" };
}

let tag = findTagForVer(ver, opts);
let tag = opts.tag;

sha = tag.commit.sha ?? false;
tarball = tag.tarball_url ?? false;
Expand All @@ -180,7 +173,7 @@ function buildAbsentVer(ver, opts) {
// Here we will build an "absent" version object. Since we don't have the
// `package.json` of this version, it's considered absent, and will only receive
// the mandatory fields we can discover via the current version, and it's tag
let tag = findTagForVer(ver, opts);
let tag = opts.tag;

let sha = false;
let tarball = false;
Expand Down Expand Up @@ -213,21 +206,3 @@ function buildAbsentVer(ver, opts) {

return out;
}

function findTagForVer(wantedTag, opts) {
let tag = semver.clean(wantedTag);
let tagFound = false;

for (let i = 0; i < opts.tags.length; i++) {
if (semver.clean(opts.tags[i].name) === tag) {
tagFound = opts.tags[i];
}
}

throwIfFalse(tagFound, "", () => {
throw new Error(
`Unable to locate the tag for 'package.json' version '${tag}'. Are you sure you published a matching tag?`
);
});
return tagFound;
}
39 changes: 23 additions & 16 deletions src/vcs.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ async function ownership(userObj, packObj, dev_override = false) {
* Contains the full package data. This includes the Readme, the package.json, and all version data.
* @todo Stop hardcoding the service that is passed here.
*/
async function newPackageData(userObj, ownerRepo, service) {
async function newPackageData(userObj, ownerRepo, service, possibleTag) {
try {
let provider = null;
// Provider above, is the provider that should be assigned to allow interaction
Expand Down Expand Up @@ -129,25 +129,32 @@ async function newPackageData(userObj, ownerRepo, service) {
// information.
// See: https://github.com/pulsar-edit/package-backend/issues/205

const tags = await provider.tags(userObj, ownerRepo);
let tag;
if(possibleTag) {
tag = await provider.tag(userObj, ownerRepo, possibleTag);
tag = tag.content

Check notice

Code scanning / CodeQL

Semicolon insertion

Avoid automated semicolon insertion (91% of all statements in [the enclosing function](1) have an explicit semicolon).
} else {
tags = await provider.tags(userObj, ownerRepo);

Check warning

Code scanning / CodeQL

Missing variable declaration

Variable tags is used like a local variable, but is missing a declaration.

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

if (!tags.ok) {
return new ServerStatus()
.notOk()
.setContent(`Failed to get gh tags for ${ownerRepo} - ${tags.short}`)
.setShort("Server Error")
.build();
// Sort the tags into descending order
tags.content.sort((a, b) => {
return semver.rcompare(a.name, b.name);
});
tag = tags.content[0]

Check notice

Code scanning / CodeQL

Semicolon insertion

Avoid automated semicolon insertion (91% of all statements in [the enclosing function](1) have an explicit semicolon).
}

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

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

if (!pack.ok) {
Expand All @@ -162,7 +169,7 @@ async function newPackageData(userObj, ownerRepo, service) {
const readme = await provider.readme(
userObj,
ownerRepo,
tags.content[0]?.name
tag.name
);

if (!readme.ok) {
Expand Down Expand Up @@ -203,7 +210,7 @@ async function newPackageData(userObj, ownerRepo, service) {
ownerRepo: ownerRepo,
provider: packRepoObj,
packageJson: pack.content,
tags: tags.content,
tag: tag,
readme: readme.content,
});
} catch (err) {
Expand Down
50 changes: 50 additions & 0 deletions src/vcs_providers/github.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,56 @@ class GitHub extends Git {
}
}

async tag(userObj, ownerRepo, tagString) {
try {
const raw = await this._webRequestAuth(
`/repos/${ownerRepo}/commits/${tagString}`,
userObj.token
);

if (!raw.ok) {
if (raw.short === "Failed Request") {
switch (raw.content.status) {
case 401:
return {
ok: false,
short: "Bad Auth",
content: raw.content.status,
};
default:
return {
ok: false,
short: "Server Error",
content: raw.content.status,
};
}
}
return {
ok: false,
short: "Server Error",
content: raw.content.status,
};
}

// We have valid commit, let's "coerce" into a tag.
return {
ok: true,
content: {
name: tagString,
commit: { sha: raw.content.body.sha },
tarball_url: `${this.apiUrl}/repos/${ownerRepo}/tarball/${tagString}`
},
};
} catch (err) {
return {
ok: false,
short: "Server Error",
content: null,
error: err,
};
}
}

/**
* @async
* @function packageJSON
Expand Down