Skip to content

Commit 08a1a7d

Browse files
committed
Merge branch 'master' into feature/import-api
2 parents ce17758 + c4951e5 commit 08a1a7d

6 files changed

Lines changed: 67 additions & 43 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ Go to [Settings / Access Tokens](https://gitlab.com/profile/personal_access_toke
5656

5757
Leave it null for the first run of the script. Then the script will show you which projects there are. Can be either string or number.
5858

59+
#### gitlab.sessionCookie
60+
61+
GitLab's API [does not allow downloading of attachments](https://gitlab.com/gitlab-org/gitlab/-/issues/24155) and only images can be downloaded using HTTP. To work around this limitation and enable binary attachments to be migrated one can use the session cookie set in the browser after logging in to the gitlab instance. The cookie is named `_gitlab_session`.
62+
5963
### github
6064

6165
#### github.baseUrl

sample_settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export default {
55
// url: 'https://gitlab.mycompany.com',
66
token: '{{gitlab private token}}',
77
projectId: null,
8+
sessionCookie: null,
89
},
910
github: {
1011
// baseUrl: 'https://gitlab.mycompany.com:123/etc',

src/githubHelper.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,9 +1084,7 @@ export default class GithubHelper {
10841084
}
10851085
);
10861086

1087-
if (settings.s3) {
1088-
strWithMigLine = await utils.migrateAttachments(strWithMigLine, this.repoId, settings.s3, this.gitlabHelper);
1089-
}
1087+
strWithMigLine = await utils.migrateAttachments(strWithMigLine, this.repoId, settings.s3, this.gitlabHelper);
10901088

10911089
return strWithMigLine;
10921090
}

