diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 0ba8f2c..4c340c2 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -1,9 +1,11 @@ name: Test Action on: - pull_request: - types: [labeled] - + # pull_request: + # types: [labeled] + push: + branches: + - dev jobs: hello-world-job: runs-on: ubuntu-latest @@ -24,7 +26,12 @@ jobs: uses: ./ id: hello with: - who-to-greet: "John" - label: ${{ github.event.label.name }} + label: minor + githubToken: ${{ secrets.GITHUB_TOKEN }} + + # ${{ github.event.label.name }} - name: Get the output time - run: echo "The time was ${{ steps.hello.outputs.time }}" + run: | + echo The label was label + +# ${{ steps.hello.outputs.label }} diff --git a/action.yml b/action.yml index d400bde..1c0992f 100644 --- a/action.yml +++ b/action.yml @@ -1,13 +1,16 @@ name: "Hello World" description: "Greet someone and record the time" inputs: - who-to-greet: # id of input - description: "Who to greet" - required: true - default: "World" label: description: "Optional label" required: false + filePath: + description: "File path of the project info (e.g: package.json) relative to the root directory of the repository." + required: false + githubToken: + description: GitHub repository token + required: true + outputs: time: # id of output description: "The time we greeted you" diff --git a/index.js b/index.js index eb7669b..637155f 100644 --- a/index.js +++ b/index.js @@ -1,19 +1,198 @@ -const core = require('@actions/core'); -const github = require('@actions/github'); +const core = require('@actions/core') +const github = require('@actions/github') +const fs = require('fs') +const axios = require('axios'); + +run(); +async function run() { + try { + console.log(`CWD: ${process.cwd()}`) + + const filePathInput = core.getInput('filePath'); + const labelInput = core.getInput('label'); + + const filePath = getProjectInfoFilePath(filePathInput); + const file = require(filePath); -try { - const nameToGreet = core.getInput('who-to-greet'); - const label = core.getInput('label'); - console.log(`Lable: ${label}`) - console.log(`Hello ${nameToGreet}!`); - const time = (new Date()).toTimeString(); + console.log(`Label: ${labelInput}`) + console.log(`File path: ${file}`) - core.setOutput("time", time); + core.setOutput("label", labelInput); - const payload = JSON.stringify(github.context.payload, undefined, 2) + const version = getProjectVersion(filePath); - console.log(`The event payload: ${payload}`); -} catch (error) { - core.setFailed(error.message); + // the version is in semantic format, so we can split it by dot + const versionParts = version.split('.'); + // 1.2.3 => [1, 2, 3] + if (labelInput === 'major') { + + versionParts[0] = parseInt(versionParts[0]) + 1; + versionParts[1] = 0; + versionParts[2] = 0; + + } else if (labelInput == 'minor') { + + versionParts[1] = parseInt(versionParts[1]) + 1; + versionParts[2] = 0; + + } + else if (labelInput == 'patch') + versionParts[2] = parseInt(versionParts[2]) + 1; + + + // join the parts back together + const newVersion = versionParts.join('.'); + + updateProjectVersion(filePath, newVersion); + + console.log(`Old version: ${version}. New version: ${newVersion}`) + + const filePathRelatedToRoot = getProjectInfoFilePath(filePathInput, true); + await commitChanges(file, filePathRelatedToRoot); + + // console.log(`The event payload: ${payload}`); + } catch (error) { + core.setFailed(error.message); + } +} + + +// Region functions +async function commitChanges(file, filePath) { + const commitMessage = 'Commit message here'; + + let newContent = JSON.stringify(file, null, 2); + // Append a newline character to the end of the new content + newContent += '\n'; + + const githubToken = core.getInput('githubToken'); + + // Get the repository owner and name + const repoFullName = process.env.GITHUB_REPOSITORY; + const [owner, repo] = repoFullName.split('/'); + + // Get the current branch + const branch = process.env.GITHUB_REF.replace('refs/heads/', ''); + + try { + // Get the current commit SHA for the branch + const branchResponse = await axios.get( + `https://api.github.com/repos/${owner}/${repo}/branches/${branch}` + ); + + const baseTreeSha = branchResponse.data.commit.sha; + console.log(typeof file, file) + // Create a new blob with the updated content + const blobResponse = await axios.post( + `https://api.github.com/repos/${owner}/${repo}/git/blobs`, + { + content: newContent, + encoding: 'utf-8', + }, + { + headers: { + 'Accept': 'application/vnd.github.v3+json', + 'Authorization': `Bearer ${githubToken}`, + }, + } + ); + + console.log('Blob Created') + console.log('File path: ', filePath) + const newBlobSha = blobResponse.data.sha; + // Create a new tree with the updated blob + const treeResponse = await axios.post( + `https://api.github.com/repos/${owner}/${repo}/git/trees`, + { + base_tree: baseTreeSha, + tree: [ + { + path: filePath, + mode: '100644', + type: 'blob', + sha: newBlobSha, + }, + ], + }, + { + headers: { + 'Accept': 'application/vnd.github+json', + 'Authorization': `Bearer ${githubToken}` + }, + } + ); + + console.log('Tree Created') + const newTreeSha = treeResponse.data.sha; + + // Create a new commit + const commitResponse = await axios.post( + `https://api.github.com/repos/${owner}/${repo}/git/commits`, + { + message: commitMessage, + tree: newTreeSha, + parents: [baseTreeSha], + }, + { + headers: { + 'Accept': 'application/vnd.github+json', + 'Authorization': `Bearer ${githubToken}`, + }, + } + ); + + console.log('Commit Created') + const newCommitSha = commitResponse.data.sha; + + // Update the branch reference + await axios.patch( + `https://api.github.com/repos/${owner}/${repo}/git/refs/heads/${branch}`, + { + sha: newCommitSha, + }, + { + headers: { + 'Accept': 'application/vnd.github+json', + 'Authorization': `Bearer ${githubToken}`, + }, + } + ); + console.log('Branch Updated') + } catch (error) { + core.setFailed(error); + + } +} + +function getProjectInfoFilePath(filePath, relativeToRoot = false) { + if (filePath == null || filePath == undefined || filePath == '') { + // List files inside the root directory of the repository + const files = fs.readdirSync(process.cwd()); + // Return the first file that matches .csproj or package.json + const projectInfoFile = files.find(file => file.match(/\.csproj|package\.json/)); + return relativeToRoot ? projectInfoFile : `${process.cwd()}/${projectInfoFile}`; + } + else + return relativeToRoot ? filePath : `${process.cwd()}/${filePath}`; +} +function getProjectVersion(filePath) { + const projectInfoFile = require(filePath); + + // Update the version if the file is .csproj + if (filePath.match(/\.csproj/)) + return projectInfoFile.Project.PropertyGroup[0].Version; + else if (filePath.match(/package\.json/)) + return projectInfoFile.version; + +} +function updateProjectVersion(filePath, newVersion) { + + const projectInfoFile = require(filePath); + + // Update the version if the file is .csproj + if (filePath.match(/\.csproj/)) + projectInfoFile.Project.PropertyGroup[0].Version = newVersion; + else if (filePath.match(/package\.json/)) + projectInfoFile.version = newVersion; } diff --git a/package-lock.json b/package-lock.json index 0d9a52b..adac13d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,13 @@ "license": "ISC", "dependencies": { "@actions/core": "^1.10.0", - "@actions/github": "^5.1.1" + "@actions/github": "^5.1.1", + "@actions/io": "^1.1.3", + "axios": "^1.5.0", + "xml2js": "^0.6.2" + }, + "devDependencies": { + "@types/node": "^20.6.2" } }, "node_modules/@actions/core": { @@ -41,6 +47,11 @@ "tunnel": "^0.0.6" } }, + "node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==" + }, "node_modules/@octokit/auth-token": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", @@ -142,16 +153,88 @@ "@octokit/openapi-types": "^12.11.0" } }, + "node_modules/@types/node": { + "version": "20.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz", + "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/deprecation": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", @@ -160,6 +243,25 @@ "node": ">=0.10.0" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -187,6 +289,16 @@ "wrappy": "1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -231,6 +343,26 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } } } } diff --git a/package.json b/package.json index 92a599d..e12b423 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docker-container-action", - "version": "1.0.0", + "version": "1.6.0", "description": "This action prints \"Hello World\" or \"Hello\" + the name of a person to greet to the log.", "main": "index.js", "scripts": { @@ -11,6 +11,12 @@ "license": "ISC", "dependencies": { "@actions/core": "^1.10.0", - "@actions/github": "^5.1.1" + "@actions/github": "^5.1.1", + "@actions/io": "^1.1.3", + "axios": "^1.5.0", + "xml2js": "^0.6.2" + }, + "devDependencies": { + "@types/node": "^20.6.2" } }