Skip to content

Commit

Permalink
Option to add a timestamp to branch-based image tags
Browse files Browse the repository at this point in the history
If `useBranchTimestamp` is true, adds a ms timestamp suffix to
branch-based image tag names. Used to sort images for gitops.
  • Loading branch information
brew committed Jun 3, 2021
1 parent 51dc8f1 commit 7d3b34d
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 45 deletions.
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ steps:
## Inputs
| Name | Description | Required |
|------------|-----------------------------------------------------------------------------------------|----------|
| image | Docker image name | Yes |
| tag | Docker image tag (see [Tagging the image with GitOps](#tagging-the-image-using-gitops)) | No |
| registry | Docker registry host | Yes |
| dockerfile | Location of Dockerfile (defaults to `Dockerfile`) | No |
| buildArgs | Docker build arguments in format `KEY=VALUE,KEY=VALUE` | No |
| username | Docker registry username | No |
| password | Docker registry password or token | No |
| Name | Description | Required |
|--------------------|-----------------------------------------------------------------------------------------|----------|
| image | Docker image name | Yes |
| tag | Docker image tag (see [Tagging the image with GitOps](#tagging-the-image-using-gitops)) | No |
| registry | Docker registry host | Yes |
| dockerfile | Location of Dockerfile (defaults to `Dockerfile`) | No |
| buildArgs | Docker build arguments in format `KEY=VALUE,KEY=VALUE` | No |
| username | Docker registry username | No |
| password | Docker registry password or token | No |
| useBranchTimestamp | A boolean to determine whether to add a timestamp to branch-based tags | No |

## Examples

Expand Down Expand Up @@ -105,3 +106,5 @@ on:
```

This will tag the Docker image with only the semver part of the tag `v1.0.0`.

If `useBranchTimestamp` option is `true`, add a timestamp (ms) to branch-based image tags. Github tag-based tags are unaffected.
29 changes: 14 additions & 15 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -536,10 +536,7 @@ const isGitHubTag = ref => ref && ref.includes('refs/tags/');

const isReleaseTag = ref => ref && ref.includes('refs/tags/release/');

const isMasterBranch = ref => ref && ref === 'refs/heads/master';

const isNotMasterBranch = ref =>
ref && ref.includes('refs/heads/') && ref !== 'refs/heads/master';
const isBranch = ref => ref && ref.includes('refs/heads/');

const createBuildCommand = (dockerfile, imageName, target, buildArgs) => {
let buildCommandPrefix = `docker build -f ${dockerfile} -t ${imageName}`;
Expand All @@ -554,7 +551,7 @@ const createBuildCommand = (dockerfile, imageName, target, buildArgs) => {
return `${buildCommandPrefix} .`;
};

const createTag = () => {
const createTag = useBranchTimestamp => {
core.info('Creating Docker image tag...');
const { sha } = context;
const ref = context.ref.toLowerCase();
Expand All @@ -569,17 +566,18 @@ const createTag = () => {
// If GitHub tag exists, use it as the Docker tag
dockerTag = ref.replace('refs/tags/', '');
}
} else if (isMasterBranch(ref)) {
// If we're on the master branch, use master-{GIT_SHORT_SHA} as the Docker tag
dockerTag = `master-${shortSha}`;
} else if (isNotMasterBranch(ref)) {
// If we're on a non-master branch, use branch-prefix-{GIT_SHORT_SHA) as the Docker tag
} else if (isBranch(ref)) {
// If we're not building a tag, use branch-prefix-{GIT_SHORT_SHA) as the Docker tag
// refs/heads/jira-123/feature/something
const branchName = ref.replace('refs/heads/', '');
const branchPrefix = branchName.includes('/')
? branchName.substring(0, branchName.indexOf('/'))
: branchName;
dockerTag = `${branchPrefix}-${shortSha}`;
const safeBranchName = branchName
.replace(/[^\w.-]+/g, '-')
.replace(/^[^\w]+/, '')
.substring(0, 120);
dockerTag = `${safeBranchName}-${shortSha}`;
if (useBranchTimestamp) {
dockerTag = `${dockerTag}-${Date.now()}`;
}
} else {
core.setFailed(
'Unsupported GitHub event - only supports push https://help.github.com/en/articles/events-that-trigger-workflows#push-event-push',
Expand Down Expand Up @@ -1618,7 +1616,8 @@ const run = () => {
// Get GitHub Action inputs
const image = core.getInput('image', { required: true });
const registry = core.getInput('registry', { required: true });
const tag = core.getInput('tag') || docker.createTag();
const useBranchTimestamp = core.getInput('useBranchTimestamp') || false;
const tag = core.getInput('tag') || docker.createTag(useBranchTimestamp);
const buildArgs = processBuildArgsInput(core.getInput('buildArgs'));
const target = core.getInput('target') || false;

Expand Down
3 changes: 2 additions & 1 deletion src/docker-build-push.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const run = () => {
// Get GitHub Action inputs
const image = core.getInput('image', { required: true });
const registry = core.getInput('registry', { required: true });
const tag = core.getInput('tag') || docker.createTag();
const useBranchTimestamp = core.getInput('useBranchTimestamp') || false;
const tag = core.getInput('tag') || docker.createTag(useBranchTimestamp);
const buildArgs = processBuildArgsInput(core.getInput('buildArgs'));
const target = core.getInput('target') || false;

Expand Down
26 changes: 12 additions & 14 deletions src/docker.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ const isGitHubTag = ref => ref && ref.includes('refs/tags/');

const isReleaseTag = ref => ref && ref.includes('refs/tags/release/');

const isMasterBranch = ref => ref && ref === 'refs/heads/master';

const isNotMasterBranch = ref =>
ref && ref.includes('refs/heads/') && ref !== 'refs/heads/master';
const isBranch = ref => ref && ref.includes('refs/heads/');

const createBuildCommand = (dockerfile, imageName, target, buildArgs) => {
let buildCommandPrefix = `docker build -f ${dockerfile} -t ${imageName}`;
Expand All @@ -26,7 +23,7 @@ const createBuildCommand = (dockerfile, imageName, target, buildArgs) => {
return `${buildCommandPrefix} .`;
};

const createTag = () => {
const createTag = useBranchTimestamp => {
core.info('Creating Docker image tag...');
const { sha } = context;
const ref = context.ref.toLowerCase();
Expand All @@ -41,17 +38,18 @@ const createTag = () => {
// If GitHub tag exists, use it as the Docker tag
dockerTag = ref.replace('refs/tags/', '');
}
} else if (isMasterBranch(ref)) {
// If we're on the master branch, use master-{GIT_SHORT_SHA} as the Docker tag
dockerTag = `master-${shortSha}`;
} else if (isNotMasterBranch(ref)) {
// If we're on a non-master branch, use branch-prefix-{GIT_SHORT_SHA) as the Docker tag
} else if (isBranch(ref)) {
// If we're not building a tag, use branch-prefix-{GIT_SHORT_SHA) as the Docker tag
// refs/heads/jira-123/feature/something
const branchName = ref.replace('refs/heads/', '');
const branchPrefix = branchName.includes('/')
? branchName.substring(0, branchName.indexOf('/'))
: branchName;
dockerTag = `${branchPrefix}-${shortSha}`;
const safeBranchName = branchName
.replace(/[^\w.-]+/g, '-')
.replace(/^[^\w]+/, '')
.substring(0, 120);
dockerTag = `${safeBranchName}-${shortSha}`;
if (useBranchTimestamp) {
dockerTag = `${dockerTag}-${Date.now()}`;
}
} else {
core.setFailed(
'Unsupported GitHub event - only supports push https://help.github.com/en/articles/events-that-trigger-workflows#push-event-push',
Expand Down
37 changes: 32 additions & 5 deletions tests/docker-build-push.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ beforeAll(() => {
docker.push = jest.fn();
});

const mockInputs = (image, registry, tag, buildArgs, target, dockerfile) => {
const mockInputs = (
image,
registry,
useBranchTimestamp,
tag,
buildArgs,
target,
dockerfile,
) => {
core.getInput = jest
.fn()
.mockReturnValueOnce(image)
.mockReturnValueOnce(registry)
.mockReturnValueOnce(useBranchTimestamp)
.mockReturnValueOnce(tag)
.mockReturnValueOnce(buildArgs)
.mockReturnValueOnce(target)
Expand All @@ -29,10 +38,19 @@ describe('Create & push Docker image', () => {
const tag = 'master-1234567';
const buildArgs = '';
const dockerfile = 'Dockerfile';
const useBranchTimestamp = false;

docker.login = jest.fn();
docker.createTag = jest.fn().mockReturnValueOnce(tag);
mockInputs(image, registry, null, buildArgs, false, dockerfile);
mockInputs(
image,
registry,
useBranchTimestamp,
null,
buildArgs,
false,
dockerfile,
);
core.setOutput = jest
.fn()
.mockReturnValueOnce('imageFullName', `${registry}/${image}:${tag}`);
Expand All @@ -41,7 +59,7 @@ describe('Create & push Docker image', () => {
run();

expect(docker.createTag).toHaveBeenCalledTimes(1);
expect(core.getInput).toHaveBeenCalledTimes(6);
expect(core.getInput).toHaveBeenCalledTimes(7);
expect(core.setOutput).toHaveBeenCalledWith(
'imageFullName',
`${registry}/${image}:${tag}`,
Expand All @@ -63,10 +81,19 @@ describe('Create & push Docker image with build args', () => {
const tag = 'latest';
const buildArgs = 'VERSION=1.1.1,BUILD_DATE=2020-01-14';
const dockerfile = 'Dockerfile.custom';
const useBranchTimestamp = false;

docker.login = jest.fn();
docker.createTag = jest.fn().mockReturnValueOnce(tag);
mockInputs(image, registry, null, buildArgs, false, dockerfile);
mockInputs(
image,
registry,
useBranchTimestamp,
null,
buildArgs,
false,
dockerfile,
);
core.setOutput = jest
.fn()
.mockReturnValueOnce('imageFullName', `${registry}/${image}:${tag}`);
Expand All @@ -75,7 +102,7 @@ describe('Create & push Docker image with build args', () => {
run();

expect(docker.createTag).toHaveBeenCalledTimes(1);
expect(core.getInput).toHaveBeenCalledTimes(6);
expect(core.getInput).toHaveBeenCalledTimes(7);
expect(core.setOutput).toHaveBeenCalledWith(
'imageFullName',
`${registry}/${image}:${tag}`,
Expand Down
4 changes: 3 additions & 1 deletion tests/docker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ describe('Create Docker image tag from git ref', () => {
context.ref = 'refs/heads/jira-123/feature/some-cool-feature';
context.sha = 'f427b0b731ed7664ce4a9fba291ab25fa2e57bd3';

expect(docker.createTag()).toBe('jira-123-f427b0b');
expect(docker.createTag()).toBe(
'jira-123-feature-some-cool-feature-f427b0b',
);
});

test('Create from feature branch without Jira number', () => {
Expand Down

0 comments on commit 7d3b34d

Please sign in to comment.