src/gitlabHelper.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export default class GitlabHelper {
1111
gitlabUrl?: string;
1212
gitlabToken: string;
1313
gitlabProjectId: number;
14+
sessionCookie: string;
1415

1516
host: string;
1617
projectPath?: string;
@@ -25,6 +26,7 @@ export default class GitlabHelper {
2526
this.gitlabToken = gitlabSettings.token;
2627
this.gitlabProjectId = gitlabSettings.projectId;
2728
this.host = gitlabSettings.url ? gitlabSettings.url : 'http://gitlab.com';
29+
this.sessionCookie = gitlabSettings.sessionCookie;
2830
this.allBranches = null;
2931
}
3032

@@ -94,7 +96,13 @@ export default class GitlabHelper {
9496
try {
9597
const host = this.host.endsWith('/') ? this.host : this.host + '/';
9698
const attachmentUrl = host + this.projectPath + relurl;
97-
const data = (await axios.get(attachmentUrl, {responseType: 'arraybuffer'})).data;
99+
const data = (await axios.get(attachmentUrl, {
100+
responseType: 'arraybuffer',
101+
headers: {
102+
// HACK: work around GitLab's API lack of GET for attachments
103+
// See https://gitlab.com/gitlab-org/gitlab/-/issues/24155
104+
Cookie: `_gitlab_session=${this.sessionCookie}`
105+
}})).data;
98106
return Buffer.from(data, 'binary')
99107
} catch (err) {
100108
console.error(`Could not download attachment #${relurl}.`);

src/settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export interface GitlabSettings {
4444
url?: string;
4545
token: string;
4646
projectId: number;
47+
sessionCookie: string;
4748
}
4849

4950
export interface S3Settings {

src/utils.ts

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const generateUserProjectRegex = () => {
3434

3535
// Creates new attachments and replaces old links
3636
export const migrateAttachments = async (body: string, githubRepoId: number | undefined, s3: S3Settings, gitlabHelper: GitlabHelper) => {
37-
const regexp = /!\[([^\]]+)\]\((\/uploads[^)]+)\)/g;
37+
const regexp = /(!?)\[([^\]]+)\]\((\/uploads[^)]+)\)/g;
3838

3939
// Maps link offset to a new name in S3
4040
const offsetToAttachment: {
@@ -45,45 +45,57 @@ export const migrateAttachments = async (body: string, githubRepoId: number | un
4545
const matches = body.matchAll(regexp);
4646

4747
for (const match of matches) {
48-
const name = match[1];
49-
const url = match[2];
50-
51-
const basename = path.basename(url);
52-
const extension = path.extname(url);
53-
const mimeType = mime.lookup(basename);
54-
const attachmentBuffer = await gitlabHelper.getAttachment(url);
55-
56-
// Generate new random file name for S3 bucket
57-
const id = crypto.randomBytes(16).toString('hex');
58-
const newFileName = id + extension;
59-
const relativePath = githubRepoId ? `${githubRepoId}/${newFileName}` : newFileName;
60-
61-
// Doesn't seem like it is easy to upload an issue to github, so upload to S3
62-
//https://stackoverflow.com/questions/41581151/how-to-upload-an-image-to-use-in-issue-comments-via-github-api
63-
64-
const s3url = `https://${s3.bucket}.s3.amazonaws.com/${relativePath}`;
65-
66-
const s3bucket = new S3();
67-
s3bucket.createBucket(() => {
68-
const params: S3.PutObjectRequest = {
69-
Key: relativePath,
70-
Body: attachmentBuffer,
71-
ContentType: mimeType === false ? null : mimeType,
72-
Bucket: s3.bucket,
73-
};
74-
75-
s3bucket.upload(params, function (err, data) {
76-
console.log(`\tUploaded ${basename} to ${s3url}`);
77-
if (err) {
78-
console.log('ERROR MSG: ', err);
79-
}
48+
const prefix = match[1] || '';
49+
const name = match[2];
50+
const url = match[3];
51+
52+
if (s3 && s3.bucket) {
53+
const basename = path.basename(url);
54+
const mimeType = mime.lookup(basename);
55+
const attachmentBuffer = await gitlabHelper.getAttachment(url);
56+
if (!attachmentBuffer) {
57+
continue;
58+
}
59+
60+
// // Generate file name for S3 bucket from URL
61+
const hash = crypto.createHash('sha256');
62+
hash.update(url);
63+
const newFileName = hash.digest('hex') + '/' + basename
64+
const relativePath = githubRepoId ? `${githubRepoId}/${newFileName}` : newFileName;
65+
// Doesn't seem like it is easy to upload an issue to github, so upload to S3
66+
//https://stackoverflow.com/questions/41581151/how-to-upload-an-image-to-use-in-issue-comments-via-github-api
67+
68+
const s3url = `https://${s3.bucket}.s3.amazonaws.com/${relativePath}`;
69+
70+
const s3bucket = new S3();
71+
s3bucket.createBucket(() => {
72+
const params: S3.PutObjectRequest = {
73+
Key: relativePath,
74+
Body: attachmentBuffer,
75+
ContentType: mimeType === false ? null : mimeType,
76+
Bucket: s3.bucket,
77+
};
78+
79+
s3bucket.upload(params, function (err, data) {
80+
console.log(`\tUploading ${basename} to ${s3url}... `);
81+
if (err) {
82+
console.log('ERROR: ', err);
83+
} else {
84+
console.log(`\t...Done uploading`);
85+
}
86+
});
8087
});
81-
});
82-
83-
// Add the new URL to the map
84-
offsetToAttachment[match.index] = `![${name}](${s3url})`;
85-
88+
89+
// Add the new URL to the map
90+
offsetToAttachment[match.index] = `${prefix}[${name}](${s3url})`;
91+
} else {
92+
// Not using S3: default to old URL, adding absolute path
93+
const host = gitlabHelper.host.endsWith('/')
94+
? gitlabHelper.host : gitlabHelper.host + '/';
95+
const attachmentUrl = host + gitlabHelper.projectPath + url;
96+
offsetToAttachment[match.index] = `${prefix}[${name}](${attachmentUrl})`;
97+
}
8698
}
8799

88-
return body.replace(regexp, ({},{},{},offset,{}) => offsetToAttachment[offset]);
100+
return body.replace(regexp, ({},{},{},{},offset,{}) => offsetToAttachment[offset]);
89101
};

0 commit comments

Comments
 (0)