Skip to content
Draft
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
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
4 changes: 3 additions & 1 deletion tests/full/publish.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@ describe("publish packages", () => {
const pack = res.body;

expect(pack.name).toBe("b-pulsar-package");
expect(pack).toMatchObject(require("./fixtures/b-pulsar-package/match.js"));
let fixture = require("./fixtures/b-pulsar-package/match.js")
fixture.versions = { "2.0.0": fixture.versions["2.0.0"] }
expect(pack).toMatchObject(fixture);

await database.removePackageByName("b-pulsar-package", true);
});
Expand Down