Skip to content

Commit

Permalink
chore: use GitHub actions to sanitize themes & plugins list (#2164)
Browse files Browse the repository at this point in the history
Co-authored-by: Uiolee <[email protected]>
  • Loading branch information
stevenjoezhang and uiolee committed Apr 15, 2024
1 parent 13f4ad0 commit 46652e7
Show file tree
Hide file tree
Showing 2 changed files with 223 additions and 0 deletions.
160 changes: 160 additions & 0 deletions .github/workflows/cleaner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
'use strict';

// eslint-disable-next-line node/no-extraneous-require
const yaml = require('js-yaml');
const fs = require('fs');
const { join, basename } = require('path');

function load(type) {
const base = `source/_data/${type}`;
const items = fs.readdirSync(base);
return items.map(item => {
const file = `${base}/${item}`;
const content = yaml.load(fs.readFileSync(file));
return {
file,
content
};
});
}

// Set your GitHub Personal Access Token
const headers = {
Authorization: 'Bearer ' + process.env.GITHUB_TOKEN
};

// Define the GraphQL query template
const queryTemplate = `
query {
{repos}
}
`;

// Function to get a sanitized key supported by GraphQL
function getKey(owner, repo) {
return (owner + repo).replace(/[^a-zA-Z0-9]/g, '').replace(/^\d+/, '');
}

// Function to build a query string for a repository
function buildRepoQuery(owner, repo) {
return `
${getKey(owner, repo)}: repository(owner: "${owner}", name: "${repo}") {
name
stargazers {
totalCount
}
owner {
login
}
url
isArchived
defaultBranchRef {
target {
... on Commit {
history(first: 1) {
edges {
node {
committedDate
}
}
}
}
}
}
}
`;
}

// Function to read GitHub repositories list and make the GraphQL query
async function queryRepos(reposList, batchSize = 100) {
let result = {};
try {
for (let i = 0; i < reposList.length; i += batchSize) {
// Construct the query for a batch of repositories
const reposQuery = reposList.slice(i, i + batchSize).map(({ owner, repo }) => buildRepoQuery(owner, repo)).join(' ');
const query = queryTemplate.replace('{repos}', reposQuery);

// Send the GraphQL query
const response = await fetch('https://api.github.com/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': headers.Authorization
},
body: JSON.stringify({ query: query })
});

if (!response.ok) {
throw new Error(`Query failed with status code ${response.status}: ${response.statusText}`);
}

const json = await response.json();
const { data, errors } = json;
if (errors) {
console.log(`Query failed with error: ${JSON.stringify(errors)}`);
}
result = { ...result, ...data };
}
} catch (error) {
console.error('Error:', error);
}
return result;
}

async function validate(type) {
const list = load(type);
const repos = [];
list.forEach(({ file, content }) => {
const { link } = content;
if (!link.startsWith('https://github.com/')) {
console.log('Skip', link);
} else {
// Extract owner and repo from github url
const parts = link.split('/');
repos.push({
owner: parts[3],
repo: parts[4].replace(/\.git$/, '')
});
}
});
const result = await queryRepos(repos);
list.forEach(({ file, content }) => {
const { link } = content;
if (!link.startsWith('https://github.com/')) {
console.log('Skip', link);
} else {
// Extract owner and repo from github url
const parts = link.split('/');
const owner = parts[3];
const repo = parts[4].replace(/\.git$/, '');
const repoKey = getKey(owner, repo);
if (result[repoKey]) {
const entry = result[repoKey];
const stars = entry.stargazers.totalCount;
const isArchived = entry.isArchived;
const lastCommitDate = entry.defaultBranchRef.target.history.edges[0].node.committedDate;
console.log(`Repo: ${owner}/${repo}, Stars: ${stars}, Archived: ${isArchived}, Last Commit Date: ${lastCommitDate}`);
const newOwner = entry.owner.login;
const newRepo = entry.name;
if (owner !== newOwner || repo !== newRepo) {
console.log(`Repo: ${owner}/${repo} has been renamed to ${newOwner}/${newRepo}`);
content.link = `https://github.com/${newOwner}/${newRepo}`;
fs.writeFileSync(file, yaml.dump(content));
}
} else {
console.log(`Repo: ${owner}/${repo} does not exist or is private.`);
console.log(`Remove: ${file}`);
fs.unlinkSync(file);
if (type === 'themes') {
const screenshotsPath = 'source/themes/screenshots';
const screenshot = join(screenshotsPath, basename(file).replace('yml', 'png'));
console.log(`Remove: ${screenshot}`);
fs.unlinkSync(screenshot);
}
}
}
});
}

validate('themes');
validate('plugins');
63 changes: 63 additions & 0 deletions .github/workflows/cleaner.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Cleaner

on:
schedule:
- cron: '0 0 * * 0'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
cache: "npm"
cache-dependency-path: "package.json"
- name: Install Dependencies
run: npm install
- name: Cleanup
run: node .github/workflows/cleaner.js
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Config
run: |
git config --global user.name 'Hexo'
git config --global user.email '[email protected]'
- name: Commit
run: |
git checkout -b cleanup
git add .
git commit -m 'chore: clean up themes & plugins'
- name: Push
run: |
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
git push origin cleanup -f
- name: Check for existing PR
id: check_pr
uses: actions/github-script@v7
with:
script: |
const owner = context.repo.owner;
const headBranch = `${owner}:cleanup`;
const { data: pullRequests } = await github.rest.pulls.list({
owner: owner,
repo: context.repo.repo,
state: 'open',
head: headBranch,
base: 'master'
});
return pullRequests.length > 0;
result-encoding: string
- name: Open PR
if: steps.check_pr.outputs.result == 'false'
run: |
gh pr create -B master -H cleanup --title 'chore: clean up themes & plugins' --body 'Created by Github Actions'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

0 comments on commit 46652e7

Please sign in to comment.