Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor git-push-service action #1767

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 0 additions & 82 deletions git-push-service/src/application.ts

This file was deleted.

81 changes: 52 additions & 29 deletions git-push-service/src/arrange.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { promises as fs } from 'fs'
import * as core from '@actions/core'
import * as fs from 'fs/promises'
import * as io from '@actions/io'
import * as path from 'path'
import { Application, generateApplicationManifest } from './application.js'
import * as yaml from 'js-yaml'

type Inputs = {
workspace: string
Expand All @@ -13,48 +13,71 @@ type Inputs = {
branch: string
applicationAnnotations: string[]
destinationRepository: string
currentRef: string
currentSha: string
}

export const arrangeManifests = async (inputs: Inputs): Promise<void> => {
return await arrangeServiceManifests(inputs)
export const writeManifests = async (inputs: Inputs): Promise<void> => {
await writeServiceManifest(inputs.manifests, `${inputs.workspace}/services/${inputs.service}/generated.yaml`)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename the functions to write prefix.

await writeApplicationManifest(inputs)
}

const arrangeServiceManifests = async (inputs: Inputs): Promise<void> => {
core.info(`arrange the manifests of the service`)
await concatServiceManifests(inputs.manifests, `${inputs.workspace}/services/${inputs.service}/generated.yaml`)
const writeServiceManifest = async (sourcePaths: string[], destinationPath: string) => {
const sourceContents = await Promise.all(
sourcePaths.map(async (manifestPath) => await fs.readFile(manifestPath, 'utf-8')),
)
const concatManifest = sourceContents.join('\n---\n')
core.info(`Writing the service manifest to ${destinationPath}`)
await io.mkdirP(path.dirname(destinationPath))
await fs.writeFile(destinationPath, concatManifest)
}

await putApplicationManifest(
{
const writeApplicationManifest = async (inputs: Inputs) => {
const application = {
apiVersion: 'argoproj.io/v1alpha1',
kind: 'Application',
metadata: {
name: `${inputs.namespace}--${inputs.service}`,
namespace: 'argocd',
finalizers: ['resources-finalizer.argocd.argoproj.io'],
annotations: {
...parseApplicationAnnotations(inputs.applicationAnnotations),
'github.ref': inputs.currentRef,
'github.sha': inputs.currentSha,
'github.action': 'git-push-service',
},
},
Comment on lines +43 to +48
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from:

const applicationAnnotations = [
...inputs.applicationAnnotations,
`github.ref=${github.context.ref}`,
`github.sha=${github.context.sha}`,
`github.action=git-push-service`,
]

spec: {
project: inputs.project,
source: {
repository: inputs.destinationRepository,
branch: inputs.branch,
repoURL: `https://github.com/${inputs.destinationRepository}.git`,
targetRevision: inputs.branch,
path: `services/${inputs.service}`,
},
destination: {
server: `https://kubernetes.default.svc`,
namespace: inputs.namespace,
},
annotations: inputs.applicationAnnotations,
syncPolicy: {
automated: {
prune: true,
},
},
},
inputs.workspace,
)
}
}

Comment on lines +36 to +67
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from:

const application: KubernetesApplication = {
apiVersion: 'argoproj.io/v1alpha1',
kind: 'Application',
metadata: {
name: a.name,
namespace: 'argocd',
finalizers: ['resources-finalizer.argocd.argoproj.io'],
},
spec: {
project: a.project,
source: {
repoURL: `https://github.com/${a.source.repository}.git`,
targetRevision: a.source.branch,
path: a.source.path,
},
destination: {
server: `https://kubernetes.default.svc`,
namespace: a.destination.namespace,
},
syncPolicy: {
automated: {
prune: true,
},
},
},
}

const concatServiceManifests = async (manifestPaths: string[], destinationPath: string) => {
const manifestContents = await Promise.all(
manifestPaths.map(async (manifestPath) => (await fs.readFile(manifestPath)).toString()),
)
const concatManifest = manifestContents.join('\n---\n')
core.info(`writing to ${destinationPath}`)
await io.mkdirP(path.dirname(destinationPath))
await fs.writeFile(destinationPath, concatManifest)
await io.mkdirP(`${inputs.workspace}/applications`)
const destination = `${inputs.workspace}/applications/${application.metadata.name}.yaml`
core.info(`Writing the application manifest to ${destination}`)
await fs.writeFile(destination, yaml.dump(application))
}

const putApplicationManifest = async (application: Application, workspace: string) => {
await io.mkdirP(`${workspace}/applications`)
const destination = `${workspace}/applications/${application.name}.yaml`
core.info(`writing to ${destination}`)
const content = generateApplicationManifest(application)
await fs.writeFile(destination, content)
const parseApplicationAnnotations = (applicationAnnotations: string[]): Record<string, string> => {
const r: Record<string, string> = {}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from:

if (a.annotations.length > 0) {
const annotations: { [_: string]: string } = {}
for (const s of a.annotations) {
const k = s.substring(0, s.indexOf('='))
const v = s.substring(s.indexOf('=') + 1)
annotations[k] = v
}
application.metadata.annotations = annotations
}

for (const s of applicationAnnotations) {
const k = s.substring(0, s.indexOf('='))
const v = s.substring(s.indexOf('=') + 1)
r[k] = v
}
return r
}
31 changes: 13 additions & 18 deletions git-push-service/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as core from '@actions/core'
import * as github from '@actions/github'
import * as git from './git.js'
import * as glob from '@actions/glob'
import { arrangeManifests } from './arrange.js'
import { writeManifests } from './arrange.js'
import { retry } from './retry.js'
import { updateBranchByPullRequest } from './pull.js'

Expand Down Expand Up @@ -54,7 +54,7 @@ export const run = async (inputs: Inputs): Promise<Outputs> => {

const push = async (manifests: string[], inputs: Inputs): Promise<Outputs | Error> => {
const workspace = await fs.mkdtemp(path.join(os.tmpdir(), 'git-push-service-action-'))
core.info(`created workspace at ${workspace}`)
core.info(`Created a workspace at ${workspace}`)

const [owner, repo] = inputs.destinationRepository.split('/')
const project = github.context.repo.repo
Expand All @@ -63,42 +63,37 @@ const push = async (manifests: string[], inputs: Inputs): Promise<Outputs | Erro
branch = inputs.destinationBranch
}

core.startGroup(`checkout branch ${branch} if exist`)
core.startGroup(`Checking out the branch ${branch} if exist`)
await git.init(workspace, owner, repo, inputs.token)
const branchNotExist = (await git.checkoutIfExist(workspace, branch)) > 0
core.endGroup()

const applicationAnnotations = [
...inputs.applicationAnnotations,
`github.ref=${github.context.ref}`,
`github.sha=${github.context.sha}`,
`github.action=git-push-service`,
]

core.startGroup(`arrange manifests into workspace ${workspace}`)
await arrangeManifests({
core.startGroup(`Writing the manifests into workspace ${workspace}`)
await writeManifests({
workspace,
manifests,
service: inputs.service,
namespace: inputs.namespace,
project,
branch,
applicationAnnotations,
applicationAnnotations: inputs.applicationAnnotations,
destinationRepository: inputs.destinationRepository,
currentRef: github.context.ref,
currentSha: github.context.sha,
})
core.endGroup()

const status = await git.status(workspace)
if (status === '') {
core.info('nothing to commit')
core.info('Nothing to commit')
return {}
}
const message = `Deploy ${project}/${inputs.namespace}/${inputs.service}\n\n${commitMessageFooter}`
core.summary.addHeading(`Deploy ${project}/${inputs.namespace}/${inputs.service}`)
await core.group(`create a commit`, () => git.commit(workspace, message))
await core.group(`Creating a commit`, () => git.commit(workspace, message))

if (!inputs.updateViaPullRequest) {
const code = await core.group(`push branch ${branch}`, () => git.pushByFastForward(workspace, branch))
const code = await core.group(`Pushing the branch ${branch}`, () => git.pushByFastForward(workspace, branch))
if (code > 0) {
return new Error(`failed to push branch ${branch} by fast-forward`)
}
Expand All @@ -108,7 +103,7 @@ const push = async (manifests: string[], inputs: Inputs): Promise<Outputs | Erro
}

if (branchNotExist) {
const code = await core.group(`push a new branch ${branch}`, () => git.pushByFastForward(workspace, branch))
const code = await core.group(`Pushing a new branch ${branch}`, () => git.pushByFastForward(workspace, branch))
if (code > 0) {
return new Error(`failed to push a new branch ${branch} by fast-forward`)
}
Expand All @@ -117,7 +112,7 @@ const push = async (manifests: string[], inputs: Inputs): Promise<Outputs | Erro
return {}
}

core.info(`updating branch ${branch} by a pull request`)
core.info(`Updating branch ${branch} by a pull request`)
return await updateBranchByPullRequest({
owner,
repo,
Expand Down
33 changes: 21 additions & 12 deletions git-push-service/tests/arrange.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import * as os from 'os'
import { promises as fs } from 'fs'
import * as fs from 'fs/promises'
import * as path from 'path'
import { arrangeManifests } from '../src/arrange.js'
import { writeManifests } from '../src/arrange.js'

const readContent = async (f: string) => (await fs.readFile(f)).toString()
const readContent = async (f: string) => await fs.readFile(f, 'utf-8')

test('arrange a service manifest', async () => {
it('writes the service and application manifests', async () => {
const workspace = await fs.mkdtemp(path.join(os.tmpdir(), 'git-push-action-'))

await arrangeManifests({
await writeManifests({
workspace,
manifests: [path.join(__dirname, `fixtures/a/generated.yaml`)],
branch: `ns/project/overlay/namespace`,
namespace: 'namespace',
service: 'a',
project: 'project',
applicationAnnotations: ['github.ref=refs/heads/main'],
applicationAnnotations: ['example=foo'],
destinationRepository: 'octocat/manifests',
currentRef: 'refs/heads/main',
currentSha: '1234567890abcdef',
})

expect(await readContent(path.join(workspace, `applications/namespace--a.yaml`))).toBe(applicationA)
Expand All @@ -25,18 +27,20 @@ test('arrange a service manifest', async () => {
)
})

it('should concatenate service manifests if multiple are given', async () => {
it('concatenates the service manifests if multiple are given', async () => {
const workspace = await fs.mkdtemp(path.join(os.tmpdir(), 'git-push-action-'))

await arrangeManifests({
await writeManifests({
workspace,
manifests: [path.join(__dirname, `fixtures/a/generated.yaml`), path.join(__dirname, `fixtures/b/generated.yaml`)],
branch: `ns/project/overlay/namespace`,
namespace: 'namespace',
service: 'service',
project: 'project',
applicationAnnotations: ['github.ref=refs/heads/main'],
applicationAnnotations: ['example=foo'],
destinationRepository: 'octocat/manifests',
currentRef: 'refs/heads/main',
currentSha: '1234567890abcdef',
})

expect(await readContent(path.join(workspace, `services/service/generated.yaml`))).toBe(`\
Expand All @@ -45,7 +49,7 @@ ${await readContent(path.join(__dirname, `fixtures/a/generated.yaml`))}
${await readContent(path.join(__dirname, `fixtures/b/generated.yaml`))}`)
})

test('overwrite even if a file exists', async () => {
it('overwrites if a file exists', async () => {
const workspace = await fs.mkdtemp(path.join(os.tmpdir(), 'git-push-action-'))

// put dummy files
Expand All @@ -55,15 +59,17 @@ test('overwrite even if a file exists', async () => {
await fs.mkdir(path.join(workspace, `services/a`))
await fs.writeFile(path.join(workspace, `services/a/generated.yaml`), 'fixture-generated-manifest')

await arrangeManifests({
await writeManifests({
workspace,
manifests: [path.join(__dirname, `fixtures/a/generated.yaml`)],
branch: `ns/project/overlay/namespace`,
namespace: 'namespace',
service: 'a',
project: 'project',
applicationAnnotations: ['github.ref=refs/heads/main'],
applicationAnnotations: ['example=foo'],
destinationRepository: 'octocat/manifests',
currentRef: 'refs/heads/main',
currentSha: '1234567890abcdef',
})

expect(await readContent(path.join(workspace, `applications/namespace--a.yaml`))).toBe(applicationA)
Expand All @@ -81,7 +87,10 @@ metadata:
finalizers:
- resources-finalizer.argocd.argoproj.io
annotations:
example: foo
github.ref: refs/heads/main
github.sha: 1234567890abcdef
github.action: git-push-service
spec:
project: project
source:
Expand Down
Loading