Skip to content

Commit 190d8c5

Browse files
Create transfer.yml
1 parent 810744e commit 190d8c5

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

.github/workflows/transfer.yml

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
name: "Transfer Accepted Submission to Private Repo"
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
issue_number:
7+
description: "Issue number to transfer"
8+
required: true
9+
type: number
10+
11+
permissions:
12+
contents: read
13+
issues: write
14+
15+
jobs:
16+
transfer-submission:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Checkout Repo
20+
uses: actions/checkout@v4
21+
22+
- name: Transfer Issue to Private Repo
23+
uses: actions/github-script@v7
24+
env:
25+
PRIVATE_REPO_TOKEN: ${{ secrets.PRIVATE_REPO_TOKEN }} # PAT with access to pytorch-fdn/ambassador-program-management
26+
with:
27+
github-token: ${{ secrets.GITHUB_TOKEN }} # public repo ops
28+
script: |
29+
const issue_number = parseInt(core.getInput("issue_number"));
30+
const repoOwner = context.repo.owner;
31+
const publicRepo = context.repo.repo;
32+
33+
// Private repo target (fixed owner/name)
34+
const privateOwner = "pytorch-fdn";
35+
const privateName = "ambassador-program-management";
36+
const assignee = "reginankenchor";
37+
38+
const { Octokit } = require("@octokit/rest");
39+
const priv = new Octokit({ auth: process.env.PRIVATE_REPO_TOKEN });
40+
41+
// 1) Public: fetch the issue
42+
const issue = await github.rest.issues.get({ owner: repoOwner, repo: publicRepo, issue_number });
43+
44+
// Accept label check (case-insensitive contains "accept")
45+
const hasAccepted = (issue.data.labels || []).some(l => String(l.name || "").toLowerCase().includes("accept"));
46+
if (!hasAccepted) {
47+
throw new Error(`Issue #${issue_number} does not have an 'Accepted' label. Aborting transfer.`);
48+
}
49+
50+
// 2) Private: sanity-check token can access private repo
51+
await priv.rest.repos.get({ owner: privateOwner, repo: privateName });
52+
53+
// 3) Private: create the new issue
54+
const bodyContent = [
55+
"📝 Submission Transferred from Public Repository",
56+
"",
57+
"----------------------------------------",
58+
issue.data.body || "",
59+
"----------------------------------------",
60+
`Source: ${issue.data.html_url}`,
61+
`Original Author: @${issue.data.user?.login || "unknown"}`,
62+
"",
63+
`🔔 @${assignee} — this submission has been accepted and is now ready for program-level follow-up.`
64+
].join("\n\n");
65+
66+
const newIssue = await priv.rest.issues.create({
67+
owner: privateOwner,
68+
repo: privateName,
69+
title: issue.data.title,
70+
body: bodyContent,
71+
assignees: [assignee]
72+
});
73+
74+
// 4) Private: invite applicant (read-only)
75+
const applicant = issue.data.user?.login;
76+
if (applicant) {
77+
try {
78+
await priv.rest.repos.addCollaborator({
79+
owner: privateOwner,
80+
repo: privateName,
81+
username: applicant,
82+
permission: "pull"
83+
});
84+
} catch (e) {
85+
core.info(`Invite for @${applicant} ignored: ${e.message}`);
86+
}
87+
}
88+
89+
// 5) Public: ensure unlocked, then comment; leave unlocked (do not close)
90+
const confirmation = [
91+
"✅ This submission has been **accepted** and transferred to the private program management repository.",
92+
"",
93+
`🔗 **Private tracking issue:** ${newIssue.data.html_url}`,
94+
"",
95+
"<!-- transferred-to-private -->"
96+
].join("\n");
97+
98+
try {
99+
await github.rest.issues.unlock({ owner: repoOwner, repo: publicRepo, issue_number });
100+
} catch (e) { /* already unlocked or not lockable */ }
101+
102+
await github.rest.issues.createComment({
103+
owner: repoOwner,
104+
repo: publicRepo,
105+
issue_number,
106+
body: confirmation
107+
});
108+
109+
// NOTE: No closing of public issue

0 commit comments

Comments
 (0)