Skip to content

Commit 1f8b896

Browse files
Copilotfgreinacher
andcommitted
fix: fix template expansion for asset globbing patterns with wildcards
Template variables in asset paths are now expanded before globbing, allowing wildcard patterns to work correctly. Co-authored-by: fgreinacher <[email protected]>
1 parent dc0f981 commit 1f8b896

File tree

3 files changed

+87
-23
lines changed

3 files changed

+87
-23
lines changed

lib/publish.js

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -56,30 +56,48 @@ export default async (pluginConfig, context) => {
5656
debug("milestones: %o", milestones);
5757

5858
if (assets && assets.length > 0) {
59+
const templatedAssets = assets.map((asset) => {
60+
if (isPlainObject(asset)) {
61+
const templatedAsset = { ...asset };
62+
if (asset.path) {
63+
templatedAsset.path = Array.isArray(asset.path)
64+
? asset.path.map((pattern) => template(pattern)(context))
65+
: template(asset.path)(context);
66+
}
67+
templatedAsset.url = asset.url ? template(asset.url)(context) : asset.url;
68+
templatedAsset.label = asset.label ? template(asset.label)(context) : asset.label;
69+
templatedAsset.type = asset.type ? template(asset.type)(context) : asset.type;
70+
templatedAsset.filepath = asset.filepath ? template(asset.filepath)(context) : asset.filepath;
71+
templatedAsset.target = asset.target ? template(asset.target)(context) : asset.target;
72+
templatedAsset.status = asset.status ? template(asset.status)(context) : asset.status;
73+
return templatedAsset;
74+
} else if (Array.isArray(asset)) {
75+
// Handle array of glob patterns
76+
return asset.map((pattern) => template(pattern)(context));
77+
} else {
78+
// String asset path
79+
return template(asset)(context);
80+
}
81+
});
82+
5983
// Skip glob if url is provided
60-
const urlAssets = assets.filter((asset) => asset.url);
84+
const urlAssets = templatedAssets.filter((asset) => asset.url);
6185
debug("url assets: %o", urlAssets);
6286
const globbedAssets = await getAssets(
6387
context,
64-
assets.filter((asset) => !asset.url)
88+
templatedAssets.filter((asset) => !asset.url)
6589
);
6690
debug("globbed assets: %o", globbedAssets);
6791
const allAssets = [...urlAssets, ...globbedAssets];
6892
debug("all assets: %o", allAssets);
6993

7094
await Promise.all(
7195
allAssets.map(async (asset) => {
72-
const path = template((isPlainObject(asset) ? asset : { path: asset }).path)(context);
73-
const _url = asset.url ? template(asset.url)(context) : undefined;
74-
const label = asset.label ? template(asset.label)(context) : undefined;
75-
const type = asset.type ? template(asset.type)(context) : undefined;
76-
const filepath = asset.filepath ? template(asset.filepath)(context) : undefined;
77-
const target = asset.target ? template(asset.target)(context) : undefined;
78-
const status = asset.status ? template(asset.status)(context) : undefined;
79-
80-
if (_url) {
81-
assetsList.push({ label, rawUrl: _url, type, filepath });
82-
debug("use link from release setting: %s", _url);
96+
const path = isPlainObject(asset) ? asset.path : asset;
97+
98+
if (asset.url) {
99+
assetsList.push({ label: asset.label, rawUrl: asset.url, type: asset.type, filepath: asset.filepath });
100+
debug("use link from release setting: %s", asset.url);
83101
} else {
84102
const file = pathlib.resolve(cwd, path);
85103

@@ -98,24 +116,24 @@ export default async (pluginConfig, context) => {
98116
}
99117

100118
debug("file path: %o", path);
101-
debug("file label: %o", label);
102-
debug("file type: %o", type);
103-
debug("file filepath: %o", filepath);
104-
debug("file target: %o", target);
105-
debug("file status: %o", status);
119+
debug("file label: %o", asset.label);
120+
debug("file type: %o", asset.type);
121+
debug("file filepath: %o", asset.filepath);
122+
debug("file target: %o", asset.target);
123+
debug("file status: %o", asset.status);
106124

107125
let uploadEndpoint;
108126
let response;
109127

110-
if (target === "generic_package") {
111-
const finalLabel = label ?? pathlib.basename(file);
128+
if (asset.target === "generic_package") {
129+
const finalLabel = asset.label ?? pathlib.basename(file);
112130
// Upload generic packages
113131
const encodedLabel = encodeURIComponent(finalLabel);
114132
// https://docs.gitlab.com/ee/user/packages/generic_packages/#publish-a-package-file
115133
uploadEndpoint = urlJoin(
116134
projectApiUrl,
117135
`packages/generic/release/${encodedVersion}/${encodedLabel}?${
118-
status ? `status=${status}&` : ""
136+
asset.status ? `status=${asset.status}&` : ""
119137
}select=package_file`
120138
);
121139

@@ -131,7 +149,7 @@ export default async (pluginConfig, context) => {
131149
// https://docs.gitlab.com/ee/user/packages/generic_packages/#download-package-file
132150
const url = urlJoin(projectApiUrl, `packages/generic/release/${encodedVersion}/${encodedLabel}`);
133151

134-
assetsList.push({ label: finalLabel, alt: "release", url, type: "package", filepath });
152+
assetsList.push({ label: finalLabel, alt: "release", url, type: "package", filepath: asset.filepath });
135153

136154
logger.log("Uploaded file: %s (%s)", url, response.file.url);
137155
} else {
@@ -152,7 +170,7 @@ export default async (pluginConfig, context) => {
152170
const { alt, full_path } = response;
153171
const url = urlJoin(gitlabUrl, full_path);
154172

155-
assetsList.push({ label, alt, url, type, filepath });
173+
assetsList.push({ label: asset.label, alt, url, type: asset.type, filepath: asset.filepath });
156174

157175
logger.log("Uploaded file: %s", url);
158176
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Test file content for release with version in filename.

test/publish.test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,3 +712,48 @@ test.serial("Publish a release with error response", async (t) => {
712712
t.is(error.message, `Response code 499 (Something went wrong)`);
713713
t.true(gitlab.isDone());
714714
});
715+
716+
test.serial("Publish a release with templated wildcard path", async (t) => {
717+
const cwd = "test/fixtures";
718+
const owner = "test_user";
719+
const repo = "test_repo";
720+
const env = { GITLAB_TOKEN: "gitlab_token" };
721+
const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" };
722+
const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` };
723+
const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`);
724+
const encodedGitTag = encodeURIComponent(nextRelease.gitTag);
725+
726+
const assets = ["versioned/upload_v${nextRelease.version}.txt"];
727+
728+
const uploaded = {
729+
url: "/uploads/upload_v1.0.0.txt",
730+
alt: "upload_v1.0.0.txt",
731+
full_path: "/-/project/4/66dbcd21ec5d24ed6ea225176098d52b/upload_v1.0.0.txt",
732+
};
733+
734+
const gitlab = authenticate(env)
735+
.post(`/projects/${encodedProjectPath}/releases`, {
736+
tag_name: nextRelease.gitTag,
737+
description: nextRelease.notes,
738+
assets: {
739+
links: [
740+
{
741+
name: "upload_v1.0.0.txt",
742+
url: `https://gitlab.com${uploaded.full_path}`,
743+
},
744+
],
745+
},
746+
})
747+
.reply(200);
748+
const gitlabUpload = authenticate(env)
749+
.post(`/projects/${encodedProjectPath}/uploads`, /Content-Disposition.*upload_v1\.0\.0\.txt/g)
750+
.reply(200, uploaded);
751+
752+
const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger });
753+
754+
t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`);
755+
t.deepEqual(t.context.log.args[0], ["Uploaded file: %s", `https://gitlab.com${uploaded.full_path}`]);
756+
t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]);
757+
t.true(gitlab.isDone());
758+
t.true(gitlabUpload.isDone());
759+
});

0 commit comments

Comments
 (0)